lkdtm/heap: Add vmalloc linear overflow test
[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                 BUG();
113         }
114         pr_info("Memory was not poisoned\n");
115
116         kfree(val);
117 }
118
119 void lkdtm_WRITE_BUDDY_AFTER_FREE(void)
120 {
121         unsigned long p = __get_free_page(GFP_KERNEL);
122         if (!p) {
123                 pr_info("Unable to allocate free page\n");
124                 return;
125         }
126
127         pr_info("Writing to the buddy page before free\n");
128         memset((void *)p, 0x3, PAGE_SIZE);
129         free_page(p);
130         schedule();
131         pr_info("Attempting bad write to the buddy page after free\n");
132         memset((void *)p, 0x78, PAGE_SIZE);
133         /* Attempt to notice the overwrite. */
134         p = __get_free_page(GFP_KERNEL);
135         free_page(p);
136         schedule();
137 }
138
139 void lkdtm_READ_BUDDY_AFTER_FREE(void)
140 {
141         unsigned long p = __get_free_page(GFP_KERNEL);
142         int saw, *val;
143         int *base;
144
145         if (!p) {
146                 pr_info("Unable to allocate free page\n");
147                 return;
148         }
149
150         val = kmalloc(1024, GFP_KERNEL);
151         if (!val) {
152                 pr_info("Unable to allocate val memory.\n");
153                 free_page(p);
154                 return;
155         }
156
157         base = (int *)p;
158
159         *val = 0x12345678;
160         base[0] = *val;
161         pr_info("Value in memory before free: %x\n", base[0]);
162         free_page(p);
163         pr_info("Attempting to read from freed memory\n");
164         saw = base[0];
165         if (saw != *val) {
166                 /* Good! Poisoning happened, so declare a win. */
167                 pr_info("Memory correctly poisoned (%x)\n", saw);
168                 BUG();
169         }
170         pr_info("Buddy page was not poisoned\n");
171
172         kfree(val);
173 }
174
175 void lkdtm_SLAB_FREE_DOUBLE(void)
176 {
177         int *val;
178
179         val = kmem_cache_alloc(double_free_cache, GFP_KERNEL);
180         if (!val) {
181                 pr_info("Unable to allocate double_free_cache memory.\n");
182                 return;
183         }
184
185         /* Just make sure we got real memory. */
186         *val = 0x12345678;
187         pr_info("Attempting double slab free ...\n");
188         kmem_cache_free(double_free_cache, val);
189         kmem_cache_free(double_free_cache, val);
190 }
191
192 void lkdtm_SLAB_FREE_CROSS(void)
193 {
194         int *val;
195
196         val = kmem_cache_alloc(a_cache, GFP_KERNEL);
197         if (!val) {
198                 pr_info("Unable to allocate a_cache memory.\n");
199                 return;
200         }
201
202         /* Just make sure we got real memory. */
203         *val = 0x12345679;
204         pr_info("Attempting cross-cache slab free ...\n");
205         kmem_cache_free(b_cache, val);
206 }
207
208 void lkdtm_SLAB_FREE_PAGE(void)
209 {
210         unsigned long p = __get_free_page(GFP_KERNEL);
211
212         pr_info("Attempting non-Slab slab free ...\n");
213         kmem_cache_free(NULL, (void *)p);
214         free_page(p);
215 }
216
217 /*
218  * We have constructors to keep the caches distinctly separated without
219  * needing to boot with "slab_nomerge".
220  */
221 static void ctor_double_free(void *region)
222 { }
223 static void ctor_a(void *region)
224 { }
225 static void ctor_b(void *region)
226 { }
227
228 void __init lkdtm_heap_init(void)
229 {
230         double_free_cache = kmem_cache_create("lkdtm-heap-double_free",
231                                               64, 0, 0, ctor_double_free);
232         a_cache = kmem_cache_create("lkdtm-heap-a", 64, 0, 0, ctor_a);
233         b_cache = kmem_cache_create("lkdtm-heap-b", 64, 0, 0, ctor_b);
234 }
235
236 void __exit lkdtm_heap_exit(void)
237 {
238         kmem_cache_destroy(double_free_cache);
239         kmem_cache_destroy(a_cache);
240         kmem_cache_destroy(b_cache);
241 }