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 @@  #include <scsi/scsi_cmnd.h>  #include <linux/debugfs.h>  #include <linux/vmalloc.h> +#include <linux/mman.h>  #ifdef CONFIG_IDE  #include <linux/ide.h>  #endif +/* + * Make sure our attempts to over run the kernel stack doesn't trigger + * a compiler warning when CONFIG_FRAME_WARN is set. Then make sure we + * recurse past the end of THREAD_SIZE by default. + */ +#if defined(CONFIG_FRAME_WARN) && (CONFIG_FRAME_WARN > 0) +#define REC_STACK_SIZE (CONFIG_FRAME_WARN / 2) +#else +#define REC_STACK_SIZE (THREAD_SIZE / 8) +#endif +#define REC_NUM_DEFAULT ((THREAD_SIZE / REC_STACK_SIZE) * 2) +  #define DEFAULT_COUNT 10 -#define REC_NUM_DEFAULT 10  #define EXEC_SIZE 64  enum cname { @@ -86,6 +98,9 @@ enum ctype {  	CT_EXEC_STACK,  	CT_EXEC_KMALLOC,  	CT_EXEC_VMALLOC, +	CT_EXEC_USERSPACE, +	CT_ACCESS_USERSPACE, +	CT_WRITE_RO,  };  static char* cp_name[] = { @@ -119,6 +134,9 @@ static char* cp_type[] = {  	"EXEC_STACK",  	"EXEC_KMALLOC",  	"EXEC_VMALLOC", +	"EXEC_USERSPACE", +	"ACCESS_USERSPACE", +	"WRITE_RO",  };  static struct jprobe lkdtm; @@ -139,9 +157,10 @@ static DEFINE_SPINLOCK(lock_me_up);  static u8 data_area[EXEC_SIZE]; +static const unsigned long rodata = 0xAA55AA55; +  module_param(recur_count, int, 0644); -MODULE_PARM_DESC(recur_count, " Recursion level for the stack overflow test, "\ -				 "default is 10"); +MODULE_PARM_DESC(recur_count, " Recursion level for the stack overflow test");  module_param(cpoint_name, charp, 0444);  MODULE_PARM_DESC(cpoint_name, " Crash Point, where kernel is to be crashed");  module_param(cpoint_type, charp, 0444); @@ -280,16 +299,16 @@ static int lkdtm_parse_commandline(void)  	return -EINVAL;  } -static int recursive_loop(int a) +static int recursive_loop(int remaining)  { -	char buf[1024]; +	char buf[REC_STACK_SIZE]; -	memset(buf,0xFF,1024); -	recur_count--; -	if (!recur_count) +	/* Make sure compiler does not optimize this away. */ +	memset(buf, (remaining & 0xff) | 0x1, REC_STACK_SIZE); +	if (!remaining)  		return 0;  	else -        	return recursive_loop(a); +		return recursive_loop(remaining - 1);  }  static void do_nothing(void) @@ -297,6 +316,14 @@ static void do_nothing(void)  	return;  } +static noinline void corrupt_stack(void) +{ +	/* Use default char array length that triggers stack protection. */ +	char data[8]; + +	memset((void *)data, 0, 64); +} +  static void execute_location(void *dst)  {  	void (*func)(void) = dst; @@ -305,6 +332,15 @@ static void execute_location(void *dst)  	func();  } +static void execute_user_location(void *dst) +{ +	void (*func)(void) = dst; + +	if (copy_to_user(dst, do_nothing, EXEC_SIZE)) +		return; +	func(); +} +  static void lkdtm_do_action(enum ctype which)  {  	switch (which) { @@ -325,15 +361,11 @@ static void lkdtm_do_action(enum ctype which)  			;  		break;  	case CT_OVERFLOW: -		(void) recursive_loop(0); +		(void) recursive_loop(recur_count);  		break; -	case CT_CORRUPT_STACK: { -		/* Make sure the compiler creates and uses an 8 char array. */ -		volatile char data[8]; - -		memset((void *)data, 0, 64); +	case CT_CORRUPT_STACK: +		corrupt_stack();  		break; -	}  	case CT_UNALIGNED_LOAD_STORE_WRITE: {  		static u8 data[5] __attribute__((aligned(4))) = {1, 2,  				3, 4, 5}; @@ -401,6 +433,49 @@ static void lkdtm_do_action(enum ctype which)  		vfree(vmalloc_area);  		break;  	} +	case CT_EXEC_USERSPACE: { +		unsigned long user_addr; + +		user_addr = vm_mmap(NULL, 0, PAGE_SIZE, +				    PROT_READ | PROT_WRITE | PROT_EXEC, +				    MAP_ANONYMOUS | MAP_PRIVATE, 0); +		if (user_addr >= TASK_SIZE) { +			pr_warn("Failed to allocate user memory\n"); +			return; +		} +		execute_user_location((void *)user_addr); +		vm_munmap(user_addr, PAGE_SIZE); +		break; +	} +	case CT_ACCESS_USERSPACE: { +		unsigned long user_addr, tmp; +		unsigned long *ptr; + +		user_addr = vm_mmap(NULL, 0, PAGE_SIZE, +				    PROT_READ | PROT_WRITE | PROT_EXEC, +				    MAP_ANONYMOUS | MAP_PRIVATE, 0); +		if (user_addr >= TASK_SIZE) { +			pr_warn("Failed to allocate user memory\n"); +			return; +		} + +		ptr = (unsigned long *)user_addr; +		tmp = *ptr; +		tmp += 0xc0dec0de; +		*ptr = tmp; + +		vm_munmap(user_addr, PAGE_SIZE); + +		break; +	} +	case CT_WRITE_RO: { +		unsigned long *ptr; + +		ptr = (unsigned long *)&rodata; +		*ptr ^= 0xabcd1234; + +		break; +	}  	case CT_NONE:  	default:  		break;  | 
