--- zzzz-none-000/linux-3.10.107/drivers/misc/lkdtm.c 2017-06-27 09:49:32.000000000 +0000 +++ scorpion-7490-727/linux-3.10.107/drivers/misc/lkdtm.c 2021-02-04 17:41:59.000000000 +0000 @@ -30,6 +30,7 @@ * * See Documentation/fault-injection/provoke-crashes.txt for instructions */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #include #include @@ -43,13 +44,28 @@ #include #include #include +#include +#include +#include #ifdef CONFIG_IDE #include #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 { CN_INVALID, @@ -68,6 +84,7 @@ CT_NONE, CT_PANIC, CT_BUG, + CT_WARNING, CT_EXCEPTION, CT_LOOP, CT_OVERFLOW, @@ -77,7 +94,16 @@ CT_WRITE_AFTER_FREE, CT_SOFTLOCKUP, CT_HARDLOCKUP, + CT_SPINLOCKUP, CT_HUNG_TASK, + CT_EXEC_DATA, + CT_EXEC_STACK, + CT_EXEC_KMALLOC, + CT_EXEC_VMALLOC, + CT_EXEC_USERSPACE, + CT_ACCESS_USERSPACE, + CT_WRITE_RO, + CT_WRITE_KERN, }; static char* cp_name[] = { @@ -95,6 +121,7 @@ static char* cp_type[] = { "PANIC", "BUG", + "WARNING", "EXCEPTION", "LOOP", "OVERFLOW", @@ -104,7 +131,16 @@ "WRITE_AFTER_FREE", "SOFTLOCKUP", "HARDLOCKUP", + "SPINLOCKUP", "HUNG_TASK", + "EXEC_DATA", + "EXEC_STACK", + "EXEC_KMALLOC", + "EXEC_VMALLOC", + "EXEC_USERSPACE", + "ACCESS_USERSPACE", + "WRITE_RO", + "WRITE_KERN", }; static struct jprobe lkdtm; @@ -121,10 +157,14 @@ static enum ctype cptype = CT_NONE; static int count = DEFAULT_COUNT; static DEFINE_SPINLOCK(count_lock); +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); @@ -188,7 +228,7 @@ } #ifdef CONFIG_IDE -int jp_generic_ide_ioctl(ide_drive_t *drive, struct file *file, +static int jp_generic_ide_ioctl(ide_drive_t *drive, struct file *file, struct block_device *bdev, unsigned int cmd, unsigned long arg) { @@ -263,16 +303,64 @@ 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) +{ + return; +} + +/* Must immediately follow do_nothing for size calculuations to work out. */ +static void do_overwritten(void) +{ + pr_info("do_overwritten wasn't overwritten!\n"); + 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; + + pr_info("attempting ok execution at %p\n", do_nothing); + do_nothing(); + + memcpy(dst, do_nothing, EXEC_SIZE); + flush_icache_range((unsigned long)dst, (unsigned long)dst + EXEC_SIZE); + pr_info("attempting bad execution at %p\n", func); + func(); +} + +static void execute_user_location(void *dst) +{ + /* Intentionally crossing kernel/user memory boundary. */ + void (*func)(void) = dst; + + pr_info("attempting ok execution at %p\n", do_nothing); + do_nothing(); + + if (copy_to_user((void __user *)dst, do_nothing, EXEC_SIZE)) + return; + flush_icache_range((unsigned long)dst, (unsigned long)dst + EXEC_SIZE); + pr_info("attempting bad execution at %p\n", func); + func(); } static void lkdtm_do_action(enum ctype which) @@ -284,6 +372,9 @@ case CT_BUG: BUG(); break; + case CT_WARNING: + WARN_ON(1); + break; case CT_EXCEPTION: *((int *) 0) = 0; break; @@ -292,15 +383,11 @@ ; break; case CT_OVERFLOW: - (void) recursive_loop(0); + (void) recursive_loop(recur_count); break; - case CT_CORRUPT_STACK: { - volatile u32 data[8]; - volatile u32 *p = data; - - p[12] = 0x12345678; + 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}; @@ -340,10 +427,107 @@ for (;;) cpu_relax(); break; + case CT_SPINLOCKUP: + /* Must be called twice to trigger. */ + spin_lock(&lock_me_up); + /* Let sparse know we intended to exit holding the lock. */ + __release(&lock_me_up); + break; case CT_HUNG_TASK: set_current_state(TASK_UNINTERRUPTIBLE); schedule(); break; + case CT_EXEC_DATA: + execute_location(data_area); + break; + case CT_EXEC_STACK: { + u8 stack_area[EXEC_SIZE]; + execute_location(stack_area); + break; + } + case CT_EXEC_KMALLOC: { + u32 *kmalloc_area = kmalloc(EXEC_SIZE, GFP_KERNEL); + execute_location(kmalloc_area); + kfree(kmalloc_area); + break; + } + case CT_EXEC_VMALLOC: { + u32 *vmalloc_area = vmalloc(EXEC_SIZE); + execute_location(vmalloc_area); + 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 = 0; + 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; + } + + if (copy_to_user((void __user *)user_addr, &tmp, sizeof(tmp))) { + pr_warn("copy_to_user failed\n"); + vm_munmap(user_addr, PAGE_SIZE); + return; + } + + ptr = (unsigned long *)user_addr; + + pr_info("attempting bad read at %p\n", ptr); + tmp = *ptr; + tmp += 0xc0dec0de; + + pr_info("attempting bad write at %p\n", ptr); + *ptr = tmp; + + vm_munmap(user_addr, PAGE_SIZE); + + break; + } + case CT_WRITE_RO: { + unsigned long *ptr; + + ptr = (unsigned long *)&rodata; + + pr_info("attempting bad write at %p\n", ptr); + *ptr ^= 0xabcd1234; + + break; + } + case CT_WRITE_KERN: { + size_t size; + unsigned char *ptr; + + size = (unsigned long)do_overwritten - + (unsigned long)do_nothing; + ptr = (unsigned char *)do_overwritten; + + pr_info("attempting bad %zu byte write at %p\n", size, ptr); + memcpy(ptr, (unsigned char *)do_nothing, size); + flush_icache_range((unsigned long)ptr, + (unsigned long)(ptr + size)); + + do_overwritten(); + break; + } case CT_NONE: default: break; @@ -358,8 +542,8 @@ spin_lock_irqsave(&count_lock, flags); count--; - printk(KERN_INFO "lkdtm: Crash point %s of type %s hit, trigger in %d rounds\n", - cp_name_to_str(cpoint), cp_type_to_str(cptype), count); + pr_info("Crash point %s of type %s hit, trigger in %d rounds\n", + cp_name_to_str(cpoint), cp_type_to_str(cptype), count); if (count == 0) { do_it = true; @@ -416,18 +600,18 @@ lkdtm.kp.symbol_name = "generic_ide_ioctl"; lkdtm.entry = (kprobe_opcode_t*) jp_generic_ide_ioctl; #else - printk(KERN_INFO "lkdtm: Crash point not available\n"); + pr_info("Crash point not available\n"); return -EINVAL; #endif break; default: - printk(KERN_INFO "lkdtm: Invalid Crash Point\n"); + pr_info("Invalid Crash Point\n"); return -EINVAL; } cpoint = which; if ((ret = register_jprobe(&lkdtm)) < 0) { - printk(KERN_INFO "lkdtm: Couldn't register jprobe\n"); + pr_info("Couldn't register jprobe\n"); cpoint = CN_INVALID; } @@ -574,8 +758,7 @@ if (type == CT_NONE) return -EINVAL; - printk(KERN_INFO "lkdtm: Performing direct entry %s\n", - cp_type_to_str(type)); + pr_info("Performing direct entry %s\n", cp_type_to_str(type)); lkdtm_do_action(type); *off += count; @@ -637,7 +820,7 @@ /* Register debugfs interface */ lkdtm_debugfs_root = debugfs_create_dir("provoke-crash", NULL); if (!lkdtm_debugfs_root) { - printk(KERN_ERR "lkdtm: creating root dir failed\n"); + pr_err("creating root dir failed\n"); return -ENODEV; } @@ -652,28 +835,26 @@ de = debugfs_create_file(cur->name, 0644, lkdtm_debugfs_root, NULL, &cur->fops); if (de == NULL) { - printk(KERN_ERR "lkdtm: could not create %s\n", - cur->name); + pr_err("could not create %s\n", cur->name); goto out_err; } } if (lkdtm_parse_commandline() == -EINVAL) { - printk(KERN_INFO "lkdtm: Invalid command\n"); + pr_info("Invalid command\n"); goto out_err; } if (cpoint != CN_INVALID && cptype != CT_NONE) { ret = lkdtm_register_cpoint(cpoint); if (ret < 0) { - printk(KERN_INFO "lkdtm: Invalid crash point %d\n", - cpoint); + pr_info("Invalid crash point %d\n", cpoint); goto out_err; } - printk(KERN_INFO "lkdtm: Crash point %s of type %s registered\n", - cpoint_name, cpoint_type); + pr_info("Crash point %s of type %s registered\n", + cpoint_name, cpoint_type); } else { - printk(KERN_INFO "lkdtm: No crash points registered, enable through debugfs\n"); + pr_info("No crash points registered, enable through debugfs\n"); } return 0; @@ -688,10 +869,11 @@ debugfs_remove_recursive(lkdtm_debugfs_root); unregister_jprobe(&lkdtm); - printk(KERN_INFO "lkdtm: Crash point unregistered\n"); + pr_info("Crash point unregistered\n"); } module_init(lkdtm_module_init); module_exit(lkdtm_module_exit); MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Kprobe module for testing crash dumps");