MIPS: SEAD3: Use symbolic addresses from sead-addr.h in LED driver.
[linux-drm-fsl-dcu.git] / lib / test_kasan.c
1 /*
2  *
3  * Copyright (c) 2014 Samsung Electronics Co., Ltd.
4  * Author: Andrey Ryabinin <a.ryabinin@samsung.com>
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License version 2 as
8  * published by the Free Software Foundation.
9  *
10  */
11
12 #define pr_fmt(fmt) "kasan test: %s " fmt, __func__
13
14 #include <linux/kernel.h>
15 #include <linux/printk.h>
16 #include <linux/slab.h>
17 #include <linux/string.h>
18 #include <linux/module.h>
19
20 static noinline void __init kmalloc_oob_right(void)
21 {
22         char *ptr;
23         size_t size = 123;
24
25         pr_info("out-of-bounds to right\n");
26         ptr = kmalloc(size, GFP_KERNEL);
27         if (!ptr) {
28                 pr_err("Allocation failed\n");
29                 return;
30         }
31
32         ptr[size] = 'x';
33         kfree(ptr);
34 }
35
36 static noinline void __init kmalloc_oob_left(void)
37 {
38         char *ptr;
39         size_t size = 15;
40
41         pr_info("out-of-bounds to left\n");
42         ptr = kmalloc(size, GFP_KERNEL);
43         if (!ptr) {
44                 pr_err("Allocation failed\n");
45                 return;
46         }
47
48         *ptr = *(ptr - 1);
49         kfree(ptr);
50 }
51
52 static noinline void __init kmalloc_node_oob_right(void)
53 {
54         char *ptr;
55         size_t size = 4096;
56
57         pr_info("kmalloc_node(): out-of-bounds to right\n");
58         ptr = kmalloc_node(size, GFP_KERNEL, 0);
59         if (!ptr) {
60                 pr_err("Allocation failed\n");
61                 return;
62         }
63
64         ptr[size] = 0;
65         kfree(ptr);
66 }
67
68 static noinline void __init kmalloc_large_oob_rigth(void)
69 {
70         char *ptr;
71         size_t size = KMALLOC_MAX_CACHE_SIZE + 10;
72
73         pr_info("kmalloc large allocation: out-of-bounds to right\n");
74         ptr = kmalloc(size, GFP_KERNEL);
75         if (!ptr) {
76                 pr_err("Allocation failed\n");
77                 return;
78         }
79
80         ptr[size] = 0;
81         kfree(ptr);
82 }
83
84 static noinline void __init kmalloc_oob_krealloc_more(void)
85 {
86         char *ptr1, *ptr2;
87         size_t size1 = 17;
88         size_t size2 = 19;
89
90         pr_info("out-of-bounds after krealloc more\n");
91         ptr1 = kmalloc(size1, GFP_KERNEL);
92         ptr2 = krealloc(ptr1, size2, GFP_KERNEL);
93         if (!ptr1 || !ptr2) {
94                 pr_err("Allocation failed\n");
95                 kfree(ptr1);
96                 return;
97         }
98
99         ptr2[size2] = 'x';
100         kfree(ptr2);
101 }
102
103 static noinline void __init kmalloc_oob_krealloc_less(void)
104 {
105         char *ptr1, *ptr2;
106         size_t size1 = 17;
107         size_t size2 = 15;
108
109         pr_info("out-of-bounds after krealloc less\n");
110         ptr1 = kmalloc(size1, GFP_KERNEL);
111         ptr2 = krealloc(ptr1, size2, GFP_KERNEL);
112         if (!ptr1 || !ptr2) {
113                 pr_err("Allocation failed\n");
114                 kfree(ptr1);
115                 return;
116         }
117         ptr2[size1] = 'x';
118         kfree(ptr2);
119 }
120
121 static noinline void __init kmalloc_oob_16(void)
122 {
123         struct {
124                 u64 words[2];
125         } *ptr1, *ptr2;
126
127         pr_info("kmalloc out-of-bounds for 16-bytes access\n");
128         ptr1 = kmalloc(sizeof(*ptr1) - 3, GFP_KERNEL);
129         ptr2 = kmalloc(sizeof(*ptr2), GFP_KERNEL);
130         if (!ptr1 || !ptr2) {
131                 pr_err("Allocation failed\n");
132                 kfree(ptr1);
133                 kfree(ptr2);
134                 return;
135         }
136         *ptr1 = *ptr2;
137         kfree(ptr1);
138         kfree(ptr2);
139 }
140
141 static noinline void __init kmalloc_oob_in_memset(void)
142 {
143         char *ptr;
144         size_t size = 666;
145
146         pr_info("out-of-bounds in memset\n");
147         ptr = kmalloc(size, GFP_KERNEL);
148         if (!ptr) {
149                 pr_err("Allocation failed\n");
150                 return;
151         }
152
153         memset(ptr, 0, size+5);
154         kfree(ptr);
155 }
156
157 static noinline void __init kmalloc_uaf(void)
158 {
159         char *ptr;
160         size_t size = 10;
161
162         pr_info("use-after-free\n");
163         ptr = kmalloc(size, GFP_KERNEL);
164         if (!ptr) {
165                 pr_err("Allocation failed\n");
166                 return;
167         }
168
169         kfree(ptr);
170         *(ptr + 8) = 'x';
171 }
172
173 static noinline void __init kmalloc_uaf_memset(void)
174 {
175         char *ptr;
176         size_t size = 33;
177
178         pr_info("use-after-free in memset\n");
179         ptr = kmalloc(size, GFP_KERNEL);
180         if (!ptr) {
181                 pr_err("Allocation failed\n");
182                 return;
183         }
184
185         kfree(ptr);
186         memset(ptr, 0, size);
187 }
188
189 static noinline void __init kmalloc_uaf2(void)
190 {
191         char *ptr1, *ptr2;
192         size_t size = 43;
193
194         pr_info("use-after-free after another kmalloc\n");
195         ptr1 = kmalloc(size, GFP_KERNEL);
196         if (!ptr1) {
197                 pr_err("Allocation failed\n");
198                 return;
199         }
200
201         kfree(ptr1);
202         ptr2 = kmalloc(size, GFP_KERNEL);
203         if (!ptr2) {
204                 pr_err("Allocation failed\n");
205                 return;
206         }
207
208         ptr1[40] = 'x';
209         kfree(ptr2);
210 }
211
212 static noinline void __init kmem_cache_oob(void)
213 {
214         char *p;
215         size_t size = 200;
216         struct kmem_cache *cache = kmem_cache_create("test_cache",
217                                                 size, 0,
218                                                 0, NULL);
219         if (!cache) {
220                 pr_err("Cache allocation failed\n");
221                 return;
222         }
223         pr_info("out-of-bounds in kmem_cache_alloc\n");
224         p = kmem_cache_alloc(cache, GFP_KERNEL);
225         if (!p) {
226                 pr_err("Allocation failed\n");
227                 kmem_cache_destroy(cache);
228                 return;
229         }
230
231         *p = p[size];
232         kmem_cache_free(cache, p);
233         kmem_cache_destroy(cache);
234 }
235
236 static char global_array[10];
237
238 static noinline void __init kasan_global_oob(void)
239 {
240         volatile int i = 3;
241         char *p = &global_array[ARRAY_SIZE(global_array) + i];
242
243         pr_info("out-of-bounds global variable\n");
244         *(volatile char *)p;
245 }
246
247 static noinline void __init kasan_stack_oob(void)
248 {
249         char stack_array[10];
250         volatile int i = 0;
251         char *p = &stack_array[ARRAY_SIZE(stack_array) + i];
252
253         pr_info("out-of-bounds on stack\n");
254         *(volatile char *)p;
255 }
256
257 static int __init kmalloc_tests_init(void)
258 {
259         kmalloc_oob_right();
260         kmalloc_oob_left();
261         kmalloc_node_oob_right();
262         kmalloc_large_oob_rigth();
263         kmalloc_oob_krealloc_more();
264         kmalloc_oob_krealloc_less();
265         kmalloc_oob_16();
266         kmalloc_oob_in_memset();
267         kmalloc_uaf();
268         kmalloc_uaf_memset();
269         kmalloc_uaf2();
270         kmem_cache_oob();
271         kasan_stack_oob();
272         kasan_global_oob();
273         return -EAGAIN;
274 }
275
276 module_init(kmalloc_tests_init);
277 MODULE_LICENSE("GPL");