1*d6d1731bSAleksandr Iashchenko // SPDX-License-Identifier: BSD-2-Clause 2*d6d1731bSAleksandr Iashchenko /* 3*d6d1731bSAleksandr Iashchenko * Copyright (c) 2016, Linaro Limited 4*d6d1731bSAleksandr Iashchenko * Copyright (c) 2018-2020 Maxime Villard, m00nbsd.net 5*d6d1731bSAleksandr Iashchenko */ 6*d6d1731bSAleksandr Iashchenko 7*d6d1731bSAleksandr Iashchenko #include <asan.h> 8*d6d1731bSAleksandr Iashchenko #include <assert.h> 9*d6d1731bSAleksandr Iashchenko #include <compiler.h> 10*d6d1731bSAleksandr Iashchenko #include <keep.h> 11*d6d1731bSAleksandr Iashchenko #include <kernel/panic.h> 12*d6d1731bSAleksandr Iashchenko #include <printk.h> 13*d6d1731bSAleksandr Iashchenko #include <setjmp.h> 14*d6d1731bSAleksandr Iashchenko #include <string.h> 15*d6d1731bSAleksandr Iashchenko #include <trace.h> 16*d6d1731bSAleksandr Iashchenko #include <types_ext.h> 17*d6d1731bSAleksandr Iashchenko #include <util.h> 18*d6d1731bSAleksandr Iashchenko 19*d6d1731bSAleksandr Iashchenko #if __GCC_VERSION >= 70000 20*d6d1731bSAleksandr Iashchenko #define ASAN_ABI_VERSION 7 21*d6d1731bSAleksandr Iashchenko #else 22*d6d1731bSAleksandr Iashchenko #define ASAN_ABI_VERSION 6 23*d6d1731bSAleksandr Iashchenko #endif 24*d6d1731bSAleksandr Iashchenko 25*d6d1731bSAleksandr Iashchenko struct asan_source_location { 26*d6d1731bSAleksandr Iashchenko const char *file_name; 27*d6d1731bSAleksandr Iashchenko int line_no; 28*d6d1731bSAleksandr Iashchenko int column_no; 29*d6d1731bSAleksandr Iashchenko }; 30*d6d1731bSAleksandr Iashchenko 31*d6d1731bSAleksandr Iashchenko struct asan_global { 32*d6d1731bSAleksandr Iashchenko uintptr_t beg; 33*d6d1731bSAleksandr Iashchenko uintptr_t size; 34*d6d1731bSAleksandr Iashchenko uintptr_t size_with_redzone; 35*d6d1731bSAleksandr Iashchenko const char *name; 36*d6d1731bSAleksandr Iashchenko const char *module_name; 37*d6d1731bSAleksandr Iashchenko uintptr_t has_dynamic_init; 38*d6d1731bSAleksandr Iashchenko struct asan_source_location *location; 39*d6d1731bSAleksandr Iashchenko #if ASAN_ABI_VERSION >= 7 40*d6d1731bSAleksandr Iashchenko uintptr_t odr_indicator; 41*d6d1731bSAleksandr Iashchenko #endif 42*d6d1731bSAleksandr Iashchenko }; 43*d6d1731bSAleksandr Iashchenko 44*d6d1731bSAleksandr Iashchenko static vaddr_t asan_va_base; 45*d6d1731bSAleksandr Iashchenko static size_t asan_va_size; 46*d6d1731bSAleksandr Iashchenko static bool asan_active; 47*d6d1731bSAleksandr Iashchenko static asan_panic_cb_t asan_panic_cb = asan_panic; 48*d6d1731bSAleksandr Iashchenko 49*d6d1731bSAleksandr Iashchenko static bool addr_crosses_scale_boundary(vaddr_t addr, size_t size) 50*d6d1731bSAleksandr Iashchenko { 51*d6d1731bSAleksandr Iashchenko return (addr >> ASAN_BLOCK_SHIFT) != 52*d6d1731bSAleksandr Iashchenko ((addr + size - 1) >> ASAN_BLOCK_SHIFT); 53*d6d1731bSAleksandr Iashchenko } 54*d6d1731bSAleksandr Iashchenko 55*d6d1731bSAleksandr Iashchenko static int8_t *va_to_shadow(const void *va) 56*d6d1731bSAleksandr Iashchenko { 57*d6d1731bSAleksandr Iashchenko vaddr_t sa = ((vaddr_t)va / ASAN_BLOCK_SIZE) + CFG_ASAN_SHADOW_OFFSET; 58*d6d1731bSAleksandr Iashchenko 59*d6d1731bSAleksandr Iashchenko return (int8_t *)sa; 60*d6d1731bSAleksandr Iashchenko } 61*d6d1731bSAleksandr Iashchenko 62*d6d1731bSAleksandr Iashchenko static size_t va_range_to_shadow_size(const void *begin, const void *end) 63*d6d1731bSAleksandr Iashchenko { 64*d6d1731bSAleksandr Iashchenko return ((vaddr_t)end - (vaddr_t)begin) / ASAN_BLOCK_SIZE; 65*d6d1731bSAleksandr Iashchenko } 66*d6d1731bSAleksandr Iashchenko 67*d6d1731bSAleksandr Iashchenko static bool va_range_inside_shadow(const void *begin, const void *end) 68*d6d1731bSAleksandr Iashchenko { 69*d6d1731bSAleksandr Iashchenko vaddr_t b = (vaddr_t)begin; 70*d6d1731bSAleksandr Iashchenko vaddr_t e = (vaddr_t)end; 71*d6d1731bSAleksandr Iashchenko 72*d6d1731bSAleksandr Iashchenko if (b >= e) 73*d6d1731bSAleksandr Iashchenko return false; 74*d6d1731bSAleksandr Iashchenko return (b >= asan_va_base) && (e <= (asan_va_base + asan_va_size)); 75*d6d1731bSAleksandr Iashchenko } 76*d6d1731bSAleksandr Iashchenko 77*d6d1731bSAleksandr Iashchenko static bool va_range_outside_shadow(const void *begin, const void *end) 78*d6d1731bSAleksandr Iashchenko { 79*d6d1731bSAleksandr Iashchenko vaddr_t b = (vaddr_t)begin; 80*d6d1731bSAleksandr Iashchenko vaddr_t e = (vaddr_t)end; 81*d6d1731bSAleksandr Iashchenko 82*d6d1731bSAleksandr Iashchenko if (b >= e) 83*d6d1731bSAleksandr Iashchenko return false; 84*d6d1731bSAleksandr Iashchenko return (e <= asan_va_base) || (b >= (asan_va_base + asan_va_size)); 85*d6d1731bSAleksandr Iashchenko } 86*d6d1731bSAleksandr Iashchenko 87*d6d1731bSAleksandr Iashchenko static size_t va_misalignment(const void *va) 88*d6d1731bSAleksandr Iashchenko { 89*d6d1731bSAleksandr Iashchenko return (vaddr_t)va & ASAN_BLOCK_MASK; 90*d6d1731bSAleksandr Iashchenko } 91*d6d1731bSAleksandr Iashchenko 92*d6d1731bSAleksandr Iashchenko static bool va_is_well_aligned(const void *va) 93*d6d1731bSAleksandr Iashchenko { 94*d6d1731bSAleksandr Iashchenko return !va_misalignment(va); 95*d6d1731bSAleksandr Iashchenko } 96*d6d1731bSAleksandr Iashchenko 97*d6d1731bSAleksandr Iashchenko void asan_set_shadowed(const void *begin, const void *end) 98*d6d1731bSAleksandr Iashchenko { 99*d6d1731bSAleksandr Iashchenko vaddr_t b = (vaddr_t)begin; 100*d6d1731bSAleksandr Iashchenko vaddr_t e = (vaddr_t)end; 101*d6d1731bSAleksandr Iashchenko 102*d6d1731bSAleksandr Iashchenko assert(!asan_va_base); 103*d6d1731bSAleksandr Iashchenko assert(va_is_well_aligned(begin)); 104*d6d1731bSAleksandr Iashchenko assert(va_is_well_aligned(end)); 105*d6d1731bSAleksandr Iashchenko assert(b < e); 106*d6d1731bSAleksandr Iashchenko 107*d6d1731bSAleksandr Iashchenko asan_va_base = b; 108*d6d1731bSAleksandr Iashchenko asan_va_size = e - b; 109*d6d1731bSAleksandr Iashchenko } 110*d6d1731bSAleksandr Iashchenko 111*d6d1731bSAleksandr Iashchenko void asan_tag_no_access(const void *begin, const void *end) 112*d6d1731bSAleksandr Iashchenko { 113*d6d1731bSAleksandr Iashchenko assert(va_is_well_aligned(begin)); 114*d6d1731bSAleksandr Iashchenko assert(va_is_well_aligned(end)); 115*d6d1731bSAleksandr Iashchenko assert(va_range_inside_shadow(begin, end)); 116*d6d1731bSAleksandr Iashchenko 117*d6d1731bSAleksandr Iashchenko asan_memset_unchecked(va_to_shadow(begin), ASAN_DATA_RED_ZONE, 118*d6d1731bSAleksandr Iashchenko va_range_to_shadow_size(begin, end)); 119*d6d1731bSAleksandr Iashchenko } 120*d6d1731bSAleksandr Iashchenko 121*d6d1731bSAleksandr Iashchenko void asan_tag_access(const void *begin, const void *end) 122*d6d1731bSAleksandr Iashchenko { 123*d6d1731bSAleksandr Iashchenko if (!asan_va_base || (begin == end)) 124*d6d1731bSAleksandr Iashchenko return; 125*d6d1731bSAleksandr Iashchenko 126*d6d1731bSAleksandr Iashchenko assert(va_range_inside_shadow(begin, end)); 127*d6d1731bSAleksandr Iashchenko assert(va_is_well_aligned(begin)); 128*d6d1731bSAleksandr Iashchenko 129*d6d1731bSAleksandr Iashchenko asan_memset_unchecked(va_to_shadow(begin), 0, 130*d6d1731bSAleksandr Iashchenko va_range_to_shadow_size(begin, end)); 131*d6d1731bSAleksandr Iashchenko if (!va_is_well_aligned(end)) 132*d6d1731bSAleksandr Iashchenko *va_to_shadow(end) = va_misalignment(end); 133*d6d1731bSAleksandr Iashchenko } 134*d6d1731bSAleksandr Iashchenko 135*d6d1731bSAleksandr Iashchenko void asan_tag_heap_free(const void *begin, const void *end) 136*d6d1731bSAleksandr Iashchenko { 137*d6d1731bSAleksandr Iashchenko if (!asan_va_base) 138*d6d1731bSAleksandr Iashchenko return; 139*d6d1731bSAleksandr Iashchenko 140*d6d1731bSAleksandr Iashchenko assert(va_range_inside_shadow(begin, end)); 141*d6d1731bSAleksandr Iashchenko assert(va_is_well_aligned(begin)); 142*d6d1731bSAleksandr Iashchenko assert(va_is_well_aligned(end)); 143*d6d1731bSAleksandr Iashchenko 144*d6d1731bSAleksandr Iashchenko asan_memset_unchecked(va_to_shadow(begin), ASAN_HEAP_RED_ZONE, 145*d6d1731bSAleksandr Iashchenko va_range_to_shadow_size(begin, end)); 146*d6d1731bSAleksandr Iashchenko } 147*d6d1731bSAleksandr Iashchenko 148*d6d1731bSAleksandr Iashchenko __inhibit_loop_to_libcall void *asan_memset_unchecked(void *s, int c, size_t n) 149*d6d1731bSAleksandr Iashchenko { 150*d6d1731bSAleksandr Iashchenko uint8_t *b = s; 151*d6d1731bSAleksandr Iashchenko size_t m; 152*d6d1731bSAleksandr Iashchenko 153*d6d1731bSAleksandr Iashchenko for (m = 0; m < n; m++) 154*d6d1731bSAleksandr Iashchenko b[m] = c; 155*d6d1731bSAleksandr Iashchenko 156*d6d1731bSAleksandr Iashchenko return s; 157*d6d1731bSAleksandr Iashchenko } 158*d6d1731bSAleksandr Iashchenko 159*d6d1731bSAleksandr Iashchenko __inhibit_loop_to_libcall 160*d6d1731bSAleksandr Iashchenko void *asan_memcpy_unchecked(void *__restrict dst, const void *__restrict src, 161*d6d1731bSAleksandr Iashchenko size_t len) 162*d6d1731bSAleksandr Iashchenko { 163*d6d1731bSAleksandr Iashchenko uint8_t *__restrict d = dst; 164*d6d1731bSAleksandr Iashchenko const uint8_t *__restrict s = src; 165*d6d1731bSAleksandr Iashchenko size_t n; 166*d6d1731bSAleksandr Iashchenko 167*d6d1731bSAleksandr Iashchenko for (n = 0; n < len; n++) 168*d6d1731bSAleksandr Iashchenko d[n] = s[n]; 169*d6d1731bSAleksandr Iashchenko 170*d6d1731bSAleksandr Iashchenko return dst; 171*d6d1731bSAleksandr Iashchenko } 172*d6d1731bSAleksandr Iashchenko 173*d6d1731bSAleksandr Iashchenko void asan_start(void) 174*d6d1731bSAleksandr Iashchenko { 175*d6d1731bSAleksandr Iashchenko assert(asan_va_base && !asan_active); 176*d6d1731bSAleksandr Iashchenko asan_active = true; 177*d6d1731bSAleksandr Iashchenko } 178*d6d1731bSAleksandr Iashchenko 179*d6d1731bSAleksandr Iashchenko void __noreturn asan_panic(void) 180*d6d1731bSAleksandr Iashchenko { 181*d6d1731bSAleksandr Iashchenko panic(); 182*d6d1731bSAleksandr Iashchenko } 183*d6d1731bSAleksandr Iashchenko 184*d6d1731bSAleksandr Iashchenko void asan_set_panic_cb(asan_panic_cb_t panic_cb) 185*d6d1731bSAleksandr Iashchenko { 186*d6d1731bSAleksandr Iashchenko asan_panic_cb = panic_cb; 187*d6d1731bSAleksandr Iashchenko } 188*d6d1731bSAleksandr Iashchenko 189*d6d1731bSAleksandr Iashchenko static void asan_report(vaddr_t addr, size_t size) 190*d6d1731bSAleksandr Iashchenko { 191*d6d1731bSAleksandr Iashchenko #ifdef KASAN_DUMP_SHADOW 192*d6d1731bSAleksandr Iashchenko char buf[128] = {0}; 193*d6d1731bSAleksandr Iashchenko int r = 0, rc = 0; 194*d6d1731bSAleksandr Iashchenko vaddr_t b = 0, e = 0, saddr = 0; 195*d6d1731bSAleksandr Iashchenko 196*d6d1731bSAleksandr Iashchenko b = ROUNDDOWN(addr, ASAN_BLOCK_SIZE) - ASAN_BLOCK_SIZE; 197*d6d1731bSAleksandr Iashchenko e = ROUNDDOWN(addr, ASAN_BLOCK_SIZE) + ASAN_BLOCK_SIZE; 198*d6d1731bSAleksandr Iashchenko 199*d6d1731bSAleksandr Iashchenko /* Print shadow map nearby */ 200*d6d1731bSAleksandr Iashchenko if (va_range_inside_shadow((void *)b, (void *)e)) { 201*d6d1731bSAleksandr Iashchenko rc = snprintk(buf + r, sizeof(buf) - r, "%lx: ", b); 202*d6d1731bSAleksandr Iashchenko assert(rc > 0); 203*d6d1731bSAleksandr Iashchenko r += rc; 204*d6d1731bSAleksandr Iashchenko for (saddr = b; saddr <= e; saddr += ASAN_BLOCK_SIZE) { 205*d6d1731bSAleksandr Iashchenko int8_t *sbyte = va_to_shadow((void *)saddr); 206*d6d1731bSAleksandr Iashchenko 207*d6d1731bSAleksandr Iashchenko rc = snprintk(buf + r, sizeof(buf) - r, 208*d6d1731bSAleksandr Iashchenko "0x%02x ", (uint8_t)*sbyte); 209*d6d1731bSAleksandr Iashchenko assert(rc > 0); 210*d6d1731bSAleksandr Iashchenko r += rc; 211*d6d1731bSAleksandr Iashchenko } 212*d6d1731bSAleksandr Iashchenko EMSG("%s", buf); 213*d6d1731bSAleksandr Iashchenko } 214*d6d1731bSAleksandr Iashchenko #endif 215*d6d1731bSAleksandr Iashchenko EMSG("[ASAN]: access violation, addr: %lx size: %zu\n", 216*d6d1731bSAleksandr Iashchenko addr, size); 217*d6d1731bSAleksandr Iashchenko 218*d6d1731bSAleksandr Iashchenko asan_panic_cb(); 219*d6d1731bSAleksandr Iashchenko } 220*d6d1731bSAleksandr Iashchenko 221*d6d1731bSAleksandr Iashchenko static __always_inline bool asan_shadow_1byte_isvalid(vaddr_t addr) 222*d6d1731bSAleksandr Iashchenko { 223*d6d1731bSAleksandr Iashchenko int8_t last = (addr & ASAN_BLOCK_MASK) + 1; 224*d6d1731bSAleksandr Iashchenko int8_t *byte = va_to_shadow((void *)addr); 225*d6d1731bSAleksandr Iashchenko 226*d6d1731bSAleksandr Iashchenko if (*byte == 0 || last <= *byte) 227*d6d1731bSAleksandr Iashchenko return true; 228*d6d1731bSAleksandr Iashchenko 229*d6d1731bSAleksandr Iashchenko return false; 230*d6d1731bSAleksandr Iashchenko } 231*d6d1731bSAleksandr Iashchenko 232*d6d1731bSAleksandr Iashchenko static __always_inline bool asan_shadow_2byte_isvalid(vaddr_t addr) 233*d6d1731bSAleksandr Iashchenko { 234*d6d1731bSAleksandr Iashchenko if (addr_crosses_scale_boundary(addr, 2)) { 235*d6d1731bSAleksandr Iashchenko return (asan_shadow_1byte_isvalid(addr) && 236*d6d1731bSAleksandr Iashchenko asan_shadow_1byte_isvalid(addr + 1)); 237*d6d1731bSAleksandr Iashchenko } else { 238*d6d1731bSAleksandr Iashchenko int8_t last = ((addr + 1) & ASAN_BLOCK_MASK) + 1; 239*d6d1731bSAleksandr Iashchenko int8_t *byte = va_to_shadow((void *)addr); 240*d6d1731bSAleksandr Iashchenko 241*d6d1731bSAleksandr Iashchenko if (*byte == 0 || last <= *byte) 242*d6d1731bSAleksandr Iashchenko return true; 243*d6d1731bSAleksandr Iashchenko 244*d6d1731bSAleksandr Iashchenko return false; 245*d6d1731bSAleksandr Iashchenko } 246*d6d1731bSAleksandr Iashchenko } 247*d6d1731bSAleksandr Iashchenko 248*d6d1731bSAleksandr Iashchenko static __always_inline bool asan_shadow_4byte_isvalid(vaddr_t addr) 249*d6d1731bSAleksandr Iashchenko { 250*d6d1731bSAleksandr Iashchenko if (addr_crosses_scale_boundary(addr, 4)) { 251*d6d1731bSAleksandr Iashchenko return (asan_shadow_2byte_isvalid(addr) && 252*d6d1731bSAleksandr Iashchenko asan_shadow_2byte_isvalid(addr + 2)); 253*d6d1731bSAleksandr Iashchenko } else { 254*d6d1731bSAleksandr Iashchenko int8_t last = ((addr + 3) & ASAN_BLOCK_MASK) + 1; 255*d6d1731bSAleksandr Iashchenko int8_t *byte = va_to_shadow((void *)addr); 256*d6d1731bSAleksandr Iashchenko 257*d6d1731bSAleksandr Iashchenko if (*byte == 0 || last <= *byte) 258*d6d1731bSAleksandr Iashchenko return true; 259*d6d1731bSAleksandr Iashchenko 260*d6d1731bSAleksandr Iashchenko return false; 261*d6d1731bSAleksandr Iashchenko } 262*d6d1731bSAleksandr Iashchenko } 263*d6d1731bSAleksandr Iashchenko 264*d6d1731bSAleksandr Iashchenko static __always_inline bool asan_shadow_8byte_isvalid(vaddr_t addr) 265*d6d1731bSAleksandr Iashchenko { 266*d6d1731bSAleksandr Iashchenko if (addr_crosses_scale_boundary(addr, 8)) { 267*d6d1731bSAleksandr Iashchenko return (asan_shadow_4byte_isvalid(addr) && 268*d6d1731bSAleksandr Iashchenko asan_shadow_4byte_isvalid(addr + 4)); 269*d6d1731bSAleksandr Iashchenko } else { 270*d6d1731bSAleksandr Iashchenko int8_t last = ((addr + 7) & ASAN_BLOCK_MASK) + 1; 271*d6d1731bSAleksandr Iashchenko int8_t *byte = va_to_shadow((void *)addr); 272*d6d1731bSAleksandr Iashchenko 273*d6d1731bSAleksandr Iashchenko if (*byte == 0 || last <= *byte) 274*d6d1731bSAleksandr Iashchenko return true; 275*d6d1731bSAleksandr Iashchenko 276*d6d1731bSAleksandr Iashchenko return false; 277*d6d1731bSAleksandr Iashchenko } 278*d6d1731bSAleksandr Iashchenko } 279*d6d1731bSAleksandr Iashchenko 280*d6d1731bSAleksandr Iashchenko static __always_inline bool asan_shadow_Nbyte_isvalid(vaddr_t addr, 281*d6d1731bSAleksandr Iashchenko size_t size) 282*d6d1731bSAleksandr Iashchenko { 283*d6d1731bSAleksandr Iashchenko size_t i = 0; 284*d6d1731bSAleksandr Iashchenko 285*d6d1731bSAleksandr Iashchenko for (; i < size; i++) { 286*d6d1731bSAleksandr Iashchenko if (!asan_shadow_1byte_isvalid(addr + i)) 287*d6d1731bSAleksandr Iashchenko return false; 288*d6d1731bSAleksandr Iashchenko } 289*d6d1731bSAleksandr Iashchenko 290*d6d1731bSAleksandr Iashchenko return true; 291*d6d1731bSAleksandr Iashchenko } 292*d6d1731bSAleksandr Iashchenko 293*d6d1731bSAleksandr Iashchenko static __always_inline void check_access(vaddr_t addr, size_t size) 294*d6d1731bSAleksandr Iashchenko { 295*d6d1731bSAleksandr Iashchenko bool valid = false; 296*d6d1731bSAleksandr Iashchenko void *begin = (void *)addr; 297*d6d1731bSAleksandr Iashchenko void *end = (void *)(addr + size); 298*d6d1731bSAleksandr Iashchenko 299*d6d1731bSAleksandr Iashchenko if (!asan_active) 300*d6d1731bSAleksandr Iashchenko return; 301*d6d1731bSAleksandr Iashchenko if (size == 0) 302*d6d1731bSAleksandr Iashchenko return; 303*d6d1731bSAleksandr Iashchenko if (va_range_outside_shadow(begin, end)) 304*d6d1731bSAleksandr Iashchenko return; 305*d6d1731bSAleksandr Iashchenko /* 306*d6d1731bSAleksandr Iashchenko * If it isn't outside it has to be completely inside or there's a 307*d6d1731bSAleksandr Iashchenko * problem. 308*d6d1731bSAleksandr Iashchenko */ 309*d6d1731bSAleksandr Iashchenko if (!va_range_inside_shadow(begin, end)) 310*d6d1731bSAleksandr Iashchenko panic(); 311*d6d1731bSAleksandr Iashchenko 312*d6d1731bSAleksandr Iashchenko if (__builtin_constant_p(size)) { 313*d6d1731bSAleksandr Iashchenko switch (size) { 314*d6d1731bSAleksandr Iashchenko case 1: 315*d6d1731bSAleksandr Iashchenko valid = asan_shadow_1byte_isvalid(addr); 316*d6d1731bSAleksandr Iashchenko break; 317*d6d1731bSAleksandr Iashchenko case 2: 318*d6d1731bSAleksandr Iashchenko valid = asan_shadow_2byte_isvalid(addr); 319*d6d1731bSAleksandr Iashchenko break; 320*d6d1731bSAleksandr Iashchenko case 4: 321*d6d1731bSAleksandr Iashchenko valid = asan_shadow_4byte_isvalid(addr); 322*d6d1731bSAleksandr Iashchenko break; 323*d6d1731bSAleksandr Iashchenko case 8: 324*d6d1731bSAleksandr Iashchenko valid = asan_shadow_8byte_isvalid(addr); 325*d6d1731bSAleksandr Iashchenko break; 326*d6d1731bSAleksandr Iashchenko default: 327*d6d1731bSAleksandr Iashchenko valid = asan_shadow_Nbyte_isvalid(addr, size); 328*d6d1731bSAleksandr Iashchenko break; 329*d6d1731bSAleksandr Iashchenko } 330*d6d1731bSAleksandr Iashchenko } else { 331*d6d1731bSAleksandr Iashchenko valid = asan_shadow_Nbyte_isvalid(addr, size); 332*d6d1731bSAleksandr Iashchenko } 333*d6d1731bSAleksandr Iashchenko 334*d6d1731bSAleksandr Iashchenko if (!valid) 335*d6d1731bSAleksandr Iashchenko asan_report(addr, size); 336*d6d1731bSAleksandr Iashchenko } 337*d6d1731bSAleksandr Iashchenko 338*d6d1731bSAleksandr Iashchenko static __always_inline void check_load(vaddr_t addr, size_t size) 339*d6d1731bSAleksandr Iashchenko { 340*d6d1731bSAleksandr Iashchenko check_access(addr, size); 341*d6d1731bSAleksandr Iashchenko } 342*d6d1731bSAleksandr Iashchenko 343*d6d1731bSAleksandr Iashchenko static __always_inline void check_store(vaddr_t addr, size_t size) 344*d6d1731bSAleksandr Iashchenko { 345*d6d1731bSAleksandr Iashchenko check_access(addr, size); 346*d6d1731bSAleksandr Iashchenko } 347*d6d1731bSAleksandr Iashchenko 348*d6d1731bSAleksandr Iashchenko static void __noreturn report_load(vaddr_t addr __unused, size_t size __unused) 349*d6d1731bSAleksandr Iashchenko { 350*d6d1731bSAleksandr Iashchenko panic(); 351*d6d1731bSAleksandr Iashchenko } 352*d6d1731bSAleksandr Iashchenko 353*d6d1731bSAleksandr Iashchenko static void __noreturn report_store(vaddr_t addr __unused, size_t size __unused) 354*d6d1731bSAleksandr Iashchenko { 355*d6d1731bSAleksandr Iashchenko panic(); 356*d6d1731bSAleksandr Iashchenko } 357*d6d1731bSAleksandr Iashchenko 358*d6d1731bSAleksandr Iashchenko 359*d6d1731bSAleksandr Iashchenko 360*d6d1731bSAleksandr Iashchenko #define DEFINE_ASAN_FUNC(type, size) \ 361*d6d1731bSAleksandr Iashchenko void __asan_##type##size(vaddr_t addr); \ 362*d6d1731bSAleksandr Iashchenko void __asan_##type##size(vaddr_t addr) \ 363*d6d1731bSAleksandr Iashchenko { check_##type(addr, size); } \ 364*d6d1731bSAleksandr Iashchenko void __asan_##type##size##_noabort(vaddr_t addr); \ 365*d6d1731bSAleksandr Iashchenko void __asan_##type##size##_noabort(vaddr_t addr) \ 366*d6d1731bSAleksandr Iashchenko { check_##type(addr, size); } \ 367*d6d1731bSAleksandr Iashchenko void __asan_report_##type##size##_noabort(vaddr_t addr);\ 368*d6d1731bSAleksandr Iashchenko void __noreturn __asan_report_##type##size##_noabort(vaddr_t addr) \ 369*d6d1731bSAleksandr Iashchenko { report_##type(addr, size); } 370*d6d1731bSAleksandr Iashchenko 371*d6d1731bSAleksandr Iashchenko DEFINE_ASAN_FUNC(load, 1) 372*d6d1731bSAleksandr Iashchenko DEFINE_ASAN_FUNC(load, 2) 373*d6d1731bSAleksandr Iashchenko DEFINE_ASAN_FUNC(load, 4) 374*d6d1731bSAleksandr Iashchenko DEFINE_ASAN_FUNC(load, 8) 375*d6d1731bSAleksandr Iashchenko DEFINE_ASAN_FUNC(load, 16) 376*d6d1731bSAleksandr Iashchenko DEFINE_ASAN_FUNC(store, 1) 377*d6d1731bSAleksandr Iashchenko DEFINE_ASAN_FUNC(store, 2) 378*d6d1731bSAleksandr Iashchenko DEFINE_ASAN_FUNC(store, 4) 379*d6d1731bSAleksandr Iashchenko DEFINE_ASAN_FUNC(store, 8) 380*d6d1731bSAleksandr Iashchenko DEFINE_ASAN_FUNC(store, 16) 381*d6d1731bSAleksandr Iashchenko 382*d6d1731bSAleksandr Iashchenko void __asan_loadN_noabort(vaddr_t addr, size_t size); 383*d6d1731bSAleksandr Iashchenko void __asan_loadN_noabort(vaddr_t addr, size_t size) 384*d6d1731bSAleksandr Iashchenko { 385*d6d1731bSAleksandr Iashchenko check_load(addr, size); 386*d6d1731bSAleksandr Iashchenko } 387*d6d1731bSAleksandr Iashchenko 388*d6d1731bSAleksandr Iashchenko void __asan_storeN_noabort(vaddr_t addr, size_t size); 389*d6d1731bSAleksandr Iashchenko void __asan_storeN_noabort(vaddr_t addr, size_t size) 390*d6d1731bSAleksandr Iashchenko { 391*d6d1731bSAleksandr Iashchenko check_store(addr, size); 392*d6d1731bSAleksandr Iashchenko } 393*d6d1731bSAleksandr Iashchenko 394*d6d1731bSAleksandr Iashchenko void __asan_report_load_n_noabort(vaddr_t addr, size_t size); 395*d6d1731bSAleksandr Iashchenko void __noreturn __asan_report_load_n_noabort(vaddr_t addr, size_t size) 396*d6d1731bSAleksandr Iashchenko { 397*d6d1731bSAleksandr Iashchenko report_load(addr, size); 398*d6d1731bSAleksandr Iashchenko } 399*d6d1731bSAleksandr Iashchenko 400*d6d1731bSAleksandr Iashchenko void __asan_report_store_n_noabort(vaddr_t addr, size_t size); 401*d6d1731bSAleksandr Iashchenko void __noreturn __asan_report_store_n_noabort(vaddr_t addr, size_t size) 402*d6d1731bSAleksandr Iashchenko { 403*d6d1731bSAleksandr Iashchenko report_store(addr, size); 404*d6d1731bSAleksandr Iashchenko } 405*d6d1731bSAleksandr Iashchenko 406*d6d1731bSAleksandr Iashchenko void __asan_handle_no_return(void); 407*d6d1731bSAleksandr Iashchenko void __asan_handle_no_return(void) 408*d6d1731bSAleksandr Iashchenko { 409*d6d1731bSAleksandr Iashchenko } 410*d6d1731bSAleksandr Iashchenko 411*d6d1731bSAleksandr Iashchenko void __asan_register_globals(struct asan_global *globals, size_t size); 412*d6d1731bSAleksandr Iashchenko void __asan_register_globals(struct asan_global *globals, size_t size) 413*d6d1731bSAleksandr Iashchenko { 414*d6d1731bSAleksandr Iashchenko size_t n = 0; 415*d6d1731bSAleksandr Iashchenko 416*d6d1731bSAleksandr Iashchenko for (n = 0; n < size; n++) { 417*d6d1731bSAleksandr Iashchenko vaddr_t begin = globals[n].beg; 418*d6d1731bSAleksandr Iashchenko vaddr_t end = begin + globals[n].size; 419*d6d1731bSAleksandr Iashchenko vaddr_t end_align = ROUNDUP(end, ASAN_BLOCK_SIZE); 420*d6d1731bSAleksandr Iashchenko vaddr_t end_rz = begin + globals[n].size_with_redzone; 421*d6d1731bSAleksandr Iashchenko 422*d6d1731bSAleksandr Iashchenko asan_tag_access((void *)begin, (void *)end); 423*d6d1731bSAleksandr Iashchenko asan_tag_no_access((void *)end_align, (void *)end_rz); 424*d6d1731bSAleksandr Iashchenko } 425*d6d1731bSAleksandr Iashchenko } 426*d6d1731bSAleksandr Iashchenko DECLARE_KEEP_INIT(__asan_register_globals); 427*d6d1731bSAleksandr Iashchenko 428*d6d1731bSAleksandr Iashchenko void __asan_unregister_globals(struct asan_global *globals, size_t size); 429*d6d1731bSAleksandr Iashchenko void __asan_unregister_globals(struct asan_global *globals __unused, 430*d6d1731bSAleksandr Iashchenko size_t size __unused) 431*d6d1731bSAleksandr Iashchenko { 432*d6d1731bSAleksandr Iashchenko } 433*d6d1731bSAleksandr Iashchenko 434*d6d1731bSAleksandr Iashchenko void asan_handle_longjmp(void *old_sp) 435*d6d1731bSAleksandr Iashchenko { 436*d6d1731bSAleksandr Iashchenko void *top = old_sp; 437*d6d1731bSAleksandr Iashchenko void *bottom = (void *)ROUNDDOWN((vaddr_t)&top, 438*d6d1731bSAleksandr Iashchenko ASAN_BLOCK_SIZE); 439*d6d1731bSAleksandr Iashchenko 440*d6d1731bSAleksandr Iashchenko asan_tag_access(bottom, top); 441*d6d1731bSAleksandr Iashchenko } 442