aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/misc/lkdtm.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/misc/lkdtm.c')
-rw-r--r--drivers/misc/lkdtm.c107
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
56enum cname { 68enum 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
91static char* cp_name[] = { 106static 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
124static struct jprobe lkdtm; 142static struct jprobe lkdtm;
@@ -139,9 +157,10 @@ static DEFINE_SPINLOCK(lock_me_up);
139 157
140static u8 data_area[EXEC_SIZE]; 158static u8 data_area[EXEC_SIZE];
141 159
160static const unsigned long rodata = 0xAA55AA55;
161
142module_param(recur_count, int, 0644); 162module_param(recur_count, int, 0644);
143MODULE_PARM_DESC(recur_count, " Recursion level for the stack overflow test, "\ 163MODULE_PARM_DESC(recur_count, " Recursion level for the stack overflow test");
144 "default is 10");
145module_param(cpoint_name, charp, 0444); 164module_param(cpoint_name, charp, 0444);
146MODULE_PARM_DESC(cpoint_name, " Crash Point, where kernel is to be crashed"); 165MODULE_PARM_DESC(cpoint_name, " Crash Point, where kernel is to be crashed");
147module_param(cpoint_type, charp, 0444); 166module_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
283static int recursive_loop(int a) 302static 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
295static void do_nothing(void) 314static void do_nothing(void)
@@ -297,6 +316,14 @@ static void do_nothing(void)
297 return; 316 return;
298} 317}
299 318
319static 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
300static void execute_location(void *dst) 327static 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
335static 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
308static void lkdtm_do_action(enum ctype which) 344static 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;