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