1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * This is for all the tests relating directly to heap memory, including 4 * page allocation and slab allocations. 5 */ 6 #include "lkdtm.h" 7 #include <linux/slab.h> 8 #include <linux/vmalloc.h> 9 #include <linux/sched.h> 10 11 static struct kmem_cache *double_free_cache; 12 static struct kmem_cache *a_cache; 13 static struct kmem_cache *b_cache; 14 15 /* 16 * Using volatile here means the compiler cannot ever make assumptions 17 * about this value. This means compile-time length checks involving 18 * this variable cannot be performed; only run-time checks. 19 */ 20 static volatile int __offset = 1; 21 22 /* 23 * If there aren't guard pages, it's likely that a consecutive allocation will 24 * let us overflow into the second allocation without overwriting something real. 25 */ 26 void lkdtm_VMALLOC_LINEAR_OVERFLOW(void) 27 { 28 char *one, *two; 29 30 one = vzalloc(PAGE_SIZE); 31 two = vzalloc(PAGE_SIZE); 32 33 pr_info("Attempting vmalloc linear overflow ...\n"); 34 memset(one, 0xAA, PAGE_SIZE + __offset); 35 36 vfree(two); 37 vfree(one); 38 } 39 40 /* 41 * This tries to stay within the next largest power-of-2 kmalloc cache 42 * to avoid actually overwriting anything important if it's not detected 43 * correctly. 44 */ 45 void lkdtm_SLAB_LINEAR_OVERFLOW(void) 46 { 47 size_t len = 1020; 48 u32 *data = kmalloc(len, GFP_KERNEL); 49 if (!data) 50 return; 51 52 pr_info("Attempting slab linear overflow ...\n"); 53 data[1024 / sizeof(u32)] = 0x12345678; 54 kfree(data); 55 } 56 57 void lkdtm_WRITE_AFTER_FREE(void) 58 { 59 int *base, *again; 60 size_t len = 1024; 61 /* 62 * The slub allocator uses the first word to store the free 63 * pointer in some configurations. Use the middle of the 64 * allocation to avoid running into the freelist 65 */ 66 size_t offset = (len / sizeof(*base)) / 2; 67 68 base = kmalloc(len, GFP_KERNEL); 69 if (!base) 70 return; 71 pr_info("Allocated memory %p-%p\n", base, &base[offset * 2]); 72 pr_info("Attempting bad write to freed memory at %p\n", 73 &base[offset]); 74 kfree(base); 75 base[offset] = 0x0abcdef0; 76 /* Attempt to notice the overwrite. */ 77 again = kmalloc(len, GFP_KERNEL); 78 kfree(again); 79 if (again != base) 80 pr_info("Hmm, didn't get the same memory range.\n"); 81 } 82 83 void lkdtm_READ_AFTER_FREE(void) 84 { 85 int *base, *val, saw; 86 size_t len = 1024; 87 /* 88 * The slub allocator will use the either the first word or 89 * the middle of the allocation to store the free pointer, 90 * depending on configurations. Store in the second word to 91 * avoid running into the freelist. 92 */ 93 size_t offset = sizeof(*base); 94 95 base = kmalloc(len, GFP_KERNEL); 96 if (!base) { 97 pr_info("Unable to allocate base memory.\n"); 98 return; 99 } 100 101 val = kmalloc(len, GFP_KERNEL); 102 if (!val) { 103 pr_info("Unable to allocate val memory.\n"); 104 kfree(base); 105 return; 106 } 107 108 *val = 0x12345678; 109 base[offset] = *val; 110 pr_info("Value in memory before free: %x\n", base[offset]); 111 112 kfree(base); 113 114 pr_info("Attempting bad read from freed memory\n"); 115 saw = base[offset]; 116 if (saw != *val) { 117 /* Good! Poisoning happened, so declare a win. */ 118 pr_info("Memory correctly poisoned (%x)\n", saw); 119 } else { 120 pr_err("FAIL: Memory was not poisoned!\n"); 121 pr_expected_config_param(CONFIG_INIT_ON_FREE_DEFAULT_ON, "init_on_free"); 122 } 123 124 kfree(val); 125 } 126 127 void lkdtm_WRITE_BUDDY_AFTER_FREE(void) 128 { 129 unsigned long p = __get_free_page(GFP_KERNEL); 130 if (!p) { 131 pr_info("Unable to allocate free page\n"); 132 return; 133 } 134 135 pr_info("Writing to the buddy page before free\n"); 136 memset((void *)p, 0x3, PAGE_SIZE); 137 free_page(p); 138 schedule(); 139 pr_info("Attempting bad write to the buddy page after free\n"); 140 memset((void *)p, 0x78, PAGE_SIZE); 141 /* Attempt to notice the overwrite. */ 142 p = __get_free_page(GFP_KERNEL); 143 free_page(p); 144 schedule(); 145 } 146 147 void lkdtm_READ_BUDDY_AFTER_FREE(void) 148 { 149 unsigned long p = __get_free_page(GFP_KERNEL); 150 int saw, *val; 151 int *base; 152 153 if (!p) { 154 pr_info("Unable to allocate free page\n"); 155 return; 156 } 157 158 val = kmalloc(1024, GFP_KERNEL); 159 if (!val) { 160 pr_info("Unable to allocate val memory.\n"); 161 free_page(p); 162 return; 163 } 164 165 base = (int *)p; 166 167 *val = 0x12345678; 168 base[0] = *val; 169 pr_info("Value in memory before free: %x\n", base[0]); 170 free_page(p); 171 pr_info("Attempting to read from freed memory\n"); 172 saw = base[0]; 173 if (saw != *val) { 174 /* Good! Poisoning happened, so declare a win. */ 175 pr_info("Memory correctly poisoned (%x)\n", saw); 176 } else { 177 pr_err("FAIL: Buddy page was not poisoned!\n"); 178 pr_expected_config_param(CONFIG_INIT_ON_FREE_DEFAULT_ON, "init_on_free"); 179 } 180 181 kfree(val); 182 } 183 184 void lkdtm_SLAB_INIT_ON_ALLOC(void) 185 { 186 u8 *first; 187 u8 *val; 188 189 first = kmalloc(512, GFP_KERNEL); 190 if (!first) { 191 pr_info("Unable to allocate 512 bytes the first time.\n"); 192 return; 193 } 194 195 memset(first, 0xAB, 512); 196 kfree(first); 197 198 val = kmalloc(512, GFP_KERNEL); 199 if (!val) { 200 pr_info("Unable to allocate 512 bytes the second time.\n"); 201 return; 202 } 203 if (val != first) { 204 pr_warn("Reallocation missed clobbered memory.\n"); 205 } 206 207 if (memchr(val, 0xAB, 512) == NULL) { 208 pr_info("Memory appears initialized (%x, no earlier values)\n", *val); 209 } else { 210 pr_err("FAIL: Slab was not initialized\n"); 211 pr_expected_config_param(CONFIG_INIT_ON_ALLOC_DEFAULT_ON, "init_on_alloc"); 212 } 213 kfree(val); 214 } 215 216 void lkdtm_BUDDY_INIT_ON_ALLOC(void) 217 { 218 u8 *first; 219 u8 *val; 220 221 first = (u8 *)__get_free_page(GFP_KERNEL); 222 if (!first) { 223 pr_info("Unable to allocate first free page\n"); 224 return; 225 } 226 227 memset(first, 0xAB, PAGE_SIZE); 228 free_page((unsigned long)first); 229 230 val = (u8 *)__get_free_page(GFP_KERNEL); 231 if (!val) { 232 pr_info("Unable to allocate second free page\n"); 233 return; 234 } 235 236 if (val != first) { 237 pr_warn("Reallocation missed clobbered memory.\n"); 238 } 239 240 if (memchr(val, 0xAB, PAGE_SIZE) == NULL) { 241 pr_info("Memory appears initialized (%x, no earlier values)\n", *val); 242 } else { 243 pr_err("FAIL: Slab was not initialized\n"); 244 pr_expected_config_param(CONFIG_INIT_ON_ALLOC_DEFAULT_ON, "init_on_alloc"); 245 } 246 free_page((unsigned long)val); 247 } 248 249 void lkdtm_SLAB_FREE_DOUBLE(void) 250 { 251 int *val; 252 253 val = kmem_cache_alloc(double_free_cache, GFP_KERNEL); 254 if (!val) { 255 pr_info("Unable to allocate double_free_cache memory.\n"); 256 return; 257 } 258 259 /* Just make sure we got real memory. */ 260 *val = 0x12345678; 261 pr_info("Attempting double slab free ...\n"); 262 kmem_cache_free(double_free_cache, val); 263 kmem_cache_free(double_free_cache, val); 264 } 265 266 void lkdtm_SLAB_FREE_CROSS(void) 267 { 268 int *val; 269 270 val = kmem_cache_alloc(a_cache, GFP_KERNEL); 271 if (!val) { 272 pr_info("Unable to allocate a_cache memory.\n"); 273 return; 274 } 275 276 /* Just make sure we got real memory. */ 277 *val = 0x12345679; 278 pr_info("Attempting cross-cache slab free ...\n"); 279 kmem_cache_free(b_cache, val); 280 } 281 282 void lkdtm_SLAB_FREE_PAGE(void) 283 { 284 unsigned long p = __get_free_page(GFP_KERNEL); 285 286 pr_info("Attempting non-Slab slab free ...\n"); 287 kmem_cache_free(NULL, (void *)p); 288 free_page(p); 289 } 290 291 /* 292 * We have constructors to keep the caches distinctly separated without 293 * needing to boot with "slab_nomerge". 294 */ 295 static void ctor_double_free(void *region) 296 { } 297 static void ctor_a(void *region) 298 { } 299 static void ctor_b(void *region) 300 { } 301 302 void __init lkdtm_heap_init(void) 303 { 304 double_free_cache = kmem_cache_create("lkdtm-heap-double_free", 305 64, 0, 0, ctor_double_free); 306 a_cache = kmem_cache_create("lkdtm-heap-a", 64, 0, 0, ctor_a); 307 b_cache = kmem_cache_create("lkdtm-heap-b", 64, 0, 0, ctor_b); 308 } 309 310 void __exit lkdtm_heap_exit(void) 311 { 312 kmem_cache_destroy(double_free_cache); 313 kmem_cache_destroy(a_cache); 314 kmem_cache_destroy(b_cache); 315 } 316