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 /* 61039a1c42SKees Cook * The slub allocator uses the first word to store the free 62039a1c42SKees Cook * pointer in some configurations. Use the middle of the 63039a1c42SKees Cook * allocation to avoid running into the freelist 64039a1c42SKees Cook */ 65039a1c42SKees Cook size_t offset = (len / sizeof(*base)) / 2; 66039a1c42SKees Cook 67039a1c42SKees Cook base = kmalloc(len, GFP_KERNEL); 68039a1c42SKees Cook if (!base) { 69039a1c42SKees Cook pr_info("Unable to allocate base memory.\n"); 70039a1c42SKees Cook return; 71039a1c42SKees Cook } 72039a1c42SKees Cook 73039a1c42SKees Cook val = kmalloc(len, GFP_KERNEL); 74039a1c42SKees Cook if (!val) { 75039a1c42SKees Cook pr_info("Unable to allocate val memory.\n"); 76039a1c42SKees Cook kfree(base); 77039a1c42SKees Cook return; 78039a1c42SKees Cook } 79039a1c42SKees Cook 80039a1c42SKees Cook *val = 0x12345678; 81039a1c42SKees Cook base[offset] = *val; 82039a1c42SKees Cook pr_info("Value in memory before free: %x\n", base[offset]); 83039a1c42SKees Cook 84039a1c42SKees Cook kfree(base); 85039a1c42SKees Cook 86039a1c42SKees Cook pr_info("Attempting bad read from freed memory\n"); 87039a1c42SKees Cook saw = base[offset]; 88039a1c42SKees Cook if (saw != *val) { 89039a1c42SKees Cook /* Good! Poisoning happened, so declare a win. */ 90039a1c42SKees Cook pr_info("Memory correctly poisoned (%x)\n", saw); 91039a1c42SKees Cook BUG(); 92039a1c42SKees Cook } 93039a1c42SKees Cook pr_info("Memory was not poisoned\n"); 94039a1c42SKees Cook 95039a1c42SKees Cook kfree(val); 96039a1c42SKees Cook } 97039a1c42SKees Cook 98039a1c42SKees Cook void lkdtm_WRITE_BUDDY_AFTER_FREE(void) 99039a1c42SKees Cook { 100039a1c42SKees Cook unsigned long p = __get_free_page(GFP_KERNEL); 101039a1c42SKees Cook if (!p) { 102039a1c42SKees Cook pr_info("Unable to allocate free page\n"); 103039a1c42SKees Cook return; 104039a1c42SKees Cook } 105039a1c42SKees Cook 106039a1c42SKees Cook pr_info("Writing to the buddy page before free\n"); 107039a1c42SKees Cook memset((void *)p, 0x3, PAGE_SIZE); 108039a1c42SKees Cook free_page(p); 109039a1c42SKees Cook schedule(); 110039a1c42SKees Cook pr_info("Attempting bad write to the buddy page after free\n"); 111039a1c42SKees Cook memset((void *)p, 0x78, PAGE_SIZE); 112039a1c42SKees Cook /* Attempt to notice the overwrite. */ 113039a1c42SKees Cook p = __get_free_page(GFP_KERNEL); 114039a1c42SKees Cook free_page(p); 115039a1c42SKees Cook schedule(); 116039a1c42SKees Cook } 117039a1c42SKees Cook 118039a1c42SKees Cook void lkdtm_READ_BUDDY_AFTER_FREE(void) 119039a1c42SKees Cook { 120039a1c42SKees Cook unsigned long p = __get_free_page(GFP_KERNEL); 121039a1c42SKees Cook int saw, *val; 122039a1c42SKees Cook int *base; 123039a1c42SKees Cook 124039a1c42SKees Cook if (!p) { 125039a1c42SKees Cook pr_info("Unable to allocate free page\n"); 126039a1c42SKees Cook return; 127039a1c42SKees Cook } 128039a1c42SKees Cook 129039a1c42SKees Cook val = kmalloc(1024, GFP_KERNEL); 130039a1c42SKees Cook if (!val) { 131039a1c42SKees Cook pr_info("Unable to allocate val memory.\n"); 132039a1c42SKees Cook free_page(p); 133039a1c42SKees Cook return; 134039a1c42SKees Cook } 135039a1c42SKees Cook 136039a1c42SKees Cook base = (int *)p; 137039a1c42SKees Cook 138039a1c42SKees Cook *val = 0x12345678; 139039a1c42SKees Cook base[0] = *val; 140039a1c42SKees Cook pr_info("Value in memory before free: %x\n", base[0]); 141039a1c42SKees Cook free_page(p); 142039a1c42SKees Cook pr_info("Attempting to read from freed memory\n"); 143039a1c42SKees Cook saw = base[0]; 144039a1c42SKees Cook if (saw != *val) { 145039a1c42SKees Cook /* Good! Poisoning happened, so declare a win. */ 146039a1c42SKees Cook pr_info("Memory correctly poisoned (%x)\n", saw); 147039a1c42SKees Cook BUG(); 148039a1c42SKees Cook } 149039a1c42SKees Cook pr_info("Buddy page was not poisoned\n"); 150039a1c42SKees Cook 151039a1c42SKees Cook kfree(val); 152039a1c42SKees Cook } 153966fede8SKees Cook 154966fede8SKees Cook void lkdtm_SLAB_FREE_DOUBLE(void) 155966fede8SKees Cook { 156966fede8SKees Cook int *val; 157966fede8SKees Cook 158966fede8SKees Cook val = kmem_cache_alloc(double_free_cache, GFP_KERNEL); 159966fede8SKees Cook if (!val) { 160966fede8SKees Cook pr_info("Unable to allocate double_free_cache memory.\n"); 161966fede8SKees Cook return; 162966fede8SKees Cook } 163966fede8SKees Cook 164966fede8SKees Cook /* Just make sure we got real memory. */ 165966fede8SKees Cook *val = 0x12345678; 166966fede8SKees Cook pr_info("Attempting double slab free ...\n"); 167966fede8SKees Cook kmem_cache_free(double_free_cache, val); 168966fede8SKees Cook kmem_cache_free(double_free_cache, val); 169966fede8SKees Cook } 170966fede8SKees Cook 171966fede8SKees Cook void lkdtm_SLAB_FREE_CROSS(void) 172966fede8SKees Cook { 173966fede8SKees Cook int *val; 174966fede8SKees Cook 175966fede8SKees Cook val = kmem_cache_alloc(a_cache, GFP_KERNEL); 176966fede8SKees Cook if (!val) { 177966fede8SKees Cook pr_info("Unable to allocate a_cache memory.\n"); 178966fede8SKees Cook return; 179966fede8SKees Cook } 180966fede8SKees Cook 181966fede8SKees Cook /* Just make sure we got real memory. */ 182966fede8SKees Cook *val = 0x12345679; 183966fede8SKees Cook pr_info("Attempting cross-cache slab free ...\n"); 184966fede8SKees Cook kmem_cache_free(b_cache, val); 185966fede8SKees Cook } 186966fede8SKees Cook 187966fede8SKees Cook void lkdtm_SLAB_FREE_PAGE(void) 188966fede8SKees Cook { 189966fede8SKees Cook unsigned long p = __get_free_page(GFP_KERNEL); 190966fede8SKees Cook 191966fede8SKees Cook pr_info("Attempting non-Slab slab free ...\n"); 192966fede8SKees Cook kmem_cache_free(NULL, (void *)p); 193966fede8SKees Cook free_page(p); 194966fede8SKees Cook } 195966fede8SKees Cook 196966fede8SKees Cook /* 197966fede8SKees Cook * We have constructors to keep the caches distinctly separated without 198966fede8SKees Cook * needing to boot with "slab_nomerge". 199966fede8SKees Cook */ 200966fede8SKees Cook static void ctor_double_free(void *region) 201966fede8SKees Cook { } 202966fede8SKees Cook static void ctor_a(void *region) 203966fede8SKees Cook { } 204966fede8SKees Cook static void ctor_b(void *region) 205966fede8SKees Cook { } 206966fede8SKees Cook 207966fede8SKees Cook void __init lkdtm_heap_init(void) 208966fede8SKees Cook { 209966fede8SKees Cook double_free_cache = kmem_cache_create("lkdtm-heap-double_free", 210966fede8SKees Cook 64, 0, 0, ctor_double_free); 211966fede8SKees Cook a_cache = kmem_cache_create("lkdtm-heap-a", 64, 0, 0, ctor_a); 212966fede8SKees Cook b_cache = kmem_cache_create("lkdtm-heap-b", 64, 0, 0, ctor_b); 213966fede8SKees Cook } 214966fede8SKees Cook 215966fede8SKees Cook void __exit lkdtm_heap_exit(void) 216966fede8SKees Cook { 217966fede8SKees Cook kmem_cache_destroy(double_free_cache); 218966fede8SKees Cook kmem_cache_destroy(a_cache); 219966fede8SKees Cook kmem_cache_destroy(b_cache); 220966fede8SKees Cook } 221