xref: /openbmc/linux/drivers/misc/lkdtm/heap.c (revision 9fb29c73)
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/sched.h>
9 
10 /*
11  * This tries to stay within the next largest power-of-2 kmalloc cache
12  * to avoid actually overwriting anything important if it's not detected
13  * correctly.
14  */
15 void lkdtm_OVERWRITE_ALLOCATION(void)
16 {
17 	size_t len = 1020;
18 	u32 *data = kmalloc(len, GFP_KERNEL);
19 	if (!data)
20 		return;
21 
22 	data[1024 / sizeof(u32)] = 0x12345678;
23 	kfree(data);
24 }
25 
26 void lkdtm_WRITE_AFTER_FREE(void)
27 {
28 	int *base, *again;
29 	size_t len = 1024;
30 	/*
31 	 * The slub allocator uses the first word to store the free
32 	 * pointer in some configurations. Use the middle of the
33 	 * allocation to avoid running into the freelist
34 	 */
35 	size_t offset = (len / sizeof(*base)) / 2;
36 
37 	base = kmalloc(len, GFP_KERNEL);
38 	if (!base)
39 		return;
40 	pr_info("Allocated memory %p-%p\n", base, &base[offset * 2]);
41 	pr_info("Attempting bad write to freed memory at %p\n",
42 		&base[offset]);
43 	kfree(base);
44 	base[offset] = 0x0abcdef0;
45 	/* Attempt to notice the overwrite. */
46 	again = kmalloc(len, GFP_KERNEL);
47 	kfree(again);
48 	if (again != base)
49 		pr_info("Hmm, didn't get the same memory range.\n");
50 }
51 
52 void lkdtm_READ_AFTER_FREE(void)
53 {
54 	int *base, *val, saw;
55 	size_t len = 1024;
56 	/*
57 	 * The slub allocator uses the first word to store the free
58 	 * pointer in some configurations. Use the middle of the
59 	 * allocation to avoid running into the freelist
60 	 */
61 	size_t offset = (len / sizeof(*base)) / 2;
62 
63 	base = kmalloc(len, GFP_KERNEL);
64 	if (!base) {
65 		pr_info("Unable to allocate base memory.\n");
66 		return;
67 	}
68 
69 	val = kmalloc(len, GFP_KERNEL);
70 	if (!val) {
71 		pr_info("Unable to allocate val memory.\n");
72 		kfree(base);
73 		return;
74 	}
75 
76 	*val = 0x12345678;
77 	base[offset] = *val;
78 	pr_info("Value in memory before free: %x\n", base[offset]);
79 
80 	kfree(base);
81 
82 	pr_info("Attempting bad read from freed memory\n");
83 	saw = base[offset];
84 	if (saw != *val) {
85 		/* Good! Poisoning happened, so declare a win. */
86 		pr_info("Memory correctly poisoned (%x)\n", saw);
87 		BUG();
88 	}
89 	pr_info("Memory was not poisoned\n");
90 
91 	kfree(val);
92 }
93 
94 void lkdtm_WRITE_BUDDY_AFTER_FREE(void)
95 {
96 	unsigned long p = __get_free_page(GFP_KERNEL);
97 	if (!p) {
98 		pr_info("Unable to allocate free page\n");
99 		return;
100 	}
101 
102 	pr_info("Writing to the buddy page before free\n");
103 	memset((void *)p, 0x3, PAGE_SIZE);
104 	free_page(p);
105 	schedule();
106 	pr_info("Attempting bad write to the buddy page after free\n");
107 	memset((void *)p, 0x78, PAGE_SIZE);
108 	/* Attempt to notice the overwrite. */
109 	p = __get_free_page(GFP_KERNEL);
110 	free_page(p);
111 	schedule();
112 }
113 
114 void lkdtm_READ_BUDDY_AFTER_FREE(void)
115 {
116 	unsigned long p = __get_free_page(GFP_KERNEL);
117 	int saw, *val;
118 	int *base;
119 
120 	if (!p) {
121 		pr_info("Unable to allocate free page\n");
122 		return;
123 	}
124 
125 	val = kmalloc(1024, GFP_KERNEL);
126 	if (!val) {
127 		pr_info("Unable to allocate val memory.\n");
128 		free_page(p);
129 		return;
130 	}
131 
132 	base = (int *)p;
133 
134 	*val = 0x12345678;
135 	base[0] = *val;
136 	pr_info("Value in memory before free: %x\n", base[0]);
137 	free_page(p);
138 	pr_info("Attempting to read from freed memory\n");
139 	saw = base[0];
140 	if (saw != *val) {
141 		/* Good! Poisoning happened, so declare a win. */
142 		pr_info("Memory correctly poisoned (%x)\n", saw);
143 		BUG();
144 	}
145 	pr_info("Buddy page was not poisoned\n");
146 
147 	kfree(val);
148 }
149