diff options
-rw-r--r-- | Documentation/kasan.txt | 170 | ||||
-rw-r--r-- | Makefile | 3 | ||||
-rw-r--r-- | drivers/firmware/efi/libstub/Makefile | 1 | ||||
-rw-r--r-- | include/linux/kasan.h | 46 | ||||
-rw-r--r-- | include/linux/sched.h | 3 | ||||
-rw-r--r-- | lib/Kconfig.debug | 2 | ||||
-rw-r--r-- | lib/Kconfig.kasan | 43 | ||||
-rw-r--r-- | mm/Makefile | 1 | ||||
-rw-r--r-- | mm/kasan/Makefile | 8 | ||||
-rw-r--r-- | mm/kasan/kasan.c | 302 | ||||
-rw-r--r-- | mm/kasan/kasan.h | 34 | ||||
-rw-r--r-- | mm/kasan/report.c | 209 | ||||
-rw-r--r-- | scripts/Makefile.kasan | 24 | ||||
-rw-r--r-- | scripts/Makefile.lib | 10 |
14 files changed, 855 insertions, 1 deletions
diff --git a/Documentation/kasan.txt b/Documentation/kasan.txt new file mode 100644 index 000000000000..f0645a8a992f --- /dev/null +++ b/Documentation/kasan.txt | |||
@@ -0,0 +1,170 @@ | |||
1 | Kernel address sanitizer | ||
2 | ================ | ||
3 | |||
4 | 0. Overview | ||
5 | =========== | ||
6 | |||
7 | Kernel Address sanitizer (KASan) is a dynamic memory error detector. It provides | ||
8 | a fast and comprehensive solution for finding use-after-free and out-of-bounds | ||
9 | bugs. | ||
10 | |||
11 | KASan uses compile-time instrumentation for checking every memory access, | ||
12 | therefore you will need a certain version of GCC >= 4.9.2 | ||
13 | |||
14 | Currently KASan is supported only for x86_64 architecture and requires that the | ||
15 | kernel be built with the SLUB allocator. | ||
16 | |||
17 | 1. Usage | ||
18 | ========= | ||
19 | |||
20 | To enable KASAN configure kernel with: | ||
21 | |||
22 | CONFIG_KASAN = y | ||
23 | |||
24 | and choose between CONFIG_KASAN_OUTLINE and CONFIG_KASAN_INLINE. Outline/inline | ||
25 | is compiler instrumentation types. The former produces smaller binary the | ||
26 | latter is 1.1 - 2 times faster. Inline instrumentation requires GCC 5.0 or | ||
27 | latter. | ||
28 | |||
29 | Currently KASAN works only with the SLUB memory allocator. | ||
30 | For better bug detection and nicer report, enable CONFIG_STACKTRACE and put | ||
31 | at least 'slub_debug=U' in the boot cmdline. | ||
32 | |||
33 | To disable instrumentation for specific files or directories, add a line | ||
34 | similar to the following to the respective kernel Makefile: | ||
35 | |||
36 | For a single file (e.g. main.o): | ||
37 | KASAN_SANITIZE_main.o := n | ||
38 | |||
39 | For all files in one directory: | ||
40 | KASAN_SANITIZE := n | ||
41 | |||
42 | 1.1 Error reports | ||
43 | ========== | ||
44 | |||
45 | A typical out of bounds access report looks like this: | ||
46 | |||
47 | ================================================================== | ||
48 | BUG: AddressSanitizer: out of bounds access in kmalloc_oob_right+0x65/0x75 [test_kasan] at addr ffff8800693bc5d3 | ||
49 | Write of size 1 by task modprobe/1689 | ||
50 | ============================================================================= | ||
51 | BUG kmalloc-128 (Not tainted): kasan error | ||
52 | ----------------------------------------------------------------------------- | ||
53 | |||
54 | Disabling lock debugging due to kernel taint | ||
55 | INFO: Allocated in kmalloc_oob_right+0x3d/0x75 [test_kasan] age=0 cpu=0 pid=1689 | ||
56 | __slab_alloc+0x4b4/0x4f0 | ||
57 | kmem_cache_alloc_trace+0x10b/0x190 | ||
58 | kmalloc_oob_right+0x3d/0x75 [test_kasan] | ||
59 | init_module+0x9/0x47 [test_kasan] | ||
60 | do_one_initcall+0x99/0x200 | ||
61 | load_module+0x2cb3/0x3b20 | ||
62 | SyS_finit_module+0x76/0x80 | ||
63 | system_call_fastpath+0x12/0x17 | ||
64 | INFO: Slab 0xffffea0001a4ef00 objects=17 used=7 fp=0xffff8800693bd728 flags=0x100000000004080 | ||
65 | INFO: Object 0xffff8800693bc558 @offset=1368 fp=0xffff8800693bc720 | ||
66 | |||
67 | Bytes b4 ffff8800693bc548: 00 00 00 00 00 00 00 00 5a 5a 5a 5a 5a 5a 5a 5a ........ZZZZZZZZ | ||
68 | Object ffff8800693bc558: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b kkkkkkkkkkkkkkkk | ||
69 | Object ffff8800693bc568: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b kkkkkkkkkkkkkkkk | ||
70 | Object ffff8800693bc578: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b kkkkkkkkkkkkkkkk | ||
71 | Object ffff8800693bc588: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b kkkkkkkkkkkkkkkk | ||
72 | Object ffff8800693bc598: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b kkkkkkkkkkkkkkkk | ||
73 | Object ffff8800693bc5a8: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b kkkkkkkkkkkkkkkk | ||
74 | Object ffff8800693bc5b8: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b kkkkkkkkkkkkkkkk | ||
75 | Object ffff8800693bc5c8: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b a5 kkkkkkkkkkkkkkk. | ||
76 | Redzone ffff8800693bc5d8: cc cc cc cc cc cc cc cc ........ | ||
77 | Padding ffff8800693bc718: 5a 5a 5a 5a 5a 5a 5a 5a ZZZZZZZZ | ||
78 | CPU: 0 PID: 1689 Comm: modprobe Tainted: G B 3.18.0-rc1-mm1+ #98 | ||
79 | Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS rel-1.7.5-0-ge51488c-20140602_164612-nilsson.home.kraxel.org 04/01/2014 | ||
80 | ffff8800693bc000 0000000000000000 ffff8800693bc558 ffff88006923bb78 | ||
81 | ffffffff81cc68ae 00000000000000f3 ffff88006d407600 ffff88006923bba8 | ||
82 | ffffffff811fd848 ffff88006d407600 ffffea0001a4ef00 ffff8800693bc558 | ||
83 | Call Trace: | ||
84 | [<ffffffff81cc68ae>] dump_stack+0x46/0x58 | ||
85 | [<ffffffff811fd848>] print_trailer+0xf8/0x160 | ||
86 | [<ffffffffa00026a7>] ? kmem_cache_oob+0xc3/0xc3 [test_kasan] | ||
87 | [<ffffffff811ff0f5>] object_err+0x35/0x40 | ||
88 | [<ffffffffa0002065>] ? kmalloc_oob_right+0x65/0x75 [test_kasan] | ||
89 | [<ffffffff8120b9fa>] kasan_report_error+0x38a/0x3f0 | ||
90 | [<ffffffff8120a79f>] ? kasan_poison_shadow+0x2f/0x40 | ||
91 | [<ffffffff8120b344>] ? kasan_unpoison_shadow+0x14/0x40 | ||
92 | [<ffffffff8120a79f>] ? kasan_poison_shadow+0x2f/0x40 | ||
93 | [<ffffffffa00026a7>] ? kmem_cache_oob+0xc3/0xc3 [test_kasan] | ||
94 | [<ffffffff8120a995>] __asan_store1+0x75/0xb0 | ||
95 | [<ffffffffa0002601>] ? kmem_cache_oob+0x1d/0xc3 [test_kasan] | ||
96 | [<ffffffffa0002065>] ? kmalloc_oob_right+0x65/0x75 [test_kasan] | ||
97 | [<ffffffffa0002065>] kmalloc_oob_right+0x65/0x75 [test_kasan] | ||
98 | [<ffffffffa00026b0>] init_module+0x9/0x47 [test_kasan] | ||
99 | [<ffffffff810002d9>] do_one_initcall+0x99/0x200 | ||
100 | [<ffffffff811e4e5c>] ? __vunmap+0xec/0x160 | ||
101 | [<ffffffff81114f63>] load_module+0x2cb3/0x3b20 | ||
102 | [<ffffffff8110fd70>] ? m_show+0x240/0x240 | ||
103 | [<ffffffff81115f06>] SyS_finit_module+0x76/0x80 | ||
104 | [<ffffffff81cd3129>] system_call_fastpath+0x12/0x17 | ||
105 | Memory state around the buggy address: | ||
106 | ffff8800693bc300: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc | ||
107 | ffff8800693bc380: fc fc 00 00 00 00 00 00 00 00 00 00 00 00 00 fc | ||
108 | ffff8800693bc400: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc | ||
109 | ffff8800693bc480: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc | ||
110 | ffff8800693bc500: fc fc fc fc fc fc fc fc fc fc fc 00 00 00 00 00 | ||
111 | >ffff8800693bc580: 00 00 00 00 00 00 00 00 00 00 03 fc fc fc fc fc | ||
112 | ^ | ||
113 | ffff8800693bc600: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc | ||
114 | ffff8800693bc680: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc | ||
115 | ffff8800693bc700: fc fc fc fc fb fb fb fb fb fb fb fb fb fb fb fb | ||
116 | ffff8800693bc780: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb | ||
117 | ffff8800693bc800: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb | ||
118 | ================================================================== | ||
119 | |||
120 | First sections describe slub object where bad access happened. | ||
121 | See 'SLUB Debug output' section in Documentation/vm/slub.txt for details. | ||
122 | |||
123 | In the last section the report shows memory state around the accessed address. | ||
124 | Reading this part requires some more understanding of how KASAN works. | ||
125 | |||
126 | Each 8 bytes of memory are encoded in one shadow byte as accessible, | ||
127 | partially accessible, freed or they can be part of a redzone. | ||
128 | We use the following encoding for each shadow byte: 0 means that all 8 bytes | ||
129 | of the corresponding memory region are accessible; number N (1 <= N <= 7) means | ||
130 | that the first N bytes are accessible, and other (8 - N) bytes are not; | ||
131 | any negative value indicates that the entire 8-byte word is inaccessible. | ||
132 | We use different negative values to distinguish between different kinds of | ||
133 | inaccessible memory like redzones or freed memory (see mm/kasan/kasan.h). | ||
134 | |||
135 | In the report above the arrows point to the shadow byte 03, which means that | ||
136 | the accessed address is partially accessible. | ||
137 | |||
138 | |||
139 | 2. Implementation details | ||
140 | ======================== | ||
141 | |||
142 | From a high level, our approach to memory error detection is similar to that | ||
143 | of kmemcheck: use shadow memory to record whether each byte of memory is safe | ||
144 | to access, and use compile-time instrumentation to check shadow memory on each | ||
145 | memory access. | ||
146 | |||
147 | AddressSanitizer dedicates 1/8 of kernel memory to its shadow memory | ||
148 | (e.g. 16TB to cover 128TB on x86_64) and uses direct mapping with a scale and | ||
149 | offset to translate a memory address to its corresponding shadow address. | ||
150 | |||
151 | Here is the function witch translate an address to its corresponding shadow | ||
152 | address: | ||
153 | |||
154 | static inline void *kasan_mem_to_shadow(const void *addr) | ||
155 | { | ||
156 | return ((unsigned long)addr >> KASAN_SHADOW_SCALE_SHIFT) | ||
157 | + KASAN_SHADOW_OFFSET; | ||
158 | } | ||
159 | |||
160 | where KASAN_SHADOW_SCALE_SHIFT = 3. | ||
161 | |||
162 | Compile-time instrumentation used for checking memory accesses. Compiler inserts | ||
163 | function calls (__asan_load*(addr), __asan_store*(addr)) before each memory | ||
164 | access of size 1, 2, 4, 8 or 16. These functions check whether memory access is | ||
165 | valid or not by checking corresponding shadow memory. | ||
166 | |||
167 | GCC 5.0 has possibility to perform inline instrumentation. Instead of making | ||
168 | function calls GCC directly inserts the code to check the shadow memory. | ||
169 | This option significantly enlarges kernel but it gives x1.1-x2 performance | ||
170 | boost over outline instrumented kernel. | ||
@@ -423,7 +423,7 @@ export MAKE AWK GENKSYMS INSTALLKERNEL PERL PYTHON UTS_MACHINE | |||
423 | export HOSTCXX HOSTCXXFLAGS LDFLAGS_MODULE CHECK CHECKFLAGS | 423 | export HOSTCXX HOSTCXXFLAGS LDFLAGS_MODULE CHECK CHECKFLAGS |
424 | 424 | ||
425 | export KBUILD_CPPFLAGS NOSTDINC_FLAGS LINUXINCLUDE OBJCOPYFLAGS LDFLAGS | 425 | export KBUILD_CPPFLAGS NOSTDINC_FLAGS LINUXINCLUDE OBJCOPYFLAGS LDFLAGS |
426 | export KBUILD_CFLAGS CFLAGS_KERNEL CFLAGS_MODULE CFLAGS_GCOV | 426 | export KBUILD_CFLAGS CFLAGS_KERNEL CFLAGS_MODULE CFLAGS_GCOV CFLAGS_KASAN |
427 | export KBUILD_AFLAGS AFLAGS_KERNEL AFLAGS_MODULE | 427 | export KBUILD_AFLAGS AFLAGS_KERNEL AFLAGS_MODULE |
428 | export KBUILD_AFLAGS_MODULE KBUILD_CFLAGS_MODULE KBUILD_LDFLAGS_MODULE | 428 | export KBUILD_AFLAGS_MODULE KBUILD_CFLAGS_MODULE KBUILD_LDFLAGS_MODULE |
429 | export KBUILD_AFLAGS_KERNEL KBUILD_CFLAGS_KERNEL | 429 | export KBUILD_AFLAGS_KERNEL KBUILD_CFLAGS_KERNEL |
@@ -781,6 +781,7 @@ ifeq ($(shell $(CONFIG_SHELL) $(srctree)/scripts/gcc-goto.sh $(CC)), y) | |||
781 | KBUILD_CFLAGS += -DCC_HAVE_ASM_GOTO | 781 | KBUILD_CFLAGS += -DCC_HAVE_ASM_GOTO |
782 | endif | 782 | endif |
783 | 783 | ||
784 | include $(srctree)/scripts/Makefile.kasan | ||
784 | include $(srctree)/scripts/Makefile.extrawarn | 785 | include $(srctree)/scripts/Makefile.extrawarn |
785 | 786 | ||
786 | # Add user supplied CPPFLAGS, AFLAGS and CFLAGS as the last assignments | 787 | # Add user supplied CPPFLAGS, AFLAGS and CFLAGS as the last assignments |
diff --git a/drivers/firmware/efi/libstub/Makefile b/drivers/firmware/efi/libstub/Makefile index 8902f52e0998..280bc0a63365 100644 --- a/drivers/firmware/efi/libstub/Makefile +++ b/drivers/firmware/efi/libstub/Makefile | |||
@@ -19,6 +19,7 @@ KBUILD_CFLAGS := $(cflags-y) \ | |||
19 | $(call cc-option,-fno-stack-protector) | 19 | $(call cc-option,-fno-stack-protector) |
20 | 20 | ||
21 | GCOV_PROFILE := n | 21 | GCOV_PROFILE := n |
22 | KASAN_SANITIZE := n | ||
22 | 23 | ||
23 | lib-y := efi-stub-helper.o | 24 | lib-y := efi-stub-helper.o |
24 | lib-$(CONFIG_EFI_ARMSTUB) += arm-stub.o fdt.o | 25 | lib-$(CONFIG_EFI_ARMSTUB) += arm-stub.o fdt.o |
diff --git a/include/linux/kasan.h b/include/linux/kasan.h new file mode 100644 index 000000000000..9102fda60def --- /dev/null +++ b/include/linux/kasan.h | |||
@@ -0,0 +1,46 @@ | |||
1 | #ifndef _LINUX_KASAN_H | ||
2 | #define _LINUX_KASAN_H | ||
3 | |||
4 | #include <linux/types.h> | ||
5 | |||
6 | struct kmem_cache; | ||
7 | struct page; | ||
8 | |||
9 | #ifdef CONFIG_KASAN | ||
10 | |||
11 | #define KASAN_SHADOW_SCALE_SHIFT 3 | ||
12 | #define KASAN_SHADOW_OFFSET _AC(CONFIG_KASAN_SHADOW_OFFSET, UL) | ||
13 | |||
14 | #include <asm/kasan.h> | ||
15 | #include <linux/sched.h> | ||
16 | |||
17 | static inline void *kasan_mem_to_shadow(const void *addr) | ||
18 | { | ||
19 | return (void *)((unsigned long)addr >> KASAN_SHADOW_SCALE_SHIFT) | ||
20 | + KASAN_SHADOW_OFFSET; | ||
21 | } | ||
22 | |||
23 | /* Enable reporting bugs after kasan_disable_current() */ | ||
24 | static inline void kasan_enable_current(void) | ||
25 | { | ||
26 | current->kasan_depth++; | ||
27 | } | ||
28 | |||
29 | /* Disable reporting bugs for current task */ | ||
30 | static inline void kasan_disable_current(void) | ||
31 | { | ||
32 | current->kasan_depth--; | ||
33 | } | ||
34 | |||
35 | void kasan_unpoison_shadow(const void *address, size_t size); | ||
36 | |||
37 | #else /* CONFIG_KASAN */ | ||
38 | |||
39 | static inline void kasan_unpoison_shadow(const void *address, size_t size) {} | ||
40 | |||
41 | static inline void kasan_enable_current(void) {} | ||
42 | static inline void kasan_disable_current(void) {} | ||
43 | |||
44 | #endif /* CONFIG_KASAN */ | ||
45 | |||
46 | #endif /* LINUX_KASAN_H */ | ||
diff --git a/include/linux/sched.h b/include/linux/sched.h index 048b91b983ed..41c60e5302d7 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h | |||
@@ -1664,6 +1664,9 @@ struct task_struct { | |||
1664 | unsigned long timer_slack_ns; | 1664 | unsigned long timer_slack_ns; |
1665 | unsigned long default_timer_slack_ns; | 1665 | unsigned long default_timer_slack_ns; |
1666 | 1666 | ||
1667 | #ifdef CONFIG_KASAN | ||
1668 | unsigned int kasan_depth; | ||
1669 | #endif | ||
1667 | #ifdef CONFIG_FUNCTION_GRAPH_TRACER | 1670 | #ifdef CONFIG_FUNCTION_GRAPH_TRACER |
1668 | /* Index of current stored address in ret_stack */ | 1671 | /* Index of current stored address in ret_stack */ |
1669 | int curr_ret_stack; | 1672 | int curr_ret_stack; |
diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug index 79a9bb67aeaf..ecb3516f6546 100644 --- a/lib/Kconfig.debug +++ b/lib/Kconfig.debug | |||
@@ -651,6 +651,8 @@ config DEBUG_STACKOVERFLOW | |||
651 | 651 | ||
652 | source "lib/Kconfig.kmemcheck" | 652 | source "lib/Kconfig.kmemcheck" |
653 | 653 | ||
654 | source "lib/Kconfig.kasan" | ||
655 | |||
654 | endmenu # "Memory Debugging" | 656 | endmenu # "Memory Debugging" |
655 | 657 | ||
656 | config DEBUG_SHIRQ | 658 | config DEBUG_SHIRQ |
diff --git a/lib/Kconfig.kasan b/lib/Kconfig.kasan new file mode 100644 index 000000000000..e5b3fbe5560f --- /dev/null +++ b/lib/Kconfig.kasan | |||
@@ -0,0 +1,43 @@ | |||
1 | config HAVE_ARCH_KASAN | ||
2 | bool | ||
3 | |||
4 | if HAVE_ARCH_KASAN | ||
5 | |||
6 | config KASAN | ||
7 | bool "KASan: runtime memory debugger" | ||
8 | help | ||
9 | Enables kernel address sanitizer - runtime memory debugger, | ||
10 | designed to find out-of-bounds accesses and use-after-free bugs. | ||
11 | This is strictly debugging feature. It consumes about 1/8 | ||
12 | of available memory and brings about ~x3 performance slowdown. | ||
13 | For better error detection enable CONFIG_STACKTRACE, | ||
14 | and add slub_debug=U to boot cmdline. | ||
15 | |||
16 | config KASAN_SHADOW_OFFSET | ||
17 | hex | ||
18 | |||
19 | choice | ||
20 | prompt "Instrumentation type" | ||
21 | depends on KASAN | ||
22 | default KASAN_OUTLINE | ||
23 | |||
24 | config KASAN_OUTLINE | ||
25 | bool "Outline instrumentation" | ||
26 | help | ||
27 | Before every memory access compiler insert function call | ||
28 | __asan_load*/__asan_store*. These functions performs check | ||
29 | of shadow memory. This is slower than inline instrumentation, | ||
30 | however it doesn't bloat size of kernel's .text section so | ||
31 | much as inline does. | ||
32 | |||
33 | config KASAN_INLINE | ||
34 | bool "Inline instrumentation" | ||
35 | help | ||
36 | Compiler directly inserts code checking shadow memory before | ||
37 | memory accesses. This is faster than outline (in some workloads | ||
38 | it gives about x2 boost over outline instrumentation), but | ||
39 | make kernel's .text size much bigger. | ||
40 | |||
41 | endchoice | ||
42 | |||
43 | endif | ||
diff --git a/mm/Makefile b/mm/Makefile index 3548460ab7b6..930b52df4aca 100644 --- a/mm/Makefile +++ b/mm/Makefile | |||
@@ -49,6 +49,7 @@ obj-$(CONFIG_PAGE_POISONING) += debug-pagealloc.o | |||
49 | obj-$(CONFIG_SLAB) += slab.o | 49 | obj-$(CONFIG_SLAB) += slab.o |
50 | obj-$(CONFIG_SLUB) += slub.o | 50 | obj-$(CONFIG_SLUB) += slub.o |
51 | obj-$(CONFIG_KMEMCHECK) += kmemcheck.o | 51 | obj-$(CONFIG_KMEMCHECK) += kmemcheck.o |
52 | obj-$(CONFIG_KASAN) += kasan/ | ||
52 | obj-$(CONFIG_FAILSLAB) += failslab.o | 53 | obj-$(CONFIG_FAILSLAB) += failslab.o |
53 | obj-$(CONFIG_MEMORY_HOTPLUG) += memory_hotplug.o | 54 | obj-$(CONFIG_MEMORY_HOTPLUG) += memory_hotplug.o |
54 | obj-$(CONFIG_FS_XIP) += filemap_xip.o | 55 | obj-$(CONFIG_FS_XIP) += filemap_xip.o |
diff --git a/mm/kasan/Makefile b/mm/kasan/Makefile new file mode 100644 index 000000000000..bd837b8c2f41 --- /dev/null +++ b/mm/kasan/Makefile | |||
@@ -0,0 +1,8 @@ | |||
1 | KASAN_SANITIZE := n | ||
2 | |||
3 | CFLAGS_REMOVE_kasan.o = -pg | ||
4 | # Function splitter causes unnecessary splits in __asan_load1/__asan_store1 | ||
5 | # see: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=63533 | ||
6 | CFLAGS_kasan.o := $(call cc-option, -fno-conserve-stack -fno-stack-protector) | ||
7 | |||
8 | obj-y := kasan.o report.o | ||
diff --git a/mm/kasan/kasan.c b/mm/kasan/kasan.c new file mode 100644 index 000000000000..6dc1aa7cefcc --- /dev/null +++ b/mm/kasan/kasan.c | |||
@@ -0,0 +1,302 @@ | |||
1 | /* | ||
2 | * This file contains shadow memory manipulation code. | ||
3 | * | ||
4 | * Copyright (c) 2014 Samsung Electronics Co., Ltd. | ||
5 | * Author: Andrey Ryabinin <a.ryabinin@samsung.com> | ||
6 | * | ||
7 | * Some of code borrowed from https://github.com/xairy/linux by | ||
8 | * Andrey Konovalov <adech.fo@gmail.com> | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify | ||
11 | * it under the terms of the GNU General Public License version 2 as | ||
12 | * published by the Free Software Foundation. | ||
13 | * | ||
14 | */ | ||
15 | |||
16 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt | ||
17 | #define DISABLE_BRANCH_PROFILING | ||
18 | |||
19 | #include <linux/export.h> | ||
20 | #include <linux/init.h> | ||
21 | #include <linux/kernel.h> | ||
22 | #include <linux/memblock.h> | ||
23 | #include <linux/mm.h> | ||
24 | #include <linux/printk.h> | ||
25 | #include <linux/sched.h> | ||
26 | #include <linux/slab.h> | ||
27 | #include <linux/stacktrace.h> | ||
28 | #include <linux/string.h> | ||
29 | #include <linux/types.h> | ||
30 | #include <linux/kasan.h> | ||
31 | |||
32 | #include "kasan.h" | ||
33 | |||
34 | /* | ||
35 | * Poisons the shadow memory for 'size' bytes starting from 'addr'. | ||
36 | * Memory addresses should be aligned to KASAN_SHADOW_SCALE_SIZE. | ||
37 | */ | ||
38 | static void kasan_poison_shadow(const void *address, size_t size, u8 value) | ||
39 | { | ||
40 | void *shadow_start, *shadow_end; | ||
41 | |||
42 | shadow_start = kasan_mem_to_shadow(address); | ||
43 | shadow_end = kasan_mem_to_shadow(address + size); | ||
44 | |||
45 | memset(shadow_start, value, shadow_end - shadow_start); | ||
46 | } | ||
47 | |||
48 | void kasan_unpoison_shadow(const void *address, size_t size) | ||
49 | { | ||
50 | kasan_poison_shadow(address, size, 0); | ||
51 | |||
52 | if (size & KASAN_SHADOW_MASK) { | ||
53 | u8 *shadow = (u8 *)kasan_mem_to_shadow(address + size); | ||
54 | *shadow = size & KASAN_SHADOW_MASK; | ||
55 | } | ||
56 | } | ||
57 | |||
58 | |||
59 | /* | ||
60 | * All functions below always inlined so compiler could | ||
61 | * perform better optimizations in each of __asan_loadX/__assn_storeX | ||
62 | * depending on memory access size X. | ||
63 | */ | ||
64 | |||
65 | static __always_inline bool memory_is_poisoned_1(unsigned long addr) | ||
66 | { | ||
67 | s8 shadow_value = *(s8 *)kasan_mem_to_shadow((void *)addr); | ||
68 | |||
69 | if (unlikely(shadow_value)) { | ||
70 | s8 last_accessible_byte = addr & KASAN_SHADOW_MASK; | ||
71 | return unlikely(last_accessible_byte >= shadow_value); | ||
72 | } | ||
73 | |||
74 | return false; | ||
75 | } | ||
76 | |||
77 | static __always_inline bool memory_is_poisoned_2(unsigned long addr) | ||
78 | { | ||
79 | u16 *shadow_addr = (u16 *)kasan_mem_to_shadow((void *)addr); | ||
80 | |||
81 | if (unlikely(*shadow_addr)) { | ||
82 | if (memory_is_poisoned_1(addr + 1)) | ||
83 | return true; | ||
84 | |||
85 | if (likely(((addr + 1) & KASAN_SHADOW_MASK) != 0)) | ||
86 | return false; | ||
87 | |||
88 | return unlikely(*(u8 *)shadow_addr); | ||
89 | } | ||
90 | |||
91 | return false; | ||
92 | } | ||
93 | |||
94 | static __always_inline bool memory_is_poisoned_4(unsigned long addr) | ||
95 | { | ||
96 | u16 *shadow_addr = (u16 *)kasan_mem_to_shadow((void *)addr); | ||
97 | |||
98 | if (unlikely(*shadow_addr)) { | ||
99 | if (memory_is_poisoned_1(addr + 3)) | ||
100 | return true; | ||
101 | |||
102 | if (likely(((addr + 3) & KASAN_SHADOW_MASK) >= 3)) | ||
103 | return false; | ||
104 | |||
105 | return unlikely(*(u8 *)shadow_addr); | ||
106 | } | ||
107 | |||
108 | return false; | ||
109 | } | ||
110 | |||
111 | static __always_inline bool memory_is_poisoned_8(unsigned long addr) | ||
112 | { | ||
113 | u16 *shadow_addr = (u16 *)kasan_mem_to_shadow((void *)addr); | ||
114 | |||
115 | if (unlikely(*shadow_addr)) { | ||
116 | if (memory_is_poisoned_1(addr + 7)) | ||
117 | return true; | ||
118 | |||
119 | if (likely(((addr + 7) & KASAN_SHADOW_MASK) >= 7)) | ||
120 | return false; | ||
121 | |||
122 | return unlikely(*(u8 *)shadow_addr); | ||
123 | } | ||
124 | |||
125 | return false; | ||
126 | } | ||
127 | |||
128 | static __always_inline bool memory_is_poisoned_16(unsigned long addr) | ||
129 | { | ||
130 | u32 *shadow_addr = (u32 *)kasan_mem_to_shadow((void *)addr); | ||
131 | |||
132 | if (unlikely(*shadow_addr)) { | ||
133 | u16 shadow_first_bytes = *(u16 *)shadow_addr; | ||
134 | s8 last_byte = (addr + 15) & KASAN_SHADOW_MASK; | ||
135 | |||
136 | if (unlikely(shadow_first_bytes)) | ||
137 | return true; | ||
138 | |||
139 | if (likely(!last_byte)) | ||
140 | return false; | ||
141 | |||
142 | return memory_is_poisoned_1(addr + 15); | ||
143 | } | ||
144 | |||
145 | return false; | ||
146 | } | ||
147 | |||
148 | static __always_inline unsigned long bytes_is_zero(const u8 *start, | ||
149 | size_t size) | ||
150 | { | ||
151 | while (size) { | ||
152 | if (unlikely(*start)) | ||
153 | return (unsigned long)start; | ||
154 | start++; | ||
155 | size--; | ||
156 | } | ||
157 | |||
158 | return 0; | ||
159 | } | ||
160 | |||
161 | static __always_inline unsigned long memory_is_zero(const void *start, | ||
162 | const void *end) | ||
163 | { | ||
164 | unsigned int words; | ||
165 | unsigned long ret; | ||
166 | unsigned int prefix = (unsigned long)start % 8; | ||
167 | |||
168 | if (end - start <= 16) | ||
169 | return bytes_is_zero(start, end - start); | ||
170 | |||
171 | if (prefix) { | ||
172 | prefix = 8 - prefix; | ||
173 | ret = bytes_is_zero(start, prefix); | ||
174 | if (unlikely(ret)) | ||
175 | return ret; | ||
176 | start += prefix; | ||
177 | } | ||
178 | |||
179 | words = (end - start) / 8; | ||
180 | while (words) { | ||
181 | if (unlikely(*(u64 *)start)) | ||
182 | return bytes_is_zero(start, 8); | ||
183 | start += 8; | ||
184 | words--; | ||
185 | } | ||
186 | |||
187 | return bytes_is_zero(start, (end - start) % 8); | ||
188 | } | ||
189 | |||
190 | static __always_inline bool memory_is_poisoned_n(unsigned long addr, | ||
191 | size_t size) | ||
192 | { | ||
193 | unsigned long ret; | ||
194 | |||
195 | ret = memory_is_zero(kasan_mem_to_shadow((void *)addr), | ||
196 | kasan_mem_to_shadow((void *)addr + size - 1) + 1); | ||
197 | |||
198 | if (unlikely(ret)) { | ||
199 | unsigned long last_byte = addr + size - 1; | ||
200 | s8 *last_shadow = (s8 *)kasan_mem_to_shadow((void *)last_byte); | ||
201 | |||
202 | if (unlikely(ret != (unsigned long)last_shadow || | ||
203 | ((last_byte & KASAN_SHADOW_MASK) >= *last_shadow))) | ||
204 | return true; | ||
205 | } | ||
206 | return false; | ||
207 | } | ||
208 | |||
209 | static __always_inline bool memory_is_poisoned(unsigned long addr, size_t size) | ||
210 | { | ||
211 | if (__builtin_constant_p(size)) { | ||
212 | switch (size) { | ||
213 | case 1: | ||
214 | return memory_is_poisoned_1(addr); | ||
215 | case 2: | ||
216 | return memory_is_poisoned_2(addr); | ||
217 | case 4: | ||
218 | return memory_is_poisoned_4(addr); | ||
219 | case 8: | ||
220 | return memory_is_poisoned_8(addr); | ||
221 | case 16: | ||
222 | return memory_is_poisoned_16(addr); | ||
223 | default: | ||
224 | BUILD_BUG(); | ||
225 | } | ||
226 | } | ||
227 | |||
228 | return memory_is_poisoned_n(addr, size); | ||
229 | } | ||
230 | |||
231 | |||
232 | static __always_inline void check_memory_region(unsigned long addr, | ||
233 | size_t size, bool write) | ||
234 | { | ||
235 | struct kasan_access_info info; | ||
236 | |||
237 | if (unlikely(size == 0)) | ||
238 | return; | ||
239 | |||
240 | if (unlikely((void *)addr < | ||
241 | kasan_shadow_to_mem((void *)KASAN_SHADOW_START))) { | ||
242 | info.access_addr = (void *)addr; | ||
243 | info.access_size = size; | ||
244 | info.is_write = write; | ||
245 | info.ip = _RET_IP_; | ||
246 | kasan_report_user_access(&info); | ||
247 | return; | ||
248 | } | ||
249 | |||
250 | if (likely(!memory_is_poisoned(addr, size))) | ||
251 | return; | ||
252 | |||
253 | kasan_report(addr, size, write, _RET_IP_); | ||
254 | } | ||
255 | |||
256 | #define DEFINE_ASAN_LOAD_STORE(size) \ | ||
257 | void __asan_load##size(unsigned long addr) \ | ||
258 | { \ | ||
259 | check_memory_region(addr, size, false); \ | ||
260 | } \ | ||
261 | EXPORT_SYMBOL(__asan_load##size); \ | ||
262 | __alias(__asan_load##size) \ | ||
263 | void __asan_load##size##_noabort(unsigned long); \ | ||
264 | EXPORT_SYMBOL(__asan_load##size##_noabort); \ | ||
265 | void __asan_store##size(unsigned long addr) \ | ||
266 | { \ | ||
267 | check_memory_region(addr, size, true); \ | ||
268 | } \ | ||
269 | EXPORT_SYMBOL(__asan_store##size); \ | ||
270 | __alias(__asan_store##size) \ | ||
271 | void __asan_store##size##_noabort(unsigned long); \ | ||
272 | EXPORT_SYMBOL(__asan_store##size##_noabort) | ||
273 | |||
274 | DEFINE_ASAN_LOAD_STORE(1); | ||
275 | DEFINE_ASAN_LOAD_STORE(2); | ||
276 | DEFINE_ASAN_LOAD_STORE(4); | ||
277 | DEFINE_ASAN_LOAD_STORE(8); | ||
278 | DEFINE_ASAN_LOAD_STORE(16); | ||
279 | |||
280 | void __asan_loadN(unsigned long addr, size_t size) | ||
281 | { | ||
282 | check_memory_region(addr, size, false); | ||
283 | } | ||
284 | EXPORT_SYMBOL(__asan_loadN); | ||
285 | |||
286 | __alias(__asan_loadN) | ||
287 | void __asan_loadN_noabort(unsigned long, size_t); | ||
288 | EXPORT_SYMBOL(__asan_loadN_noabort); | ||
289 | |||
290 | void __asan_storeN(unsigned long addr, size_t size) | ||
291 | { | ||
292 | check_memory_region(addr, size, true); | ||
293 | } | ||
294 | EXPORT_SYMBOL(__asan_storeN); | ||
295 | |||
296 | __alias(__asan_storeN) | ||
297 | void __asan_storeN_noabort(unsigned long, size_t); | ||
298 | EXPORT_SYMBOL(__asan_storeN_noabort); | ||
299 | |||
300 | /* to shut up compiler complaints */ | ||
301 | void __asan_handle_no_return(void) {} | ||
302 | EXPORT_SYMBOL(__asan_handle_no_return); | ||
diff --git a/mm/kasan/kasan.h b/mm/kasan/kasan.h new file mode 100644 index 000000000000..648b9c006f3f --- /dev/null +++ b/mm/kasan/kasan.h | |||
@@ -0,0 +1,34 @@ | |||
1 | #ifndef __MM_KASAN_KASAN_H | ||
2 | #define __MM_KASAN_KASAN_H | ||
3 | |||
4 | #include <linux/kasan.h> | ||
5 | |||
6 | #define KASAN_SHADOW_SCALE_SIZE (1UL << KASAN_SHADOW_SCALE_SHIFT) | ||
7 | #define KASAN_SHADOW_MASK (KASAN_SHADOW_SCALE_SIZE - 1) | ||
8 | |||
9 | struct kasan_access_info { | ||
10 | const void *access_addr; | ||
11 | const void *first_bad_addr; | ||
12 | size_t access_size; | ||
13 | bool is_write; | ||
14 | unsigned long ip; | ||
15 | }; | ||
16 | |||
17 | void kasan_report_error(struct kasan_access_info *info); | ||
18 | void kasan_report_user_access(struct kasan_access_info *info); | ||
19 | |||
20 | static inline const void *kasan_shadow_to_mem(const void *shadow_addr) | ||
21 | { | ||
22 | return (void *)(((unsigned long)shadow_addr - KASAN_SHADOW_OFFSET) | ||
23 | << KASAN_SHADOW_SCALE_SHIFT); | ||
24 | } | ||
25 | |||
26 | static inline bool kasan_enabled(void) | ||
27 | { | ||
28 | return !current->kasan_depth; | ||
29 | } | ||
30 | |||
31 | void kasan_report(unsigned long addr, size_t size, | ||
32 | bool is_write, unsigned long ip); | ||
33 | |||
34 | #endif | ||
diff --git a/mm/kasan/report.c b/mm/kasan/report.c new file mode 100644 index 000000000000..5835d69563f5 --- /dev/null +++ b/mm/kasan/report.c | |||
@@ -0,0 +1,209 @@ | |||
1 | /* | ||
2 | * This file contains error reporting code. | ||
3 | * | ||
4 | * Copyright (c) 2014 Samsung Electronics Co., Ltd. | ||
5 | * Author: Andrey Ryabinin <a.ryabinin@samsung.com> | ||
6 | * | ||
7 | * Some of code borrowed from https://github.com/xairy/linux by | ||
8 | * Andrey Konovalov <adech.fo@gmail.com> | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify | ||
11 | * it under the terms of the GNU General Public License version 2 as | ||
12 | * published by the Free Software Foundation. | ||
13 | * | ||
14 | */ | ||
15 | |||
16 | #include <linux/kernel.h> | ||
17 | #include <linux/mm.h> | ||
18 | #include <linux/printk.h> | ||
19 | #include <linux/sched.h> | ||
20 | #include <linux/slab.h> | ||
21 | #include <linux/stacktrace.h> | ||
22 | #include <linux/string.h> | ||
23 | #include <linux/types.h> | ||
24 | #include <linux/kasan.h> | ||
25 | |||
26 | #include "kasan.h" | ||
27 | |||
28 | /* Shadow layout customization. */ | ||
29 | #define SHADOW_BYTES_PER_BLOCK 1 | ||
30 | #define SHADOW_BLOCKS_PER_ROW 16 | ||
31 | #define SHADOW_BYTES_PER_ROW (SHADOW_BLOCKS_PER_ROW * SHADOW_BYTES_PER_BLOCK) | ||
32 | #define SHADOW_ROWS_AROUND_ADDR 2 | ||
33 | |||
34 | static const void *find_first_bad_addr(const void *addr, size_t size) | ||
35 | { | ||
36 | u8 shadow_val = *(u8 *)kasan_mem_to_shadow(addr); | ||
37 | const void *first_bad_addr = addr; | ||
38 | |||
39 | while (!shadow_val && first_bad_addr < addr + size) { | ||
40 | first_bad_addr += KASAN_SHADOW_SCALE_SIZE; | ||
41 | shadow_val = *(u8 *)kasan_mem_to_shadow(first_bad_addr); | ||
42 | } | ||
43 | return first_bad_addr; | ||
44 | } | ||
45 | |||
46 | static void print_error_description(struct kasan_access_info *info) | ||
47 | { | ||
48 | const char *bug_type = "unknown crash"; | ||
49 | u8 shadow_val; | ||
50 | |||
51 | info->first_bad_addr = find_first_bad_addr(info->access_addr, | ||
52 | info->access_size); | ||
53 | |||
54 | shadow_val = *(u8 *)kasan_mem_to_shadow(info->first_bad_addr); | ||
55 | |||
56 | switch (shadow_val) { | ||
57 | case 0 ... KASAN_SHADOW_SCALE_SIZE - 1: | ||
58 | bug_type = "out of bounds access"; | ||
59 | break; | ||
60 | } | ||
61 | |||
62 | pr_err("BUG: KASan: %s in %pS at addr %p\n", | ||
63 | bug_type, (void *)info->ip, | ||
64 | info->access_addr); | ||
65 | pr_err("%s of size %zu by task %s/%d\n", | ||
66 | info->is_write ? "Write" : "Read", | ||
67 | info->access_size, current->comm, task_pid_nr(current)); | ||
68 | } | ||
69 | |||
70 | static void print_address_description(struct kasan_access_info *info) | ||
71 | { | ||
72 | dump_stack(); | ||
73 | } | ||
74 | |||
75 | static bool row_is_guilty(const void *row, const void *guilty) | ||
76 | { | ||
77 | return (row <= guilty) && (guilty < row + SHADOW_BYTES_PER_ROW); | ||
78 | } | ||
79 | |||
80 | static int shadow_pointer_offset(const void *row, const void *shadow) | ||
81 | { | ||
82 | /* The length of ">ff00ff00ff00ff00: " is | ||
83 | * 3 + (BITS_PER_LONG/8)*2 chars. | ||
84 | */ | ||
85 | return 3 + (BITS_PER_LONG/8)*2 + (shadow - row)*2 + | ||
86 | (shadow - row) / SHADOW_BYTES_PER_BLOCK + 1; | ||
87 | } | ||
88 | |||
89 | static void print_shadow_for_address(const void *addr) | ||
90 | { | ||
91 | int i; | ||
92 | const void *shadow = kasan_mem_to_shadow(addr); | ||
93 | const void *shadow_row; | ||
94 | |||
95 | shadow_row = (void *)round_down((unsigned long)shadow, | ||
96 | SHADOW_BYTES_PER_ROW) | ||
97 | - SHADOW_ROWS_AROUND_ADDR * SHADOW_BYTES_PER_ROW; | ||
98 | |||
99 | pr_err("Memory state around the buggy address:\n"); | ||
100 | |||
101 | for (i = -SHADOW_ROWS_AROUND_ADDR; i <= SHADOW_ROWS_AROUND_ADDR; i++) { | ||
102 | const void *kaddr = kasan_shadow_to_mem(shadow_row); | ||
103 | char buffer[4 + (BITS_PER_LONG/8)*2]; | ||
104 | |||
105 | snprintf(buffer, sizeof(buffer), | ||
106 | (i == 0) ? ">%p: " : " %p: ", kaddr); | ||
107 | |||
108 | kasan_disable_current(); | ||
109 | print_hex_dump(KERN_ERR, buffer, | ||
110 | DUMP_PREFIX_NONE, SHADOW_BYTES_PER_ROW, 1, | ||
111 | shadow_row, SHADOW_BYTES_PER_ROW, 0); | ||
112 | kasan_enable_current(); | ||
113 | |||
114 | if (row_is_guilty(shadow_row, shadow)) | ||
115 | pr_err("%*c\n", | ||
116 | shadow_pointer_offset(shadow_row, shadow), | ||
117 | '^'); | ||
118 | |||
119 | shadow_row += SHADOW_BYTES_PER_ROW; | ||
120 | } | ||
121 | } | ||
122 | |||
123 | static DEFINE_SPINLOCK(report_lock); | ||
124 | |||
125 | void kasan_report_error(struct kasan_access_info *info) | ||
126 | { | ||
127 | unsigned long flags; | ||
128 | |||
129 | spin_lock_irqsave(&report_lock, flags); | ||
130 | pr_err("=================================" | ||
131 | "=================================\n"); | ||
132 | print_error_description(info); | ||
133 | print_address_description(info); | ||
134 | print_shadow_for_address(info->first_bad_addr); | ||
135 | pr_err("=================================" | ||
136 | "=================================\n"); | ||
137 | spin_unlock_irqrestore(&report_lock, flags); | ||
138 | } | ||
139 | |||
140 | void kasan_report_user_access(struct kasan_access_info *info) | ||
141 | { | ||
142 | unsigned long flags; | ||
143 | |||
144 | spin_lock_irqsave(&report_lock, flags); | ||
145 | pr_err("=================================" | ||
146 | "=================================\n"); | ||
147 | pr_err("BUG: KASan: user-memory-access on address %p\n", | ||
148 | info->access_addr); | ||
149 | pr_err("%s of size %zu by task %s/%d\n", | ||
150 | info->is_write ? "Write" : "Read", | ||
151 | info->access_size, current->comm, task_pid_nr(current)); | ||
152 | dump_stack(); | ||
153 | pr_err("=================================" | ||
154 | "=================================\n"); | ||
155 | spin_unlock_irqrestore(&report_lock, flags); | ||
156 | } | ||
157 | |||
158 | void kasan_report(unsigned long addr, size_t size, | ||
159 | bool is_write, unsigned long ip) | ||
160 | { | ||
161 | struct kasan_access_info info; | ||
162 | |||
163 | if (likely(!kasan_enabled())) | ||
164 | return; | ||
165 | |||
166 | info.access_addr = (void *)addr; | ||
167 | info.access_size = size; | ||
168 | info.is_write = is_write; | ||
169 | info.ip = ip; | ||
170 | kasan_report_error(&info); | ||
171 | } | ||
172 | |||
173 | |||
174 | #define DEFINE_ASAN_REPORT_LOAD(size) \ | ||
175 | void __asan_report_load##size##_noabort(unsigned long addr) \ | ||
176 | { \ | ||
177 | kasan_report(addr, size, false, _RET_IP_); \ | ||
178 | } \ | ||
179 | EXPORT_SYMBOL(__asan_report_load##size##_noabort) | ||
180 | |||
181 | #define DEFINE_ASAN_REPORT_STORE(size) \ | ||
182 | void __asan_report_store##size##_noabort(unsigned long addr) \ | ||
183 | { \ | ||
184 | kasan_report(addr, size, true, _RET_IP_); \ | ||
185 | } \ | ||
186 | EXPORT_SYMBOL(__asan_report_store##size##_noabort) | ||
187 | |||
188 | DEFINE_ASAN_REPORT_LOAD(1); | ||
189 | DEFINE_ASAN_REPORT_LOAD(2); | ||
190 | DEFINE_ASAN_REPORT_LOAD(4); | ||
191 | DEFINE_ASAN_REPORT_LOAD(8); | ||
192 | DEFINE_ASAN_REPORT_LOAD(16); | ||
193 | DEFINE_ASAN_REPORT_STORE(1); | ||
194 | DEFINE_ASAN_REPORT_STORE(2); | ||
195 | DEFINE_ASAN_REPORT_STORE(4); | ||
196 | DEFINE_ASAN_REPORT_STORE(8); | ||
197 | DEFINE_ASAN_REPORT_STORE(16); | ||
198 | |||
199 | void __asan_report_load_n_noabort(unsigned long addr, size_t size) | ||
200 | { | ||
201 | kasan_report(addr, size, false, _RET_IP_); | ||
202 | } | ||
203 | EXPORT_SYMBOL(__asan_report_load_n_noabort); | ||
204 | |||
205 | void __asan_report_store_n_noabort(unsigned long addr, size_t size) | ||
206 | { | ||
207 | kasan_report(addr, size, true, _RET_IP_); | ||
208 | } | ||
209 | EXPORT_SYMBOL(__asan_report_store_n_noabort); | ||
diff --git a/scripts/Makefile.kasan b/scripts/Makefile.kasan new file mode 100644 index 000000000000..7acd6faa0335 --- /dev/null +++ b/scripts/Makefile.kasan | |||
@@ -0,0 +1,24 @@ | |||
1 | ifdef CONFIG_KASAN | ||
2 | ifdef CONFIG_KASAN_INLINE | ||
3 | call_threshold := 10000 | ||
4 | else | ||
5 | call_threshold := 0 | ||
6 | endif | ||
7 | |||
8 | CFLAGS_KASAN_MINIMAL := -fsanitize=kernel-address | ||
9 | |||
10 | CFLAGS_KASAN := $(call cc-option, -fsanitize=kernel-address \ | ||
11 | -fasan-shadow-offset=$(CONFIG_KASAN_SHADOW_OFFSET) \ | ||
12 | --param asan-instrumentation-with-call-threshold=$(call_threshold)) | ||
13 | |||
14 | ifeq ($(call cc-option, $(CFLAGS_KASAN_MINIMAL) -Werror),) | ||
15 | $(warning Cannot use CONFIG_KASAN: \ | ||
16 | -fsanitize=kernel-address is not supported by compiler) | ||
17 | else | ||
18 | ifeq ($(CFLAGS_KASAN),) | ||
19 | $(warning CONFIG_KASAN: compiler does not support all options.\ | ||
20 | Trying minimal configuration) | ||
21 | CFLAGS_KASAN := $(CFLAGS_KASAN_MINIMAL) | ||
22 | endif | ||
23 | endif | ||
24 | endif | ||
diff --git a/scripts/Makefile.lib b/scripts/Makefile.lib index 511755200634..044eb4f89a91 100644 --- a/scripts/Makefile.lib +++ b/scripts/Makefile.lib | |||
@@ -119,6 +119,16 @@ _c_flags += $(if $(patsubst n%,, \ | |||
119 | $(CFLAGS_GCOV)) | 119 | $(CFLAGS_GCOV)) |
120 | endif | 120 | endif |
121 | 121 | ||
122 | # | ||
123 | # Enable address sanitizer flags for kernel except some files or directories | ||
124 | # we don't want to check (depends on variables KASAN_SANITIZE_obj.o, KASAN_SANITIZE) | ||
125 | # | ||
126 | ifeq ($(CONFIG_KASAN),y) | ||
127 | _c_flags += $(if $(patsubst n%,, \ | ||
128 | $(KASAN_SANITIZE_$(basetarget).o)$(KASAN_SANITIZE)y), \ | ||
129 | $(CFLAGS_KASAN)) | ||
130 | endif | ||
131 | |||
122 | # If building the kernel in a separate objtree expand all occurrences | 132 | # If building the kernel in a separate objtree expand all occurrences |
123 | # of -Idir to -I$(srctree)/dir except for absolute paths (starting with '/'). | 133 | # of -Idir to -I$(srctree)/dir except for absolute paths (starting with '/'). |
124 | 134 | ||