18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * This file contains core generic KASAN 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#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_ci#include <linux/export.h> 208c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 218c2ecf20Sopenharmony_ci#include <linux/init.h> 228c2ecf20Sopenharmony_ci#include <linux/kasan.h> 238c2ecf20Sopenharmony_ci#include <linux/kernel.h> 248c2ecf20Sopenharmony_ci#include <linux/kmemleak.h> 258c2ecf20Sopenharmony_ci#include <linux/linkage.h> 268c2ecf20Sopenharmony_ci#include <linux/memblock.h> 278c2ecf20Sopenharmony_ci#include <linux/memory.h> 288c2ecf20Sopenharmony_ci#include <linux/mm.h> 298c2ecf20Sopenharmony_ci#include <linux/module.h> 308c2ecf20Sopenharmony_ci#include <linux/printk.h> 318c2ecf20Sopenharmony_ci#include <linux/sched.h> 328c2ecf20Sopenharmony_ci#include <linux/sched/task_stack.h> 338c2ecf20Sopenharmony_ci#include <linux/slab.h> 348c2ecf20Sopenharmony_ci#include <linux/stacktrace.h> 358c2ecf20Sopenharmony_ci#include <linux/string.h> 368c2ecf20Sopenharmony_ci#include <linux/types.h> 378c2ecf20Sopenharmony_ci#include <linux/vmalloc.h> 388c2ecf20Sopenharmony_ci#include <linux/bug.h> 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_ci#include "kasan.h" 418c2ecf20Sopenharmony_ci#include "../slab.h" 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_ci/* 448c2ecf20Sopenharmony_ci * All functions below always inlined so compiler could 458c2ecf20Sopenharmony_ci * perform better optimizations in each of __asan_loadX/__assn_storeX 468c2ecf20Sopenharmony_ci * depending on memory access size X. 478c2ecf20Sopenharmony_ci */ 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_cistatic __always_inline bool memory_is_poisoned_1(unsigned long addr) 508c2ecf20Sopenharmony_ci{ 518c2ecf20Sopenharmony_ci s8 shadow_value = *(s8 *)kasan_mem_to_shadow((void *)addr); 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_ci if (unlikely(shadow_value)) { 548c2ecf20Sopenharmony_ci s8 last_accessible_byte = addr & KASAN_SHADOW_MASK; 558c2ecf20Sopenharmony_ci return unlikely(last_accessible_byte >= shadow_value); 568c2ecf20Sopenharmony_ci } 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_ci return false; 598c2ecf20Sopenharmony_ci} 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_cistatic __always_inline bool memory_is_poisoned_2_4_8(unsigned long addr, 628c2ecf20Sopenharmony_ci unsigned long size) 638c2ecf20Sopenharmony_ci{ 648c2ecf20Sopenharmony_ci u8 *shadow_addr = (u8 *)kasan_mem_to_shadow((void *)addr); 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_ci /* 678c2ecf20Sopenharmony_ci * Access crosses 8(shadow size)-byte boundary. Such access maps 688c2ecf20Sopenharmony_ci * into 2 shadow bytes, so we need to check them both. 698c2ecf20Sopenharmony_ci */ 708c2ecf20Sopenharmony_ci if (unlikely(((addr + size - 1) & KASAN_SHADOW_MASK) < size - 1)) 718c2ecf20Sopenharmony_ci return *shadow_addr || memory_is_poisoned_1(addr + size - 1); 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_ci return memory_is_poisoned_1(addr + size - 1); 748c2ecf20Sopenharmony_ci} 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_cistatic __always_inline bool memory_is_poisoned_16(unsigned long addr) 778c2ecf20Sopenharmony_ci{ 788c2ecf20Sopenharmony_ci u16 *shadow_addr = (u16 *)kasan_mem_to_shadow((void *)addr); 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_ci /* Unaligned 16-bytes access maps into 3 shadow bytes. */ 818c2ecf20Sopenharmony_ci if (unlikely(!IS_ALIGNED(addr, KASAN_SHADOW_SCALE_SIZE))) 828c2ecf20Sopenharmony_ci return *shadow_addr || memory_is_poisoned_1(addr + 15); 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_ci return *shadow_addr; 858c2ecf20Sopenharmony_ci} 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_cistatic __always_inline unsigned long bytes_is_nonzero(const u8 *start, 888c2ecf20Sopenharmony_ci size_t size) 898c2ecf20Sopenharmony_ci{ 908c2ecf20Sopenharmony_ci while (size) { 918c2ecf20Sopenharmony_ci if (unlikely(*start)) 928c2ecf20Sopenharmony_ci return (unsigned long)start; 938c2ecf20Sopenharmony_ci start++; 948c2ecf20Sopenharmony_ci size--; 958c2ecf20Sopenharmony_ci } 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_ci return 0; 988c2ecf20Sopenharmony_ci} 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_cistatic __always_inline unsigned long memory_is_nonzero(const void *start, 1018c2ecf20Sopenharmony_ci const void *end) 1028c2ecf20Sopenharmony_ci{ 1038c2ecf20Sopenharmony_ci unsigned int words; 1048c2ecf20Sopenharmony_ci unsigned long ret; 1058c2ecf20Sopenharmony_ci unsigned int prefix = (unsigned long)start % 8; 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_ci if (end - start <= 16) 1088c2ecf20Sopenharmony_ci return bytes_is_nonzero(start, end - start); 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_ci if (prefix) { 1118c2ecf20Sopenharmony_ci prefix = 8 - prefix; 1128c2ecf20Sopenharmony_ci ret = bytes_is_nonzero(start, prefix); 1138c2ecf20Sopenharmony_ci if (unlikely(ret)) 1148c2ecf20Sopenharmony_ci return ret; 1158c2ecf20Sopenharmony_ci start += prefix; 1168c2ecf20Sopenharmony_ci } 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_ci words = (end - start) / 8; 1198c2ecf20Sopenharmony_ci while (words) { 1208c2ecf20Sopenharmony_ci if (unlikely(*(u64 *)start)) 1218c2ecf20Sopenharmony_ci return bytes_is_nonzero(start, 8); 1228c2ecf20Sopenharmony_ci start += 8; 1238c2ecf20Sopenharmony_ci words--; 1248c2ecf20Sopenharmony_ci } 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_ci return bytes_is_nonzero(start, (end - start) % 8); 1278c2ecf20Sopenharmony_ci} 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_cistatic __always_inline bool memory_is_poisoned_n(unsigned long addr, 1308c2ecf20Sopenharmony_ci size_t size) 1318c2ecf20Sopenharmony_ci{ 1328c2ecf20Sopenharmony_ci unsigned long ret; 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_ci ret = memory_is_nonzero(kasan_mem_to_shadow((void *)addr), 1358c2ecf20Sopenharmony_ci kasan_mem_to_shadow((void *)addr + size - 1) + 1); 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_ci if (unlikely(ret)) { 1388c2ecf20Sopenharmony_ci unsigned long last_byte = addr + size - 1; 1398c2ecf20Sopenharmony_ci s8 *last_shadow = (s8 *)kasan_mem_to_shadow((void *)last_byte); 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_ci if (unlikely(ret != (unsigned long)last_shadow || 1428c2ecf20Sopenharmony_ci ((long)(last_byte & KASAN_SHADOW_MASK) >= *last_shadow))) 1438c2ecf20Sopenharmony_ci return true; 1448c2ecf20Sopenharmony_ci } 1458c2ecf20Sopenharmony_ci return false; 1468c2ecf20Sopenharmony_ci} 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_cistatic __always_inline bool memory_is_poisoned(unsigned long addr, size_t size) 1498c2ecf20Sopenharmony_ci{ 1508c2ecf20Sopenharmony_ci if (__builtin_constant_p(size)) { 1518c2ecf20Sopenharmony_ci switch (size) { 1528c2ecf20Sopenharmony_ci case 1: 1538c2ecf20Sopenharmony_ci return memory_is_poisoned_1(addr); 1548c2ecf20Sopenharmony_ci case 2: 1558c2ecf20Sopenharmony_ci case 4: 1568c2ecf20Sopenharmony_ci case 8: 1578c2ecf20Sopenharmony_ci return memory_is_poisoned_2_4_8(addr, size); 1588c2ecf20Sopenharmony_ci case 16: 1598c2ecf20Sopenharmony_ci return memory_is_poisoned_16(addr); 1608c2ecf20Sopenharmony_ci default: 1618c2ecf20Sopenharmony_ci BUILD_BUG(); 1628c2ecf20Sopenharmony_ci } 1638c2ecf20Sopenharmony_ci } 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_ci return memory_is_poisoned_n(addr, size); 1668c2ecf20Sopenharmony_ci} 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_cistatic __always_inline bool check_memory_region_inline(unsigned long addr, 1698c2ecf20Sopenharmony_ci size_t size, bool write, 1708c2ecf20Sopenharmony_ci unsigned long ret_ip) 1718c2ecf20Sopenharmony_ci{ 1728c2ecf20Sopenharmony_ci if (unlikely(size == 0)) 1738c2ecf20Sopenharmony_ci return true; 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_ci if (unlikely(addr + size < addr)) 1768c2ecf20Sopenharmony_ci return !kasan_report(addr, size, write, ret_ip); 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_ci#ifndef __HAVE_ARCH_SHADOW_MAP 1798c2ecf20Sopenharmony_ci if (unlikely((void *)addr < 1808c2ecf20Sopenharmony_ci kasan_shadow_to_mem((void *)KASAN_SHADOW_START))) { 1818c2ecf20Sopenharmony_ci return !kasan_report(addr, size, write, ret_ip); 1828c2ecf20Sopenharmony_ci } 1838c2ecf20Sopenharmony_ci#else 1848c2ecf20Sopenharmony_ci if (unlikely(kasan_mem_to_shadow((void *)addr) == NULL)) { 1858c2ecf20Sopenharmony_ci return !kasan_report(addr, size, write, ret_ip); 1868c2ecf20Sopenharmony_ci } 1878c2ecf20Sopenharmony_ci#endif 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_ci if (likely(!memory_is_poisoned(addr, size))) 1908c2ecf20Sopenharmony_ci return true; 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_ci return !kasan_report(addr, size, write, ret_ip); 1938c2ecf20Sopenharmony_ci} 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_cibool check_memory_region(unsigned long addr, size_t size, bool write, 1968c2ecf20Sopenharmony_ci unsigned long ret_ip) 1978c2ecf20Sopenharmony_ci{ 1988c2ecf20Sopenharmony_ci return check_memory_region_inline(addr, size, write, ret_ip); 1998c2ecf20Sopenharmony_ci} 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_civoid kasan_cache_shrink(struct kmem_cache *cache) 2028c2ecf20Sopenharmony_ci{ 2038c2ecf20Sopenharmony_ci quarantine_remove_cache(cache); 2048c2ecf20Sopenharmony_ci} 2058c2ecf20Sopenharmony_ci 2068c2ecf20Sopenharmony_civoid kasan_cache_shutdown(struct kmem_cache *cache) 2078c2ecf20Sopenharmony_ci{ 2088c2ecf20Sopenharmony_ci if (!__kmem_cache_empty(cache)) 2098c2ecf20Sopenharmony_ci quarantine_remove_cache(cache); 2108c2ecf20Sopenharmony_ci} 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_cistatic void register_global(struct kasan_global *global) 2138c2ecf20Sopenharmony_ci{ 2148c2ecf20Sopenharmony_ci size_t aligned_size = round_up(global->size, KASAN_SHADOW_SCALE_SIZE); 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_ci kasan_unpoison_shadow(global->beg, global->size); 2178c2ecf20Sopenharmony_ci 2188c2ecf20Sopenharmony_ci kasan_poison_shadow(global->beg + aligned_size, 2198c2ecf20Sopenharmony_ci global->size_with_redzone - aligned_size, 2208c2ecf20Sopenharmony_ci KASAN_GLOBAL_REDZONE); 2218c2ecf20Sopenharmony_ci} 2228c2ecf20Sopenharmony_ci 2238c2ecf20Sopenharmony_civoid __asan_register_globals(struct kasan_global *globals, size_t size) 2248c2ecf20Sopenharmony_ci{ 2258c2ecf20Sopenharmony_ci int i; 2268c2ecf20Sopenharmony_ci 2278c2ecf20Sopenharmony_ci for (i = 0; i < size; i++) 2288c2ecf20Sopenharmony_ci register_global(&globals[i]); 2298c2ecf20Sopenharmony_ci} 2308c2ecf20Sopenharmony_ciEXPORT_SYMBOL(__asan_register_globals); 2318c2ecf20Sopenharmony_ci 2328c2ecf20Sopenharmony_civoid __asan_unregister_globals(struct kasan_global *globals, size_t size) 2338c2ecf20Sopenharmony_ci{ 2348c2ecf20Sopenharmony_ci} 2358c2ecf20Sopenharmony_ciEXPORT_SYMBOL(__asan_unregister_globals); 2368c2ecf20Sopenharmony_ci 2378c2ecf20Sopenharmony_ci#define DEFINE_ASAN_LOAD_STORE(size) \ 2388c2ecf20Sopenharmony_ci void __asan_load##size(unsigned long addr) \ 2398c2ecf20Sopenharmony_ci { \ 2408c2ecf20Sopenharmony_ci check_memory_region_inline(addr, size, false, _RET_IP_);\ 2418c2ecf20Sopenharmony_ci } \ 2428c2ecf20Sopenharmony_ci EXPORT_SYMBOL(__asan_load##size); \ 2438c2ecf20Sopenharmony_ci __alias(__asan_load##size) \ 2448c2ecf20Sopenharmony_ci void __asan_load##size##_noabort(unsigned long); \ 2458c2ecf20Sopenharmony_ci EXPORT_SYMBOL(__asan_load##size##_noabort); \ 2468c2ecf20Sopenharmony_ci void __asan_store##size(unsigned long addr) \ 2478c2ecf20Sopenharmony_ci { \ 2488c2ecf20Sopenharmony_ci check_memory_region_inline(addr, size, true, _RET_IP_); \ 2498c2ecf20Sopenharmony_ci } \ 2508c2ecf20Sopenharmony_ci EXPORT_SYMBOL(__asan_store##size); \ 2518c2ecf20Sopenharmony_ci __alias(__asan_store##size) \ 2528c2ecf20Sopenharmony_ci void __asan_store##size##_noabort(unsigned long); \ 2538c2ecf20Sopenharmony_ci EXPORT_SYMBOL(__asan_store##size##_noabort) 2548c2ecf20Sopenharmony_ci 2558c2ecf20Sopenharmony_ciDEFINE_ASAN_LOAD_STORE(1); 2568c2ecf20Sopenharmony_ciDEFINE_ASAN_LOAD_STORE(2); 2578c2ecf20Sopenharmony_ciDEFINE_ASAN_LOAD_STORE(4); 2588c2ecf20Sopenharmony_ciDEFINE_ASAN_LOAD_STORE(8); 2598c2ecf20Sopenharmony_ciDEFINE_ASAN_LOAD_STORE(16); 2608c2ecf20Sopenharmony_ci 2618c2ecf20Sopenharmony_civoid __asan_loadN(unsigned long addr, size_t size) 2628c2ecf20Sopenharmony_ci{ 2638c2ecf20Sopenharmony_ci check_memory_region(addr, size, false, _RET_IP_); 2648c2ecf20Sopenharmony_ci} 2658c2ecf20Sopenharmony_ciEXPORT_SYMBOL(__asan_loadN); 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_ci__alias(__asan_loadN) 2688c2ecf20Sopenharmony_civoid __asan_loadN_noabort(unsigned long, size_t); 2698c2ecf20Sopenharmony_ciEXPORT_SYMBOL(__asan_loadN_noabort); 2708c2ecf20Sopenharmony_ci 2718c2ecf20Sopenharmony_civoid __asan_storeN(unsigned long addr, size_t size) 2728c2ecf20Sopenharmony_ci{ 2738c2ecf20Sopenharmony_ci check_memory_region(addr, size, true, _RET_IP_); 2748c2ecf20Sopenharmony_ci} 2758c2ecf20Sopenharmony_ciEXPORT_SYMBOL(__asan_storeN); 2768c2ecf20Sopenharmony_ci 2778c2ecf20Sopenharmony_ci__alias(__asan_storeN) 2788c2ecf20Sopenharmony_civoid __asan_storeN_noabort(unsigned long, size_t); 2798c2ecf20Sopenharmony_ciEXPORT_SYMBOL(__asan_storeN_noabort); 2808c2ecf20Sopenharmony_ci 2818c2ecf20Sopenharmony_ci/* to shut up compiler complaints */ 2828c2ecf20Sopenharmony_civoid __asan_handle_no_return(void) {} 2838c2ecf20Sopenharmony_ciEXPORT_SYMBOL(__asan_handle_no_return); 2848c2ecf20Sopenharmony_ci 2858c2ecf20Sopenharmony_ci/* Emitted by compiler to poison alloca()ed objects. */ 2868c2ecf20Sopenharmony_civoid __asan_alloca_poison(unsigned long addr, size_t size) 2878c2ecf20Sopenharmony_ci{ 2888c2ecf20Sopenharmony_ci size_t rounded_up_size = round_up(size, KASAN_SHADOW_SCALE_SIZE); 2898c2ecf20Sopenharmony_ci size_t padding_size = round_up(size, KASAN_ALLOCA_REDZONE_SIZE) - 2908c2ecf20Sopenharmony_ci rounded_up_size; 2918c2ecf20Sopenharmony_ci size_t rounded_down_size = round_down(size, KASAN_SHADOW_SCALE_SIZE); 2928c2ecf20Sopenharmony_ci 2938c2ecf20Sopenharmony_ci const void *left_redzone = (const void *)(addr - 2948c2ecf20Sopenharmony_ci KASAN_ALLOCA_REDZONE_SIZE); 2958c2ecf20Sopenharmony_ci const void *right_redzone = (const void *)(addr + rounded_up_size); 2968c2ecf20Sopenharmony_ci 2978c2ecf20Sopenharmony_ci WARN_ON(!IS_ALIGNED(addr, KASAN_ALLOCA_REDZONE_SIZE)); 2988c2ecf20Sopenharmony_ci 2998c2ecf20Sopenharmony_ci kasan_unpoison_shadow((const void *)(addr + rounded_down_size), 3008c2ecf20Sopenharmony_ci size - rounded_down_size); 3018c2ecf20Sopenharmony_ci kasan_poison_shadow(left_redzone, KASAN_ALLOCA_REDZONE_SIZE, 3028c2ecf20Sopenharmony_ci KASAN_ALLOCA_LEFT); 3038c2ecf20Sopenharmony_ci kasan_poison_shadow(right_redzone, 3048c2ecf20Sopenharmony_ci padding_size + KASAN_ALLOCA_REDZONE_SIZE, 3058c2ecf20Sopenharmony_ci KASAN_ALLOCA_RIGHT); 3068c2ecf20Sopenharmony_ci} 3078c2ecf20Sopenharmony_ciEXPORT_SYMBOL(__asan_alloca_poison); 3088c2ecf20Sopenharmony_ci 3098c2ecf20Sopenharmony_ci/* Emitted by compiler to unpoison alloca()ed areas when the stack unwinds. */ 3108c2ecf20Sopenharmony_civoid __asan_allocas_unpoison(const void *stack_top, const void *stack_bottom) 3118c2ecf20Sopenharmony_ci{ 3128c2ecf20Sopenharmony_ci if (unlikely(!stack_top || stack_top > stack_bottom)) 3138c2ecf20Sopenharmony_ci return; 3148c2ecf20Sopenharmony_ci 3158c2ecf20Sopenharmony_ci kasan_unpoison_shadow(stack_top, stack_bottom - stack_top); 3168c2ecf20Sopenharmony_ci} 3178c2ecf20Sopenharmony_ciEXPORT_SYMBOL(__asan_allocas_unpoison); 3188c2ecf20Sopenharmony_ci 3198c2ecf20Sopenharmony_ci/* Emitted by the compiler to [un]poison local variables. */ 3208c2ecf20Sopenharmony_ci#define DEFINE_ASAN_SET_SHADOW(byte) \ 3218c2ecf20Sopenharmony_ci void __asan_set_shadow_##byte(const void *addr, size_t size) \ 3228c2ecf20Sopenharmony_ci { \ 3238c2ecf20Sopenharmony_ci __memset((void *)addr, 0x##byte, size); \ 3248c2ecf20Sopenharmony_ci } \ 3258c2ecf20Sopenharmony_ci EXPORT_SYMBOL(__asan_set_shadow_##byte) 3268c2ecf20Sopenharmony_ci 3278c2ecf20Sopenharmony_ciDEFINE_ASAN_SET_SHADOW(00); 3288c2ecf20Sopenharmony_ciDEFINE_ASAN_SET_SHADOW(f1); 3298c2ecf20Sopenharmony_ciDEFINE_ASAN_SET_SHADOW(f2); 3308c2ecf20Sopenharmony_ciDEFINE_ASAN_SET_SHADOW(f3); 3318c2ecf20Sopenharmony_ciDEFINE_ASAN_SET_SHADOW(f5); 3328c2ecf20Sopenharmony_ciDEFINE_ASAN_SET_SHADOW(f8); 3338c2ecf20Sopenharmony_ci 3348c2ecf20Sopenharmony_civoid kasan_record_aux_stack(void *addr) 3358c2ecf20Sopenharmony_ci{ 3368c2ecf20Sopenharmony_ci struct page *page = kasan_addr_to_page(addr); 3378c2ecf20Sopenharmony_ci struct kmem_cache *cache; 3388c2ecf20Sopenharmony_ci struct kasan_alloc_meta *alloc_info; 3398c2ecf20Sopenharmony_ci void *object; 3408c2ecf20Sopenharmony_ci 3418c2ecf20Sopenharmony_ci if (!(page && PageSlab(page))) 3428c2ecf20Sopenharmony_ci return; 3438c2ecf20Sopenharmony_ci 3448c2ecf20Sopenharmony_ci cache = page->slab_cache; 3458c2ecf20Sopenharmony_ci object = nearest_obj(cache, page, addr); 3468c2ecf20Sopenharmony_ci alloc_info = get_alloc_info(cache, object); 3478c2ecf20Sopenharmony_ci if (!alloc_info) 3488c2ecf20Sopenharmony_ci return; 3498c2ecf20Sopenharmony_ci 3508c2ecf20Sopenharmony_ci /* 3518c2ecf20Sopenharmony_ci * record the last two call_rcu() call stacks. 3528c2ecf20Sopenharmony_ci */ 3538c2ecf20Sopenharmony_ci alloc_info->aux_stack[1] = alloc_info->aux_stack[0]; 3548c2ecf20Sopenharmony_ci alloc_info->aux_stack[0] = kasan_save_stack(GFP_NOWAIT); 3558c2ecf20Sopenharmony_ci} 3568c2ecf20Sopenharmony_ci 3578c2ecf20Sopenharmony_civoid kasan_set_free_info(struct kmem_cache *cache, 3588c2ecf20Sopenharmony_ci void *object, u8 tag) 3598c2ecf20Sopenharmony_ci{ 3608c2ecf20Sopenharmony_ci struct kasan_free_meta *free_meta; 3618c2ecf20Sopenharmony_ci 3628c2ecf20Sopenharmony_ci free_meta = get_free_info(cache, object); 3638c2ecf20Sopenharmony_ci kasan_set_track(&free_meta->free_track, GFP_NOWAIT); 3648c2ecf20Sopenharmony_ci 3658c2ecf20Sopenharmony_ci /* 3668c2ecf20Sopenharmony_ci * the object was freed and has free track set 3678c2ecf20Sopenharmony_ci */ 3688c2ecf20Sopenharmony_ci *(u8 *)kasan_mem_to_shadow(object) = KASAN_KMALLOC_FREETRACK; 3698c2ecf20Sopenharmony_ci} 3708c2ecf20Sopenharmony_ci 3718c2ecf20Sopenharmony_cistruct kasan_track *kasan_get_free_track(struct kmem_cache *cache, 3728c2ecf20Sopenharmony_ci void *object, u8 tag) 3738c2ecf20Sopenharmony_ci{ 3748c2ecf20Sopenharmony_ci if (*(u8 *)kasan_mem_to_shadow(object) != KASAN_KMALLOC_FREETRACK) 3758c2ecf20Sopenharmony_ci return NULL; 3768c2ecf20Sopenharmony_ci return &get_free_info(cache, object)->free_track; 3778c2ecf20Sopenharmony_ci} 378