1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * This file contains software tag-based 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 const char *kasan_get_bug_type(struct kasan_access_info *info) 33 { 34 #ifdef CONFIG_KASAN_SW_TAGS_IDENTIFY 35 struct kasan_alloc_meta *alloc_meta; 36 struct kmem_cache *cache; 37 struct page *page; 38 const void *addr; 39 void *object; 40 u8 tag; 41 int i; 42 43 tag = get_tag(info->access_addr); 44 addr = kasan_reset_tag(info->access_addr); 45 page = kasan_addr_to_page(addr); 46 if (page && PageSlab(page)) { 47 cache = page->slab_cache; 48 object = nearest_obj(cache, page, (void *)addr); 49 alloc_meta = kasan_get_alloc_meta(cache, object); 50 51 if (alloc_meta) { 52 for (i = 0; i < KASAN_NR_FREE_STACKS; i++) { 53 if (alloc_meta->free_pointer_tag[i] == tag) 54 return "use-after-free"; 55 } 56 } 57 return "out-of-bounds"; 58 } 59 60 #endif 61 /* 62 * If access_size is a negative number, then it has reason to be 63 * defined as out-of-bounds bug type. 64 * 65 * Casting negative numbers to size_t would indeed turn up as 66 * a large size_t and its value will be larger than ULONG_MAX/2, 67 * so that this can qualify as out-of-bounds. 68 */ 69 if (info->access_addr + info->access_size < info->access_addr) 70 return "out-of-bounds"; 71 72 return "invalid-access"; 73 } 74 75 void *kasan_find_first_bad_addr(void *addr, size_t size) 76 { 77 u8 tag = get_tag(addr); 78 void *p = kasan_reset_tag(addr); 79 void *end = p + size; 80 81 while (p < end && tag == *(u8 *)kasan_mem_to_shadow(p)) 82 p += KASAN_GRANULE_SIZE; 83 return p; 84 } 85 86 void kasan_metadata_fetch_row(char *buffer, void *row) 87 { 88 memcpy(buffer, kasan_mem_to_shadow(row), META_BYTES_PER_ROW); 89 } 90 91 void kasan_print_tags(u8 addr_tag, const void *addr) 92 { 93 u8 *shadow = (u8 *)kasan_mem_to_shadow(addr); 94 95 pr_err("Pointer tag: [%02x], memory tag: [%02x]\n", addr_tag, *shadow); 96 } 97