Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v4.8-rc7 199 lines 4.7 kB view raw
1/* 2 * This is for all the tests related to validating kernel memory 3 * permissions: non-executable regions, non-writable regions, and 4 * even non-readable regions. 5 */ 6#include "lkdtm.h" 7#include <linux/slab.h> 8#include <linux/vmalloc.h> 9#include <linux/mman.h> 10#include <linux/uaccess.h> 11#include <asm/cacheflush.h> 12 13/* Whether or not to fill the target memory area with do_nothing(). */ 14#define CODE_WRITE true 15#define CODE_AS_IS false 16 17/* How many bytes to copy to be sure we've copied enough of do_nothing(). */ 18#define EXEC_SIZE 64 19 20/* This is non-const, so it will end up in the .data section. */ 21static u8 data_area[EXEC_SIZE]; 22 23/* This is cost, so it will end up in the .rodata section. */ 24static const unsigned long rodata = 0xAA55AA55; 25 26/* This is marked __ro_after_init, so it should ultimately be .rodata. */ 27static unsigned long ro_after_init __ro_after_init = 0x55AA5500; 28 29/* 30 * This just returns to the caller. It is designed to be copied into 31 * non-executable memory regions. 32 */ 33static void do_nothing(void) 34{ 35 return; 36} 37 38/* Must immediately follow do_nothing for size calculuations to work out. */ 39static void do_overwritten(void) 40{ 41 pr_info("do_overwritten wasn't overwritten!\n"); 42 return; 43} 44 45static noinline void execute_location(void *dst, bool write) 46{ 47 void (*func)(void) = dst; 48 49 pr_info("attempting ok execution at %p\n", do_nothing); 50 do_nothing(); 51 52 if (write == CODE_WRITE) { 53 memcpy(dst, do_nothing, EXEC_SIZE); 54 flush_icache_range((unsigned long)dst, 55 (unsigned long)dst + EXEC_SIZE); 56 } 57 pr_info("attempting bad execution at %p\n", func); 58 func(); 59} 60 61static void execute_user_location(void *dst) 62{ 63 /* Intentionally crossing kernel/user memory boundary. */ 64 void (*func)(void) = dst; 65 66 pr_info("attempting ok execution at %p\n", do_nothing); 67 do_nothing(); 68 69 if (copy_to_user((void __user *)dst, do_nothing, EXEC_SIZE)) 70 return; 71 flush_icache_range((unsigned long)dst, (unsigned long)dst + EXEC_SIZE); 72 pr_info("attempting bad execution at %p\n", func); 73 func(); 74} 75 76void lkdtm_WRITE_RO(void) 77{ 78 /* Explicitly cast away "const" for the test. */ 79 unsigned long *ptr = (unsigned long *)&rodata; 80 81 pr_info("attempting bad rodata write at %p\n", ptr); 82 *ptr ^= 0xabcd1234; 83} 84 85void lkdtm_WRITE_RO_AFTER_INIT(void) 86{ 87 unsigned long *ptr = &ro_after_init; 88 89 /* 90 * Verify we were written to during init. Since an Oops 91 * is considered a "success", a failure is to just skip the 92 * real test. 93 */ 94 if ((*ptr & 0xAA) != 0xAA) { 95 pr_info("%p was NOT written during init!?\n", ptr); 96 return; 97 } 98 99 pr_info("attempting bad ro_after_init write at %p\n", ptr); 100 *ptr ^= 0xabcd1234; 101} 102 103void lkdtm_WRITE_KERN(void) 104{ 105 size_t size; 106 unsigned char *ptr; 107 108 size = (unsigned long)do_overwritten - (unsigned long)do_nothing; 109 ptr = (unsigned char *)do_overwritten; 110 111 pr_info("attempting bad %zu byte write at %p\n", size, ptr); 112 memcpy(ptr, (unsigned char *)do_nothing, size); 113 flush_icache_range((unsigned long)ptr, (unsigned long)(ptr + size)); 114 115 do_overwritten(); 116} 117 118void lkdtm_EXEC_DATA(void) 119{ 120 execute_location(data_area, CODE_WRITE); 121} 122 123void lkdtm_EXEC_STACK(void) 124{ 125 u8 stack_area[EXEC_SIZE]; 126 execute_location(stack_area, CODE_WRITE); 127} 128 129void lkdtm_EXEC_KMALLOC(void) 130{ 131 u32 *kmalloc_area = kmalloc(EXEC_SIZE, GFP_KERNEL); 132 execute_location(kmalloc_area, CODE_WRITE); 133 kfree(kmalloc_area); 134} 135 136void lkdtm_EXEC_VMALLOC(void) 137{ 138 u32 *vmalloc_area = vmalloc(EXEC_SIZE); 139 execute_location(vmalloc_area, CODE_WRITE); 140 vfree(vmalloc_area); 141} 142 143void lkdtm_EXEC_RODATA(void) 144{ 145 execute_location(lkdtm_rodata_do_nothing, CODE_AS_IS); 146} 147 148void lkdtm_EXEC_USERSPACE(void) 149{ 150 unsigned long user_addr; 151 152 user_addr = vm_mmap(NULL, 0, PAGE_SIZE, 153 PROT_READ | PROT_WRITE | PROT_EXEC, 154 MAP_ANONYMOUS | MAP_PRIVATE, 0); 155 if (user_addr >= TASK_SIZE) { 156 pr_warn("Failed to allocate user memory\n"); 157 return; 158 } 159 execute_user_location((void *)user_addr); 160 vm_munmap(user_addr, PAGE_SIZE); 161} 162 163void lkdtm_ACCESS_USERSPACE(void) 164{ 165 unsigned long user_addr, tmp = 0; 166 unsigned long *ptr; 167 168 user_addr = vm_mmap(NULL, 0, PAGE_SIZE, 169 PROT_READ | PROT_WRITE | PROT_EXEC, 170 MAP_ANONYMOUS | MAP_PRIVATE, 0); 171 if (user_addr >= TASK_SIZE) { 172 pr_warn("Failed to allocate user memory\n"); 173 return; 174 } 175 176 if (copy_to_user((void __user *)user_addr, &tmp, sizeof(tmp))) { 177 pr_warn("copy_to_user failed\n"); 178 vm_munmap(user_addr, PAGE_SIZE); 179 return; 180 } 181 182 ptr = (unsigned long *)user_addr; 183 184 pr_info("attempting bad read at %p\n", ptr); 185 tmp = *ptr; 186 tmp += 0xc0dec0de; 187 188 pr_info("attempting bad write at %p\n", ptr); 189 *ptr = tmp; 190 191 vm_munmap(user_addr, PAGE_SIZE); 192} 193 194void __init lkdtm_perms_init(void) 195{ 196 /* Make sure we can write to __ro_after_init values during __init */ 197 ro_after_init |= 0xAA; 198 199}