18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * This file contains generic KASAN specific error reporting code. 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (c) 2014 Samsung Electronics Co., Ltd. 68c2ecf20Sopenharmony_ci * Author: Andrey Ryabinin <ryabinin.a.a@gmail.com> 78c2ecf20Sopenharmony_ci * 88c2ecf20Sopenharmony_ci * Some code borrowed from https://github.com/xairy/kasan-prototype by 98c2ecf20Sopenharmony_ci * Andrey Konovalov <andreyknvl@gmail.com> 108c2ecf20Sopenharmony_ci * 118c2ecf20Sopenharmony_ci * This program is free software; you can redistribute it and/or modify 128c2ecf20Sopenharmony_ci * it under the terms of the GNU General Public License version 2 as 138c2ecf20Sopenharmony_ci * published by the Free Software Foundation. 148c2ecf20Sopenharmony_ci * 158c2ecf20Sopenharmony_ci */ 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_ci#include <linux/bitops.h> 188c2ecf20Sopenharmony_ci#include <linux/ftrace.h> 198c2ecf20Sopenharmony_ci#include <linux/init.h> 208c2ecf20Sopenharmony_ci#include <linux/kernel.h> 218c2ecf20Sopenharmony_ci#include <linux/mm.h> 228c2ecf20Sopenharmony_ci#include <linux/printk.h> 238c2ecf20Sopenharmony_ci#include <linux/sched.h> 248c2ecf20Sopenharmony_ci#include <linux/slab.h> 258c2ecf20Sopenharmony_ci#include <linux/stackdepot.h> 268c2ecf20Sopenharmony_ci#include <linux/stacktrace.h> 278c2ecf20Sopenharmony_ci#include <linux/string.h> 288c2ecf20Sopenharmony_ci#include <linux/types.h> 298c2ecf20Sopenharmony_ci#include <linux/kasan.h> 308c2ecf20Sopenharmony_ci#include <linux/module.h> 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_ci#include <asm/sections.h> 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_ci#include "kasan.h" 358c2ecf20Sopenharmony_ci#include "../slab.h" 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_civoid *find_first_bad_addr(void *addr, size_t size) 388c2ecf20Sopenharmony_ci{ 398c2ecf20Sopenharmony_ci void *p = addr; 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_ci while (p < addr + size && !(*(u8 *)kasan_mem_to_shadow(p))) 428c2ecf20Sopenharmony_ci p += KASAN_SHADOW_SCALE_SIZE; 438c2ecf20Sopenharmony_ci return p; 448c2ecf20Sopenharmony_ci} 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_cistatic const char *get_shadow_bug_type(struct kasan_access_info *info) 478c2ecf20Sopenharmony_ci{ 488c2ecf20Sopenharmony_ci const char *bug_type = "unknown-crash"; 498c2ecf20Sopenharmony_ci u8 *shadow_addr; 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_ci shadow_addr = (u8 *)kasan_mem_to_shadow(info->first_bad_addr); 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_ci /* 548c2ecf20Sopenharmony_ci * If shadow byte value is in [0, KASAN_SHADOW_SCALE_SIZE) we can look 558c2ecf20Sopenharmony_ci * at the next shadow byte to determine the type of the bad access. 568c2ecf20Sopenharmony_ci */ 578c2ecf20Sopenharmony_ci if (*shadow_addr > 0 && *shadow_addr <= KASAN_SHADOW_SCALE_SIZE - 1) 588c2ecf20Sopenharmony_ci shadow_addr++; 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_ci switch (*shadow_addr) { 618c2ecf20Sopenharmony_ci case 0 ... KASAN_SHADOW_SCALE_SIZE - 1: 628c2ecf20Sopenharmony_ci /* 638c2ecf20Sopenharmony_ci * In theory it's still possible to see these shadow values 648c2ecf20Sopenharmony_ci * due to a data race in the kernel code. 658c2ecf20Sopenharmony_ci */ 668c2ecf20Sopenharmony_ci bug_type = "out-of-bounds"; 678c2ecf20Sopenharmony_ci break; 688c2ecf20Sopenharmony_ci case KASAN_PAGE_REDZONE: 698c2ecf20Sopenharmony_ci case KASAN_KMALLOC_REDZONE: 708c2ecf20Sopenharmony_ci bug_type = "slab-out-of-bounds"; 718c2ecf20Sopenharmony_ci break; 728c2ecf20Sopenharmony_ci case KASAN_GLOBAL_REDZONE: 738c2ecf20Sopenharmony_ci bug_type = "global-out-of-bounds"; 748c2ecf20Sopenharmony_ci break; 758c2ecf20Sopenharmony_ci case KASAN_STACK_LEFT: 768c2ecf20Sopenharmony_ci case KASAN_STACK_MID: 778c2ecf20Sopenharmony_ci case KASAN_STACK_RIGHT: 788c2ecf20Sopenharmony_ci case KASAN_STACK_PARTIAL: 798c2ecf20Sopenharmony_ci bug_type = "stack-out-of-bounds"; 808c2ecf20Sopenharmony_ci break; 818c2ecf20Sopenharmony_ci case KASAN_FREE_PAGE: 828c2ecf20Sopenharmony_ci case KASAN_KMALLOC_FREE: 838c2ecf20Sopenharmony_ci case KASAN_KMALLOC_FREETRACK: 848c2ecf20Sopenharmony_ci bug_type = "use-after-free"; 858c2ecf20Sopenharmony_ci break; 868c2ecf20Sopenharmony_ci case KASAN_ALLOCA_LEFT: 878c2ecf20Sopenharmony_ci case KASAN_ALLOCA_RIGHT: 888c2ecf20Sopenharmony_ci bug_type = "alloca-out-of-bounds"; 898c2ecf20Sopenharmony_ci break; 908c2ecf20Sopenharmony_ci case KASAN_VMALLOC_INVALID: 918c2ecf20Sopenharmony_ci bug_type = "vmalloc-out-of-bounds"; 928c2ecf20Sopenharmony_ci break; 938c2ecf20Sopenharmony_ci } 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_ci return bug_type; 968c2ecf20Sopenharmony_ci} 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_cistatic const char *get_wild_bug_type(struct kasan_access_info *info) 998c2ecf20Sopenharmony_ci{ 1008c2ecf20Sopenharmony_ci const char *bug_type = "unknown-crash"; 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_ci if ((unsigned long)info->access_addr < PAGE_SIZE) 1038c2ecf20Sopenharmony_ci bug_type = "null-ptr-deref"; 1048c2ecf20Sopenharmony_ci else if ((unsigned long)info->access_addr < TASK_SIZE) 1058c2ecf20Sopenharmony_ci bug_type = "user-memory-access"; 1068c2ecf20Sopenharmony_ci else 1078c2ecf20Sopenharmony_ci bug_type = "wild-memory-access"; 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_ci return bug_type; 1108c2ecf20Sopenharmony_ci} 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_ciconst char *get_bug_type(struct kasan_access_info *info) 1138c2ecf20Sopenharmony_ci{ 1148c2ecf20Sopenharmony_ci /* 1158c2ecf20Sopenharmony_ci * If access_size is a negative number, then it has reason to be 1168c2ecf20Sopenharmony_ci * defined as out-of-bounds bug type. 1178c2ecf20Sopenharmony_ci * 1188c2ecf20Sopenharmony_ci * Casting negative numbers to size_t would indeed turn up as 1198c2ecf20Sopenharmony_ci * a large size_t and its value will be larger than ULONG_MAX/2, 1208c2ecf20Sopenharmony_ci * so that this can qualify as out-of-bounds. 1218c2ecf20Sopenharmony_ci */ 1228c2ecf20Sopenharmony_ci if (info->access_addr + info->access_size < info->access_addr) 1238c2ecf20Sopenharmony_ci return "out-of-bounds"; 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_ci if (addr_has_shadow(info->access_addr)) 1268c2ecf20Sopenharmony_ci return get_shadow_bug_type(info); 1278c2ecf20Sopenharmony_ci return get_wild_bug_type(info); 1288c2ecf20Sopenharmony_ci} 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_ci#define DEFINE_ASAN_REPORT_LOAD(size) \ 1318c2ecf20Sopenharmony_civoid __asan_report_load##size##_noabort(unsigned long addr) \ 1328c2ecf20Sopenharmony_ci{ \ 1338c2ecf20Sopenharmony_ci kasan_report(addr, size, false, _RET_IP_); \ 1348c2ecf20Sopenharmony_ci} \ 1358c2ecf20Sopenharmony_ciEXPORT_SYMBOL(__asan_report_load##size##_noabort) 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_ci#define DEFINE_ASAN_REPORT_STORE(size) \ 1388c2ecf20Sopenharmony_civoid __asan_report_store##size##_noabort(unsigned long addr) \ 1398c2ecf20Sopenharmony_ci{ \ 1408c2ecf20Sopenharmony_ci kasan_report(addr, size, true, _RET_IP_); \ 1418c2ecf20Sopenharmony_ci} \ 1428c2ecf20Sopenharmony_ciEXPORT_SYMBOL(__asan_report_store##size##_noabort) 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_ciDEFINE_ASAN_REPORT_LOAD(1); 1458c2ecf20Sopenharmony_ciDEFINE_ASAN_REPORT_LOAD(2); 1468c2ecf20Sopenharmony_ciDEFINE_ASAN_REPORT_LOAD(4); 1478c2ecf20Sopenharmony_ciDEFINE_ASAN_REPORT_LOAD(8); 1488c2ecf20Sopenharmony_ciDEFINE_ASAN_REPORT_LOAD(16); 1498c2ecf20Sopenharmony_ciDEFINE_ASAN_REPORT_STORE(1); 1508c2ecf20Sopenharmony_ciDEFINE_ASAN_REPORT_STORE(2); 1518c2ecf20Sopenharmony_ciDEFINE_ASAN_REPORT_STORE(4); 1528c2ecf20Sopenharmony_ciDEFINE_ASAN_REPORT_STORE(8); 1538c2ecf20Sopenharmony_ciDEFINE_ASAN_REPORT_STORE(16); 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_civoid __asan_report_load_n_noabort(unsigned long addr, size_t size) 1568c2ecf20Sopenharmony_ci{ 1578c2ecf20Sopenharmony_ci kasan_report(addr, size, false, _RET_IP_); 1588c2ecf20Sopenharmony_ci} 1598c2ecf20Sopenharmony_ciEXPORT_SYMBOL(__asan_report_load_n_noabort); 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_civoid __asan_report_store_n_noabort(unsigned long addr, size_t size) 1628c2ecf20Sopenharmony_ci{ 1638c2ecf20Sopenharmony_ci kasan_report(addr, size, true, _RET_IP_); 1648c2ecf20Sopenharmony_ci} 1658c2ecf20Sopenharmony_ciEXPORT_SYMBOL(__asan_report_store_n_noabort); 166