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