7d5b9e5c7cfe8fd8d82cd46c3c37f006e5725aab
[linux-2.6-microblaze.git] / mm / kasan / generic_report.c
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * This file contains generic KASAN specific error reporting code.
4  *
5  * Copyright (c) 2014 Samsung Electronics Co., Ltd.
6  * Author: Andrey Ryabinin <ryabinin.a.a@gmail.com>
7  *
8  * Some code borrowed from https://github.com/xairy/kasan-prototype by
9  *        Andrey Konovalov <andreyknvl@gmail.com>
10  */
11
12 #include <linux/bitops.h>
13 #include <linux/ftrace.h>
14 #include <linux/init.h>
15 #include <linux/kernel.h>
16 #include <linux/mm.h>
17 #include <linux/printk.h>
18 #include <linux/sched.h>
19 #include <linux/slab.h>
20 #include <linux/stackdepot.h>
21 #include <linux/stacktrace.h>
22 #include <linux/string.h>
23 #include <linux/types.h>
24 #include <linux/kasan.h>
25 #include <linux/module.h>
26
27 #include <asm/sections.h>
28
29 #include "kasan.h"
30 #include "../slab.h"
31
32 void *find_first_bad_addr(void *addr, size_t size)
33 {
34         void *p = addr;
35
36         while (p < addr + size && !(*(u8 *)kasan_mem_to_shadow(p)))
37                 p += KASAN_GRANULE_SIZE;
38         return p;
39 }
40
41 static const char *get_shadow_bug_type(struct kasan_access_info *info)
42 {
43         const char *bug_type = "unknown-crash";
44         u8 *shadow_addr;
45
46         shadow_addr = (u8 *)kasan_mem_to_shadow(info->first_bad_addr);
47
48         /*
49          * If shadow byte value is in [0, KASAN_GRANULE_SIZE) we can look
50          * at the next shadow byte to determine the type of the bad access.
51          */
52         if (*shadow_addr > 0 && *shadow_addr <= KASAN_GRANULE_SIZE - 1)
53                 shadow_addr++;
54
55         switch (*shadow_addr) {
56         case 0 ... KASAN_GRANULE_SIZE - 1:
57                 /*
58                  * In theory it's still possible to see these shadow values
59                  * due to a data race in the kernel code.
60                  */
61                 bug_type = "out-of-bounds";
62                 break;
63         case KASAN_PAGE_REDZONE:
64         case KASAN_KMALLOC_REDZONE:
65                 bug_type = "slab-out-of-bounds";
66                 break;
67         case KASAN_GLOBAL_REDZONE:
68                 bug_type = "global-out-of-bounds";
69                 break;
70         case KASAN_STACK_LEFT:
71         case KASAN_STACK_MID:
72         case KASAN_STACK_RIGHT:
73         case KASAN_STACK_PARTIAL:
74                 bug_type = "stack-out-of-bounds";
75                 break;
76         case KASAN_FREE_PAGE:
77         case KASAN_KMALLOC_FREE:
78         case KASAN_KMALLOC_FREETRACK:
79                 bug_type = "use-after-free";
80                 break;
81         case KASAN_ALLOCA_LEFT:
82         case KASAN_ALLOCA_RIGHT:
83                 bug_type = "alloca-out-of-bounds";
84                 break;
85         case KASAN_VMALLOC_INVALID:
86                 bug_type = "vmalloc-out-of-bounds";
87                 break;
88         }
89
90         return bug_type;
91 }
92
93 static const char *get_wild_bug_type(struct kasan_access_info *info)
94 {
95         const char *bug_type = "unknown-crash";
96
97         if ((unsigned long)info->access_addr < PAGE_SIZE)
98                 bug_type = "null-ptr-deref";
99         else if ((unsigned long)info->access_addr < TASK_SIZE)
100                 bug_type = "user-memory-access";
101         else
102                 bug_type = "wild-memory-access";
103
104         return bug_type;
105 }
106
107 const char *get_bug_type(struct kasan_access_info *info)
108 {
109         /*
110          * If access_size is a negative number, then it has reason to be
111          * defined as out-of-bounds bug type.
112          *
113          * Casting negative numbers to size_t would indeed turn up as
114          * a large size_t and its value will be larger than ULONG_MAX/2,
115          * so that this can qualify as out-of-bounds.
116          */
117         if (info->access_addr + info->access_size < info->access_addr)
118                 return "out-of-bounds";
119
120         if (addr_has_shadow(info->access_addr))
121                 return get_shadow_bug_type(info);
122         return get_wild_bug_type(info);
123 }
124
125 #define DEFINE_ASAN_REPORT_LOAD(size)                     \
126 void __asan_report_load##size##_noabort(unsigned long addr) \
127 {                                                         \
128         kasan_report(addr, size, false, _RET_IP_);        \
129 }                                                         \
130 EXPORT_SYMBOL(__asan_report_load##size##_noabort)
131
132 #define DEFINE_ASAN_REPORT_STORE(size)                     \
133 void __asan_report_store##size##_noabort(unsigned long addr) \
134 {                                                          \
135         kasan_report(addr, size, true, _RET_IP_);          \
136 }                                                          \
137 EXPORT_SYMBOL(__asan_report_store##size##_noabort)
138
139 DEFINE_ASAN_REPORT_LOAD(1);
140 DEFINE_ASAN_REPORT_LOAD(2);
141 DEFINE_ASAN_REPORT_LOAD(4);
142 DEFINE_ASAN_REPORT_LOAD(8);
143 DEFINE_ASAN_REPORT_LOAD(16);
144 DEFINE_ASAN_REPORT_STORE(1);
145 DEFINE_ASAN_REPORT_STORE(2);
146 DEFINE_ASAN_REPORT_STORE(4);
147 DEFINE_ASAN_REPORT_STORE(8);
148 DEFINE_ASAN_REPORT_STORE(16);
149
150 void __asan_report_load_n_noabort(unsigned long addr, size_t size)
151 {
152         kasan_report(addr, size, false, _RET_IP_);
153 }
154 EXPORT_SYMBOL(__asan_report_load_n_noabort);
155
156 void __asan_report_store_n_noabort(unsigned long addr, size_t size)
157 {
158         kasan_report(addr, size, true, _RET_IP_);
159 }
160 EXPORT_SYMBOL(__asan_report_store_n_noabort);