1039a1c42SKees Cook // SPDX-License-Identifier: GPL-2.0 2039a1c42SKees Cook /* 3039a1c42SKees Cook * This is for all the tests relating directly to heap memory, including 4039a1c42SKees Cook * page allocation and slab allocations. 5039a1c42SKees Cook */ 6039a1c42SKees Cook #include "lkdtm.h" 7039a1c42SKees Cook #include <linux/slab.h> 8039a1c42SKees Cook #include <linux/sched.h> 9039a1c42SKees Cook 10966fede8SKees Cook static struct kmem_cache *double_free_cache; 11966fede8SKees Cook static struct kmem_cache *a_cache; 12966fede8SKees Cook static struct kmem_cache *b_cache; 13966fede8SKees Cook 14039a1c42SKees Cook /* 15039a1c42SKees Cook * This tries to stay within the next largest power-of-2 kmalloc cache 16039a1c42SKees Cook * to avoid actually overwriting anything important if it's not detected 17039a1c42SKees Cook * correctly. 18039a1c42SKees Cook */ 19039a1c42SKees Cook void lkdtm_OVERWRITE_ALLOCATION(void) 20039a1c42SKees Cook { 21039a1c42SKees Cook size_t len = 1020; 22039a1c42SKees Cook u32 *data = kmalloc(len, GFP_KERNEL); 23039a1c42SKees Cook if (!data) 24039a1c42SKees Cook return; 25039a1c42SKees Cook 26039a1c42SKees Cook data[1024 / sizeof(u32)] = 0x12345678; 27039a1c42SKees Cook kfree(data); 28039a1c42SKees Cook } 29039a1c42SKees Cook 30039a1c42SKees Cook void lkdtm_WRITE_AFTER_FREE(void) 31039a1c42SKees Cook { 32039a1c42SKees Cook int *base, *again; 33039a1c42SKees Cook size_t len = 1024; 34039a1c42SKees Cook /* 35039a1c42SKees Cook * The slub allocator uses the first word to store the free 36039a1c42SKees Cook * pointer in some configurations. Use the middle of the 37039a1c42SKees Cook * allocation to avoid running into the freelist 38039a1c42SKees Cook */ 39039a1c42SKees Cook size_t offset = (len / sizeof(*base)) / 2; 40039a1c42SKees Cook 41039a1c42SKees Cook base = kmalloc(len, GFP_KERNEL); 42039a1c42SKees Cook if (!base) 43039a1c42SKees Cook return; 44039a1c42SKees Cook pr_info("Allocated memory %p-%p\n", base, &base[offset * 2]); 45039a1c42SKees Cook pr_info("Attempting bad write to freed memory at %p\n", 46039a1c42SKees Cook &base[offset]); 47039a1c42SKees Cook kfree(base); 48039a1c42SKees Cook base[offset] = 0x0abcdef0; 49039a1c42SKees Cook /* Attempt to notice the overwrite. */ 50039a1c42SKees Cook again = kmalloc(len, GFP_KERNEL); 51039a1c42SKees Cook kfree(again); 52039a1c42SKees Cook if (again != base) 53039a1c42SKees Cook pr_info("Hmm, didn't get the same memory range.\n"); 54039a1c42SKees Cook } 55039a1c42SKees Cook 56039a1c42SKees Cook void lkdtm_READ_AFTER_FREE(void) 57039a1c42SKees Cook { 58039a1c42SKees Cook int *base, *val, saw; 59039a1c42SKees Cook size_t len = 1024; 60039a1c42SKees Cook /* 61*e12145cfSKees Cook * The slub allocator will use the either the first word or 62*e12145cfSKees Cook * the middle of the allocation to store the free pointer, 63*e12145cfSKees Cook * depending on configurations. Store in the second word to 64*e12145cfSKees Cook * avoid running into the freelist. 65039a1c42SKees Cook */ 66*e12145cfSKees Cook size_t offset = sizeof(*base); 67039a1c42SKees Cook 68039a1c42SKees Cook base = kmalloc(len, GFP_KERNEL); 69039a1c42SKees Cook if (!base) { 70039a1c42SKees Cook pr_info("Unable to allocate base memory.\n"); 71039a1c42SKees Cook return; 72039a1c42SKees Cook } 73039a1c42SKees Cook 74039a1c42SKees Cook val = kmalloc(len, GFP_KERNEL); 75039a1c42SKees Cook if (!val) { 76039a1c42SKees Cook pr_info("Unable to allocate val memory.\n"); 77039a1c42SKees Cook kfree(base); 78039a1c42SKees Cook return; 79039a1c42SKees Cook } 80039a1c42SKees Cook 81039a1c42SKees Cook *val = 0x12345678; 82039a1c42SKees Cook base[offset] = *val; 83039a1c42SKees Cook pr_info("Value in memory before free: %x\n", base[offset]); 84039a1c42SKees Cook 85039a1c42SKees Cook kfree(base); 86039a1c42SKees Cook 87039a1c42SKees Cook pr_info("Attempting bad read from freed memory\n"); 88039a1c42SKees Cook saw = base[offset]; 89039a1c42SKees Cook if (saw != *val) { 90039a1c42SKees Cook /* Good! Poisoning happened, so declare a win. */ 91039a1c42SKees Cook pr_info("Memory correctly poisoned (%x)\n", saw); 92039a1c42SKees Cook BUG(); 93039a1c42SKees Cook } 94039a1c42SKees Cook pr_info("Memory was not poisoned\n"); 95039a1c42SKees Cook 96039a1c42SKees Cook kfree(val); 97039a1c42SKees Cook } 98039a1c42SKees Cook 99039a1c42SKees Cook void lkdtm_WRITE_BUDDY_AFTER_FREE(void) 100039a1c42SKees Cook { 101039a1c42SKees Cook unsigned long p = __get_free_page(GFP_KERNEL); 102039a1c42SKees Cook if (!p) { 103039a1c42SKees Cook pr_info("Unable to allocate free page\n"); 104039a1c42SKees Cook return; 105039a1c42SKees Cook } 106039a1c42SKees Cook 107039a1c42SKees Cook pr_info("Writing to the buddy page before free\n"); 108039a1c42SKees Cook memset((void *)p, 0x3, PAGE_SIZE); 109039a1c42SKees Cook free_page(p); 110039a1c42SKees Cook schedule(); 111039a1c42SKees Cook pr_info("Attempting bad write to the buddy page after free\n"); 112039a1c42SKees Cook memset((void *)p, 0x78, PAGE_SIZE); 113039a1c42SKees Cook /* Attempt to notice the overwrite. */ 114039a1c42SKees Cook p = __get_free_page(GFP_KERNEL); 115039a1c42SKees Cook free_page(p); 116039a1c42SKees Cook schedule(); 117039a1c42SKees Cook } 118039a1c42SKees Cook 119039a1c42SKees Cook void lkdtm_READ_BUDDY_AFTER_FREE(void) 120039a1c42SKees Cook { 121039a1c42SKees Cook unsigned long p = __get_free_page(GFP_KERNEL); 122039a1c42SKees Cook int saw, *val; 123039a1c42SKees Cook int *base; 124039a1c42SKees Cook 125039a1c42SKees Cook if (!p) { 126039a1c42SKees Cook pr_info("Unable to allocate free page\n"); 127039a1c42SKees Cook return; 128039a1c42SKees Cook } 129039a1c42SKees Cook 130039a1c42SKees Cook val = kmalloc(1024, GFP_KERNEL); 131039a1c42SKees Cook if (!val) { 132039a1c42SKees Cook pr_info("Unable to allocate val memory.\n"); 133039a1c42SKees Cook free_page(p); 134039a1c42SKees Cook return; 135039a1c42SKees Cook } 136039a1c42SKees Cook 137039a1c42SKees Cook base = (int *)p; 138039a1c42SKees Cook 139039a1c42SKees Cook *val = 0x12345678; 140039a1c42SKees Cook base[0] = *val; 141039a1c42SKees Cook pr_info("Value in memory before free: %x\n", base[0]); 142039a1c42SKees Cook free_page(p); 143039a1c42SKees Cook pr_info("Attempting to read from freed memory\n"); 144039a1c42SKees Cook saw = base[0]; 145039a1c42SKees Cook if (saw != *val) { 146039a1c42SKees Cook /* Good! Poisoning happened, so declare a win. */ 147039a1c42SKees Cook pr_info("Memory correctly poisoned (%x)\n", saw); 148039a1c42SKees Cook BUG(); 149039a1c42SKees Cook } 150039a1c42SKees Cook pr_info("Buddy page was not poisoned\n"); 151039a1c42SKees Cook 152039a1c42SKees Cook kfree(val); 153039a1c42SKees Cook } 154966fede8SKees Cook 155966fede8SKees Cook void lkdtm_SLAB_FREE_DOUBLE(void) 156966fede8SKees Cook { 157966fede8SKees Cook int *val; 158966fede8SKees Cook 159966fede8SKees Cook val = kmem_cache_alloc(double_free_cache, GFP_KERNEL); 160966fede8SKees Cook if (!val) { 161966fede8SKees Cook pr_info("Unable to allocate double_free_cache memory.\n"); 162966fede8SKees Cook return; 163966fede8SKees Cook } 164966fede8SKees Cook 165966fede8SKees Cook /* Just make sure we got real memory. */ 166966fede8SKees Cook *val = 0x12345678; 167966fede8SKees Cook pr_info("Attempting double slab free ...\n"); 168966fede8SKees Cook kmem_cache_free(double_free_cache, val); 169966fede8SKees Cook kmem_cache_free(double_free_cache, val); 170966fede8SKees Cook } 171966fede8SKees Cook 172966fede8SKees Cook void lkdtm_SLAB_FREE_CROSS(void) 173966fede8SKees Cook { 174966fede8SKees Cook int *val; 175966fede8SKees Cook 176966fede8SKees Cook val = kmem_cache_alloc(a_cache, GFP_KERNEL); 177966fede8SKees Cook if (!val) { 178966fede8SKees Cook pr_info("Unable to allocate a_cache memory.\n"); 179966fede8SKees Cook return; 180966fede8SKees Cook } 181966fede8SKees Cook 182966fede8SKees Cook /* Just make sure we got real memory. */ 183966fede8SKees Cook *val = 0x12345679; 184966fede8SKees Cook pr_info("Attempting cross-cache slab free ...\n"); 185966fede8SKees Cook kmem_cache_free(b_cache, val); 186966fede8SKees Cook } 187966fede8SKees Cook 188966fede8SKees Cook void lkdtm_SLAB_FREE_PAGE(void) 189966fede8SKees Cook { 190966fede8SKees Cook unsigned long p = __get_free_page(GFP_KERNEL); 191966fede8SKees Cook 192966fede8SKees Cook pr_info("Attempting non-Slab slab free ...\n"); 193966fede8SKees Cook kmem_cache_free(NULL, (void *)p); 194966fede8SKees Cook free_page(p); 195966fede8SKees Cook } 196966fede8SKees Cook 197966fede8SKees Cook /* 198966fede8SKees Cook * We have constructors to keep the caches distinctly separated without 199966fede8SKees Cook * needing to boot with "slab_nomerge". 200966fede8SKees Cook */ 201966fede8SKees Cook static void ctor_double_free(void *region) 202966fede8SKees Cook { } 203966fede8SKees Cook static void ctor_a(void *region) 204966fede8SKees Cook { } 205966fede8SKees Cook static void ctor_b(void *region) 206966fede8SKees Cook { } 207966fede8SKees Cook 208966fede8SKees Cook void __init lkdtm_heap_init(void) 209966fede8SKees Cook { 210966fede8SKees Cook double_free_cache = kmem_cache_create("lkdtm-heap-double_free", 211966fede8SKees Cook 64, 0, 0, ctor_double_free); 212966fede8SKees Cook a_cache = kmem_cache_create("lkdtm-heap-a", 64, 0, 0, ctor_a); 213966fede8SKees Cook b_cache = kmem_cache_create("lkdtm-heap-b", 64, 0, 0, ctor_b); 214966fede8SKees Cook } 215966fede8SKees Cook 216966fede8SKees Cook void __exit lkdtm_heap_exit(void) 217966fede8SKees Cook { 218966fede8SKees Cook kmem_cache_destroy(double_free_cache); 219966fede8SKees Cook kmem_cache_destroy(a_cache); 220966fede8SKees Cook kmem_cache_destroy(b_cache); 221966fede8SKees Cook } 222