xref: /linux/mm/kasan/report_generic.c (revision 06d07429858317ded2db7986113a9e0129cd599b)
159fd51b2SAndrey Konovalov // SPDX-License-Identifier: GPL-2.0
259fd51b2SAndrey Konovalov /*
359fd51b2SAndrey Konovalov  * This file contains generic KASAN specific error reporting code.
459fd51b2SAndrey Konovalov  *
559fd51b2SAndrey Konovalov  * Copyright (c) 2014 Samsung Electronics Co., Ltd.
659fd51b2SAndrey Konovalov  * Author: Andrey Ryabinin <ryabinin.a.a@gmail.com>
759fd51b2SAndrey Konovalov  *
859fd51b2SAndrey Konovalov  * Some code borrowed from https://github.com/xairy/kasan-prototype by
959fd51b2SAndrey Konovalov  *        Andrey Konovalov <andreyknvl@gmail.com>
1059fd51b2SAndrey Konovalov  */
1159fd51b2SAndrey Konovalov 
1259fd51b2SAndrey Konovalov #include <linux/bitops.h>
1359fd51b2SAndrey Konovalov #include <linux/ftrace.h>
1459fd51b2SAndrey Konovalov #include <linux/init.h>
1559fd51b2SAndrey Konovalov #include <linux/kernel.h>
1659fd51b2SAndrey Konovalov #include <linux/mm.h>
1759fd51b2SAndrey Konovalov #include <linux/printk.h>
1859fd51b2SAndrey Konovalov #include <linux/sched.h>
1997fc7122SAndrey Konovalov #include <linux/sched/task_stack.h>
2059fd51b2SAndrey Konovalov #include <linux/slab.h>
2159fd51b2SAndrey Konovalov #include <linux/stackdepot.h>
2259fd51b2SAndrey Konovalov #include <linux/stacktrace.h>
2359fd51b2SAndrey Konovalov #include <linux/string.h>
2459fd51b2SAndrey Konovalov #include <linux/types.h>
2559fd51b2SAndrey Konovalov #include <linux/kasan.h>
2659fd51b2SAndrey Konovalov #include <linux/module.h>
2759fd51b2SAndrey Konovalov 
2859fd51b2SAndrey Konovalov #include <asm/sections.h>
2959fd51b2SAndrey Konovalov 
3059fd51b2SAndrey Konovalov #include "kasan.h"
3159fd51b2SAndrey Konovalov #include "../slab.h"
3259fd51b2SAndrey Konovalov 
kasan_find_first_bad_addr(const void * addr,size_t size)33bb6e04a1SArnd Bergmann const void *kasan_find_first_bad_addr(const void *addr, size_t size)
3459fd51b2SAndrey Konovalov {
35bb6e04a1SArnd Bergmann 	const void *p = addr;
3659fd51b2SAndrey Konovalov 
37b9132800SAndrey Konovalov 	if (!addr_has_metadata(p))
38b9132800SAndrey Konovalov 		return p;
39b9132800SAndrey Konovalov 
4059fd51b2SAndrey Konovalov 	while (p < addr + size && !(*(u8 *)kasan_mem_to_shadow(p)))
4159fd51b2SAndrey Konovalov 		p += KASAN_GRANULE_SIZE;
42b9132800SAndrey Konovalov 
4359fd51b2SAndrey Konovalov 	return p;
4459fd51b2SAndrey Konovalov }
4559fd51b2SAndrey Konovalov 
kasan_get_alloc_size(void * object,struct kmem_cache * cache)468f17febbSKuan-Ying Lee size_t kasan_get_alloc_size(void *object, struct kmem_cache *cache)
478f17febbSKuan-Ying Lee {
488f17febbSKuan-Ying Lee 	size_t size = 0;
498f17febbSKuan-Ying Lee 	u8 *shadow;
508f17febbSKuan-Ying Lee 
518f17febbSKuan-Ying Lee 	/*
528f17febbSKuan-Ying Lee 	 * Skip the addr_has_metadata check, as this function only operates on
538f17febbSKuan-Ying Lee 	 * slab memory, which must have metadata.
548f17febbSKuan-Ying Lee 	 */
558f17febbSKuan-Ying Lee 
568f17febbSKuan-Ying Lee 	/*
578f17febbSKuan-Ying Lee 	 * The loop below returns 0 for freed objects, for which KASAN cannot
588f17febbSKuan-Ying Lee 	 * calculate the allocation size based on the metadata.
598f17febbSKuan-Ying Lee 	 */
608f17febbSKuan-Ying Lee 	shadow = (u8 *)kasan_mem_to_shadow(object);
618f17febbSKuan-Ying Lee 	while (size < cache->object_size) {
628f17febbSKuan-Ying Lee 		if (*shadow == 0)
638f17febbSKuan-Ying Lee 			size += KASAN_GRANULE_SIZE;
648f17febbSKuan-Ying Lee 		else if (*shadow >= 1 && *shadow <= KASAN_GRANULE_SIZE - 1)
658f17febbSKuan-Ying Lee 			return size + *shadow;
668f17febbSKuan-Ying Lee 		else
678f17febbSKuan-Ying Lee 			return size;
688f17febbSKuan-Ying Lee 		shadow++;
698f17febbSKuan-Ying Lee 	}
708f17febbSKuan-Ying Lee 
718f17febbSKuan-Ying Lee 	return cache->object_size;
728f17febbSKuan-Ying Lee }
738f17febbSKuan-Ying Lee 
get_shadow_bug_type(struct kasan_report_info * info)74c965cdd6SAndrey Konovalov static const char *get_shadow_bug_type(struct kasan_report_info *info)
7559fd51b2SAndrey Konovalov {
7659fd51b2SAndrey Konovalov 	const char *bug_type = "unknown-crash";
7759fd51b2SAndrey Konovalov 	u8 *shadow_addr;
7859fd51b2SAndrey Konovalov 
7959fd51b2SAndrey Konovalov 	shadow_addr = (u8 *)kasan_mem_to_shadow(info->first_bad_addr);
8059fd51b2SAndrey Konovalov 
8159fd51b2SAndrey Konovalov 	/*
8259fd51b2SAndrey Konovalov 	 * If shadow byte value is in [0, KASAN_GRANULE_SIZE) we can look
8359fd51b2SAndrey Konovalov 	 * at the next shadow byte to determine the type of the bad access.
8459fd51b2SAndrey Konovalov 	 */
8559fd51b2SAndrey Konovalov 	if (*shadow_addr > 0 && *shadow_addr <= KASAN_GRANULE_SIZE - 1)
8659fd51b2SAndrey Konovalov 		shadow_addr++;
8759fd51b2SAndrey Konovalov 
8859fd51b2SAndrey Konovalov 	switch (*shadow_addr) {
8959fd51b2SAndrey Konovalov 	case 0 ... KASAN_GRANULE_SIZE - 1:
9059fd51b2SAndrey Konovalov 		/*
9159fd51b2SAndrey Konovalov 		 * In theory it's still possible to see these shadow values
9259fd51b2SAndrey Konovalov 		 * due to a data race in the kernel code.
9359fd51b2SAndrey Konovalov 		 */
9459fd51b2SAndrey Konovalov 		bug_type = "out-of-bounds";
9559fd51b2SAndrey Konovalov 		break;
9659fd51b2SAndrey Konovalov 	case KASAN_PAGE_REDZONE:
9706bc4cf6SAndrey Konovalov 	case KASAN_SLAB_REDZONE:
9859fd51b2SAndrey Konovalov 		bug_type = "slab-out-of-bounds";
9959fd51b2SAndrey Konovalov 		break;
10059fd51b2SAndrey Konovalov 	case KASAN_GLOBAL_REDZONE:
10159fd51b2SAndrey Konovalov 		bug_type = "global-out-of-bounds";
10259fd51b2SAndrey Konovalov 		break;
10359fd51b2SAndrey Konovalov 	case KASAN_STACK_LEFT:
10459fd51b2SAndrey Konovalov 	case KASAN_STACK_MID:
10559fd51b2SAndrey Konovalov 	case KASAN_STACK_RIGHT:
10659fd51b2SAndrey Konovalov 	case KASAN_STACK_PARTIAL:
10759fd51b2SAndrey Konovalov 		bug_type = "stack-out-of-bounds";
10859fd51b2SAndrey Konovalov 		break;
10906bc4cf6SAndrey Konovalov 	case KASAN_PAGE_FREE:
1108f17febbSKuan-Ying Lee 		bug_type = "use-after-free";
1118f17febbSKuan-Ying Lee 		break;
11206bc4cf6SAndrey Konovalov 	case KASAN_SLAB_FREE:
113*63b85ac5SAndrey Konovalov 	case KASAN_SLAB_FREE_META:
1148f17febbSKuan-Ying Lee 		bug_type = "slab-use-after-free";
11559fd51b2SAndrey Konovalov 		break;
11659fd51b2SAndrey Konovalov 	case KASAN_ALLOCA_LEFT:
11759fd51b2SAndrey Konovalov 	case KASAN_ALLOCA_RIGHT:
11859fd51b2SAndrey Konovalov 		bug_type = "alloca-out-of-bounds";
11959fd51b2SAndrey Konovalov 		break;
12059fd51b2SAndrey Konovalov 	case KASAN_VMALLOC_INVALID:
12159fd51b2SAndrey Konovalov 		bug_type = "vmalloc-out-of-bounds";
12259fd51b2SAndrey Konovalov 		break;
12359fd51b2SAndrey Konovalov 	}
12459fd51b2SAndrey Konovalov 
12559fd51b2SAndrey Konovalov 	return bug_type;
12659fd51b2SAndrey Konovalov }
12759fd51b2SAndrey Konovalov 
get_wild_bug_type(struct kasan_report_info * info)128c965cdd6SAndrey Konovalov static const char *get_wild_bug_type(struct kasan_report_info *info)
12959fd51b2SAndrey Konovalov {
13059fd51b2SAndrey Konovalov 	const char *bug_type = "unknown-crash";
13159fd51b2SAndrey Konovalov 
13259fd51b2SAndrey Konovalov 	if ((unsigned long)info->access_addr < PAGE_SIZE)
13359fd51b2SAndrey Konovalov 		bug_type = "null-ptr-deref";
13459fd51b2SAndrey Konovalov 	else if ((unsigned long)info->access_addr < TASK_SIZE)
13559fd51b2SAndrey Konovalov 		bug_type = "user-memory-access";
13659fd51b2SAndrey Konovalov 	else
13759fd51b2SAndrey Konovalov 		bug_type = "wild-memory-access";
13859fd51b2SAndrey Konovalov 
13959fd51b2SAndrey Konovalov 	return bug_type;
14059fd51b2SAndrey Konovalov }
14159fd51b2SAndrey Konovalov 
get_bug_type(struct kasan_report_info * info)14259e6e098SAndrey Konovalov static const char *get_bug_type(struct kasan_report_info *info)
14359fd51b2SAndrey Konovalov {
14459fd51b2SAndrey Konovalov 	/*
14559fd51b2SAndrey Konovalov 	 * If access_size is a negative number, then it has reason to be
14659fd51b2SAndrey Konovalov 	 * defined as out-of-bounds bug type.
14759fd51b2SAndrey Konovalov 	 *
14859fd51b2SAndrey Konovalov 	 * Casting negative numbers to size_t would indeed turn up as
14959fd51b2SAndrey Konovalov 	 * a large size_t and its value will be larger than ULONG_MAX/2,
15059fd51b2SAndrey Konovalov 	 * so that this can qualify as out-of-bounds.
15159fd51b2SAndrey Konovalov 	 */
15259fd51b2SAndrey Konovalov 	if (info->access_addr + info->access_size < info->access_addr)
15359fd51b2SAndrey Konovalov 		return "out-of-bounds";
15459fd51b2SAndrey Konovalov 
1556882464fSAndrey Konovalov 	if (addr_has_metadata(info->access_addr))
15659fd51b2SAndrey Konovalov 		return get_shadow_bug_type(info);
15759fd51b2SAndrey Konovalov 	return get_wild_bug_type(info);
15859fd51b2SAndrey Konovalov }
15959fd51b2SAndrey Konovalov 
kasan_complete_mode_report_info(struct kasan_report_info * info)16059e6e098SAndrey Konovalov void kasan_complete_mode_report_info(struct kasan_report_info *info)
161b89933e9SAndrey Konovalov {
162b89933e9SAndrey Konovalov 	struct kasan_alloc_meta *alloc_meta;
16359e6e098SAndrey Konovalov 	struct kasan_free_meta *free_meta;
164b89933e9SAndrey Konovalov 
165dcc57966SAndrey Konovalov 	if (!info->bug_type)
16659e6e098SAndrey Konovalov 		info->bug_type = get_bug_type(info);
167b89933e9SAndrey Konovalov 
16859e6e098SAndrey Konovalov 	if (!info->cache || !info->object)
16959e6e098SAndrey Konovalov 		return;
170b89933e9SAndrey Konovalov 
17159e6e098SAndrey Konovalov 	alloc_meta = kasan_get_alloc_meta(info->cache, info->object);
17259e6e098SAndrey Konovalov 	if (alloc_meta)
17359e6e098SAndrey Konovalov 		memcpy(&info->alloc_track, &alloc_meta->alloc_track,
17459e6e098SAndrey Konovalov 		       sizeof(info->alloc_track));
17559e6e098SAndrey Konovalov 
176*63b85ac5SAndrey Konovalov 	if (*(u8 *)kasan_mem_to_shadow(info->object) == KASAN_SLAB_FREE_META) {
177*63b85ac5SAndrey Konovalov 		/* Free meta must be present with KASAN_SLAB_FREE_META. */
17859e6e098SAndrey Konovalov 		free_meta = kasan_get_free_meta(info->cache, info->object);
17959e6e098SAndrey Konovalov 		memcpy(&info->free_track, &free_meta->free_track,
18059e6e098SAndrey Konovalov 		       sizeof(info->free_track));
18159e6e098SAndrey Konovalov 	}
182b89933e9SAndrey Konovalov }
183b89933e9SAndrey Konovalov 
kasan_metadata_fetch_row(char * buffer,void * row)184f00748bfSAndrey Konovalov void kasan_metadata_fetch_row(char *buffer, void *row)
18596e0279dSAndrey Konovalov {
18696e0279dSAndrey Konovalov 	memcpy(buffer, kasan_mem_to_shadow(row), META_BYTES_PER_ROW);
18796e0279dSAndrey Konovalov }
18896e0279dSAndrey Konovalov 
kasan_print_aux_stacks(struct kmem_cache * cache,const void * object)18988f29765SAndrey Konovalov void kasan_print_aux_stacks(struct kmem_cache *cache, const void *object)
19088f29765SAndrey Konovalov {
19188f29765SAndrey Konovalov 	struct kasan_alloc_meta *alloc_meta;
19288f29765SAndrey Konovalov 
19388f29765SAndrey Konovalov 	alloc_meta = kasan_get_alloc_meta(cache, object);
19488f29765SAndrey Konovalov 	if (!alloc_meta)
19588f29765SAndrey Konovalov 		return;
19688f29765SAndrey Konovalov 
19788f29765SAndrey Konovalov 	if (alloc_meta->aux_stack[0]) {
19888f29765SAndrey Konovalov 		pr_err("Last potentially related work creation:\n");
19988f29765SAndrey Konovalov 		stack_depot_print(alloc_meta->aux_stack[0]);
20088f29765SAndrey Konovalov 		pr_err("\n");
20188f29765SAndrey Konovalov 	}
20288f29765SAndrey Konovalov 	if (alloc_meta->aux_stack[1]) {
20388f29765SAndrey Konovalov 		pr_err("Second to last potentially related work creation:\n");
20488f29765SAndrey Konovalov 		stack_depot_print(alloc_meta->aux_stack[1]);
20588f29765SAndrey Konovalov 		pr_err("\n");
20688f29765SAndrey Konovalov 	}
20788f29765SAndrey Konovalov }
20888f29765SAndrey Konovalov 
20902c58773SWalter Wu #ifdef CONFIG_KASAN_STACK
tokenize_frame_descr(const char ** frame_descr,char * token,size_t max_tok_len,unsigned long * value)21097fc7122SAndrey Konovalov static bool __must_check tokenize_frame_descr(const char **frame_descr,
21197fc7122SAndrey Konovalov 					      char *token, size_t max_tok_len,
21297fc7122SAndrey Konovalov 					      unsigned long *value)
21397fc7122SAndrey Konovalov {
21497fc7122SAndrey Konovalov 	const char *sep = strchr(*frame_descr, ' ');
21597fc7122SAndrey Konovalov 
21697fc7122SAndrey Konovalov 	if (sep == NULL)
21797fc7122SAndrey Konovalov 		sep = *frame_descr + strlen(*frame_descr);
21897fc7122SAndrey Konovalov 
21997fc7122SAndrey Konovalov 	if (token != NULL) {
22097fc7122SAndrey Konovalov 		const size_t tok_len = sep - *frame_descr;
22197fc7122SAndrey Konovalov 
22297fc7122SAndrey Konovalov 		if (tok_len + 1 > max_tok_len) {
223d7196d87SAndrey Konovalov 			pr_err("internal error: frame description too long: %s\n",
22497fc7122SAndrey Konovalov 			       *frame_descr);
22597fc7122SAndrey Konovalov 			return false;
22697fc7122SAndrey Konovalov 		}
22797fc7122SAndrey Konovalov 
22897fc7122SAndrey Konovalov 		/* Copy token (+ 1 byte for '\0'). */
229f76e0c41SZhiyuan Dai 		strscpy(token, *frame_descr, tok_len + 1);
23097fc7122SAndrey Konovalov 	}
23197fc7122SAndrey Konovalov 
23297fc7122SAndrey Konovalov 	/* Advance frame_descr past separator. */
23397fc7122SAndrey Konovalov 	*frame_descr = sep + 1;
23497fc7122SAndrey Konovalov 
23597fc7122SAndrey Konovalov 	if (value != NULL && kstrtoul(token, 10, value)) {
236d7196d87SAndrey Konovalov 		pr_err("internal error: not a valid number: %s\n", token);
23797fc7122SAndrey Konovalov 		return false;
23897fc7122SAndrey Konovalov 	}
23997fc7122SAndrey Konovalov 
24097fc7122SAndrey Konovalov 	return true;
24197fc7122SAndrey Konovalov }
24297fc7122SAndrey Konovalov 
print_decoded_frame_descr(const char * frame_descr)24397fc7122SAndrey Konovalov static void print_decoded_frame_descr(const char *frame_descr)
24497fc7122SAndrey Konovalov {
24597fc7122SAndrey Konovalov 	/*
24697fc7122SAndrey Konovalov 	 * We need to parse the following string:
24797fc7122SAndrey Konovalov 	 *    "n alloc_1 alloc_2 ... alloc_n"
24897fc7122SAndrey Konovalov 	 * where alloc_i looks like
24997fc7122SAndrey Konovalov 	 *    "offset size len name"
25097fc7122SAndrey Konovalov 	 * or "offset size len name:line".
25197fc7122SAndrey Konovalov 	 */
25297fc7122SAndrey Konovalov 
25397fc7122SAndrey Konovalov 	char token[64];
25497fc7122SAndrey Konovalov 	unsigned long num_objects;
25597fc7122SAndrey Konovalov 
25697fc7122SAndrey Konovalov 	if (!tokenize_frame_descr(&frame_descr, token, sizeof(token),
25797fc7122SAndrey Konovalov 				  &num_objects))
25897fc7122SAndrey Konovalov 		return;
25997fc7122SAndrey Konovalov 
26097fc7122SAndrey Konovalov 	pr_err("\n");
26116347c31SAndrey Konovalov 	pr_err("This frame has %lu %s:\n", num_objects,
26297fc7122SAndrey Konovalov 	       num_objects == 1 ? "object" : "objects");
26397fc7122SAndrey Konovalov 
26497fc7122SAndrey Konovalov 	while (num_objects--) {
26597fc7122SAndrey Konovalov 		unsigned long offset;
26697fc7122SAndrey Konovalov 		unsigned long size;
26797fc7122SAndrey Konovalov 
26897fc7122SAndrey Konovalov 		/* access offset */
26997fc7122SAndrey Konovalov 		if (!tokenize_frame_descr(&frame_descr, token, sizeof(token),
27097fc7122SAndrey Konovalov 					  &offset))
27197fc7122SAndrey Konovalov 			return;
27297fc7122SAndrey Konovalov 		/* access size */
27397fc7122SAndrey Konovalov 		if (!tokenize_frame_descr(&frame_descr, token, sizeof(token),
27497fc7122SAndrey Konovalov 					  &size))
27597fc7122SAndrey Konovalov 			return;
27697fc7122SAndrey Konovalov 		/* name length (unused) */
27797fc7122SAndrey Konovalov 		if (!tokenize_frame_descr(&frame_descr, NULL, 0, NULL))
27897fc7122SAndrey Konovalov 			return;
27997fc7122SAndrey Konovalov 		/* object name */
28097fc7122SAndrey Konovalov 		if (!tokenize_frame_descr(&frame_descr, token, sizeof(token),
28197fc7122SAndrey Konovalov 					  NULL))
28297fc7122SAndrey Konovalov 			return;
28397fc7122SAndrey Konovalov 
28497fc7122SAndrey Konovalov 		/* Strip line number; without filename it's not very helpful. */
28597fc7122SAndrey Konovalov 		strreplace(token, ':', '\0');
28697fc7122SAndrey Konovalov 
28797fc7122SAndrey Konovalov 		/* Finally, print object information. */
28897fc7122SAndrey Konovalov 		pr_err(" [%lu, %lu) '%s'", offset, offset + size, token);
28997fc7122SAndrey Konovalov 	}
29097fc7122SAndrey Konovalov }
29197fc7122SAndrey Konovalov 
2920f9b35f3SAndrey Konovalov /* Returns true only if the address is on the current task's stack. */
get_address_stack_frame_info(const void * addr,unsigned long * offset,const char ** frame_descr,const void ** frame_pc)29397fc7122SAndrey Konovalov static bool __must_check get_address_stack_frame_info(const void *addr,
29497fc7122SAndrey Konovalov 						      unsigned long *offset,
29597fc7122SAndrey Konovalov 						      const char **frame_descr,
29697fc7122SAndrey Konovalov 						      const void **frame_pc)
29797fc7122SAndrey Konovalov {
29897fc7122SAndrey Konovalov 	unsigned long aligned_addr;
29997fc7122SAndrey Konovalov 	unsigned long mem_ptr;
30097fc7122SAndrey Konovalov 	const u8 *shadow_bottom;
30197fc7122SAndrey Konovalov 	const u8 *shadow_ptr;
30297fc7122SAndrey Konovalov 	const unsigned long *frame;
30397fc7122SAndrey Konovalov 
30497fc7122SAndrey Konovalov 	BUILD_BUG_ON(IS_ENABLED(CONFIG_STACK_GROWSUP));
30597fc7122SAndrey Konovalov 
30697fc7122SAndrey Konovalov 	aligned_addr = round_down((unsigned long)addr, sizeof(long));
30797fc7122SAndrey Konovalov 	mem_ptr = round_down(aligned_addr, KASAN_GRANULE_SIZE);
30897fc7122SAndrey Konovalov 	shadow_ptr = kasan_mem_to_shadow((void *)aligned_addr);
30997fc7122SAndrey Konovalov 	shadow_bottom = kasan_mem_to_shadow(end_of_stack(current));
31097fc7122SAndrey Konovalov 
31197fc7122SAndrey Konovalov 	while (shadow_ptr >= shadow_bottom && *shadow_ptr != KASAN_STACK_LEFT) {
31297fc7122SAndrey Konovalov 		shadow_ptr--;
31397fc7122SAndrey Konovalov 		mem_ptr -= KASAN_GRANULE_SIZE;
31497fc7122SAndrey Konovalov 	}
31597fc7122SAndrey Konovalov 
31697fc7122SAndrey Konovalov 	while (shadow_ptr >= shadow_bottom && *shadow_ptr == KASAN_STACK_LEFT) {
31797fc7122SAndrey Konovalov 		shadow_ptr--;
31897fc7122SAndrey Konovalov 		mem_ptr -= KASAN_GRANULE_SIZE;
31997fc7122SAndrey Konovalov 	}
32097fc7122SAndrey Konovalov 
32197fc7122SAndrey Konovalov 	if (shadow_ptr < shadow_bottom)
32297fc7122SAndrey Konovalov 		return false;
32397fc7122SAndrey Konovalov 
32497fc7122SAndrey Konovalov 	frame = (const unsigned long *)(mem_ptr + KASAN_GRANULE_SIZE);
32597fc7122SAndrey Konovalov 	if (frame[0] != KASAN_CURRENT_STACK_FRAME_MAGIC) {
326d7196d87SAndrey Konovalov 		pr_err("internal error: frame has invalid marker: %lu\n",
32797fc7122SAndrey Konovalov 		       frame[0]);
32897fc7122SAndrey Konovalov 		return false;
32997fc7122SAndrey Konovalov 	}
33097fc7122SAndrey Konovalov 
33197fc7122SAndrey Konovalov 	*offset = (unsigned long)addr - (unsigned long)frame;
33297fc7122SAndrey Konovalov 	*frame_descr = (const char *)frame[1];
33397fc7122SAndrey Konovalov 	*frame_pc = (void *)frame[2];
33497fc7122SAndrey Konovalov 
33597fc7122SAndrey Konovalov 	return true;
33697fc7122SAndrey Konovalov }
33797fc7122SAndrey Konovalov 
kasan_print_address_stack_frame(const void * addr)338f00748bfSAndrey Konovalov void kasan_print_address_stack_frame(const void *addr)
33997fc7122SAndrey Konovalov {
34097fc7122SAndrey Konovalov 	unsigned long offset;
34197fc7122SAndrey Konovalov 	const char *frame_descr;
34297fc7122SAndrey Konovalov 	const void *frame_pc;
34397fc7122SAndrey Konovalov 
3440f9b35f3SAndrey Konovalov 	if (WARN_ON(!object_is_on_stack(addr)))
3450f9b35f3SAndrey Konovalov 		return;
3460f9b35f3SAndrey Konovalov 
34716347c31SAndrey Konovalov 	pr_err("The buggy address belongs to stack of task %s/%d\n",
34816347c31SAndrey Konovalov 	       current->comm, task_pid_nr(current));
34916347c31SAndrey Konovalov 
35097fc7122SAndrey Konovalov 	if (!get_address_stack_frame_info(addr, &offset, &frame_descr,
35197fc7122SAndrey Konovalov 					  &frame_pc))
35297fc7122SAndrey Konovalov 		return;
35397fc7122SAndrey Konovalov 
35416347c31SAndrey Konovalov 	pr_err(" and is located at offset %lu in frame:\n", offset);
35597fc7122SAndrey Konovalov 	pr_err(" %pS\n", frame_pc);
35697fc7122SAndrey Konovalov 
35797fc7122SAndrey Konovalov 	if (!frame_descr)
35897fc7122SAndrey Konovalov 		return;
35997fc7122SAndrey Konovalov 
36097fc7122SAndrey Konovalov 	print_decoded_frame_descr(frame_descr);
36197fc7122SAndrey Konovalov }
36297fc7122SAndrey Konovalov #endif /* CONFIG_KASAN_STACK */
36397fc7122SAndrey Konovalov 
36459fd51b2SAndrey Konovalov #define DEFINE_ASAN_REPORT_LOAD(size)                     \
365bb6e04a1SArnd Bergmann void __asan_report_load##size##_noabort(void *addr) \
36659fd51b2SAndrey Konovalov {                                                         \
36759fd51b2SAndrey Konovalov 	kasan_report(addr, size, false, _RET_IP_);	  \
36859fd51b2SAndrey Konovalov }                                                         \
36959fd51b2SAndrey Konovalov EXPORT_SYMBOL(__asan_report_load##size##_noabort)
37059fd51b2SAndrey Konovalov 
37159fd51b2SAndrey Konovalov #define DEFINE_ASAN_REPORT_STORE(size)                     \
372bb6e04a1SArnd Bergmann void __asan_report_store##size##_noabort(void *addr) \
37359fd51b2SAndrey Konovalov {                                                          \
37459fd51b2SAndrey Konovalov 	kasan_report(addr, size, true, _RET_IP_);	   \
37559fd51b2SAndrey Konovalov }                                                          \
37659fd51b2SAndrey Konovalov EXPORT_SYMBOL(__asan_report_store##size##_noabort)
37759fd51b2SAndrey Konovalov 
37859fd51b2SAndrey Konovalov DEFINE_ASAN_REPORT_LOAD(1);
37959fd51b2SAndrey Konovalov DEFINE_ASAN_REPORT_LOAD(2);
38059fd51b2SAndrey Konovalov DEFINE_ASAN_REPORT_LOAD(4);
38159fd51b2SAndrey Konovalov DEFINE_ASAN_REPORT_LOAD(8);
38259fd51b2SAndrey Konovalov DEFINE_ASAN_REPORT_LOAD(16);
38359fd51b2SAndrey Konovalov DEFINE_ASAN_REPORT_STORE(1);
38459fd51b2SAndrey Konovalov DEFINE_ASAN_REPORT_STORE(2);
38559fd51b2SAndrey Konovalov DEFINE_ASAN_REPORT_STORE(4);
38659fd51b2SAndrey Konovalov DEFINE_ASAN_REPORT_STORE(8);
38759fd51b2SAndrey Konovalov DEFINE_ASAN_REPORT_STORE(16);
38859fd51b2SAndrey Konovalov 
__asan_report_load_n_noabort(void * addr,ssize_t size)389bb6e04a1SArnd Bergmann void __asan_report_load_n_noabort(void *addr, ssize_t size)
39059fd51b2SAndrey Konovalov {
39159fd51b2SAndrey Konovalov 	kasan_report(addr, size, false, _RET_IP_);
39259fd51b2SAndrey Konovalov }
39359fd51b2SAndrey Konovalov EXPORT_SYMBOL(__asan_report_load_n_noabort);
39459fd51b2SAndrey Konovalov 
__asan_report_store_n_noabort(void * addr,ssize_t size)395bb6e04a1SArnd Bergmann void __asan_report_store_n_noabort(void *addr, ssize_t size)
39659fd51b2SAndrey Konovalov {
39759fd51b2SAndrey Konovalov 	kasan_report(addr, size, true, _RET_IP_);
39859fd51b2SAndrey Konovalov }
39959fd51b2SAndrey Konovalov EXPORT_SYMBOL(__asan_report_store_n_noabort);
400