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.12-rc2 202 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 int copied; 64 65 /* Intentionally crossing kernel/user memory boundary. */ 66 void (*func)(void) = dst; 67 68 pr_info("attempting ok execution at %p\n", do_nothing); 69 do_nothing(); 70 71 copied = access_process_vm(current, (unsigned long)dst, do_nothing, 72 EXEC_SIZE, FOLL_WRITE); 73 if (copied < EXEC_SIZE) 74 return; 75 pr_info("attempting bad execution at %p\n", func); 76 func(); 77} 78 79void lkdtm_WRITE_RO(void) 80{ 81 /* Explicitly cast away "const" for the test. */ 82 unsigned long *ptr = (unsigned long *)&rodata; 83 84 pr_info("attempting bad rodata write at %p\n", ptr); 85 *ptr ^= 0xabcd1234; 86} 87 88void lkdtm_WRITE_RO_AFTER_INIT(void) 89{ 90 unsigned long *ptr = &ro_after_init; 91 92 /* 93 * Verify we were written to during init. Since an Oops 94 * is considered a "success", a failure is to just skip the 95 * real test. 96 */ 97 if ((*ptr & 0xAA) != 0xAA) { 98 pr_info("%p was NOT written during init!?\n", ptr); 99 return; 100 } 101 102 pr_info("attempting bad ro_after_init write at %p\n", ptr); 103 *ptr ^= 0xabcd1234; 104} 105 106void lkdtm_WRITE_KERN(void) 107{ 108 size_t size; 109 unsigned char *ptr; 110 111 size = (unsigned long)do_overwritten - (unsigned long)do_nothing; 112 ptr = (unsigned char *)do_overwritten; 113 114 pr_info("attempting bad %zu byte write at %p\n", size, ptr); 115 memcpy(ptr, (unsigned char *)do_nothing, size); 116 flush_icache_range((unsigned long)ptr, (unsigned long)(ptr + size)); 117 118 do_overwritten(); 119} 120 121void lkdtm_EXEC_DATA(void) 122{ 123 execute_location(data_area, CODE_WRITE); 124} 125 126void lkdtm_EXEC_STACK(void) 127{ 128 u8 stack_area[EXEC_SIZE]; 129 execute_location(stack_area, CODE_WRITE); 130} 131 132void lkdtm_EXEC_KMALLOC(void) 133{ 134 u32 *kmalloc_area = kmalloc(EXEC_SIZE, GFP_KERNEL); 135 execute_location(kmalloc_area, CODE_WRITE); 136 kfree(kmalloc_area); 137} 138 139void lkdtm_EXEC_VMALLOC(void) 140{ 141 u32 *vmalloc_area = vmalloc(EXEC_SIZE); 142 execute_location(vmalloc_area, CODE_WRITE); 143 vfree(vmalloc_area); 144} 145 146void lkdtm_EXEC_RODATA(void) 147{ 148 execute_location(lkdtm_rodata_do_nothing, CODE_AS_IS); 149} 150 151void lkdtm_EXEC_USERSPACE(void) 152{ 153 unsigned long user_addr; 154 155 user_addr = vm_mmap(NULL, 0, PAGE_SIZE, 156 PROT_READ | PROT_WRITE | PROT_EXEC, 157 MAP_ANONYMOUS | MAP_PRIVATE, 0); 158 if (user_addr >= TASK_SIZE) { 159 pr_warn("Failed to allocate user memory\n"); 160 return; 161 } 162 execute_user_location((void *)user_addr); 163 vm_munmap(user_addr, PAGE_SIZE); 164} 165 166void lkdtm_ACCESS_USERSPACE(void) 167{ 168 unsigned long user_addr, tmp = 0; 169 unsigned long *ptr; 170 171 user_addr = vm_mmap(NULL, 0, PAGE_SIZE, 172 PROT_READ | PROT_WRITE | PROT_EXEC, 173 MAP_ANONYMOUS | MAP_PRIVATE, 0); 174 if (user_addr >= TASK_SIZE) { 175 pr_warn("Failed to allocate user memory\n"); 176 return; 177 } 178 179 if (copy_to_user((void __user *)user_addr, &tmp, sizeof(tmp))) { 180 pr_warn("copy_to_user failed\n"); 181 vm_munmap(user_addr, PAGE_SIZE); 182 return; 183 } 184 185 ptr = (unsigned long *)user_addr; 186 187 pr_info("attempting bad read at %p\n", ptr); 188 tmp = *ptr; 189 tmp += 0xc0dec0de; 190 191 pr_info("attempting bad write at %p\n", ptr); 192 *ptr = tmp; 193 194 vm_munmap(user_addr, PAGE_SIZE); 195} 196 197void __init lkdtm_perms_init(void) 198{ 199 /* Make sure we can write to __ro_after_init values during __init */ 200 ro_after_init |= 0xAA; 201 202}