diff options
Diffstat (limited to 'drivers/misc/lkdtm.c')
-rw-r--r-- | drivers/misc/lkdtm.c | 107 |
1 files changed, 91 insertions, 16 deletions
diff --git a/drivers/misc/lkdtm.c b/drivers/misc/lkdtm.c index 2fc0586ce3bb..a2edb2ee0921 100644 --- a/drivers/misc/lkdtm.c +++ b/drivers/misc/lkdtm.c | |||
@@ -44,13 +44,25 @@ | |||
44 | #include <scsi/scsi_cmnd.h> | 44 | #include <scsi/scsi_cmnd.h> |
45 | #include <linux/debugfs.h> | 45 | #include <linux/debugfs.h> |
46 | #include <linux/vmalloc.h> | 46 | #include <linux/vmalloc.h> |
47 | #include <linux/mman.h> | ||
47 | 48 | ||
48 | #ifdef CONFIG_IDE | 49 | #ifdef CONFIG_IDE |
49 | #include <linux/ide.h> | 50 | #include <linux/ide.h> |
50 | #endif | 51 | #endif |
51 | 52 | ||
53 | /* | ||
54 | * Make sure our attempts to over run the kernel stack doesn't trigger | ||
55 | * a compiler warning when CONFIG_FRAME_WARN is set. Then make sure we | ||
56 | * recurse past the end of THREAD_SIZE by default. | ||
57 | */ | ||
58 | #if defined(CONFIG_FRAME_WARN) && (CONFIG_FRAME_WARN > 0) | ||
59 | #define REC_STACK_SIZE (CONFIG_FRAME_WARN / 2) | ||
60 | #else | ||
61 | #define REC_STACK_SIZE (THREAD_SIZE / 8) | ||
62 | #endif | ||
63 | #define REC_NUM_DEFAULT ((THREAD_SIZE / REC_STACK_SIZE) * 2) | ||
64 | |||
52 | #define DEFAULT_COUNT 10 | 65 | #define DEFAULT_COUNT 10 |
53 | #define REC_NUM_DEFAULT 10 | ||
54 | #define EXEC_SIZE 64 | 66 | #define EXEC_SIZE 64 |
55 | 67 | ||
56 | enum cname { | 68 | enum cname { |
@@ -86,6 +98,9 @@ enum ctype { | |||
86 | CT_EXEC_STACK, | 98 | CT_EXEC_STACK, |
87 | CT_EXEC_KMALLOC, | 99 | CT_EXEC_KMALLOC, |
88 | CT_EXEC_VMALLOC, | 100 | CT_EXEC_VMALLOC, |
101 | CT_EXEC_USERSPACE, | ||
102 | CT_ACCESS_USERSPACE, | ||
103 | CT_WRITE_RO, | ||
89 | }; | 104 | }; |
90 | 105 | ||
91 | static char* cp_name[] = { | 106 | static char* cp_name[] = { |
@@ -119,6 +134,9 @@ static char* cp_type[] = { | |||
119 | "EXEC_STACK", | 134 | "EXEC_STACK", |
120 | "EXEC_KMALLOC", | 135 | "EXEC_KMALLOC", |
121 | "EXEC_VMALLOC", | 136 | "EXEC_VMALLOC", |
137 | "EXEC_USERSPACE", | ||
138 | "ACCESS_USERSPACE", | ||
139 | "WRITE_RO", | ||
122 | }; | 140 | }; |
123 | 141 | ||
124 | static struct jprobe lkdtm; | 142 | static struct jprobe lkdtm; |
@@ -139,9 +157,10 @@ static DEFINE_SPINLOCK(lock_me_up); | |||
139 | 157 | ||
140 | static u8 data_area[EXEC_SIZE]; | 158 | static u8 data_area[EXEC_SIZE]; |
141 | 159 | ||
160 | static const unsigned long rodata = 0xAA55AA55; | ||
161 | |||
142 | module_param(recur_count, int, 0644); | 162 | module_param(recur_count, int, 0644); |
143 | MODULE_PARM_DESC(recur_count, " Recursion level for the stack overflow test, "\ | 163 | MODULE_PARM_DESC(recur_count, " Recursion level for the stack overflow test"); |
144 | "default is 10"); | ||
145 | module_param(cpoint_name, charp, 0444); | 164 | module_param(cpoint_name, charp, 0444); |
146 | MODULE_PARM_DESC(cpoint_name, " Crash Point, where kernel is to be crashed"); | 165 | MODULE_PARM_DESC(cpoint_name, " Crash Point, where kernel is to be crashed"); |
147 | module_param(cpoint_type, charp, 0444); | 166 | module_param(cpoint_type, charp, 0444); |
@@ -280,16 +299,16 @@ static int lkdtm_parse_commandline(void) | |||
280 | return -EINVAL; | 299 | return -EINVAL; |
281 | } | 300 | } |
282 | 301 | ||
283 | static int recursive_loop(int a) | 302 | static int recursive_loop(int remaining) |
284 | { | 303 | { |
285 | char buf[1024]; | 304 | char buf[REC_STACK_SIZE]; |
286 | 305 | ||
287 | memset(buf,0xFF,1024); | 306 | /* Make sure compiler does not optimize this away. */ |
288 | recur_count--; | 307 | memset(buf, (remaining & 0xff) | 0x1, REC_STACK_SIZE); |
289 | if (!recur_count) | 308 | if (!remaining) |
290 | return 0; | 309 | return 0; |
291 | else | 310 | else |
292 | return recursive_loop(a); | 311 | return recursive_loop(remaining - 1); |
293 | } | 312 | } |
294 | 313 | ||
295 | static void do_nothing(void) | 314 | static void do_nothing(void) |
@@ -297,6 +316,14 @@ static void do_nothing(void) | |||
297 | return; | 316 | return; |
298 | } | 317 | } |
299 | 318 | ||
319 | static noinline void corrupt_stack(void) | ||
320 | { | ||
321 | /* Use default char array length that triggers stack protection. */ | ||
322 | char data[8]; | ||
323 | |||
324 | memset((void *)data, 0, 64); | ||
325 | } | ||
326 | |||
300 | static void execute_location(void *dst) | 327 | static void execute_location(void *dst) |
301 | { | 328 | { |
302 | void (*func)(void) = dst; | 329 | void (*func)(void) = dst; |
@@ -305,6 +332,15 @@ static void execute_location(void *dst) | |||
305 | func(); | 332 | func(); |
306 | } | 333 | } |
307 | 334 | ||
335 | static void execute_user_location(void *dst) | ||
336 | { | ||
337 | void (*func)(void) = dst; | ||
338 | |||
339 | if (copy_to_user(dst, do_nothing, EXEC_SIZE)) | ||
340 | return; | ||
341 | func(); | ||
342 | } | ||
343 | |||
308 | static void lkdtm_do_action(enum ctype which) | 344 | static void lkdtm_do_action(enum ctype which) |
309 | { | 345 | { |
310 | switch (which) { | 346 | switch (which) { |
@@ -325,15 +361,11 @@ static void lkdtm_do_action(enum ctype which) | |||
325 | ; | 361 | ; |
326 | break; | 362 | break; |
327 | case CT_OVERFLOW: | 363 | case CT_OVERFLOW: |
328 | (void) recursive_loop(0); | 364 | (void) recursive_loop(recur_count); |
329 | break; | 365 | break; |
330 | case CT_CORRUPT_STACK: { | 366 | case CT_CORRUPT_STACK: |
331 | /* Make sure the compiler creates and uses an 8 char array. */ | 367 | corrupt_stack(); |
332 | volatile char data[8]; | ||
333 | |||
334 | memset((void *)data, 0, 64); | ||
335 | break; | 368 | break; |
336 | } | ||
337 | case CT_UNALIGNED_LOAD_STORE_WRITE: { | 369 | case CT_UNALIGNED_LOAD_STORE_WRITE: { |
338 | static u8 data[5] __attribute__((aligned(4))) = {1, 2, | 370 | static u8 data[5] __attribute__((aligned(4))) = {1, 2, |
339 | 3, 4, 5}; | 371 | 3, 4, 5}; |
@@ -401,6 +433,49 @@ static void lkdtm_do_action(enum ctype which) | |||
401 | vfree(vmalloc_area); | 433 | vfree(vmalloc_area); |
402 | break; | 434 | break; |
403 | } | 435 | } |
436 | case CT_EXEC_USERSPACE: { | ||
437 | unsigned long user_addr; | ||
438 | |||
439 | user_addr = vm_mmap(NULL, 0, PAGE_SIZE, | ||
440 | PROT_READ | PROT_WRITE | PROT_EXEC, | ||
441 | MAP_ANONYMOUS | MAP_PRIVATE, 0); | ||
442 | if (user_addr >= TASK_SIZE) { | ||
443 | pr_warn("Failed to allocate user memory\n"); | ||
444 | return; | ||
445 | } | ||
446 | execute_user_location((void *)user_addr); | ||
447 | vm_munmap(user_addr, PAGE_SIZE); | ||
448 | break; | ||
449 | } | ||
450 | case CT_ACCESS_USERSPACE: { | ||
451 | unsigned long user_addr, tmp; | ||
452 | unsigned long *ptr; | ||
453 | |||
454 | user_addr = vm_mmap(NULL, 0, PAGE_SIZE, | ||
455 | PROT_READ | PROT_WRITE | PROT_EXEC, | ||
456 | MAP_ANONYMOUS | MAP_PRIVATE, 0); | ||
457 | if (user_addr >= TASK_SIZE) { | ||
458 | pr_warn("Failed to allocate user memory\n"); | ||
459 | return; | ||
460 | } | ||
461 | |||
462 | ptr = (unsigned long *)user_addr; | ||
463 | tmp = *ptr; | ||
464 | tmp += 0xc0dec0de; | ||
465 | *ptr = tmp; | ||
466 | |||
467 | vm_munmap(user_addr, PAGE_SIZE); | ||
468 | |||
469 | break; | ||
470 | } | ||
471 | case CT_WRITE_RO: { | ||
472 | unsigned long *ptr; | ||
473 | |||
474 | ptr = (unsigned long *)&rodata; | ||
475 | *ptr ^= 0xabcd1234; | ||
476 | |||
477 | break; | ||
478 | } | ||
404 | case CT_NONE: | 479 | case CT_NONE: |
405 | default: | 480 | default: |
406 | break; | 481 | break; |