Linux Audio

Check our new training course

Yocto distribution development and maintenance

Need a Yocto distribution for your embedded project?
Loading...
Note: File does not exist in v3.15.
  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/mman.h>
 16#include <linux/mm.h>
 17#include <linux/printk.h>
 18#include <linux/slab.h>
 19#include <linux/string.h>
 20#include <linux/uaccess.h>
 21#include <linux/module.h>
 22
 23/*
 24 * Note: test functions are marked noinline so that their names appear in
 25 * reports.
 26 */
 27
 28static noinline void __init kmalloc_oob_right(void)
 29{
 30	char *ptr;
 31	size_t size = 123;
 32
 33	pr_info("out-of-bounds to right\n");
 34	ptr = kmalloc(size, GFP_KERNEL);
 35	if (!ptr) {
 36		pr_err("Allocation failed\n");
 37		return;
 38	}
 39
 40	ptr[size] = 'x';
 41	kfree(ptr);
 42}
 43
 44static noinline void __init kmalloc_oob_left(void)
 45{
 46	char *ptr;
 47	size_t size = 15;
 48
 49	pr_info("out-of-bounds to left\n");
 50	ptr = kmalloc(size, GFP_KERNEL);
 51	if (!ptr) {
 52		pr_err("Allocation failed\n");
 53		return;
 54	}
 55
 56	*ptr = *(ptr - 1);
 57	kfree(ptr);
 58}
 59
 60static noinline void __init kmalloc_node_oob_right(void)
 61{
 62	char *ptr;
 63	size_t size = 4096;
 64
 65	pr_info("kmalloc_node(): out-of-bounds to right\n");
 66	ptr = kmalloc_node(size, GFP_KERNEL, 0);
 67	if (!ptr) {
 68		pr_err("Allocation failed\n");
 69		return;
 70	}
 71
 72	ptr[size] = 0;
 73	kfree(ptr);
 74}
 75
 76#ifdef CONFIG_SLUB
 77static noinline void __init kmalloc_pagealloc_oob_right(void)
 78{
 79	char *ptr;
 80	size_t size = KMALLOC_MAX_CACHE_SIZE + 10;
 81
 82	/* Allocate a chunk that does not fit into a SLUB cache to trigger
 83	 * the page allocator fallback.
 84	 */
 85	pr_info("kmalloc pagealloc allocation: out-of-bounds to right\n");
 86	ptr = kmalloc(size, GFP_KERNEL);
 87	if (!ptr) {
 88		pr_err("Allocation failed\n");
 89		return;
 90	}
 91
 92	ptr[size] = 0;
 93	kfree(ptr);
 94}
 95#endif
 96
 97static noinline void __init kmalloc_large_oob_right(void)
 98{
 99	char *ptr;
100	size_t size = KMALLOC_MAX_CACHE_SIZE - 256;
101	/* Allocate a chunk that is large enough, but still fits into a slab
102	 * and does not trigger the page allocator fallback in SLUB.
103	 */
104	pr_info("kmalloc large allocation: out-of-bounds to right\n");
105	ptr = kmalloc(size, GFP_KERNEL);
106	if (!ptr) {
107		pr_err("Allocation failed\n");
108		return;
109	}
110
111	ptr[size] = 0;
112	kfree(ptr);
113}
114
115static noinline void __init kmalloc_oob_krealloc_more(void)
116{
117	char *ptr1, *ptr2;
118	size_t size1 = 17;
119	size_t size2 = 19;
120
121	pr_info("out-of-bounds after krealloc more\n");
122	ptr1 = kmalloc(size1, GFP_KERNEL);
123	ptr2 = krealloc(ptr1, size2, GFP_KERNEL);
124	if (!ptr1 || !ptr2) {
125		pr_err("Allocation failed\n");
126		kfree(ptr1);
127		return;
128	}
129
130	ptr2[size2] = 'x';
131	kfree(ptr2);
132}
133
134static noinline void __init kmalloc_oob_krealloc_less(void)
135{
136	char *ptr1, *ptr2;
137	size_t size1 = 17;
138	size_t size2 = 15;
139
140	pr_info("out-of-bounds after krealloc less\n");
141	ptr1 = kmalloc(size1, GFP_KERNEL);
142	ptr2 = krealloc(ptr1, size2, GFP_KERNEL);
143	if (!ptr1 || !ptr2) {
144		pr_err("Allocation failed\n");
145		kfree(ptr1);
146		return;
147	}
148	ptr2[size2] = 'x';
149	kfree(ptr2);
150}
151
152static noinline void __init kmalloc_oob_16(void)
153{
154	struct {
155		u64 words[2];
156	} *ptr1, *ptr2;
157
158	pr_info("kmalloc out-of-bounds for 16-bytes access\n");
159	ptr1 = kmalloc(sizeof(*ptr1) - 3, GFP_KERNEL);
160	ptr2 = kmalloc(sizeof(*ptr2), GFP_KERNEL);
161	if (!ptr1 || !ptr2) {
162		pr_err("Allocation failed\n");
163		kfree(ptr1);
164		kfree(ptr2);
165		return;
166	}
167	*ptr1 = *ptr2;
168	kfree(ptr1);
169	kfree(ptr2);
170}
171
172static noinline void __init kmalloc_oob_memset_2(void)
173{
174	char *ptr;
175	size_t size = 8;
176
177	pr_info("out-of-bounds in memset2\n");
178	ptr = kmalloc(size, GFP_KERNEL);
179	if (!ptr) {
180		pr_err("Allocation failed\n");
181		return;
182	}
183
184	memset(ptr+7, 0, 2);
185	kfree(ptr);
186}
187
188static noinline void __init kmalloc_oob_memset_4(void)
189{
190	char *ptr;
191	size_t size = 8;
192
193	pr_info("out-of-bounds in memset4\n");
194	ptr = kmalloc(size, GFP_KERNEL);
195	if (!ptr) {
196		pr_err("Allocation failed\n");
197		return;
198	}
199
200	memset(ptr+5, 0, 4);
201	kfree(ptr);
202}
203
204
205static noinline void __init kmalloc_oob_memset_8(void)
206{
207	char *ptr;
208	size_t size = 8;
209
210	pr_info("out-of-bounds in memset8\n");
211	ptr = kmalloc(size, GFP_KERNEL);
212	if (!ptr) {
213		pr_err("Allocation failed\n");
214		return;
215	}
216
217	memset(ptr+1, 0, 8);
218	kfree(ptr);
219}
220
221static noinline void __init kmalloc_oob_memset_16(void)
222{
223	char *ptr;
224	size_t size = 16;
225
226	pr_info("out-of-bounds in memset16\n");
227	ptr = kmalloc(size, GFP_KERNEL);
228	if (!ptr) {
229		pr_err("Allocation failed\n");
230		return;
231	}
232
233	memset(ptr+1, 0, 16);
234	kfree(ptr);
235}
236
237static noinline void __init kmalloc_oob_in_memset(void)
238{
239	char *ptr;
240	size_t size = 666;
241
242	pr_info("out-of-bounds in memset\n");
243	ptr = kmalloc(size, GFP_KERNEL);
244	if (!ptr) {
245		pr_err("Allocation failed\n");
246		return;
247	}
248
249	memset(ptr, 0, size+5);
250	kfree(ptr);
251}
252
253static noinline void __init kmalloc_uaf(void)
254{
255	char *ptr;
256	size_t size = 10;
257
258	pr_info("use-after-free\n");
259	ptr = kmalloc(size, GFP_KERNEL);
260	if (!ptr) {
261		pr_err("Allocation failed\n");
262		return;
263	}
264
265	kfree(ptr);
266	*(ptr + 8) = 'x';
267}
268
269static noinline void __init kmalloc_uaf_memset(void)
270{
271	char *ptr;
272	size_t size = 33;
273
274	pr_info("use-after-free in memset\n");
275	ptr = kmalloc(size, GFP_KERNEL);
276	if (!ptr) {
277		pr_err("Allocation failed\n");
278		return;
279	}
280
281	kfree(ptr);
282	memset(ptr, 0, size);
283}
284
285static noinline void __init kmalloc_uaf2(void)
286{
287	char *ptr1, *ptr2;
288	size_t size = 43;
289
290	pr_info("use-after-free after another kmalloc\n");
291	ptr1 = kmalloc(size, GFP_KERNEL);
292	if (!ptr1) {
293		pr_err("Allocation failed\n");
294		return;
295	}
296
297	kfree(ptr1);
298	ptr2 = kmalloc(size, GFP_KERNEL);
299	if (!ptr2) {
300		pr_err("Allocation failed\n");
301		return;
302	}
303
304	ptr1[40] = 'x';
305	if (ptr1 == ptr2)
306		pr_err("Could not detect use-after-free: ptr1 == ptr2\n");
307	kfree(ptr2);
308}
309
310static noinline void __init kmem_cache_oob(void)
311{
312	char *p;
313	size_t size = 200;
314	struct kmem_cache *cache = kmem_cache_create("test_cache",
315						size, 0,
316						0, NULL);
317	if (!cache) {
318		pr_err("Cache allocation failed\n");
319		return;
320	}
321	pr_info("out-of-bounds in kmem_cache_alloc\n");
322	p = kmem_cache_alloc(cache, GFP_KERNEL);
323	if (!p) {
324		pr_err("Allocation failed\n");
325		kmem_cache_destroy(cache);
326		return;
327	}
328
329	*p = p[size];
330	kmem_cache_free(cache, p);
331	kmem_cache_destroy(cache);
332}
333
334static char global_array[10];
335
336static noinline void __init kasan_global_oob(void)
337{
338	volatile int i = 3;
339	char *p = &global_array[ARRAY_SIZE(global_array) + i];
340
341	pr_info("out-of-bounds global variable\n");
342	*(volatile char *)p;
343}
344
345static noinline void __init kasan_stack_oob(void)
346{
347	char stack_array[10];
348	volatile int i = 0;
349	char *p = &stack_array[ARRAY_SIZE(stack_array) + i];
350
351	pr_info("out-of-bounds on stack\n");
352	*(volatile char *)p;
353}
354
355static noinline void __init ksize_unpoisons_memory(void)
356{
357	char *ptr;
358	size_t size = 123, real_size = size;
359
360	pr_info("ksize() unpoisons the whole allocated chunk\n");
361	ptr = kmalloc(size, GFP_KERNEL);
362	if (!ptr) {
363		pr_err("Allocation failed\n");
364		return;
365	}
366	real_size = ksize(ptr);
367	/* This access doesn't trigger an error. */
368	ptr[size] = 'x';
369	/* This one does. */
370	ptr[real_size] = 'y';
371	kfree(ptr);
372}
373
374static noinline void __init copy_user_test(void)
375{
376	char *kmem;
377	char __user *usermem;
378	size_t size = 10;
379	int unused;
380
381	kmem = kmalloc(size, GFP_KERNEL);
382	if (!kmem)
383		return;
384
385	usermem = (char __user *)vm_mmap(NULL, 0, PAGE_SIZE,
386			    PROT_READ | PROT_WRITE | PROT_EXEC,
387			    MAP_ANONYMOUS | MAP_PRIVATE, 0);
388	if (IS_ERR(usermem)) {
389		pr_err("Failed to allocate user memory\n");
390		kfree(kmem);
391		return;
392	}
393
394	pr_info("out-of-bounds in copy_from_user()\n");
395	unused = copy_from_user(kmem, usermem, size + 1);
396
397	pr_info("out-of-bounds in copy_to_user()\n");
398	unused = copy_to_user(usermem, kmem, size + 1);
399
400	pr_info("out-of-bounds in __copy_from_user()\n");
401	unused = __copy_from_user(kmem, usermem, size + 1);
402
403	pr_info("out-of-bounds in __copy_to_user()\n");
404	unused = __copy_to_user(usermem, kmem, size + 1);
405
406	pr_info("out-of-bounds in __copy_from_user_inatomic()\n");
407	unused = __copy_from_user_inatomic(kmem, usermem, size + 1);
408
409	pr_info("out-of-bounds in __copy_to_user_inatomic()\n");
410	unused = __copy_to_user_inatomic(usermem, kmem, size + 1);
411
412	pr_info("out-of-bounds in strncpy_from_user()\n");
413	unused = strncpy_from_user(kmem, usermem, size + 1);
414
415	vm_munmap((unsigned long)usermem, PAGE_SIZE);
416	kfree(kmem);
417}
418
419static noinline void __init use_after_scope_test(void)
420{
421	volatile char *volatile p;
422
423	pr_info("use-after-scope on int\n");
424	{
425		int local = 0;
426
427		p = (char *)&local;
428	}
429	p[0] = 1;
430	p[3] = 1;
431
432	pr_info("use-after-scope on array\n");
433	{
434		char local[1024] = {0};
435
436		p = local;
437	}
438	p[0] = 1;
439	p[1023] = 1;
440}
441
442static int __init kmalloc_tests_init(void)
443{
444	kmalloc_oob_right();
445	kmalloc_oob_left();
446	kmalloc_node_oob_right();
447#ifdef CONFIG_SLUB
448	kmalloc_pagealloc_oob_right();
449#endif
450	kmalloc_large_oob_right();
451	kmalloc_oob_krealloc_more();
452	kmalloc_oob_krealloc_less();
453	kmalloc_oob_16();
454	kmalloc_oob_in_memset();
455	kmalloc_oob_memset_2();
456	kmalloc_oob_memset_4();
457	kmalloc_oob_memset_8();
458	kmalloc_oob_memset_16();
459	kmalloc_uaf();
460	kmalloc_uaf_memset();
461	kmalloc_uaf2();
462	kmem_cache_oob();
463	kasan_stack_oob();
464	kasan_global_oob();
465	ksize_unpoisons_memory();
466	copy_user_test();
467	use_after_scope_test();
468	return -EAGAIN;
469}
470
471module_init(kmalloc_tests_init);
472MODULE_LICENSE("GPL");