Line data Source code
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/sched/task_stack.h>
20 : #include <linux/slab.h>
21 : #include <linux/stackdepot.h>
22 : #include <linux/stacktrace.h>
23 : #include <linux/string.h>
24 : #include <linux/types.h>
25 : #include <linux/kasan.h>
26 : #include <linux/module.h>
27 :
28 : #include <asm/sections.h>
29 :
30 : #include "kasan.h"
31 : #include "../slab.h"
32 :
33 0 : void *kasan_find_first_bad_addr(void *addr, size_t size)
34 : {
35 0 : void *p = addr;
36 :
37 0 : while (p < addr + size && !(*(u8 *)kasan_mem_to_shadow(p)))
38 0 : p += KASAN_GRANULE_SIZE;
39 0 : return p;
40 : }
41 :
42 0 : static const char *get_shadow_bug_type(struct kasan_access_info *info)
43 : {
44 0 : const char *bug_type = "unknown-crash";
45 0 : u8 *shadow_addr;
46 :
47 0 : shadow_addr = (u8 *)kasan_mem_to_shadow(info->first_bad_addr);
48 :
49 : /*
50 : * If shadow byte value is in [0, KASAN_GRANULE_SIZE) we can look
51 : * at the next shadow byte to determine the type of the bad access.
52 : */
53 0 : if (*shadow_addr > 0 && *shadow_addr <= KASAN_GRANULE_SIZE - 1)
54 0 : shadow_addr++;
55 :
56 0 : switch (*shadow_addr) {
57 0 : case 0 ... KASAN_GRANULE_SIZE - 1:
58 : /*
59 : * In theory it's still possible to see these shadow values
60 : * due to a data race in the kernel code.
61 : */
62 0 : bug_type = "out-of-bounds";
63 0 : break;
64 0 : case KASAN_PAGE_REDZONE:
65 : case KASAN_KMALLOC_REDZONE:
66 0 : bug_type = "slab-out-of-bounds";
67 0 : break;
68 0 : case KASAN_GLOBAL_REDZONE:
69 0 : bug_type = "global-out-of-bounds";
70 0 : break;
71 0 : case KASAN_STACK_LEFT:
72 : case KASAN_STACK_MID:
73 : case KASAN_STACK_RIGHT:
74 : case KASAN_STACK_PARTIAL:
75 0 : bug_type = "stack-out-of-bounds";
76 0 : break;
77 0 : case KASAN_FREE_PAGE:
78 : case KASAN_KMALLOC_FREE:
79 : case KASAN_KMALLOC_FREETRACK:
80 0 : bug_type = "use-after-free";
81 0 : break;
82 0 : case KASAN_ALLOCA_LEFT:
83 : case KASAN_ALLOCA_RIGHT:
84 0 : bug_type = "alloca-out-of-bounds";
85 0 : break;
86 0 : case KASAN_VMALLOC_INVALID:
87 0 : bug_type = "vmalloc-out-of-bounds";
88 0 : break;
89 : }
90 :
91 0 : return bug_type;
92 : }
93 :
94 0 : static const char *get_wild_bug_type(struct kasan_access_info *info)
95 : {
96 0 : const char *bug_type = "unknown-crash";
97 :
98 0 : if ((unsigned long)info->access_addr < PAGE_SIZE)
99 : bug_type = "null-ptr-deref";
100 0 : else if ((unsigned long)info->access_addr < TASK_SIZE)
101 : bug_type = "user-memory-access";
102 : else
103 0 : bug_type = "wild-memory-access";
104 :
105 0 : return bug_type;
106 : }
107 :
108 0 : const char *kasan_get_bug_type(struct kasan_access_info *info)
109 : {
110 : /*
111 : * If access_size is a negative number, then it has reason to be
112 : * defined as out-of-bounds bug type.
113 : *
114 : * Casting negative numbers to size_t would indeed turn up as
115 : * a large size_t and its value will be larger than ULONG_MAX/2,
116 : * so that this can qualify as out-of-bounds.
117 : */
118 0 : if (info->access_addr + info->access_size < info->access_addr)
119 : return "out-of-bounds";
120 :
121 0 : if (addr_has_metadata(info->access_addr))
122 0 : return get_shadow_bug_type(info);
123 0 : return get_wild_bug_type(info);
124 : }
125 :
126 0 : void kasan_metadata_fetch_row(char *buffer, void *row)
127 : {
128 0 : memcpy(buffer, kasan_mem_to_shadow(row), META_BYTES_PER_ROW);
129 0 : }
130 :
131 : #if CONFIG_KASAN_STACK
132 0 : static bool __must_check tokenize_frame_descr(const char **frame_descr,
133 : char *token, size_t max_tok_len,
134 : unsigned long *value)
135 : {
136 0 : const char *sep = strchr(*frame_descr, ' ');
137 :
138 0 : if (sep == NULL)
139 0 : sep = *frame_descr + strlen(*frame_descr);
140 :
141 0 : if (token != NULL) {
142 0 : const size_t tok_len = sep - *frame_descr;
143 :
144 0 : if (tok_len + 1 > max_tok_len) {
145 0 : pr_err("KASAN internal error: frame description too long: %s\n",
146 : *frame_descr);
147 0 : return false;
148 : }
149 :
150 : /* Copy token (+ 1 byte for '\0'). */
151 0 : strlcpy(token, *frame_descr, tok_len + 1);
152 : }
153 :
154 : /* Advance frame_descr past separator. */
155 0 : *frame_descr = sep + 1;
156 :
157 0 : if (value != NULL && kstrtoul(token, 10, value)) {
158 0 : pr_err("KASAN internal error: not a valid number: %s\n", token);
159 0 : return false;
160 : }
161 :
162 : return true;
163 : }
164 :
165 0 : static void print_decoded_frame_descr(const char *frame_descr)
166 : {
167 : /*
168 : * We need to parse the following string:
169 : * "n alloc_1 alloc_2 ... alloc_n"
170 : * where alloc_i looks like
171 : * "offset size len name"
172 : * or "offset size len name:line".
173 : */
174 :
175 0 : char token[64];
176 0 : unsigned long num_objects;
177 :
178 0 : if (!tokenize_frame_descr(&frame_descr, token, sizeof(token),
179 : &num_objects))
180 0 : return;
181 :
182 0 : pr_err("\n");
183 0 : pr_err("this frame has %lu %s:\n", num_objects,
184 : num_objects == 1 ? "object" : "objects");
185 :
186 0 : while (num_objects--) {
187 0 : unsigned long offset;
188 0 : unsigned long size;
189 :
190 : /* access offset */
191 0 : if (!tokenize_frame_descr(&frame_descr, token, sizeof(token),
192 : &offset))
193 0 : return;
194 : /* access size */
195 0 : if (!tokenize_frame_descr(&frame_descr, token, sizeof(token),
196 : &size))
197 : return;
198 : /* name length (unused) */
199 0 : if (!tokenize_frame_descr(&frame_descr, NULL, 0, NULL))
200 : return;
201 : /* object name */
202 0 : if (!tokenize_frame_descr(&frame_descr, token, sizeof(token),
203 : NULL))
204 : return;
205 :
206 : /* Strip line number; without filename it's not very helpful. */
207 0 : strreplace(token, ':', '\0');
208 :
209 : /* Finally, print object information. */
210 0 : pr_err(" [%lu, %lu) '%s'", offset, offset + size, token);
211 : }
212 : }
213 :
214 0 : static bool __must_check get_address_stack_frame_info(const void *addr,
215 : unsigned long *offset,
216 : const char **frame_descr,
217 : const void **frame_pc)
218 : {
219 0 : unsigned long aligned_addr;
220 0 : unsigned long mem_ptr;
221 0 : const u8 *shadow_bottom;
222 0 : const u8 *shadow_ptr;
223 0 : const unsigned long *frame;
224 :
225 0 : BUILD_BUG_ON(IS_ENABLED(CONFIG_STACK_GROWSUP));
226 :
227 : /*
228 : * NOTE: We currently only support printing frame information for
229 : * accesses to the task's own stack.
230 : */
231 0 : if (!object_is_on_stack(addr))
232 : return false;
233 :
234 0 : aligned_addr = round_down((unsigned long)addr, sizeof(long));
235 0 : mem_ptr = round_down(aligned_addr, KASAN_GRANULE_SIZE);
236 0 : shadow_ptr = kasan_mem_to_shadow((void *)aligned_addr);
237 0 : shadow_bottom = kasan_mem_to_shadow(end_of_stack(current));
238 :
239 0 : while (shadow_ptr >= shadow_bottom && *shadow_ptr != KASAN_STACK_LEFT) {
240 0 : shadow_ptr--;
241 0 : mem_ptr -= KASAN_GRANULE_SIZE;
242 : }
243 :
244 0 : while (shadow_ptr >= shadow_bottom && *shadow_ptr == KASAN_STACK_LEFT) {
245 0 : shadow_ptr--;
246 0 : mem_ptr -= KASAN_GRANULE_SIZE;
247 : }
248 :
249 0 : if (shadow_ptr < shadow_bottom)
250 : return false;
251 :
252 0 : frame = (const unsigned long *)(mem_ptr + KASAN_GRANULE_SIZE);
253 0 : if (frame[0] != KASAN_CURRENT_STACK_FRAME_MAGIC) {
254 0 : pr_err("KASAN internal error: frame info validation failed; invalid marker: %lu\n",
255 : frame[0]);
256 0 : return false;
257 : }
258 :
259 0 : *offset = (unsigned long)addr - (unsigned long)frame;
260 0 : *frame_descr = (const char *)frame[1];
261 0 : *frame_pc = (void *)frame[2];
262 :
263 0 : return true;
264 : }
265 :
266 0 : void kasan_print_address_stack_frame(const void *addr)
267 : {
268 0 : unsigned long offset;
269 0 : const char *frame_descr;
270 0 : const void *frame_pc;
271 :
272 0 : if (!get_address_stack_frame_info(addr, &offset, &frame_descr,
273 : &frame_pc))
274 0 : return;
275 :
276 : /*
277 : * get_address_stack_frame_info only returns true if the given addr is
278 : * on the current task's stack.
279 : */
280 0 : pr_err("\n");
281 0 : pr_err("addr %px is located in stack of task %s/%d at offset %lu in frame:\n",
282 : addr, current->comm, task_pid_nr(current), offset);
283 0 : pr_err(" %pS\n", frame_pc);
284 :
285 0 : if (!frame_descr)
286 : return;
287 :
288 0 : print_decoded_frame_descr(frame_descr);
289 : }
290 : #endif /* CONFIG_KASAN_STACK */
291 :
292 : #define DEFINE_ASAN_REPORT_LOAD(size) \
293 : void __asan_report_load##size##_noabort(unsigned long addr) \
294 : { \
295 : kasan_report(addr, size, false, _RET_IP_); \
296 : } \
297 : EXPORT_SYMBOL(__asan_report_load##size##_noabort)
298 :
299 : #define DEFINE_ASAN_REPORT_STORE(size) \
300 : void __asan_report_store##size##_noabort(unsigned long addr) \
301 : { \
302 : kasan_report(addr, size, true, _RET_IP_); \
303 : } \
304 : EXPORT_SYMBOL(__asan_report_store##size##_noabort)
305 :
306 8 : DEFINE_ASAN_REPORT_LOAD(1);
307 0 : DEFINE_ASAN_REPORT_LOAD(2);
308 24 : DEFINE_ASAN_REPORT_LOAD(4);
309 99 : DEFINE_ASAN_REPORT_LOAD(8);
310 0 : DEFINE_ASAN_REPORT_LOAD(16);
311 159 : DEFINE_ASAN_REPORT_STORE(1);
312 56 : DEFINE_ASAN_REPORT_STORE(2);
313 7684 : DEFINE_ASAN_REPORT_STORE(4);
314 43996 : DEFINE_ASAN_REPORT_STORE(8);
315 0 : DEFINE_ASAN_REPORT_STORE(16);
316 :
317 0 : void __asan_report_load_n_noabort(unsigned long addr, size_t size)
318 : {
319 0 : kasan_report(addr, size, false, _RET_IP_);
320 0 : }
321 : EXPORT_SYMBOL(__asan_report_load_n_noabort);
322 :
323 0 : void __asan_report_store_n_noabort(unsigned long addr, size_t size)
324 : {
325 0 : kasan_report(addr, size, true, _RET_IP_);
326 0 : }
327 : EXPORT_SYMBOL(__asan_report_store_n_noabort);
|