GNU Linux-libre 4.19.207-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         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 }