aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/kasan.txt170
-rw-r--r--Makefile3
-rw-r--r--drivers/firmware/efi/libstub/Makefile1
-rw-r--r--include/linux/kasan.h46
-rw-r--r--include/linux/sched.h3
-rw-r--r--lib/Kconfig.debug2
-rw-r--r--lib/Kconfig.kasan43
-rw-r--r--mm/Makefile1
-rw-r--r--mm/kasan/Makefile8
-rw-r--r--mm/kasan/kasan.c302
-rw-r--r--mm/kasan/kasan.h34
-rw-r--r--mm/kasan/report.c209
-rw-r--r--scripts/Makefile.kasan24
-rw-r--r--scripts/Makefile.lib10
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 @@
1Kernel address sanitizer
2================
3
40. Overview
5===========
6
7Kernel Address sanitizer (KASan) is a dynamic memory error detector. It provides
8a fast and comprehensive solution for finding use-after-free and out-of-bounds
9bugs.
10
11KASan uses compile-time instrumentation for checking every memory access,
12therefore you will need a certain version of GCC >= 4.9.2
13
14Currently KASan is supported only for x86_64 architecture and requires that the
15kernel be built with the SLUB allocator.
16
171. Usage
18=========
19
20To enable KASAN configure kernel with:
21
22 CONFIG_KASAN = y
23
24and choose between CONFIG_KASAN_OUTLINE and CONFIG_KASAN_INLINE. Outline/inline
25is compiler instrumentation types. The former produces smaller binary the
26latter is 1.1 - 2 times faster. Inline instrumentation requires GCC 5.0 or
27latter.
28
29Currently KASAN works only with the SLUB memory allocator.
30For better bug detection and nicer report, enable CONFIG_STACKTRACE and put
31at least 'slub_debug=U' in the boot cmdline.
32
33To disable instrumentation for specific files or directories, add a line
34similar 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
421.1 Error reports
43==========
44
45A typical out of bounds access report looks like this:
46
47==================================================================
48BUG: AddressSanitizer: out of bounds access in kmalloc_oob_right+0x65/0x75 [test_kasan] at addr ffff8800693bc5d3
49Write of size 1 by task modprobe/1689
50=============================================================================
51BUG kmalloc-128 (Not tainted): kasan error
52-----------------------------------------------------------------------------
53
54Disabling lock debugging due to kernel taint
55INFO: 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
64INFO: Slab 0xffffea0001a4ef00 objects=17 used=7 fp=0xffff8800693bd728 flags=0x100000000004080
65INFO: Object 0xffff8800693bc558 @offset=1368 fp=0xffff8800693bc720
66
67Bytes b4 ffff8800693bc548: 00 00 00 00 00 00 00 00 5a 5a 5a 5a 5a 5a 5a 5a ........ZZZZZZZZ
68Object ffff8800693bc558: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b kkkkkkkkkkkkkkkk
69Object ffff8800693bc568: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b kkkkkkkkkkkkkkkk
70Object ffff8800693bc578: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b kkkkkkkkkkkkkkkk
71Object ffff8800693bc588: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b kkkkkkkkkkkkkkkk
72Object ffff8800693bc598: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b kkkkkkkkkkkkkkkk
73Object ffff8800693bc5a8: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b kkkkkkkkkkkkkkkk
74Object ffff8800693bc5b8: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b kkkkkkkkkkkkkkkk
75Object ffff8800693bc5c8: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b a5 kkkkkkkkkkkkkkk.
76Redzone ffff8800693bc5d8: cc cc cc cc cc cc cc cc ........
77Padding ffff8800693bc718: 5a 5a 5a 5a 5a 5a 5a 5a ZZZZZZZZ
78CPU: 0 PID: 1689 Comm: modprobe Tainted: G B 3.18.0-rc1-mm1+ #98
79Hardware 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
83Call 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
105Memory 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
120First sections describe slub object where bad access happened.
121See 'SLUB Debug output' section in Documentation/vm/slub.txt for details.
122
123In the last section the report shows memory state around the accessed address.
124Reading this part requires some more understanding of how KASAN works.
125
126Each 8 bytes of memory are encoded in one shadow byte as accessible,
127partially accessible, freed or they can be part of a redzone.
128We use the following encoding for each shadow byte: 0 means that all 8 bytes
129of the corresponding memory region are accessible; number N (1 <= N <= 7) means
130that the first N bytes are accessible, and other (8 - N) bytes are not;
131any negative value indicates that the entire 8-byte word is inaccessible.
132We use different negative values to distinguish between different kinds of
133inaccessible memory like redzones or freed memory (see mm/kasan/kasan.h).
134
135In the report above the arrows point to the shadow byte 03, which means that
136the accessed address is partially accessible.
137
138
1392. Implementation details
140========================
141
142From a high level, our approach to memory error detection is similar to that
143of kmemcheck: use shadow memory to record whether each byte of memory is safe
144to access, and use compile-time instrumentation to check shadow memory on each
145memory access.
146
147AddressSanitizer 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
149offset to translate a memory address to its corresponding shadow address.
150
151Here is the function witch translate an address to its corresponding shadow
152address:
153
154static 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
160where KASAN_SHADOW_SCALE_SHIFT = 3.
161
162Compile-time instrumentation used for checking memory accesses. Compiler inserts
163function calls (__asan_load*(addr), __asan_store*(addr)) before each memory
164access of size 1, 2, 4, 8 or 16. These functions check whether memory access is
165valid or not by checking corresponding shadow memory.
166
167GCC 5.0 has possibility to perform inline instrumentation. Instead of making
168function calls GCC directly inserts the code to check the shadow memory.
169This option significantly enlarges kernel but it gives x1.1-x2 performance
170boost over outline instrumented kernel.
diff --git a/Makefile b/Makefile
index 5fa2e3035509..33cb15efd257 100644
--- a/Makefile
+++ b/Makefile
@@ -423,7 +423,7 @@ export MAKE AWK GENKSYMS INSTALLKERNEL PERL PYTHON UTS_MACHINE
423export HOSTCXX HOSTCXXFLAGS LDFLAGS_MODULE CHECK CHECKFLAGS 423export HOSTCXX HOSTCXXFLAGS LDFLAGS_MODULE CHECK CHECKFLAGS
424 424
425export KBUILD_CPPFLAGS NOSTDINC_FLAGS LINUXINCLUDE OBJCOPYFLAGS LDFLAGS 425export KBUILD_CPPFLAGS NOSTDINC_FLAGS LINUXINCLUDE OBJCOPYFLAGS LDFLAGS
426export KBUILD_CFLAGS CFLAGS_KERNEL CFLAGS_MODULE CFLAGS_GCOV 426export KBUILD_CFLAGS CFLAGS_KERNEL CFLAGS_MODULE CFLAGS_GCOV CFLAGS_KASAN
427export KBUILD_AFLAGS AFLAGS_KERNEL AFLAGS_MODULE 427export KBUILD_AFLAGS AFLAGS_KERNEL AFLAGS_MODULE
428export KBUILD_AFLAGS_MODULE KBUILD_CFLAGS_MODULE KBUILD_LDFLAGS_MODULE 428export KBUILD_AFLAGS_MODULE KBUILD_CFLAGS_MODULE KBUILD_LDFLAGS_MODULE
429export KBUILD_AFLAGS_KERNEL KBUILD_CFLAGS_KERNEL 429export 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
782endif 782endif
783 783
784include $(srctree)/scripts/Makefile.kasan
784include $(srctree)/scripts/Makefile.extrawarn 785include $(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
21GCOV_PROFILE := n 21GCOV_PROFILE := n
22KASAN_SANITIZE := n
22 23
23lib-y := efi-stub-helper.o 24lib-y := efi-stub-helper.o
24lib-$(CONFIG_EFI_ARMSTUB) += arm-stub.o fdt.o 25lib-$(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
6struct kmem_cache;
7struct 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
17static 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() */
24static inline void kasan_enable_current(void)
25{
26 current->kasan_depth++;
27}
28
29/* Disable reporting bugs for current task */
30static inline void kasan_disable_current(void)
31{
32 current->kasan_depth--;
33}
34
35void kasan_unpoison_shadow(const void *address, size_t size);
36
37#else /* CONFIG_KASAN */
38
39static inline void kasan_unpoison_shadow(const void *address, size_t size) {}
40
41static inline void kasan_enable_current(void) {}
42static 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
652source "lib/Kconfig.kmemcheck" 652source "lib/Kconfig.kmemcheck"
653 653
654source "lib/Kconfig.kasan"
655
654endmenu # "Memory Debugging" 656endmenu # "Memory Debugging"
655 657
656config DEBUG_SHIRQ 658config 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 @@
1config HAVE_ARCH_KASAN
2 bool
3
4if HAVE_ARCH_KASAN
5
6config 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
16config KASAN_SHADOW_OFFSET
17 hex
18
19choice
20 prompt "Instrumentation type"
21 depends on KASAN
22 default KASAN_OUTLINE
23
24config 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
33config 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
41endchoice
42
43endif
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
49obj-$(CONFIG_SLAB) += slab.o 49obj-$(CONFIG_SLAB) += slab.o
50obj-$(CONFIG_SLUB) += slub.o 50obj-$(CONFIG_SLUB) += slub.o
51obj-$(CONFIG_KMEMCHECK) += kmemcheck.o 51obj-$(CONFIG_KMEMCHECK) += kmemcheck.o
52obj-$(CONFIG_KASAN) += kasan/
52obj-$(CONFIG_FAILSLAB) += failslab.o 53obj-$(CONFIG_FAILSLAB) += failslab.o
53obj-$(CONFIG_MEMORY_HOTPLUG) += memory_hotplug.o 54obj-$(CONFIG_MEMORY_HOTPLUG) += memory_hotplug.o
54obj-$(CONFIG_FS_XIP) += filemap_xip.o 55obj-$(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 @@
1KASAN_SANITIZE := n
2
3CFLAGS_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
6CFLAGS_kasan.o := $(call cc-option, -fno-conserve-stack -fno-stack-protector)
7
8obj-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 */
38static 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
48void 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
65static __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
77static __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
94static __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
111static __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
128static __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
148static __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
161static __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
190static __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
209static __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
232static __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
274DEFINE_ASAN_LOAD_STORE(1);
275DEFINE_ASAN_LOAD_STORE(2);
276DEFINE_ASAN_LOAD_STORE(4);
277DEFINE_ASAN_LOAD_STORE(8);
278DEFINE_ASAN_LOAD_STORE(16);
279
280void __asan_loadN(unsigned long addr, size_t size)
281{
282 check_memory_region(addr, size, false);
283}
284EXPORT_SYMBOL(__asan_loadN);
285
286__alias(__asan_loadN)
287void __asan_loadN_noabort(unsigned long, size_t);
288EXPORT_SYMBOL(__asan_loadN_noabort);
289
290void __asan_storeN(unsigned long addr, size_t size)
291{
292 check_memory_region(addr, size, true);
293}
294EXPORT_SYMBOL(__asan_storeN);
295
296__alias(__asan_storeN)
297void __asan_storeN_noabort(unsigned long, size_t);
298EXPORT_SYMBOL(__asan_storeN_noabort);
299
300/* to shut up compiler complaints */
301void __asan_handle_no_return(void) {}
302EXPORT_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
9struct 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
17void kasan_report_error(struct kasan_access_info *info);
18void kasan_report_user_access(struct kasan_access_info *info);
19
20static 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
26static inline bool kasan_enabled(void)
27{
28 return !current->kasan_depth;
29}
30
31void 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
34static 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
46static 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
70static void print_address_description(struct kasan_access_info *info)
71{
72 dump_stack();
73}
74
75static bool row_is_guilty(const void *row, const void *guilty)
76{
77 return (row <= guilty) && (guilty < row + SHADOW_BYTES_PER_ROW);
78}
79
80static 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
89static 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
123static DEFINE_SPINLOCK(report_lock);
124
125void 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
140void 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
158void 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) \
175void __asan_report_load##size##_noabort(unsigned long addr) \
176{ \
177 kasan_report(addr, size, false, _RET_IP_); \
178} \
179EXPORT_SYMBOL(__asan_report_load##size##_noabort)
180
181#define DEFINE_ASAN_REPORT_STORE(size) \
182void __asan_report_store##size##_noabort(unsigned long addr) \
183{ \
184 kasan_report(addr, size, true, _RET_IP_); \
185} \
186EXPORT_SYMBOL(__asan_report_store##size##_noabort)
187
188DEFINE_ASAN_REPORT_LOAD(1);
189DEFINE_ASAN_REPORT_LOAD(2);
190DEFINE_ASAN_REPORT_LOAD(4);
191DEFINE_ASAN_REPORT_LOAD(8);
192DEFINE_ASAN_REPORT_LOAD(16);
193DEFINE_ASAN_REPORT_STORE(1);
194DEFINE_ASAN_REPORT_STORE(2);
195DEFINE_ASAN_REPORT_STORE(4);
196DEFINE_ASAN_REPORT_STORE(8);
197DEFINE_ASAN_REPORT_STORE(16);
198
199void __asan_report_load_n_noabort(unsigned long addr, size_t size)
200{
201 kasan_report(addr, size, false, _RET_IP_);
202}
203EXPORT_SYMBOL(__asan_report_load_n_noabort);
204
205void __asan_report_store_n_noabort(unsigned long addr, size_t size)
206{
207 kasan_report(addr, size, true, _RET_IP_);
208}
209EXPORT_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 @@
1ifdef CONFIG_KASAN
2ifdef CONFIG_KASAN_INLINE
3 call_threshold := 10000
4else
5 call_threshold := 0
6endif
7
8CFLAGS_KASAN_MINIMAL := -fsanitize=kernel-address
9
10CFLAGS_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
14ifeq ($(call cc-option, $(CFLAGS_KASAN_MINIMAL) -Werror),)
15 $(warning Cannot use CONFIG_KASAN: \
16 -fsanitize=kernel-address is not supported by compiler)
17else
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
23endif
24endif
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))
120endif 120endif
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#
126ifeq ($(CONFIG_KASAN),y)
127_c_flags += $(if $(patsubst n%,, \
128 $(KASAN_SANITIZE_$(basetarget).o)$(KASAN_SANITIZE)y), \
129 $(CFLAGS_KASAN))
130endif
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