report.c 13.3 KB
Newer Older
1
// SPDX-License-Identifier: GPL-2.0
2
/*
3
 * This file contains common KASAN 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
16
17
18
19
#include <linux/kernel.h>
#include <linux/mm.h>
#include <linux/printk.h>
#include <linux/sched.h>
#include <linux/slab.h>
20
#include <linux/stackdepot.h>
21
22
23
24
#include <linux/stacktrace.h>
#include <linux/string.h>
#include <linux/types.h>
#include <linux/kasan.h>
25
#include <linux/module.h>
26
#include <linux/sched/task_stack.h>
27
#include <linux/uaccess.h>
28
#include <trace/events/error_report.h>
29

30
31
#include <asm/sections.h>

Patricia Alfonso's avatar
Patricia Alfonso committed
32
33
#include <kunit/test.h>

34
#include "kasan.h"
35
#include "../slab.h"
36

37
static unsigned long kasan_flags;
38

39
40
#define KASAN_BIT_REPORTED	0
#define KASAN_BIT_MULTI_SHOT	1
41

42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
enum kasan_arg_fault {
	KASAN_ARG_FAULT_DEFAULT,
	KASAN_ARG_FAULT_REPORT,
	KASAN_ARG_FAULT_PANIC,
};

static enum kasan_arg_fault kasan_arg_fault __ro_after_init = KASAN_ARG_FAULT_DEFAULT;

/* kasan.fault=report/panic */
static int __init early_kasan_fault(char *arg)
{
	if (!arg)
		return -EINVAL;

	if (!strcmp(arg, "report"))
		kasan_arg_fault = KASAN_ARG_FAULT_REPORT;
	else if (!strcmp(arg, "panic"))
		kasan_arg_fault = KASAN_ARG_FAULT_PANIC;
	else
		return -EINVAL;

	return 0;
}
early_param("kasan.fault", early_kasan_fault);

67
bool kasan_save_enable_multi_shot(void)
68
{
69
	return test_and_set_bit(KASAN_BIT_MULTI_SHOT, &kasan_flags);
70
}
71
EXPORT_SYMBOL_GPL(kasan_save_enable_multi_shot);
72

73
void kasan_restore_multi_shot(bool enabled)
74
{
75
76
	if (!enabled)
		clear_bit(KASAN_BIT_MULTI_SHOT, &kasan_flags);
77
}
78
EXPORT_SYMBOL_GPL(kasan_restore_multi_shot);
79

80
static int __init kasan_set_multi_shot(char *str)
Andrey Konovalov's avatar
Andrey Konovalov committed
81
{
82
83
	set_bit(KASAN_BIT_MULTI_SHOT, &kasan_flags);
	return 1;
Andrey Konovalov's avatar
Andrey Konovalov committed
84
}
85
__setup("kasan_multi_shot", kasan_set_multi_shot);
Andrey Konovalov's avatar
Andrey Konovalov committed
86

87
static void print_error_description(struct kasan_access_info *info)
88
{
Andrey Konovalov's avatar
Andrey Konovalov committed
89
	pr_err("BUG: KASAN: %s in %pS\n",
90
		kasan_get_bug_type(info), (void *)info->ip);
91
92
93
94
95
96
97
98
	if (info->access_size)
		pr_err("%s of size %zu at addr %px by task %s/%d\n",
			info->is_write ? "Write" : "Read", info->access_size,
			info->access_addr, current->comm, task_pid_nr(current));
	else
		pr_err("%s at addr %px by task %s/%d\n",
			info->is_write ? "Write" : "Read",
			info->access_addr, current->comm, task_pid_nr(current));
99
100
}

101
102
static DEFINE_SPINLOCK(report_lock);

103
static void start_report(unsigned long *flags)
104
105
106
107
108
109
110
111
112
{
	/*
	 * Make sure we don't end up in loop.
	 */
	kasan_disable_current();
	spin_lock_irqsave(&report_lock, *flags);
	pr_err("==================================================================\n");
}

113
static void end_report(unsigned long *flags, unsigned long addr)
114
{
115
	if (!kasan_async_fault_possible())
116
		trace_error_report_end(ERROR_DETECTOR_KASAN, addr);
117
118
119
	pr_err("==================================================================\n");
	add_taint(TAINT_BAD_PAGE, LOCKDEP_NOW_UNRELIABLE);
	spin_unlock_irqrestore(&report_lock, *flags);
120
	if (panic_on_warn && !test_bit(KASAN_BIT_MULTI_SHOT, &kasan_flags)) {
121
122
123
124
125
126
127
		/*
		 * This thread may hit another WARN() in the panic path.
		 * Resetting this prevents additional WARN() from panicking the
		 * system on this thread.  Other threads are blocked by the
		 * panic_mutex in panic().
		 */
		panic_on_warn = 0;
Dmitry Vyukov's avatar
Dmitry Vyukov committed
128
		panic("panic_on_warn set ...\n");
129
	}
130
	if (kasan_arg_fault == KASAN_ARG_FAULT_PANIC)
131
		panic("kasan.fault=panic set ...\n");
132
133
134
	kasan_enable_current();
}

135
136
137
138
139
140
141
142
143
static void print_stack(depot_stack_handle_t stack)
{
	unsigned long *entries;
	unsigned int nr_entries;

	nr_entries = stack_depot_fetch(stack, &entries);
	stack_trace_print(entries, nr_entries, 0);
}

144
static void print_track(struct kasan_track *track, const char *prefix)
Alexander Potapenko's avatar
Alexander Potapenko committed
145
{
146
	pr_err("%s by task %u:\n", prefix, track->pid);
147
	if (track->stack) {
148
		print_stack(track->stack);
149
150
151
	} else {
		pr_err("(stack is not available)\n");
	}
Alexander Potapenko's avatar
Alexander Potapenko committed
152
153
}

154
struct page *kasan_addr_to_page(const void *addr)
155
156
157
158
159
160
161
{
	if ((addr >= (void *)PAGE_OFFSET) &&
			(addr < high_memory))
		return virt_to_head_page(addr);
	return NULL;
}

162
163
static void describe_object_addr(struct kmem_cache *cache, void *object,
				const void *addr)
Alexander Potapenko's avatar
Alexander Potapenko committed
164
{
165
166
167
168
	unsigned long access_addr = (unsigned long)addr;
	unsigned long object_addr = (unsigned long)object;
	const char *rel_type;
	int rel_bytes;
Alexander Potapenko's avatar
Alexander Potapenko committed
169

170
	pr_err("The buggy address belongs to the object at %px\n"
171
172
	       " which belongs to the cache %s of size %d\n",
		object, cache->name, cache->object_size);
173

174
	if (!addr)
Alexander Potapenko's avatar
Alexander Potapenko committed
175
		return;
176

177
178
179
180
181
182
183
184
185
186
187
188
	if (access_addr < object_addr) {
		rel_type = "to the left";
		rel_bytes = object_addr - access_addr;
	} else if (access_addr >= object_addr + cache->object_size) {
		rel_type = "to the right";
		rel_bytes = access_addr - (object_addr + cache->object_size);
	} else {
		rel_type = "inside";
		rel_bytes = access_addr - object_addr;
	}

	pr_err("The buggy address is located %d bytes %s of\n"
189
	       " %d-byte region [%px, %px)\n",
190
191
192
193
		rel_bytes, rel_type, cache->object_size, (void *)object_addr,
		(void *)(object_addr + cache->object_size));
}

194
195
static void describe_object_stacks(struct kmem_cache *cache, void *object,
					const void *addr, u8 tag)
196
{
197
198
	struct kasan_alloc_meta *alloc_meta;
	struct kasan_track *free_track;
199

200
201
	alloc_meta = kasan_get_alloc_meta(cache, object);
	if (alloc_meta) {
202
		print_track(&alloc_meta->alloc_track, "Allocated");
203
		pr_err("\n");
204
205
206
207
208
209
210
	}

	free_track = kasan_get_free_track(cache, object, tag);
	if (free_track) {
		print_track(free_track, "Freed");
		pr_err("\n");
	}
211
212

#ifdef CONFIG_KASAN_GENERIC
213
214
215
216
217
218
	if (!alloc_meta)
		return;
	if (alloc_meta->aux_stack[0]) {
		pr_err("Last potentially related work creation:\n");
		print_stack(alloc_meta->aux_stack[0]);
		pr_err("\n");
219
	}
220
221
222
223
224
225
	if (alloc_meta->aux_stack[1]) {
		pr_err("Second to last potentially related work creation:\n");
		print_stack(alloc_meta->aux_stack[1]);
		pr_err("\n");
	}
#endif
226
}
227

228
229
230
231
232
static void describe_object(struct kmem_cache *cache, void *object,
				const void *addr, u8 tag)
{
	if (kasan_stack_collection_enabled())
		describe_object_stacks(cache, object, addr, tag);
233
	describe_object_addr(cache, object, addr);
Alexander Potapenko's avatar
Alexander Potapenko committed
234
235
}

236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
static inline bool kernel_or_module_addr(const void *addr)
{
	if (addr >= (void *)_stext && addr < (void *)_end)
		return true;
	if (is_module_address((unsigned long)addr))
		return true;
	return false;
}

static inline bool init_task_stack_addr(const void *addr)
{
	return addr >= (void *)&init_thread_union.stack &&
		(addr <= (void *)&init_thread_union.stack +
			sizeof(init_thread_union.stack));
}

252
static void print_address_description(void *addr, u8 tag)
253
{
254
	struct page *page = kasan_addr_to_page(addr);
255

256
	dump_stack_lvl(KERN_ERR);
257
	pr_err("\n");
258
259
260

	if (page && PageSlab(page)) {
		struct kmem_cache *cache = page->slab_cache;
261
		void *object = nearest_obj(cache, page,	addr);
262

263
		describe_object(cache, object, addr, tag);
264
265
	}

266
267
268
269
270
271
272
273
	if (kernel_or_module_addr(addr) && !init_task_stack_addr(addr)) {
		pr_err("The buggy address belongs to the variable:\n");
		pr_err(" %pS\n", addr);
	}

	if (page) {
		pr_err("The buggy address belongs to the page:\n");
		dump_page(page, "kasan: bad access detected");
274
	}
275

276
	kasan_print_address_stack_frame(addr);
277
278
}

279
static bool meta_row_is_guilty(const void *row, const void *addr)
280
{
281
	return (row <= addr) && (addr < row + META_MEM_BYTES_PER_ROW);
282
283
}

284
static int meta_pointer_offset(const void *row, const void *addr)
285
{
286
287
288
289
290
291
292
293
294
	/*
	 * Memory state around the buggy address:
	 *  ff00ff00ff00ff00: 00 00 00 05 fe fe fe fe fe fe fe fe fe fe fe fe
	 *  ...
	 *
	 * The length of ">ff00ff00ff00ff00: " is
	 *    3 + (BITS_PER_LONG / 8) * 2 chars.
	 * The length of each granule metadata is 2 bytes
	 *    plus 1 byte for space.
295
	 */
296
297
	return 3 + (BITS_PER_LONG / 8) * 2 +
		(addr - row) / KASAN_GRANULE_SIZE * 3 + 1;
298
299
}

300
static void print_memory_metadata(const void *addr)
301
302
{
	int i;
303
	void *row;
304

305
306
	row = (void *)round_down((unsigned long)addr, META_MEM_BYTES_PER_ROW)
			- META_ROWS_AROUND_ADDR * META_MEM_BYTES_PER_ROW;
307
308
309

	pr_err("Memory state around the buggy address:\n");

310
	for (i = -META_ROWS_AROUND_ADDR; i <= META_ROWS_AROUND_ADDR; i++) {
311
312
		char buffer[4 + (BITS_PER_LONG / 8) * 2];
		char metadata[META_BYTES_PER_ROW];
313
314

		snprintf(buffer, sizeof(buffer),
315
316
				(i == 0) ? ">%px: " : " %px: ", row);

317
318
319
320
321
		/*
		 * We should not pass a shadow pointer to generic
		 * function, because generic functions may try to
		 * access kasan mapping for the passed address.
		 */
322
		kasan_metadata_fetch_row(&metadata[0], row);
323

324
		print_hex_dump(KERN_ERR, buffer,
325
			DUMP_PREFIX_NONE, META_BYTES_PER_ROW, 1,
326
			metadata, META_BYTES_PER_ROW, 0);
327

328
329
		if (meta_row_is_guilty(row, addr))
			pr_err("%*c\n", meta_pointer_offset(row, addr), '^');
330

331
		row += META_MEM_BYTES_PER_ROW;
332
333
334
	}
}

335
static bool report_enabled(void)
336
{
337
#if defined(CONFIG_KASAN_GENERIC) || defined(CONFIG_KASAN_SW_TAGS)
338
339
	if (current->kasan_depth)
		return false;
340
#endif
341
342
343
344
345
	if (test_bit(KASAN_BIT_MULTI_SHOT, &kasan_flags))
		return true;
	return !test_and_set_bit(KASAN_BIT_REPORTED, &kasan_flags);
}

Patricia Alfonso's avatar
Patricia Alfonso committed
346
347
348
349
350
351
352
353
354
355
356
357
358
359
#if IS_ENABLED(CONFIG_KUNIT)
static void kasan_update_kunit_status(struct kunit *cur_test)
{
	struct kunit_resource *resource;
	struct kunit_kasan_expectation *kasan_data;

	resource = kunit_find_named_resource(cur_test, "kasan_data");

	if (!resource) {
		kunit_set_failure(cur_test);
		return;
	}

	kasan_data = (struct kunit_kasan_expectation *)resource->data;
360
	WRITE_ONCE(kasan_data->report_found, true);
Patricia Alfonso's avatar
Patricia Alfonso committed
361
362
363
364
	kunit_put_resource(resource);
}
#endif /* IS_ENABLED(CONFIG_KUNIT) */

365
void kasan_report_invalid_free(void *object, unsigned long ip)
366
367
{
	unsigned long flags;
368
	u8 tag = get_tag(object);
369

370
	object = kasan_reset_tag(object);
Patricia Alfonso's avatar
Patricia Alfonso committed
371
372
373
374
375
376

#if IS_ENABLED(CONFIG_KUNIT)
	if (current->kunit_test)
		kasan_update_kunit_status(current->kunit_test);
#endif /* IS_ENABLED(CONFIG_KUNIT) */

377
	start_report(&flags);
378
	pr_err("BUG: KASAN: double-free or invalid-free in %pS\n", (void *)ip);
379
	kasan_print_tags(tag, object);
380
	pr_err("\n");
381
	print_address_description(object, tag);
382
	pr_err("\n");
383
	print_memory_metadata(object);
384
	end_report(&flags, (unsigned long)object);
385
386
}

387
388
389
390
391
#ifdef CONFIG_KASAN_HW_TAGS
void kasan_report_async(void)
{
	unsigned long flags;

392
393
394
395
396
#if IS_ENABLED(CONFIG_KUNIT)
	if (current->kunit_test)
		kasan_update_kunit_status(current->kunit_test);
#endif /* IS_ENABLED(CONFIG_KUNIT) */

397
398
399
400
	start_report(&flags);
	pr_err("BUG: KASAN: invalid-access\n");
	pr_err("Asynchronous mode enabled: no access details available\n");
	pr_err("\n");
401
	dump_stack_lvl(KERN_ERR);
402
403
404
405
	end_report(&flags, 0);
}
#endif /* CONFIG_KASAN_HW_TAGS */

406
407
static void __kasan_report(unsigned long addr, size_t size, bool is_write,
				unsigned long ip)
408
409
{
	struct kasan_access_info info;
410
411
412
	void *tagged_addr;
	void *untagged_addr;
	unsigned long flags;
413

Patricia Alfonso's avatar
Patricia Alfonso committed
414
415
416
417
418
#if IS_ENABLED(CONFIG_KUNIT)
	if (current->kunit_test)
		kasan_update_kunit_status(current->kunit_test);
#endif /* IS_ENABLED(CONFIG_KUNIT) */

419
420
	disable_trace_on_warning();

421
	tagged_addr = (void *)addr;
422
	untagged_addr = kasan_reset_tag(tagged_addr);
423
424

	info.access_addr = tagged_addr;
425
	if (addr_has_metadata(untagged_addr))
426
427
		info.first_bad_addr =
			kasan_find_first_bad_addr(tagged_addr, size);
428
429
	else
		info.first_bad_addr = untagged_addr;
430
431
432
	info.access_size = size;
	info.is_write = is_write;
	info.ip = ip;
433

434
435
436
	start_report(&flags);

	print_error_description(&info);
437
	if (addr_has_metadata(untagged_addr))
438
		kasan_print_tags(get_tag(tagged_addr), info.first_bad_addr);
439
440
	pr_err("\n");

441
	if (addr_has_metadata(untagged_addr)) {
442
		print_address_description(untagged_addr, get_tag(tagged_addr));
443
		pr_err("\n");
444
		print_memory_metadata(info.first_bad_addr);
445
	} else {
446
		dump_stack_lvl(KERN_ERR);
447
448
	}

449
	end_report(&flags, addr);
450
}
451

452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
bool kasan_report(unsigned long addr, size_t size, bool is_write,
			unsigned long ip)
{
	unsigned long flags = user_access_save();
	bool ret = false;

	if (likely(report_enabled())) {
		__kasan_report(addr, size, is_write, ip);
		ret = true;
	}

	user_access_restore(flags);

	return ret;
}

468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
#ifdef CONFIG_KASAN_INLINE
/*
 * With CONFIG_KASAN_INLINE, accesses to bogus pointers (outside the high
 * canonical half of the address space) cause out-of-bounds shadow memory reads
 * before the actual access. For addresses in the low canonical half of the
 * address space, as well as most non-canonical addresses, that out-of-bounds
 * shadow memory access lands in the non-canonical part of the address space.
 * Help the user figure out what the original bogus pointer was.
 */
void kasan_non_canonical_hook(unsigned long addr)
{
	unsigned long orig_addr;
	const char *bug_type;

	if (addr < KASAN_SHADOW_OFFSET)
		return;

	orig_addr = (addr - KASAN_SHADOW_OFFSET) << KASAN_SHADOW_SCALE_SHIFT;
	/*
	 * For faults near the shadow address for NULL, we can be fairly certain
	 * that this is a KASAN shadow memory access.
	 * For faults that correspond to shadow for low canonical addresses, we
	 * can still be pretty sure - that shadow region is a fairly narrow
	 * chunk of the non-canonical address space.
	 * But faults that look like shadow for non-canonical addresses are a
	 * really large chunk of the address space. In that case, we still
	 * print the decoded address, but make it clear that this is not
	 * necessarily what's actually going on.
	 */
	if (orig_addr < PAGE_SIZE)
		bug_type = "null-ptr-deref";
	else if (orig_addr < TASK_SIZE)
		bug_type = "probably user-memory-access";
	else
		bug_type = "maybe wild-memory-access";
	pr_alert("KASAN: %s in range [0x%016lx-0x%016lx]\n", bug_type,
504
		 orig_addr, orig_addr + KASAN_GRANULE_SIZE - 1);
505
506
}
#endif