diff --git a/sys/kern/subr_asan.c b/sys/kern/subr_asan.c index 9f8a7bfccd40..0edb631d1475 100644 --- a/sys/kern/subr_asan.c +++ b/sys/kern/subr_asan.c @@ -1,1242 +1,1242 @@ /* $NetBSD: subr_asan.c,v 1.26 2020/09/10 14:10:46 maxv Exp $ */ /* * Copyright (c) 2018-2020 Maxime Villard, m00nbsd.net * All rights reserved. * * This code is part of the KASAN subsystem of the NetBSD kernel. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #define SAN_RUNTIME #include #if 0 __KERNEL_RCSID(0, "$NetBSD: subr_asan.c,v 1.26 2020/09/10 14:10:46 maxv Exp $"); #endif #include #include #include #include #include #include #include #include #include /* ASAN constants. Part of the compiler ABI. */ #define KASAN_SHADOW_MASK (KASAN_SHADOW_SCALE - 1) #define KASAN_ALLOCA_SCALE_SIZE 32 /* ASAN ABI version. */ #if defined(__clang__) && (__clang_major__ - 0 >= 6) #define ASAN_ABI_VERSION 8 #elif __GNUC_PREREQ__(7, 1) && !defined(__clang__) #define ASAN_ABI_VERSION 8 #elif __GNUC_PREREQ__(6, 1) && !defined(__clang__) #define ASAN_ABI_VERSION 6 #else #error "Unsupported compiler version" #endif #define __RET_ADDR (unsigned long)__builtin_return_address(0) /* Global variable descriptor. Part of the compiler ABI. */ struct __asan_global_source_location { const char *filename; int line_no; int column_no; }; struct __asan_global { const void *beg; /* address of the global variable */ size_t size; /* size of the global variable */ size_t size_with_redzone; /* size with the redzone */ const void *name; /* name of the variable */ const void *module_name; /* name of the module where the var is declared */ unsigned long has_dynamic_init; /* the var has dyn initializer (c++) */ struct __asan_global_source_location *location; #if ASAN_ABI_VERSION >= 7 uintptr_t odr_indicator; /* the address of the ODR indicator symbol */ #endif }; FEATURE(kasan, "Kernel address sanitizer"); static SYSCTL_NODE(_debug, OID_AUTO, kasan, CTLFLAG_RD | CTLFLAG_MPSAFE, 0, "KASAN options"); static int panic_on_violation = 1; SYSCTL_INT(_debug_kasan, OID_AUTO, panic_on_violation, CTLFLAG_RDTUN, &panic_on_violation, 0, "Panic if an invalid access is detected"); #define kasan_enabled (!kasan_disabled) static bool kasan_disabled __read_mostly = true; SYSCTL_BOOL(_debug_kasan, OID_AUTO, disabled, CTLFLAG_RDTUN | CTLFLAG_NOFETCH, &kasan_disabled, 0, "KASAN is disabled"); /* -------------------------------------------------------------------------- */ void kasan_shadow_map(vm_offset_t addr, size_t size) { size_t sz, npages, i; vm_offset_t sva, eva; KASSERT(addr % KASAN_SHADOW_SCALE == 0, ("%s: invalid address %#lx", __func__, addr)); sz = roundup(size, KASAN_SHADOW_SCALE) / KASAN_SHADOW_SCALE; sva = kasan_md_addr_to_shad(addr); eva = kasan_md_addr_to_shad(addr) + sz; sva = rounddown(sva, PAGE_SIZE); eva = roundup(eva, PAGE_SIZE); npages = (eva - sva) / PAGE_SIZE; KASSERT(sva >= KASAN_MIN_ADDRESS && eva < KASAN_MAX_ADDRESS, ("%s: invalid address range %#lx-%#lx", __func__, sva, eva)); for (i = 0; i < npages; i++) pmap_san_enter(sva + ptoa(i)); } void kasan_init(void) { int disabled; disabled = 0; TUNABLE_INT_FETCH("debug.kasan.disabled", &disabled); if (disabled) return; /* MD initialization. */ kasan_md_init(); /* Now officially enabled. */ kasan_disabled = false; } void kasan_init_early(vm_offset_t stack, size_t size) { kasan_md_init_early(stack, size); } static inline const char * kasan_code_name(uint8_t code) { switch (code) { case KASAN_GENERIC_REDZONE: return "GenericRedZone"; case KASAN_MALLOC_REDZONE: return "MallocRedZone"; case KASAN_KMEM_REDZONE: return "KmemRedZone"; case KASAN_UMA_FREED: return "UMAUseAfterFree"; case KASAN_KSTACK_FREED: return "KernelStack"; case KASAN_EXEC_ARGS_FREED: return "ExecKVA"; case 1 ... 7: return "RedZonePartial"; case KASAN_STACK_LEFT: return "StackLeft"; case KASAN_STACK_MID: return "StackMiddle"; case KASAN_STACK_RIGHT: return "StackRight"; case KASAN_USE_AFTER_RET: return "UseAfterRet"; case KASAN_USE_AFTER_SCOPE: return "UseAfterScope"; default: return "Unknown"; } } #define REPORT(f, ...) do { \ if (panic_on_violation) { \ kasan_disabled = true; \ panic(f, __VA_ARGS__); \ } else { \ struct stack st; \ \ stack_save(&st); \ printf(f "\n", __VA_ARGS__); \ stack_print_ddb(&st); \ } \ } while (0) static void kasan_report(unsigned long addr, size_t size, bool write, unsigned long pc, uint8_t code) { REPORT("ASan: Invalid access, %zu-byte %s at %#lx, %s(%x)", size, (write ? "write" : "read"), addr, kasan_code_name(code), code); } static __always_inline void kasan_shadow_1byte_markvalid(unsigned long addr) { int8_t *byte = (int8_t *)kasan_md_addr_to_shad(addr); int8_t last = (addr & KASAN_SHADOW_MASK) + 1; *byte = last; } static __always_inline void kasan_shadow_Nbyte_markvalid(const void *addr, size_t size) { size_t i; for (i = 0; i < size; i++) { kasan_shadow_1byte_markvalid((unsigned long)addr + i); } } static __always_inline void kasan_shadow_Nbyte_fill(const void *addr, size_t size, uint8_t code) { void *shad; if (__predict_false(size == 0)) return; if (__predict_false(kasan_md_unsupported((vm_offset_t)addr))) return; KASSERT((vm_offset_t)addr % KASAN_SHADOW_SCALE == 0, ("%s: invalid address %p", __func__, addr)); KASSERT(size % KASAN_SHADOW_SCALE == 0, ("%s: invalid size %zu", __func__, size)); shad = (void *)kasan_md_addr_to_shad((uintptr_t)addr); size = size >> KASAN_SHADOW_SCALE_SHIFT; __builtin_memset(shad, code, size); } /* * In an area of size 'sz_with_redz', mark the 'size' first bytes as valid, * and the rest as invalid. There are generally two use cases: * * o kasan_mark(addr, origsize, size, code), with origsize < size. This marks * the redzone at the end of the buffer as invalid. If the entire is to be * marked invalid, origsize will be 0. * * o kasan_mark(addr, size, size, 0). This marks the entire buffer as valid. */ void kasan_mark(const void *addr, size_t size, size_t redzsize, uint8_t code) { size_t i, n, redz; int8_t *shad; if (__predict_false(!kasan_enabled)) return; if ((vm_offset_t)addr >= DMAP_MIN_ADDRESS && (vm_offset_t)addr < DMAP_MAX_ADDRESS) return; KASSERT((vm_offset_t)addr >= VM_MIN_KERNEL_ADDRESS && (vm_offset_t)addr < VM_MAX_KERNEL_ADDRESS, ("%s: invalid address %p", __func__, addr)); KASSERT((vm_offset_t)addr % KASAN_SHADOW_SCALE == 0, ("%s: invalid address %p", __func__, addr)); redz = redzsize - roundup(size, KASAN_SHADOW_SCALE); KASSERT(redz % KASAN_SHADOW_SCALE == 0, ("%s: invalid size %zu", __func__, redz)); shad = (int8_t *)kasan_md_addr_to_shad((uintptr_t)addr); /* Chunks of 8 bytes, valid. */ n = size / KASAN_SHADOW_SCALE; for (i = 0; i < n; i++) { *shad++ = 0; } /* Possibly one chunk, mid. */ if ((size & KASAN_SHADOW_MASK) != 0) { *shad++ = (size & KASAN_SHADOW_MASK); } /* Chunks of 8 bytes, invalid. */ n = redz / KASAN_SHADOW_SCALE; for (i = 0; i < n; i++) { *shad++ = code; } } void kasan_thread_alloc(struct thread *td) { if (td->td_kstack != 0) { kasan_mark((void *)td->td_kstack, ptoa(td->td_kstack_pages), ptoa(td->td_kstack_pages), 0); } } /* -------------------------------------------------------------------------- */ #define ADDR_CROSSES_SCALE_BOUNDARY(addr, size) \ (addr >> KASAN_SHADOW_SCALE_SHIFT) != \ ((addr + size - 1) >> KASAN_SHADOW_SCALE_SHIFT) static __always_inline bool kasan_shadow_1byte_isvalid(unsigned long addr, uint8_t *code) { int8_t *byte = (int8_t *)kasan_md_addr_to_shad(addr); int8_t last = (addr & KASAN_SHADOW_MASK) + 1; if (__predict_true(*byte == 0 || last <= *byte)) { return (true); } *code = *byte; return (false); } static __always_inline bool kasan_shadow_2byte_isvalid(unsigned long addr, uint8_t *code) { int8_t *byte, last; if (ADDR_CROSSES_SCALE_BOUNDARY(addr, 2)) { return (kasan_shadow_1byte_isvalid(addr, code) && kasan_shadow_1byte_isvalid(addr+1, code)); } byte = (int8_t *)kasan_md_addr_to_shad(addr); last = ((addr + 1) & KASAN_SHADOW_MASK) + 1; if (__predict_true(*byte == 0 || last <= *byte)) { return (true); } *code = *byte; return (false); } static __always_inline bool kasan_shadow_4byte_isvalid(unsigned long addr, uint8_t *code) { int8_t *byte, last; if (ADDR_CROSSES_SCALE_BOUNDARY(addr, 4)) { return (kasan_shadow_2byte_isvalid(addr, code) && kasan_shadow_2byte_isvalid(addr+2, code)); } byte = (int8_t *)kasan_md_addr_to_shad(addr); last = ((addr + 3) & KASAN_SHADOW_MASK) + 1; if (__predict_true(*byte == 0 || last <= *byte)) { return (true); } *code = *byte; return (false); } static __always_inline bool kasan_shadow_8byte_isvalid(unsigned long addr, uint8_t *code) { int8_t *byte, last; if (ADDR_CROSSES_SCALE_BOUNDARY(addr, 8)) { return (kasan_shadow_4byte_isvalid(addr, code) && kasan_shadow_4byte_isvalid(addr+4, code)); } byte = (int8_t *)kasan_md_addr_to_shad(addr); last = ((addr + 7) & KASAN_SHADOW_MASK) + 1; if (__predict_true(*byte == 0 || last <= *byte)) { return (true); } *code = *byte; return (false); } static __always_inline bool kasan_shadow_Nbyte_isvalid(unsigned long addr, size_t size, uint8_t *code) { size_t i; for (i = 0; i < size; i++) { if (!kasan_shadow_1byte_isvalid(addr+i, code)) return (false); } return (true); } static __always_inline void kasan_shadow_check(unsigned long addr, size_t size, bool write, unsigned long retaddr) { uint8_t code; bool valid; if (__predict_false(!kasan_enabled)) return; if (__predict_false(curthread != NULL && (curthread->td_pflags2 & TDP2_SAN_QUIET) != 0)) return; if (__predict_false(size == 0)) return; if (__predict_false(kasan_md_unsupported(addr))) return; if (KERNEL_PANICKED()) return; if (__builtin_constant_p(size)) { switch (size) { case 1: valid = kasan_shadow_1byte_isvalid(addr, &code); break; case 2: valid = kasan_shadow_2byte_isvalid(addr, &code); break; case 4: valid = kasan_shadow_4byte_isvalid(addr, &code); break; case 8: valid = kasan_shadow_8byte_isvalid(addr, &code); break; default: valid = kasan_shadow_Nbyte_isvalid(addr, size, &code); break; } } else { valid = kasan_shadow_Nbyte_isvalid(addr, size, &code); } if (__predict_false(!valid)) { kasan_report(addr, size, write, retaddr, code); } } /* -------------------------------------------------------------------------- */ void * kasan_memcpy(void *dst, const void *src, size_t len) { kasan_shadow_check((unsigned long)src, len, false, __RET_ADDR); kasan_shadow_check((unsigned long)dst, len, true, __RET_ADDR); return (__builtin_memcpy(dst, src, len)); } int kasan_memcmp(const void *b1, const void *b2, size_t len) { kasan_shadow_check((unsigned long)b1, len, false, __RET_ADDR); kasan_shadow_check((unsigned long)b2, len, false, __RET_ADDR); return (__builtin_memcmp(b1, b2, len)); } void * kasan_memset(void *b, int c, size_t len) { kasan_shadow_check((unsigned long)b, len, true, __RET_ADDR); return (__builtin_memset(b, c, len)); } void * kasan_memmove(void *dst, const void *src, size_t len) { kasan_shadow_check((unsigned long)src, len, false, __RET_ADDR); kasan_shadow_check((unsigned long)dst, len, true, __RET_ADDR); return (__builtin_memmove(dst, src, len)); } size_t kasan_strlen(const char *str) { const char *s; s = str; while (1) { kasan_shadow_check((unsigned long)s, 1, false, __RET_ADDR); if (*s == '\0') break; s++; } return (s - str); } char * kasan_strcpy(char *dst, const char *src) { char *save = dst; while (1) { kasan_shadow_check((unsigned long)src, 1, false, __RET_ADDR); kasan_shadow_check((unsigned long)dst, 1, true, __RET_ADDR); *dst = *src; if (*src == '\0') break; src++, dst++; } return save; } int kasan_strcmp(const char *s1, const char *s2) { while (1) { kasan_shadow_check((unsigned long)s1, 1, false, __RET_ADDR); kasan_shadow_check((unsigned long)s2, 1, false, __RET_ADDR); if (*s1 != *s2) break; if (*s1 == '\0') return 0; s1++, s2++; } return (*(const unsigned char *)s1 - *(const unsigned char *)s2); } int kasan_copyin(const void *uaddr, void *kaddr, size_t len) { kasan_shadow_check((unsigned long)kaddr, len, true, __RET_ADDR); return (copyin(uaddr, kaddr, len)); } int kasan_copyinstr(const void *uaddr, void *kaddr, size_t len, size_t *done) { kasan_shadow_check((unsigned long)kaddr, len, true, __RET_ADDR); return (copyinstr(uaddr, kaddr, len, done)); } int kasan_copyout(const void *kaddr, void *uaddr, size_t len) { kasan_shadow_check((unsigned long)kaddr, len, false, __RET_ADDR); return (copyout(kaddr, uaddr, len)); } /* -------------------------------------------------------------------------- */ int kasan_fubyte(volatile const void *base) { return (fubyte(base)); } int kasan_fuword16(volatile const void *base) { return (fuword16(base)); } int kasan_fueword(volatile const void *base, long *val) { kasan_shadow_check((unsigned long)val, sizeof(*val), true, __RET_ADDR); return (fueword(base, val)); } int kasan_fueword32(volatile const void *base, int32_t *val) { kasan_shadow_check((unsigned long)val, sizeof(*val), true, __RET_ADDR); return (fueword32(base, val)); } int kasan_fueword64(volatile const void *base, int64_t *val) { kasan_shadow_check((unsigned long)val, sizeof(*val), true, __RET_ADDR); return (fueword64(base, val)); } int kasan_subyte(volatile void *base, int byte) { return (subyte(base, byte)); } int kasan_suword(volatile void *base, long word) { return (suword(base, word)); } int kasan_suword16(volatile void *base, int word) { return (suword16(base, word)); } int kasan_suword32(volatile void *base, int32_t word) { return (suword32(base, word)); } int kasan_suword64(volatile void *base, int64_t word) { return (suword64(base, word)); } int kasan_casueword32(volatile uint32_t *base, uint32_t oldval, uint32_t *oldvalp, uint32_t newval) { kasan_shadow_check((unsigned long)oldvalp, sizeof(*oldvalp), true, __RET_ADDR); return (casueword32(base, oldval, oldvalp, newval)); } int kasan_casueword(volatile u_long *base, u_long oldval, u_long *oldvalp, u_long newval) { kasan_shadow_check((unsigned long)oldvalp, sizeof(*oldvalp), true, __RET_ADDR); return (casueword(base, oldval, oldvalp, newval)); } /* -------------------------------------------------------------------------- */ #include #include #define _ASAN_ATOMIC_FUNC_ADD(name, type) \ void kasan_atomic_add_##name(volatile type *ptr, type val) \ { \ kasan_shadow_check((uintptr_t)ptr, sizeof(type), true, \ __RET_ADDR); \ atomic_add_##name(ptr, val); \ } #define ASAN_ATOMIC_FUNC_ADD(name, type) \ _ASAN_ATOMIC_FUNC_ADD(name, type) \ _ASAN_ATOMIC_FUNC_ADD(acq_##name, type) \ _ASAN_ATOMIC_FUNC_ADD(rel_##name, type) #define _ASAN_ATOMIC_FUNC_SUBTRACT(name, type) \ void kasan_atomic_subtract_##name(volatile type *ptr, type val) \ { \ kasan_shadow_check((uintptr_t)ptr, sizeof(type), true, \ __RET_ADDR); \ atomic_subtract_##name(ptr, val); \ } #define ASAN_ATOMIC_FUNC_SUBTRACT(name, type) \ _ASAN_ATOMIC_FUNC_SUBTRACT(name, type) \ _ASAN_ATOMIC_FUNC_SUBTRACT(acq_##name, type) \ _ASAN_ATOMIC_FUNC_SUBTRACT(rel_##name, type) #define _ASAN_ATOMIC_FUNC_SET(name, type) \ void kasan_atomic_set_##name(volatile type *ptr, type val) \ { \ kasan_shadow_check((uintptr_t)ptr, sizeof(type), true, \ __RET_ADDR); \ atomic_set_##name(ptr, val); \ } #define ASAN_ATOMIC_FUNC_SET(name, type) \ _ASAN_ATOMIC_FUNC_SET(name, type) \ _ASAN_ATOMIC_FUNC_SET(acq_##name, type) \ _ASAN_ATOMIC_FUNC_SET(rel_##name, type) #define _ASAN_ATOMIC_FUNC_CLEAR(name, type) \ void kasan_atomic_clear_##name(volatile type *ptr, type val) \ { \ kasan_shadow_check((uintptr_t)ptr, sizeof(type), true, \ __RET_ADDR); \ atomic_clear_##name(ptr, val); \ } #define ASAN_ATOMIC_FUNC_CLEAR(name, type) \ _ASAN_ATOMIC_FUNC_CLEAR(name, type) \ _ASAN_ATOMIC_FUNC_CLEAR(acq_##name, type) \ _ASAN_ATOMIC_FUNC_CLEAR(rel_##name, type) #define ASAN_ATOMIC_FUNC_FETCHADD(name, type) \ type kasan_atomic_fetchadd_##name(volatile type *ptr, type val) \ { \ kasan_shadow_check((uintptr_t)ptr, sizeof(type), true, \ __RET_ADDR); \ return (atomic_fetchadd_##name(ptr, val)); \ } #define ASAN_ATOMIC_FUNC_READANDCLEAR(name, type) \ type kasan_atomic_readandclear_##name(volatile type *ptr) \ { \ kasan_shadow_check((uintptr_t)ptr, sizeof(type), true, \ __RET_ADDR); \ return (atomic_readandclear_##name(ptr)); \ } #define ASAN_ATOMIC_FUNC_TESTANDCLEAR(name, type) \ int kasan_atomic_testandclear_##name(volatile type *ptr, u_int v) \ { \ kasan_shadow_check((uintptr_t)ptr, sizeof(type), true, \ __RET_ADDR); \ return (atomic_testandclear_##name(ptr, v)); \ } #define ASAN_ATOMIC_FUNC_TESTANDSET(name, type) \ int kasan_atomic_testandset_##name(volatile type *ptr, u_int v) \ { \ kasan_shadow_check((uintptr_t)ptr, sizeof(type), true, \ __RET_ADDR); \ return (atomic_testandset_##name(ptr, v)); \ } #define ASAN_ATOMIC_FUNC_SWAP(name, type) \ type kasan_atomic_swap_##name(volatile type *ptr, type val) \ { \ kasan_shadow_check((uintptr_t)ptr, sizeof(type), true, \ __RET_ADDR); \ return (atomic_swap_##name(ptr, val)); \ } #define _ASAN_ATOMIC_FUNC_CMPSET(name, type) \ int kasan_atomic_cmpset_##name(volatile type *ptr, type oval, \ type nval) \ { \ kasan_shadow_check((uintptr_t)ptr, sizeof(type), true, \ __RET_ADDR); \ return (atomic_cmpset_##name(ptr, oval, nval)); \ } #define ASAN_ATOMIC_FUNC_CMPSET(name, type) \ _ASAN_ATOMIC_FUNC_CMPSET(name, type) \ _ASAN_ATOMIC_FUNC_CMPSET(acq_##name, type) \ _ASAN_ATOMIC_FUNC_CMPSET(rel_##name, type) #define _ASAN_ATOMIC_FUNC_FCMPSET(name, type) \ int kasan_atomic_fcmpset_##name(volatile type *ptr, type *oval, \ type nval) \ { \ kasan_shadow_check((uintptr_t)ptr, sizeof(type), true, \ __RET_ADDR); \ return (atomic_fcmpset_##name(ptr, oval, nval)); \ } #define ASAN_ATOMIC_FUNC_FCMPSET(name, type) \ _ASAN_ATOMIC_FUNC_FCMPSET(name, type) \ _ASAN_ATOMIC_FUNC_FCMPSET(acq_##name, type) \ _ASAN_ATOMIC_FUNC_FCMPSET(rel_##name, type) #define ASAN_ATOMIC_FUNC_THREAD_FENCE(name) \ void kasan_atomic_thread_fence_##name(void) \ { \ atomic_thread_fence_##name(); \ } #define _ASAN_ATOMIC_FUNC_LOAD(name, type) \ - type kasan_atomic_load_##name(volatile type *ptr) \ + type kasan_atomic_load_##name(const volatile type *ptr) \ { \ kasan_shadow_check((uintptr_t)ptr, sizeof(type), true, \ __RET_ADDR); \ return (atomic_load_##name(ptr)); \ } #define ASAN_ATOMIC_FUNC_LOAD(name, type) \ _ASAN_ATOMIC_FUNC_LOAD(name, type) \ _ASAN_ATOMIC_FUNC_LOAD(acq_##name, type) #define _ASAN_ATOMIC_FUNC_STORE(name, type) \ void kasan_atomic_store_##name(volatile type *ptr, type val) \ { \ kasan_shadow_check((uintptr_t)ptr, sizeof(type), true, \ __RET_ADDR); \ atomic_store_##name(ptr, val); \ } #define ASAN_ATOMIC_FUNC_STORE(name, type) \ _ASAN_ATOMIC_FUNC_STORE(name, type) \ _ASAN_ATOMIC_FUNC_STORE(rel_##name, type) ASAN_ATOMIC_FUNC_ADD(8, uint8_t); ASAN_ATOMIC_FUNC_ADD(16, uint16_t); ASAN_ATOMIC_FUNC_ADD(32, uint32_t); ASAN_ATOMIC_FUNC_ADD(64, uint64_t); ASAN_ATOMIC_FUNC_ADD(int, u_int); ASAN_ATOMIC_FUNC_ADD(long, u_long); ASAN_ATOMIC_FUNC_ADD(ptr, uintptr_t); ASAN_ATOMIC_FUNC_SUBTRACT(8, uint8_t); ASAN_ATOMIC_FUNC_SUBTRACT(16, uint16_t); ASAN_ATOMIC_FUNC_SUBTRACT(32, uint32_t); ASAN_ATOMIC_FUNC_SUBTRACT(64, uint64_t); ASAN_ATOMIC_FUNC_SUBTRACT(int, u_int); ASAN_ATOMIC_FUNC_SUBTRACT(long, u_long); ASAN_ATOMIC_FUNC_SUBTRACT(ptr, uintptr_t); ASAN_ATOMIC_FUNC_SET(8, uint8_t); ASAN_ATOMIC_FUNC_SET(16, uint16_t); ASAN_ATOMIC_FUNC_SET(32, uint32_t); ASAN_ATOMIC_FUNC_SET(64, uint64_t); ASAN_ATOMIC_FUNC_SET(int, u_int); ASAN_ATOMIC_FUNC_SET(long, u_long); ASAN_ATOMIC_FUNC_SET(ptr, uintptr_t); ASAN_ATOMIC_FUNC_CLEAR(8, uint8_t); ASAN_ATOMIC_FUNC_CLEAR(16, uint16_t); ASAN_ATOMIC_FUNC_CLEAR(32, uint32_t); ASAN_ATOMIC_FUNC_CLEAR(64, uint64_t); ASAN_ATOMIC_FUNC_CLEAR(int, u_int); ASAN_ATOMIC_FUNC_CLEAR(long, u_long); ASAN_ATOMIC_FUNC_CLEAR(ptr, uintptr_t); ASAN_ATOMIC_FUNC_FETCHADD(32, uint32_t); ASAN_ATOMIC_FUNC_FETCHADD(64, uint64_t); ASAN_ATOMIC_FUNC_FETCHADD(int, u_int); ASAN_ATOMIC_FUNC_FETCHADD(long, u_long); ASAN_ATOMIC_FUNC_READANDCLEAR(32, uint32_t); ASAN_ATOMIC_FUNC_READANDCLEAR(64, uint64_t); ASAN_ATOMIC_FUNC_READANDCLEAR(int, u_int); ASAN_ATOMIC_FUNC_READANDCLEAR(long, u_long); ASAN_ATOMIC_FUNC_READANDCLEAR(ptr, uintptr_t); ASAN_ATOMIC_FUNC_TESTANDCLEAR(32, uint32_t); ASAN_ATOMIC_FUNC_TESTANDCLEAR(64, uint64_t); ASAN_ATOMIC_FUNC_TESTANDCLEAR(int, u_int); ASAN_ATOMIC_FUNC_TESTANDCLEAR(long, u_long); ASAN_ATOMIC_FUNC_TESTANDCLEAR(ptr, uintptr_t); ASAN_ATOMIC_FUNC_TESTANDSET(32, uint32_t); ASAN_ATOMIC_FUNC_TESTANDSET(64, uint64_t); ASAN_ATOMIC_FUNC_TESTANDSET(int, u_int); ASAN_ATOMIC_FUNC_TESTANDSET(long, u_long); ASAN_ATOMIC_FUNC_TESTANDSET(ptr, uintptr_t); ASAN_ATOMIC_FUNC_SWAP(32, uint32_t); ASAN_ATOMIC_FUNC_SWAP(64, uint64_t); ASAN_ATOMIC_FUNC_SWAP(int, u_int); ASAN_ATOMIC_FUNC_SWAP(long, u_long); ASAN_ATOMIC_FUNC_SWAP(ptr, uintptr_t); ASAN_ATOMIC_FUNC_CMPSET(8, uint8_t); ASAN_ATOMIC_FUNC_CMPSET(16, uint16_t); ASAN_ATOMIC_FUNC_CMPSET(32, uint32_t); ASAN_ATOMIC_FUNC_CMPSET(64, uint64_t); ASAN_ATOMIC_FUNC_CMPSET(int, u_int); ASAN_ATOMIC_FUNC_CMPSET(long, u_long); ASAN_ATOMIC_FUNC_CMPSET(ptr, uintptr_t); ASAN_ATOMIC_FUNC_FCMPSET(8, uint8_t); ASAN_ATOMIC_FUNC_FCMPSET(16, uint16_t); ASAN_ATOMIC_FUNC_FCMPSET(32, uint32_t); ASAN_ATOMIC_FUNC_FCMPSET(64, uint64_t); ASAN_ATOMIC_FUNC_FCMPSET(int, u_int); ASAN_ATOMIC_FUNC_FCMPSET(long, u_long); ASAN_ATOMIC_FUNC_FCMPSET(ptr, uintptr_t); _ASAN_ATOMIC_FUNC_LOAD(bool, bool); ASAN_ATOMIC_FUNC_LOAD(8, uint8_t); ASAN_ATOMIC_FUNC_LOAD(16, uint16_t); ASAN_ATOMIC_FUNC_LOAD(32, uint32_t); ASAN_ATOMIC_FUNC_LOAD(64, uint64_t); ASAN_ATOMIC_FUNC_LOAD(char, u_char); ASAN_ATOMIC_FUNC_LOAD(short, u_short); ASAN_ATOMIC_FUNC_LOAD(int, u_int); ASAN_ATOMIC_FUNC_LOAD(long, u_long); ASAN_ATOMIC_FUNC_LOAD(ptr, uintptr_t); _ASAN_ATOMIC_FUNC_STORE(bool, bool); ASAN_ATOMIC_FUNC_STORE(8, uint8_t); ASAN_ATOMIC_FUNC_STORE(16, uint16_t); ASAN_ATOMIC_FUNC_STORE(32, uint32_t); ASAN_ATOMIC_FUNC_STORE(64, uint64_t); ASAN_ATOMIC_FUNC_STORE(char, u_char); ASAN_ATOMIC_FUNC_STORE(short, u_short); ASAN_ATOMIC_FUNC_STORE(int, u_int); ASAN_ATOMIC_FUNC_STORE(long, u_long); ASAN_ATOMIC_FUNC_STORE(ptr, uintptr_t); ASAN_ATOMIC_FUNC_THREAD_FENCE(acq); ASAN_ATOMIC_FUNC_THREAD_FENCE(rel); ASAN_ATOMIC_FUNC_THREAD_FENCE(acq_rel); ASAN_ATOMIC_FUNC_THREAD_FENCE(seq_cst); void kasan_atomic_interrupt_fence(void) { } /* -------------------------------------------------------------------------- */ #include #include #include int kasan_bus_space_map(bus_space_tag_t tag, bus_addr_t hnd, bus_size_t size, int flags, bus_space_handle_t *handlep) { return (bus_space_map(tag, hnd, size, flags, handlep)); } void kasan_bus_space_unmap(bus_space_tag_t tag, bus_space_handle_t hnd, bus_size_t size) { bus_space_unmap(tag, hnd, size); } int kasan_bus_space_subregion(bus_space_tag_t tag, bus_space_handle_t hnd, bus_size_t offset, bus_size_t size, bus_space_handle_t *handlep) { return (bus_space_subregion(tag, hnd, offset, size, handlep)); } void kasan_bus_space_free(bus_space_tag_t tag, bus_space_handle_t hnd, bus_size_t size) { bus_space_free(tag, hnd, size); } void kasan_bus_space_barrier(bus_space_tag_t tag, bus_space_handle_t hnd, bus_size_t offset, bus_size_t size, int flags) { bus_space_barrier(tag, hnd, offset, size, flags); } #define ASAN_BUS_READ_FUNC(func, width, type) \ type kasan_bus_space_read##func##_##width(bus_space_tag_t tag, \ bus_space_handle_t hnd, bus_size_t offset) \ { \ return (bus_space_read##func##_##width(tag, hnd, \ offset)); \ } \ #define ASAN_BUS_READ_PTR_FUNC(func, width, type) \ void kasan_bus_space_read_##func##_##width(bus_space_tag_t tag, \ bus_space_handle_t hnd, bus_size_t size, type *buf, \ bus_size_t count) \ { \ kasan_shadow_check((uintptr_t)buf, sizeof(type) * count,\ false, __RET_ADDR); \ bus_space_read_##func##_##width(tag, hnd, size, buf, \ count); \ } ASAN_BUS_READ_FUNC(, 1, uint8_t) ASAN_BUS_READ_FUNC(_stream, 1, uint8_t) ASAN_BUS_READ_PTR_FUNC(multi, 1, uint8_t) ASAN_BUS_READ_PTR_FUNC(multi_stream, 1, uint8_t) ASAN_BUS_READ_PTR_FUNC(region, 1, uint8_t) ASAN_BUS_READ_PTR_FUNC(region_stream, 1, uint8_t) ASAN_BUS_READ_FUNC(, 2, uint16_t) ASAN_BUS_READ_FUNC(_stream, 2, uint16_t) ASAN_BUS_READ_PTR_FUNC(multi, 2, uint16_t) ASAN_BUS_READ_PTR_FUNC(multi_stream, 2, uint16_t) ASAN_BUS_READ_PTR_FUNC(region, 2, uint16_t) ASAN_BUS_READ_PTR_FUNC(region_stream, 2, uint16_t) ASAN_BUS_READ_FUNC(, 4, uint32_t) ASAN_BUS_READ_FUNC(_stream, 4, uint32_t) ASAN_BUS_READ_PTR_FUNC(multi, 4, uint32_t) ASAN_BUS_READ_PTR_FUNC(multi_stream, 4, uint32_t) ASAN_BUS_READ_PTR_FUNC(region, 4, uint32_t) ASAN_BUS_READ_PTR_FUNC(region_stream, 4, uint32_t) ASAN_BUS_READ_FUNC(, 8, uint64_t) #if defined(__aarch64__) ASAN_BUS_READ_FUNC(_stream, 8, uint64_t) ASAN_BUS_READ_PTR_FUNC(multi, 8, uint64_t) ASAN_BUS_READ_PTR_FUNC(multi_stream, 8, uint64_t) ASAN_BUS_READ_PTR_FUNC(region, 8, uint64_t) ASAN_BUS_READ_PTR_FUNC(region_stream, 8, uint64_t) #endif #define ASAN_BUS_WRITE_FUNC(func, width, type) \ void kasan_bus_space_write##func##_##width(bus_space_tag_t tag, \ bus_space_handle_t hnd, bus_size_t offset, type value) \ { \ bus_space_write##func##_##width(tag, hnd, offset, value);\ } \ #define ASAN_BUS_WRITE_PTR_FUNC(func, width, type) \ void kasan_bus_space_write_##func##_##width(bus_space_tag_t tag,\ bus_space_handle_t hnd, bus_size_t size, const type *buf, \ bus_size_t count) \ { \ kasan_shadow_check((uintptr_t)buf, sizeof(type) * count,\ true, __RET_ADDR); \ bus_space_write_##func##_##width(tag, hnd, size, buf, \ count); \ } ASAN_BUS_WRITE_FUNC(, 1, uint8_t) ASAN_BUS_WRITE_FUNC(_stream, 1, uint8_t) ASAN_BUS_WRITE_PTR_FUNC(multi, 1, uint8_t) ASAN_BUS_WRITE_PTR_FUNC(multi_stream, 1, uint8_t) ASAN_BUS_WRITE_PTR_FUNC(region, 1, uint8_t) ASAN_BUS_WRITE_PTR_FUNC(region_stream, 1, uint8_t) ASAN_BUS_WRITE_FUNC(, 2, uint16_t) ASAN_BUS_WRITE_FUNC(_stream, 2, uint16_t) ASAN_BUS_WRITE_PTR_FUNC(multi, 2, uint16_t) ASAN_BUS_WRITE_PTR_FUNC(multi_stream, 2, uint16_t) ASAN_BUS_WRITE_PTR_FUNC(region, 2, uint16_t) ASAN_BUS_WRITE_PTR_FUNC(region_stream, 2, uint16_t) ASAN_BUS_WRITE_FUNC(, 4, uint32_t) ASAN_BUS_WRITE_FUNC(_stream, 4, uint32_t) ASAN_BUS_WRITE_PTR_FUNC(multi, 4, uint32_t) ASAN_BUS_WRITE_PTR_FUNC(multi_stream, 4, uint32_t) ASAN_BUS_WRITE_PTR_FUNC(region, 4, uint32_t) ASAN_BUS_WRITE_PTR_FUNC(region_stream, 4, uint32_t) ASAN_BUS_WRITE_FUNC(, 8, uint64_t) #define ASAN_BUS_SET_FUNC(func, width, type) \ void kasan_bus_space_set_##func##_##width(bus_space_tag_t tag, \ bus_space_handle_t hnd, bus_size_t offset, type value, \ bus_size_t count) \ { \ bus_space_set_##func##_##width(tag, hnd, offset, value, \ count); \ } ASAN_BUS_SET_FUNC(multi, 1, uint8_t) ASAN_BUS_SET_FUNC(region, 1, uint8_t) ASAN_BUS_SET_FUNC(multi_stream, 1, uint8_t) ASAN_BUS_SET_FUNC(region_stream, 1, uint8_t) ASAN_BUS_SET_FUNC(multi, 2, uint16_t) ASAN_BUS_SET_FUNC(region, 2, uint16_t) ASAN_BUS_SET_FUNC(multi_stream, 2, uint16_t) ASAN_BUS_SET_FUNC(region_stream, 2, uint16_t) ASAN_BUS_SET_FUNC(multi, 4, uint32_t) ASAN_BUS_SET_FUNC(region, 4, uint32_t) ASAN_BUS_SET_FUNC(multi_stream, 4, uint32_t) ASAN_BUS_SET_FUNC(region_stream, 4, uint32_t) #define ASAN_BUS_PEEK_FUNC(width, type) \ int kasan_bus_space_peek_##width(bus_space_tag_t tag, \ bus_space_handle_t hnd, bus_size_t offset, type *valuep) \ { \ return (bus_space_peek_##width(tag, hnd, offset, \ valuep)); \ } ASAN_BUS_PEEK_FUNC(1, uint8_t) ASAN_BUS_PEEK_FUNC(2, uint16_t) ASAN_BUS_PEEK_FUNC(4, uint32_t) ASAN_BUS_PEEK_FUNC(8, uint64_t) #define ASAN_BUS_POKE_FUNC(width, type) \ int kasan_bus_space_poke_##width(bus_space_tag_t tag, \ bus_space_handle_t hnd, bus_size_t offset, type value) \ { \ return (bus_space_poke_##width(tag, hnd, offset, \ value)); \ } ASAN_BUS_POKE_FUNC(1, uint8_t) ASAN_BUS_POKE_FUNC(2, uint16_t) ASAN_BUS_POKE_FUNC(4, uint32_t) ASAN_BUS_POKE_FUNC(8, uint64_t) /* -------------------------------------------------------------------------- */ void __asan_register_globals(struct __asan_global *, size_t); void __asan_unregister_globals(struct __asan_global *, size_t); void __asan_register_globals(struct __asan_global *globals, size_t n) { size_t i; for (i = 0; i < n; i++) { kasan_mark(globals[i].beg, globals[i].size, globals[i].size_with_redzone, KASAN_GENERIC_REDZONE); } } void __asan_unregister_globals(struct __asan_global *globals, size_t n) { size_t i; for (i = 0; i < n; i++) { kasan_mark(globals[i].beg, globals[i].size_with_redzone, globals[i].size_with_redzone, 0); } } #define ASAN_LOAD_STORE(size) \ void __asan_load##size(unsigned long); \ void __asan_load##size(unsigned long addr) \ { \ kasan_shadow_check(addr, size, false, __RET_ADDR);\ } \ void __asan_load##size##_noabort(unsigned long); \ void __asan_load##size##_noabort(unsigned long addr) \ { \ kasan_shadow_check(addr, size, false, __RET_ADDR);\ } \ void __asan_store##size(unsigned long); \ void __asan_store##size(unsigned long addr) \ { \ kasan_shadow_check(addr, size, true, __RET_ADDR);\ } \ void __asan_store##size##_noabort(unsigned long); \ void __asan_store##size##_noabort(unsigned long addr) \ { \ kasan_shadow_check(addr, size, true, __RET_ADDR);\ } ASAN_LOAD_STORE(1); ASAN_LOAD_STORE(2); ASAN_LOAD_STORE(4); ASAN_LOAD_STORE(8); ASAN_LOAD_STORE(16); void __asan_loadN(unsigned long, size_t); void __asan_loadN_noabort(unsigned long, size_t); void __asan_storeN(unsigned long, size_t); void __asan_storeN_noabort(unsigned long, size_t); void __asan_handle_no_return(void); void __asan_loadN(unsigned long addr, size_t size) { kasan_shadow_check(addr, size, false, __RET_ADDR); } void __asan_loadN_noabort(unsigned long addr, size_t size) { kasan_shadow_check(addr, size, false, __RET_ADDR); } void __asan_storeN(unsigned long addr, size_t size) { kasan_shadow_check(addr, size, true, __RET_ADDR); } void __asan_storeN_noabort(unsigned long addr, size_t size) { kasan_shadow_check(addr, size, true, __RET_ADDR); } void __asan_handle_no_return(void) { /* nothing */ } #define ASAN_SET_SHADOW(byte) \ void __asan_set_shadow_##byte(void *, size_t); \ void __asan_set_shadow_##byte(void *addr, size_t size) \ { \ __builtin_memset((void *)addr, 0x##byte, size); \ } ASAN_SET_SHADOW(00); ASAN_SET_SHADOW(f1); ASAN_SET_SHADOW(f2); ASAN_SET_SHADOW(f3); ASAN_SET_SHADOW(f5); ASAN_SET_SHADOW(f8); void __asan_poison_stack_memory(const void *, size_t); void __asan_unpoison_stack_memory(const void *, size_t); void __asan_poison_stack_memory(const void *addr, size_t size) { size = roundup(size, KASAN_SHADOW_SCALE); kasan_shadow_Nbyte_fill(addr, size, KASAN_USE_AFTER_SCOPE); } void __asan_unpoison_stack_memory(const void *addr, size_t size) { kasan_shadow_Nbyte_markvalid(addr, size); } void __asan_alloca_poison(const void *, size_t); void __asan_allocas_unpoison(const void *, const void *); void __asan_alloca_poison(const void *addr, size_t size) { const void *l, *r; KASSERT((vm_offset_t)addr % KASAN_ALLOCA_SCALE_SIZE == 0, ("%s: invalid address %p", __func__, addr)); l = (const uint8_t *)addr - KASAN_ALLOCA_SCALE_SIZE; r = (const uint8_t *)addr + roundup(size, KASAN_ALLOCA_SCALE_SIZE); kasan_shadow_Nbyte_fill(l, KASAN_ALLOCA_SCALE_SIZE, KASAN_STACK_LEFT); kasan_mark(addr, size, roundup(size, KASAN_ALLOCA_SCALE_SIZE), KASAN_STACK_MID); kasan_shadow_Nbyte_fill(r, KASAN_ALLOCA_SCALE_SIZE, KASAN_STACK_RIGHT); } void __asan_allocas_unpoison(const void *stkbegin, const void *stkend) { size_t size; if (__predict_false(!stkbegin)) return; if (__predict_false((uintptr_t)stkbegin > (uintptr_t)stkend)) return; size = (uintptr_t)stkend - (uintptr_t)stkbegin; kasan_shadow_Nbyte_fill(stkbegin, size, 0); } void __asan_poison_memory_region(const void *addr, size_t size); void __asan_unpoison_memory_region(const void *addr, size_t size); void __asan_poison_memory_region(const void *addr, size_t size) { } void __asan_unpoison_memory_region(const void *addr, size_t size) { } diff --git a/sys/kern/subr_csan.c b/sys/kern/subr_csan.c index 5d0e6607403c..cca5fadc5afe 100644 --- a/sys/kern/subr_csan.c +++ b/sys/kern/subr_csan.c @@ -1,904 +1,904 @@ /* $NetBSD: subr_csan.c,v 1.5 2019/11/15 08:11:37 maxv Exp $ */ /* * Copyright (c) 2019 The NetBSD Foundation, Inc. * All rights reserved. * Copyright (c) 2019 Andrew Turner * * This code is derived from software contributed to The NetBSD Foundation * by Maxime Villard. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #define SAN_RUNTIME #include "opt_ddb.h" #include #include #include #include #include #include #include #include #include #include #include #ifdef KCSAN_PANIC #define REPORT panic #else #define REPORT printf #endif typedef struct { uintptr_t addr; uint32_t size; bool write:1; bool atomic:1; uintptr_t pc; } csan_cell_t; typedef struct { bool inited; uint32_t cnt; csan_cell_t cell; } csan_cpu_t; static csan_cpu_t kcsan_cpus[MAXCPU]; static bool kcsan_enabled __read_mostly; #define __RET_ADDR (uintptr_t)__builtin_return_address(0) #define KCSAN_NACCESSES 1024 #define KCSAN_DELAY 10 /* 10 microseconds */ /* -------------------------------------------------------------------------- */ /* The MD code. */ #include /* -------------------------------------------------------------------------- */ static void kcsan_enable(void *dummy __unused) { printf("Enabling KCSCAN, expect reduced performance.\n"); kcsan_enabled = true; } SYSINIT(kcsan_enable, SI_SUB_SMP, SI_ORDER_SECOND, kcsan_enable, NULL); void kcsan_cpu_init(u_int cpu) { kcsan_cpus[cpu].inited = true; } /* -------------------------------------------------------------------------- */ static inline void kcsan_report(csan_cell_t *new, u_int newcpu, csan_cell_t *old, u_int oldcpu) { const char *newsym, *oldsym; #ifdef DDB c_db_sym_t sym; db_expr_t offset; sym = db_search_symbol((vm_offset_t)new->pc, DB_STGY_PROC, &offset); db_symbol_values(sym, &newsym, NULL); sym = db_search_symbol((vm_offset_t)old->pc, DB_STGY_PROC, &offset); db_symbol_values(sym, &oldsym, NULL); #else newsym = ""; oldsym = ""; #endif REPORT("CSan: Racy Access " "[Cpu%u %s%s Addr=%p Size=%u PC=%p<%s>] " "[Cpu%u %s%s Addr=%p Size=%u PC=%p<%s>]\n", newcpu, (new->atomic ? "Atomic " : ""), (new->write ? "Write" : "Read"), (void *)new->addr, new->size, (void *)new->pc, newsym, oldcpu, (old->atomic ? "Atomic " : ""), (old->write ? "Write" : "Read"), (void *)old->addr, old->size, (void *)old->pc, oldsym); kcsan_md_unwind(); } static inline bool kcsan_access_is_atomic(csan_cell_t *new, csan_cell_t *old) { if (new->write && !new->atomic) return false; if (old->write && !old->atomic) return false; return true; } static inline void kcsan_access(uintptr_t addr, size_t size, bool write, bool atomic, uintptr_t pc) { csan_cell_t old, new; csan_cpu_t *cpu; uint64_t intr; size_t i; if (__predict_false(!kcsan_enabled)) return; if (__predict_false(kcsan_md_unsupported((vm_offset_t)addr))) return; if (KERNEL_PANICKED()) return; new.addr = addr; new.size = size; new.write = write; new.atomic = atomic; new.pc = pc; CPU_FOREACH(i) { __builtin_memcpy(&old, &kcsan_cpus[i].cell, sizeof(old)); if (old.addr + old.size <= new.addr) continue; if (new.addr + new.size <= old.addr) continue; if (__predict_true(!old.write && !new.write)) continue; if (__predict_true(kcsan_access_is_atomic(&new, &old))) continue; kcsan_report(&new, PCPU_GET(cpuid), &old, i); break; } if (__predict_false(!kcsan_md_is_avail())) return; kcsan_md_disable_intrs(&intr); cpu = &kcsan_cpus[PCPU_GET(cpuid)]; if (__predict_false(!cpu->inited)) goto out; cpu->cnt = (cpu->cnt + 1) % KCSAN_NACCESSES; if (__predict_true(cpu->cnt != 0)) goto out; __builtin_memcpy(&cpu->cell, &new, sizeof(new)); kcsan_md_delay(KCSAN_DELAY); __builtin_memset(&cpu->cell, 0, sizeof(new)); out: kcsan_md_enable_intrs(&intr); } #define CSAN_READ(size) \ void __tsan_read##size(uintptr_t); \ void __tsan_read##size(uintptr_t addr) \ { \ kcsan_access(addr, size, false, false, __RET_ADDR); \ } \ void __tsan_unaligned_read##size(uintptr_t); \ void __tsan_unaligned_read##size(uintptr_t addr) \ { \ kcsan_access(addr, size, false, false, __RET_ADDR); \ } CSAN_READ(1) CSAN_READ(2) CSAN_READ(4) CSAN_READ(8) CSAN_READ(16) #define CSAN_WRITE(size) \ void __tsan_write##size(uintptr_t); \ void __tsan_write##size(uintptr_t addr) \ { \ kcsan_access(addr, size, true, false, __RET_ADDR); \ } \ void __tsan_unaligned_write##size(uintptr_t); \ void __tsan_unaligned_write##size(uintptr_t addr) \ { \ kcsan_access(addr, size, true, false, __RET_ADDR); \ } CSAN_WRITE(1) CSAN_WRITE(2) CSAN_WRITE(4) CSAN_WRITE(8) CSAN_WRITE(16) void __tsan_read_range(uintptr_t, size_t); void __tsan_write_range(uintptr_t, size_t); void __tsan_read_range(uintptr_t addr, size_t size) { kcsan_access(addr, size, false, false, __RET_ADDR); } void __tsan_write_range(uintptr_t addr, size_t size) { kcsan_access(addr, size, true, false, __RET_ADDR); } void __tsan_init(void); void __tsan_func_entry(void *); void __tsan_func_exit(void); void __tsan_init(void) { } void __tsan_func_entry(void *call_pc) { } void __tsan_func_exit(void) { } /* -------------------------------------------------------------------------- */ void * kcsan_memcpy(void *dst, const void *src, size_t len) { kcsan_access((uintptr_t)src, len, false, false, __RET_ADDR); kcsan_access((uintptr_t)dst, len, true, false, __RET_ADDR); return __builtin_memcpy(dst, src, len); } int kcsan_memcmp(const void *b1, const void *b2, size_t len) { kcsan_access((uintptr_t)b1, len, false, false, __RET_ADDR); kcsan_access((uintptr_t)b2, len, false, false, __RET_ADDR); return __builtin_memcmp(b1, b2, len); } void * kcsan_memset(void *b, int c, size_t len) { kcsan_access((uintptr_t)b, len, true, false, __RET_ADDR); return __builtin_memset(b, c, len); } void * kcsan_memmove(void *dst, const void *src, size_t len) { kcsan_access((uintptr_t)src, len, false, false, __RET_ADDR); kcsan_access((uintptr_t)dst, len, true, false, __RET_ADDR); return __builtin_memmove(dst, src, len); } __strong_reference(kcsan_memcpy, __tsan_memcpy); __strong_reference(kcsan_memset, __tsan_memset); __strong_reference(kcsan_memmove, __tsan_memmove); char * kcsan_strcpy(char *dst, const char *src) { char *save = dst; while (1) { kcsan_access((uintptr_t)src, 1, false, false, __RET_ADDR); kcsan_access((uintptr_t)dst, 1, true, false, __RET_ADDR); *dst = *src; if (*src == '\0') break; src++, dst++; } return save; } int kcsan_strcmp(const char *s1, const char *s2) { while (1) { kcsan_access((uintptr_t)s1, 1, false, false, __RET_ADDR); kcsan_access((uintptr_t)s2, 1, false, false, __RET_ADDR); if (*s1 != *s2) break; if (*s1 == '\0') return 0; s1++, s2++; } return (*(const unsigned char *)s1 - *(const unsigned char *)s2); } size_t kcsan_strlen(const char *str) { const char *s; s = str; while (1) { kcsan_access((uintptr_t)s, 1, false, false, __RET_ADDR); if (*s == '\0') break; s++; } return (s - str); } int kcsan_copyin(const void *uaddr, void *kaddr, size_t len) { kcsan_access((uintptr_t)kaddr, len, true, false, __RET_ADDR); return copyin(uaddr, kaddr, len); } int kcsan_copyinstr(const void *uaddr, void *kaddr, size_t len, size_t *done) { kcsan_access((uintptr_t)kaddr, len, true, false, __RET_ADDR); return copyinstr(uaddr, kaddr, len, done); } int kcsan_copyout(const void *kaddr, void *uaddr, size_t len) { kcsan_access((uintptr_t)kaddr, len, false, false, __RET_ADDR); return copyout(kaddr, uaddr, len); } /* -------------------------------------------------------------------------- */ #include #include #define _CSAN_ATOMIC_FUNC_ADD(name, type) \ void kcsan_atomic_add_##name(volatile type *ptr, type val) \ { \ kcsan_access((uintptr_t)ptr, sizeof(type), true, true, \ __RET_ADDR); \ atomic_add_##name(ptr, val); \ } #define CSAN_ATOMIC_FUNC_ADD(name, type) \ _CSAN_ATOMIC_FUNC_ADD(name, type) \ _CSAN_ATOMIC_FUNC_ADD(acq_##name, type) \ _CSAN_ATOMIC_FUNC_ADD(rel_##name, type) #define _CSAN_ATOMIC_FUNC_CLEAR(name, type) \ void kcsan_atomic_clear_##name(volatile type *ptr, type val) \ { \ kcsan_access((uintptr_t)ptr, sizeof(type), true, true, \ __RET_ADDR); \ atomic_clear_##name(ptr, val); \ } #define CSAN_ATOMIC_FUNC_CLEAR(name, type) \ _CSAN_ATOMIC_FUNC_CLEAR(name, type) \ _CSAN_ATOMIC_FUNC_CLEAR(acq_##name, type) \ _CSAN_ATOMIC_FUNC_CLEAR(rel_##name, type) #define _CSAN_ATOMIC_FUNC_CMPSET(name, type) \ int kcsan_atomic_cmpset_##name(volatile type *ptr, type val1, \ type val2) \ { \ kcsan_access((uintptr_t)ptr, sizeof(type), true, true, \ __RET_ADDR); \ return (atomic_cmpset_##name(ptr, val1, val2)); \ } #define CSAN_ATOMIC_FUNC_CMPSET(name, type) \ _CSAN_ATOMIC_FUNC_CMPSET(name, type) \ _CSAN_ATOMIC_FUNC_CMPSET(acq_##name, type) \ _CSAN_ATOMIC_FUNC_CMPSET(rel_##name, type) #define _CSAN_ATOMIC_FUNC_FCMPSET(name, type) \ int kcsan_atomic_fcmpset_##name(volatile type *ptr, type *val1, \ type val2) \ { \ kcsan_access((uintptr_t)ptr, sizeof(type), true, true, \ __RET_ADDR); \ return (atomic_fcmpset_##name(ptr, val1, val2)); \ } #define CSAN_ATOMIC_FUNC_FCMPSET(name, type) \ _CSAN_ATOMIC_FUNC_FCMPSET(name, type) \ _CSAN_ATOMIC_FUNC_FCMPSET(acq_##name, type) \ _CSAN_ATOMIC_FUNC_FCMPSET(rel_##name, type) #define CSAN_ATOMIC_FUNC_FETCHADD(name, type) \ type kcsan_atomic_fetchadd_##name(volatile type *ptr, type val) \ { \ kcsan_access((uintptr_t)ptr, sizeof(type), true, true, \ __RET_ADDR); \ return (atomic_fetchadd_##name(ptr, val)); \ } #define _CSAN_ATOMIC_FUNC_LOAD(name, type) \ - type kcsan_atomic_load_##name(volatile type *ptr) \ + type kcsan_atomic_load_##name(const volatile type *ptr) \ { \ kcsan_access((uintptr_t)ptr, sizeof(type), false, true, \ __RET_ADDR); \ return (atomic_load_##name(ptr)); \ } #define CSAN_ATOMIC_FUNC_LOAD(name, type) \ _CSAN_ATOMIC_FUNC_LOAD(name, type) \ _CSAN_ATOMIC_FUNC_LOAD(acq_##name, type) \ #define CSAN_ATOMIC_FUNC_READANDCLEAR(name, type) \ type kcsan_atomic_readandclear_##name(volatile type *ptr) \ { \ kcsan_access((uintptr_t)ptr, sizeof(type), true, true, \ __RET_ADDR); \ return (atomic_readandclear_##name(ptr)); \ } #define _CSAN_ATOMIC_FUNC_SET(name, type) \ void kcsan_atomic_set_##name(volatile type *ptr, type val) \ { \ kcsan_access((uintptr_t)ptr, sizeof(type), true, true, \ __RET_ADDR); \ atomic_set_##name(ptr, val); \ } #define CSAN_ATOMIC_FUNC_SET(name, type) \ _CSAN_ATOMIC_FUNC_SET(name, type) \ _CSAN_ATOMIC_FUNC_SET(acq_##name, type) \ _CSAN_ATOMIC_FUNC_SET(rel_##name, type) #define _CSAN_ATOMIC_FUNC_SUBTRACT(name, type) \ void kcsan_atomic_subtract_##name(volatile type *ptr, type val) \ { \ kcsan_access((uintptr_t)ptr, sizeof(type), true, true, \ __RET_ADDR); \ atomic_subtract_##name(ptr, val); \ } #define CSAN_ATOMIC_FUNC_SUBTRACT(name, type) \ _CSAN_ATOMIC_FUNC_SUBTRACT(name, type) \ _CSAN_ATOMIC_FUNC_SUBTRACT(acq_##name, type) \ _CSAN_ATOMIC_FUNC_SUBTRACT(rel_##name, type) #define _CSAN_ATOMIC_FUNC_STORE(name, type) \ void kcsan_atomic_store_##name(volatile type *ptr, type val) \ { \ kcsan_access((uintptr_t)ptr, sizeof(type), true, true, \ __RET_ADDR); \ atomic_store_##name(ptr, val); \ } #define CSAN_ATOMIC_FUNC_STORE(name, type) \ _CSAN_ATOMIC_FUNC_STORE(name, type) \ _CSAN_ATOMIC_FUNC_STORE(rel_##name, type) #define CSAN_ATOMIC_FUNC_SWAP(name, type) \ type kcsan_atomic_swap_##name(volatile type *ptr, type val) \ { \ kcsan_access((uintptr_t)ptr, sizeof(type), true, true, \ __RET_ADDR); \ return(atomic_swap_##name(ptr, val)); \ } #define CSAN_ATOMIC_FUNC_TESTANDCLEAR(name, type) \ int kcsan_atomic_testandclear_##name(volatile type *ptr, u_int val) \ { \ kcsan_access((uintptr_t)ptr, sizeof(type), true, true, \ __RET_ADDR); \ return(atomic_testandclear_##name(ptr, val)); \ } #define CSAN_ATOMIC_FUNC_TESTANDSET(name, type) \ int kcsan_atomic_testandset_##name(volatile type *ptr, u_int val) \ { \ kcsan_access((uintptr_t)ptr, sizeof(type), true, true, \ __RET_ADDR); \ return (atomic_testandset_##name(ptr, val)); \ } _CSAN_ATOMIC_FUNC_LOAD(bool, bool) _CSAN_ATOMIC_FUNC_STORE(bool, bool) CSAN_ATOMIC_FUNC_ADD(8, uint8_t) CSAN_ATOMIC_FUNC_CLEAR(8, uint8_t) CSAN_ATOMIC_FUNC_CMPSET(8, uint8_t) CSAN_ATOMIC_FUNC_FCMPSET(8, uint8_t) CSAN_ATOMIC_FUNC_LOAD(8, uint8_t) CSAN_ATOMIC_FUNC_SET(8, uint8_t) CSAN_ATOMIC_FUNC_SUBTRACT(8, uint8_t) _CSAN_ATOMIC_FUNC_STORE(8, uint8_t) #if 0 CSAN_ATOMIC_FUNC_FETCHADD(8, uint8_t) CSAN_ATOMIC_FUNC_READANDCLEAR(8, uint8_t) CSAN_ATOMIC_FUNC_SWAP(8, uint8_t) CSAN_ATOMIC_FUNC_TESTANDCLEAR(8, uint8_t) CSAN_ATOMIC_FUNC_TESTANDSET(8, uint8_t) #endif CSAN_ATOMIC_FUNC_ADD(16, uint16_t) CSAN_ATOMIC_FUNC_CLEAR(16, uint16_t) CSAN_ATOMIC_FUNC_CMPSET(16, uint16_t) CSAN_ATOMIC_FUNC_FCMPSET(16, uint16_t) CSAN_ATOMIC_FUNC_LOAD(16, uint16_t) CSAN_ATOMIC_FUNC_SET(16, uint16_t) CSAN_ATOMIC_FUNC_SUBTRACT(16, uint16_t) _CSAN_ATOMIC_FUNC_STORE(16, uint16_t) #if 0 CSAN_ATOMIC_FUNC_FETCHADD(16, uint16_t) CSAN_ATOMIC_FUNC_READANDCLEAR(16, uint16_t) CSAN_ATOMIC_FUNC_SWAP(16, uint16_t) CSAN_ATOMIC_FUNC_TESTANDCLEAR(16, uint16_t) CSAN_ATOMIC_FUNC_TESTANDSET(16, uint16_t) #endif CSAN_ATOMIC_FUNC_ADD(32, uint32_t) CSAN_ATOMIC_FUNC_CLEAR(32, uint32_t) CSAN_ATOMIC_FUNC_CMPSET(32, uint32_t) CSAN_ATOMIC_FUNC_FCMPSET(32, uint32_t) CSAN_ATOMIC_FUNC_FETCHADD(32, uint32_t) CSAN_ATOMIC_FUNC_LOAD(32, uint32_t) CSAN_ATOMIC_FUNC_READANDCLEAR(32, uint32_t) CSAN_ATOMIC_FUNC_SET(32, uint32_t) CSAN_ATOMIC_FUNC_SUBTRACT(32, uint32_t) CSAN_ATOMIC_FUNC_STORE(32, uint32_t) CSAN_ATOMIC_FUNC_SWAP(32, uint32_t) CSAN_ATOMIC_FUNC_TESTANDCLEAR(32, uint32_t) CSAN_ATOMIC_FUNC_TESTANDSET(32, uint32_t) CSAN_ATOMIC_FUNC_ADD(64, uint64_t) CSAN_ATOMIC_FUNC_CLEAR(64, uint64_t) CSAN_ATOMIC_FUNC_CMPSET(64, uint64_t) CSAN_ATOMIC_FUNC_FCMPSET(64, uint64_t) CSAN_ATOMIC_FUNC_FETCHADD(64, uint64_t) CSAN_ATOMIC_FUNC_LOAD(64, uint64_t) CSAN_ATOMIC_FUNC_READANDCLEAR(64, uint64_t) CSAN_ATOMIC_FUNC_SET(64, uint64_t) CSAN_ATOMIC_FUNC_SUBTRACT(64, uint64_t) CSAN_ATOMIC_FUNC_STORE(64, uint64_t) CSAN_ATOMIC_FUNC_SWAP(64, uint64_t) CSAN_ATOMIC_FUNC_TESTANDCLEAR(64, uint64_t) CSAN_ATOMIC_FUNC_TESTANDSET(64, uint64_t) CSAN_ATOMIC_FUNC_ADD(char, uint8_t) CSAN_ATOMIC_FUNC_CLEAR(char, uint8_t) CSAN_ATOMIC_FUNC_CMPSET(char, uint8_t) CSAN_ATOMIC_FUNC_FCMPSET(char, uint8_t) CSAN_ATOMIC_FUNC_LOAD(char, uint8_t) CSAN_ATOMIC_FUNC_SET(char, uint8_t) CSAN_ATOMIC_FUNC_SUBTRACT(char, uint8_t) _CSAN_ATOMIC_FUNC_STORE(char, uint8_t) #if 0 CSAN_ATOMIC_FUNC_FETCHADD(char, uint8_t) CSAN_ATOMIC_FUNC_READANDCLEAR(char, uint8_t) CSAN_ATOMIC_FUNC_SWAP(char, uint8_t) CSAN_ATOMIC_FUNC_TESTANDCLEAR(char, uint8_t) CSAN_ATOMIC_FUNC_TESTANDSET(char, uint8_t) #endif CSAN_ATOMIC_FUNC_ADD(short, uint16_t) CSAN_ATOMIC_FUNC_CLEAR(short, uint16_t) CSAN_ATOMIC_FUNC_CMPSET(short, uint16_t) CSAN_ATOMIC_FUNC_FCMPSET(short, uint16_t) CSAN_ATOMIC_FUNC_LOAD(short, uint16_t) CSAN_ATOMIC_FUNC_SET(short, uint16_t) CSAN_ATOMIC_FUNC_SUBTRACT(short, uint16_t) _CSAN_ATOMIC_FUNC_STORE(short, uint16_t) #if 0 CSAN_ATOMIC_FUNC_FETCHADD(short, uint16_t) CSAN_ATOMIC_FUNC_READANDCLEAR(short, uint16_t) CSAN_ATOMIC_FUNC_SWAP(short, uint16_t) CSAN_ATOMIC_FUNC_TESTANDCLEAR(short, uint16_t) CSAN_ATOMIC_FUNC_TESTANDSET(short, uint16_t) #endif CSAN_ATOMIC_FUNC_ADD(int, u_int) CSAN_ATOMIC_FUNC_CLEAR(int, u_int) CSAN_ATOMIC_FUNC_CMPSET(int, u_int) CSAN_ATOMIC_FUNC_FCMPSET(int, u_int) CSAN_ATOMIC_FUNC_FETCHADD(int, u_int) CSAN_ATOMIC_FUNC_LOAD(int, u_int) CSAN_ATOMIC_FUNC_READANDCLEAR(int, u_int) CSAN_ATOMIC_FUNC_SET(int, u_int) CSAN_ATOMIC_FUNC_SUBTRACT(int, u_int) CSAN_ATOMIC_FUNC_STORE(int, u_int) CSAN_ATOMIC_FUNC_SWAP(int, u_int) CSAN_ATOMIC_FUNC_TESTANDCLEAR(int, u_int) CSAN_ATOMIC_FUNC_TESTANDSET(int, u_int) CSAN_ATOMIC_FUNC_ADD(long, u_long) CSAN_ATOMIC_FUNC_CLEAR(long, u_long) CSAN_ATOMIC_FUNC_CMPSET(long, u_long) CSAN_ATOMIC_FUNC_FCMPSET(long, u_long) CSAN_ATOMIC_FUNC_FETCHADD(long, u_long) CSAN_ATOMIC_FUNC_LOAD(long, u_long) CSAN_ATOMIC_FUNC_READANDCLEAR(long, u_long) CSAN_ATOMIC_FUNC_SET(long, u_long) CSAN_ATOMIC_FUNC_SUBTRACT(long, u_long) CSAN_ATOMIC_FUNC_STORE(long, u_long) CSAN_ATOMIC_FUNC_SWAP(long, u_long) CSAN_ATOMIC_FUNC_TESTANDCLEAR(long, u_long) CSAN_ATOMIC_FUNC_TESTANDSET(long, u_long) CSAN_ATOMIC_FUNC_TESTANDSET(acq_long, u_long) CSAN_ATOMIC_FUNC_ADD(ptr, uintptr_t) CSAN_ATOMIC_FUNC_CLEAR(ptr, uintptr_t) CSAN_ATOMIC_FUNC_CMPSET(ptr, uintptr_t) CSAN_ATOMIC_FUNC_FCMPSET(ptr, uintptr_t) #if !defined(__amd64__) CSAN_ATOMIC_FUNC_FETCHADD(ptr, uintptr_t) #endif CSAN_ATOMIC_FUNC_LOAD(ptr, uintptr_t) CSAN_ATOMIC_FUNC_READANDCLEAR(ptr, uintptr_t) CSAN_ATOMIC_FUNC_SET(ptr, uintptr_t) CSAN_ATOMIC_FUNC_SUBTRACT(ptr, uintptr_t) CSAN_ATOMIC_FUNC_STORE(ptr, uintptr_t) CSAN_ATOMIC_FUNC_SWAP(ptr, uintptr_t) CSAN_ATOMIC_FUNC_TESTANDCLEAR(ptr, uintptr_t) CSAN_ATOMIC_FUNC_TESTANDSET(ptr, uintptr_t) #define CSAN_ATOMIC_FUNC_THREAD_FENCE(name) \ void kcsan_atomic_thread_fence_##name(void) \ { \ atomic_thread_fence_##name(); \ } CSAN_ATOMIC_FUNC_THREAD_FENCE(acq) CSAN_ATOMIC_FUNC_THREAD_FENCE(acq_rel) CSAN_ATOMIC_FUNC_THREAD_FENCE(rel) CSAN_ATOMIC_FUNC_THREAD_FENCE(seq_cst) void kcsan_atomic_interrupt_fence(void) { atomic_interrupt_fence(); } /* -------------------------------------------------------------------------- */ #include #include #include int kcsan_bus_space_map(bus_space_tag_t tag, bus_addr_t hnd, bus_size_t size, int flags, bus_space_handle_t *handlep) { return (bus_space_map(tag, hnd, size, flags, handlep)); } void kcsan_bus_space_unmap(bus_space_tag_t tag, bus_space_handle_t hnd, bus_size_t size) { bus_space_unmap(tag, hnd, size); } int kcsan_bus_space_subregion(bus_space_tag_t tag, bus_space_handle_t hnd, bus_size_t offset, bus_size_t size, bus_space_handle_t *handlep) { return (bus_space_subregion(tag, hnd, offset, size, handlep)); } #if !defined(__amd64__) int kcsan_bus_space_alloc(bus_space_tag_t tag, bus_addr_t reg_start, bus_addr_t reg_end, bus_size_t size, bus_size_t alignment, bus_size_t boundary, int flags, bus_addr_t *addrp, bus_space_handle_t *handlep) { return (bus_space_alloc(tag, reg_start, reg_end, size, alignment, boundary, flags, addrp, handlep)); } #endif void kcsan_bus_space_free(bus_space_tag_t tag, bus_space_handle_t hnd, bus_size_t size) { bus_space_free(tag, hnd, size); } void kcsan_bus_space_barrier(bus_space_tag_t tag, bus_space_handle_t hnd, bus_size_t offset, bus_size_t size, int flags) { bus_space_barrier(tag, hnd, offset, size, flags); } #define CSAN_BUS_READ_FUNC(func, width, type) \ type kcsan_bus_space_read##func##_##width(bus_space_tag_t tag, \ bus_space_handle_t hnd, bus_size_t offset) \ { \ return (bus_space_read##func##_##width(tag, hnd, \ offset)); \ } \ #define CSAN_BUS_READ_PTR_FUNC(func, width, type) \ void kcsan_bus_space_read_##func##_##width(bus_space_tag_t tag, \ bus_space_handle_t hnd, bus_size_t size, type *buf, \ bus_size_t count) \ { \ kcsan_access((uintptr_t)buf, sizeof(type) * count, \ false, false, __RET_ADDR); \ bus_space_read_##func##_##width(tag, hnd, size, buf, \ count); \ } CSAN_BUS_READ_FUNC(, 1, uint8_t) CSAN_BUS_READ_FUNC(_stream, 1, uint8_t) CSAN_BUS_READ_PTR_FUNC(multi, 1, uint8_t) CSAN_BUS_READ_PTR_FUNC(multi_stream, 1, uint8_t) CSAN_BUS_READ_PTR_FUNC(region, 1, uint8_t) CSAN_BUS_READ_PTR_FUNC(region_stream, 1, uint8_t) CSAN_BUS_READ_FUNC(, 2, uint16_t) CSAN_BUS_READ_FUNC(_stream, 2, uint16_t) CSAN_BUS_READ_PTR_FUNC(multi, 2, uint16_t) CSAN_BUS_READ_PTR_FUNC(multi_stream, 2, uint16_t) CSAN_BUS_READ_PTR_FUNC(region, 2, uint16_t) CSAN_BUS_READ_PTR_FUNC(region_stream, 2, uint16_t) CSAN_BUS_READ_FUNC(, 4, uint32_t) CSAN_BUS_READ_FUNC(_stream, 4, uint32_t) CSAN_BUS_READ_PTR_FUNC(multi, 4, uint32_t) CSAN_BUS_READ_PTR_FUNC(multi_stream, 4, uint32_t) CSAN_BUS_READ_PTR_FUNC(region, 4, uint32_t) CSAN_BUS_READ_PTR_FUNC(region_stream, 4, uint32_t) CSAN_BUS_READ_FUNC(, 8, uint64_t) #if defined(__aarch64__) CSAN_BUS_READ_FUNC(_stream, 8, uint64_t) CSAN_BUS_READ_PTR_FUNC(multi, 8, uint64_t) CSAN_BUS_READ_PTR_FUNC(multi_stream, 8, uint64_t) CSAN_BUS_READ_PTR_FUNC(region, 8, uint64_t) CSAN_BUS_READ_PTR_FUNC(region_stream, 8, uint64_t) #endif #define CSAN_BUS_WRITE_FUNC(func, width, type) \ void kcsan_bus_space_write##func##_##width(bus_space_tag_t tag, \ bus_space_handle_t hnd, bus_size_t offset, type value) \ { \ bus_space_write##func##_##width(tag, hnd, offset, value); \ } \ #define CSAN_BUS_WRITE_PTR_FUNC(func, width, type) \ void kcsan_bus_space_write_##func##_##width(bus_space_tag_t tag, \ bus_space_handle_t hnd, bus_size_t size, const type *buf, \ bus_size_t count) \ { \ kcsan_access((uintptr_t)buf, sizeof(type) * count, \ true, false, __RET_ADDR); \ bus_space_write_##func##_##width(tag, hnd, size, buf, \ count); \ } CSAN_BUS_WRITE_FUNC(, 1, uint8_t) CSAN_BUS_WRITE_FUNC(_stream, 1, uint8_t) CSAN_BUS_WRITE_PTR_FUNC(multi, 1, uint8_t) CSAN_BUS_WRITE_PTR_FUNC(multi_stream, 1, uint8_t) CSAN_BUS_WRITE_PTR_FUNC(region, 1, uint8_t) CSAN_BUS_WRITE_PTR_FUNC(region_stream, 1, uint8_t) CSAN_BUS_WRITE_FUNC(, 2, uint16_t) CSAN_BUS_WRITE_FUNC(_stream, 2, uint16_t) CSAN_BUS_WRITE_PTR_FUNC(multi, 2, uint16_t) CSAN_BUS_WRITE_PTR_FUNC(multi_stream, 2, uint16_t) CSAN_BUS_WRITE_PTR_FUNC(region, 2, uint16_t) CSAN_BUS_WRITE_PTR_FUNC(region_stream, 2, uint16_t) CSAN_BUS_WRITE_FUNC(, 4, uint32_t) CSAN_BUS_WRITE_FUNC(_stream, 4, uint32_t) CSAN_BUS_WRITE_PTR_FUNC(multi, 4, uint32_t) CSAN_BUS_WRITE_PTR_FUNC(multi_stream, 4, uint32_t) CSAN_BUS_WRITE_PTR_FUNC(region, 4, uint32_t) CSAN_BUS_WRITE_PTR_FUNC(region_stream, 4, uint32_t) CSAN_BUS_WRITE_FUNC(, 8, uint64_t) #if defined(__aarch64__) CSAN_BUS_WRITE_FUNC(_stream, 8, uint64_t) CSAN_BUS_WRITE_PTR_FUNC(multi, 8, uint64_t) CSAN_BUS_WRITE_PTR_FUNC(multi_stream, 8, uint64_t) CSAN_BUS_WRITE_PTR_FUNC(region, 8, uint64_t) CSAN_BUS_WRITE_PTR_FUNC(region_stream, 8, uint64_t) #endif #define CSAN_BUS_SET_FUNC(func, width, type) \ void kcsan_bus_space_set_##func##_##width(bus_space_tag_t tag, \ bus_space_handle_t hnd, bus_size_t offset, type value, \ bus_size_t count) \ { \ bus_space_set_##func##_##width(tag, hnd, offset, value, \ count); \ } CSAN_BUS_SET_FUNC(multi, 1, uint8_t) CSAN_BUS_SET_FUNC(region, 1, uint8_t) #if !defined(__aarch64__) CSAN_BUS_SET_FUNC(multi_stream, 1, uint8_t) CSAN_BUS_SET_FUNC(region_stream, 1, uint8_t) #endif CSAN_BUS_SET_FUNC(multi, 2, uint16_t) CSAN_BUS_SET_FUNC(region, 2, uint16_t) #if !defined(__aarch64__) CSAN_BUS_SET_FUNC(multi_stream, 2, uint16_t) CSAN_BUS_SET_FUNC(region_stream, 2, uint16_t) #endif CSAN_BUS_SET_FUNC(multi, 4, uint32_t) CSAN_BUS_SET_FUNC(region, 4, uint32_t) #if !defined(__aarch64__) CSAN_BUS_SET_FUNC(multi_stream, 4, uint32_t) CSAN_BUS_SET_FUNC(region_stream, 4, uint32_t) #endif #if !defined(__amd64__) CSAN_BUS_SET_FUNC(multi, 8, uint64_t) CSAN_BUS_SET_FUNC(region, 8, uint64_t) #if !defined(__aarch64__) CSAN_BUS_SET_FUNC(multi_stream, 8, uint64_t) CSAN_BUS_SET_FUNC(region_stream, 8, uint64_t) #endif #endif #define CSAN_BUS_PEEK_FUNC(width, type) \ int kcsan_bus_space_peek_##width(bus_space_tag_t tag, \ bus_space_handle_t hnd, bus_size_t offset, type *value) \ { \ kcsan_access((uintptr_t)value, sizeof(type), true, false, \ __RET_ADDR); \ return (bus_space_peek_##width(tag, hnd, offset, value)); \ } CSAN_BUS_PEEK_FUNC(1, uint8_t) CSAN_BUS_PEEK_FUNC(2, uint16_t) CSAN_BUS_PEEK_FUNC(4, uint32_t) #if !defined(__i386__) CSAN_BUS_PEEK_FUNC(8, uint64_t) #endif #define CSAN_BUS_POKE_FUNC(width, type) \ int kcsan_bus_space_poke_##width(bus_space_tag_t tag, \ bus_space_handle_t hnd, bus_size_t offset, type value) \ { \ return (bus_space_poke_##width(tag, hnd, offset, value)); \ } CSAN_BUS_POKE_FUNC(1, uint8_t) CSAN_BUS_POKE_FUNC(2, uint16_t) CSAN_BUS_POKE_FUNC(4, uint32_t) #if !defined(__i386__) CSAN_BUS_POKE_FUNC(8, uint64_t) #endif diff --git a/sys/kern/subr_msan.c b/sys/kern/subr_msan.c index 1c18a4a4f8e5..0c4e589ec1e6 100644 --- a/sys/kern/subr_msan.c +++ b/sys/kern/subr_msan.c @@ -1,1593 +1,1593 @@ /* $NetBSD: subr_msan.c,v 1.14 2020/09/09 16:29:59 maxv Exp $ */ /* * Copyright (c) 2019-2020 Maxime Villard, m00nbsd.net * All rights reserved. * Copyright (c) 2021 The FreeBSD Foundation * * Portions of this software were developed by Mark Johnston under sponsorship * from the FreeBSD Foundation. * * This code is part of the KMSAN subsystem of the NetBSD kernel. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #define SAN_RUNTIME #include #if 0 __KERNEL_RCSID(0, "$NetBSD: subr_msan.c,v 1.14 2020/09/09 16:29:59 maxv Exp $"); #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include void kmsan_init_arg(size_t); void kmsan_init_ret(size_t); /* -------------------------------------------------------------------------- */ /* * Part of the compiler ABI. */ typedef struct { uint8_t *shad; msan_orig_t *orig; } msan_meta_t; #define MSAN_PARAM_SIZE 800 #define MSAN_RETVAL_SIZE 800 typedef struct { uint8_t param_shadow[MSAN_PARAM_SIZE]; uint8_t retval_shadow[MSAN_RETVAL_SIZE]; uint8_t va_arg_shadow[MSAN_PARAM_SIZE]; uint8_t va_arg_origin[MSAN_PARAM_SIZE]; uint64_t va_arg_overflow_size; msan_orig_t param_origin[MSAN_PARAM_SIZE / sizeof(msan_orig_t)]; msan_orig_t retval_origin; } msan_tls_t; /* -------------------------------------------------------------------------- */ #define MSAN_NCONTEXT 4 #define MSAN_ORIG_MASK (~0x3) typedef struct kmsan_td { size_t ctx; msan_tls_t tls[MSAN_NCONTEXT]; } msan_td_t; static msan_tls_t dummy_tls; /* * Use separate dummy regions for loads and stores: stores may mark the region * as uninitialized, and that can trigger false positives. */ static uint8_t msan_dummy_shad[PAGE_SIZE] __aligned(PAGE_SIZE); static uint8_t msan_dummy_write_shad[PAGE_SIZE] __aligned(PAGE_SIZE); static uint8_t msan_dummy_orig[PAGE_SIZE] __aligned(PAGE_SIZE); static msan_td_t msan_thread0; static bool kmsan_reporting = false; /* * Avoid clobbering any thread-local state before we panic. */ #define kmsan_panic(f, ...) do { \ kmsan_disabled = true; \ panic(f, __VA_ARGS__); \ } while (0) #define REPORT(f, ...) do { \ if (panic_on_violation) { \ kmsan_panic(f, __VA_ARGS__); \ } else { \ struct stack st; \ \ stack_save(&st); \ printf(f "\n", __VA_ARGS__); \ stack_print_ddb(&st); \ } \ } while (0) FEATURE(kmsan, "Kernel memory sanitizer"); static SYSCTL_NODE(_debug, OID_AUTO, kmsan, CTLFLAG_RD | CTLFLAG_MPSAFE, 0, "KMSAN options"); static bool panic_on_violation = 1; SYSCTL_BOOL(_debug_kmsan, OID_AUTO, panic_on_violation, CTLFLAG_RWTUN, &panic_on_violation, 0, "Panic if an invalid access is detected"); static bool kmsan_disabled __read_mostly = true; #define kmsan_enabled (!kmsan_disabled) SYSCTL_BOOL(_debug_kmsan, OID_AUTO, disabled, CTLFLAG_RDTUN | CTLFLAG_NOFETCH, &kmsan_disabled, 0, "KMSAN is disabled"); static MALLOC_DEFINE(M_KMSAN, "kmsan", "Kernel memory sanitizer"); /* -------------------------------------------------------------------------- */ static inline const char * kmsan_orig_name(int type) { switch (type) { case KMSAN_TYPE_STACK: return ("stack"); case KMSAN_TYPE_KMEM: return ("kmem"); case KMSAN_TYPE_MALLOC: return ("malloc"); case KMSAN_TYPE_UMA: return ("UMA"); default: return ("unknown"); } } static void kmsan_report_hook(const void *addr, msan_orig_t *orig, size_t size, size_t off, const char *hook) { const char *typename; char *var, *fn; uintptr_t ptr; long foff; char buf[128]; int type; if (__predict_false(KERNEL_PANICKED() || kdb_active || kmsan_reporting)) return; if (__predict_false(curthread != NULL && (curthread->td_pflags2 & TDP2_SAN_QUIET) != 0)) return; kmsan_reporting = true; __compiler_membar(); if (*orig == 0) { REPORT("MSan: Uninitialized memory in %s, offset %zu", hook, off); goto out; } kmsan_md_orig_decode(*orig, &type, &ptr); typename = kmsan_orig_name(type); if (linker_ddb_search_symbol_name((caddr_t)ptr, buf, sizeof(buf), &foff) == 0) { REPORT("MSan: Uninitialized %s memory in %s, " "offset %zu/%zu, addr %p, from %s+%#lx", typename, hook, off, size, addr, buf, foff); } else if (__builtin_memcmp((void *)ptr, "----", 4) == 0) { /* * The format of the string is: "----var@function". Parse it to * display a nice warning. */ var = (char *)ptr + 4; strlcpy(buf, var, sizeof(buf)); var = buf; fn = strchr(buf, '@'); *fn++ = '\0'; REPORT("MSan: Uninitialized %s memory in %s, offset %zu, " "variable '%s' from %s", typename, hook, off, var, fn); } else { REPORT("MSan: Uninitialized %s memory in %s, " "offset %zu/%zu, addr %p, PC %p", typename, hook, off, size, addr, (void *)ptr); } out: __compiler_membar(); kmsan_reporting = false; } static void kmsan_report_inline(msan_orig_t orig, unsigned long pc) { const char *typename; char *var, *fn; uintptr_t ptr; char buf[128]; long foff; int type; if (__predict_false(KERNEL_PANICKED() || kdb_active || kmsan_reporting)) return; if (__predict_false(curthread != NULL && (curthread->td_pflags2 & TDP2_SAN_QUIET) != 0)) return; kmsan_reporting = true; __compiler_membar(); if (orig == 0) { REPORT("MSan: uninitialized variable in %p", (void *)pc); goto out; } kmsan_md_orig_decode(orig, &type, &ptr); typename = kmsan_orig_name(type); if (linker_ddb_search_symbol_name((caddr_t)ptr, buf, sizeof(buf), &foff) == 0) { REPORT("MSan: Uninitialized %s memory from %s+%#lx", typename, buf, foff); } else if (__builtin_memcmp((void *)ptr, "----", 4) == 0) { /* * The format of the string is: "----var@function". Parse it to * display a nice warning. */ var = (char *)ptr + 4; strlcpy(buf, var, sizeof(buf)); var = buf; fn = strchr(buf, '@'); *fn++ = '\0'; REPORT("MSan: Uninitialized variable '%s' from %s", var, fn); } else { REPORT("MSan: Uninitialized %s memory, origin %x", typename, orig); } out: __compiler_membar(); kmsan_reporting = false; } /* -------------------------------------------------------------------------- */ static inline msan_meta_t kmsan_meta_get(const void *addr, size_t size, const bool write) { msan_meta_t ret; if (__predict_false(!kmsan_enabled)) { ret.shad = write ? msan_dummy_write_shad : msan_dummy_shad; ret.orig = (msan_orig_t *)msan_dummy_orig; } else if (__predict_false(kmsan_md_unsupported((vm_offset_t)addr))) { ret.shad = write ? msan_dummy_write_shad : msan_dummy_shad; ret.orig = (msan_orig_t *)msan_dummy_orig; } else { ret.shad = (void *)kmsan_md_addr_to_shad((vm_offset_t)addr); ret.orig = (msan_orig_t *)kmsan_md_addr_to_orig((vm_offset_t)addr); ret.orig = (msan_orig_t *)((uintptr_t)ret.orig & MSAN_ORIG_MASK); } return (ret); } static inline void kmsan_origin_fill(const void *addr, msan_orig_t o, size_t size) { msan_orig_t *orig; size_t i; if (__predict_false(!kmsan_enabled)) return; if (__predict_false(kmsan_md_unsupported((vm_offset_t)addr))) return; orig = (msan_orig_t *)kmsan_md_addr_to_orig((vm_offset_t)addr); size += ((uintptr_t)orig & (sizeof(*orig) - 1)); orig = (msan_orig_t *)((uintptr_t)orig & MSAN_ORIG_MASK); for (i = 0; i < size; i += 4) { orig[i / 4] = o; } } static inline void kmsan_shadow_fill(uintptr_t addr, uint8_t c, size_t size) { uint8_t *shad; if (__predict_false(!kmsan_enabled)) return; if (__predict_false(kmsan_md_unsupported(addr))) return; shad = (uint8_t *)kmsan_md_addr_to_shad(addr); __builtin_memset(shad, c, size); } static inline void kmsan_meta_copy(void *dst, const void *src, size_t size) { uint8_t *orig_src, *orig_dst; uint8_t *shad_src, *shad_dst; msan_orig_t *_src, *_dst; size_t i; if (__predict_false(!kmsan_enabled)) return; if (__predict_false(kmsan_md_unsupported((vm_offset_t)dst))) return; if (__predict_false(kmsan_md_unsupported((vm_offset_t)src))) { kmsan_shadow_fill((uintptr_t)dst, KMSAN_STATE_INITED, size); return; } shad_src = (uint8_t *)kmsan_md_addr_to_shad((vm_offset_t)src); shad_dst = (uint8_t *)kmsan_md_addr_to_shad((vm_offset_t)dst); __builtin_memmove(shad_dst, shad_src, size); orig_src = (uint8_t *)kmsan_md_addr_to_orig((vm_offset_t)src); orig_dst = (uint8_t *)kmsan_md_addr_to_orig((vm_offset_t)dst); for (i = 0; i < size; i++) { _src = (msan_orig_t *)((uintptr_t)orig_src & MSAN_ORIG_MASK); _dst = (msan_orig_t *)((uintptr_t)orig_dst & MSAN_ORIG_MASK); *_dst = *_src; orig_src++; orig_dst++; } } static inline void kmsan_shadow_check(uintptr_t addr, size_t size, const char *hook) { msan_orig_t *orig; uint8_t *shad; size_t i; if (__predict_false(!kmsan_enabled)) return; if (__predict_false(kmsan_md_unsupported(addr))) return; shad = (uint8_t *)kmsan_md_addr_to_shad(addr); for (i = 0; i < size; i++) { if (__predict_true(shad[i] == 0)) continue; orig = (msan_orig_t *)kmsan_md_addr_to_orig(addr + i); orig = (msan_orig_t *)((uintptr_t)orig & MSAN_ORIG_MASK); kmsan_report_hook((const char *)addr + i, orig, size, i, hook); break; } } void kmsan_init_arg(size_t n) { msan_td_t *mtd; uint8_t *arg; if (__predict_false(!kmsan_enabled)) return; if (__predict_false(curthread == NULL)) return; mtd = curthread->td_kmsan; arg = mtd->tls[mtd->ctx].param_shadow; __builtin_memset(arg, 0, n); } void kmsan_init_ret(size_t n) { msan_td_t *mtd; uint8_t *arg; if (__predict_false(!kmsan_enabled)) return; if (__predict_false(curthread == NULL)) return; mtd = curthread->td_kmsan; arg = mtd->tls[mtd->ctx].retval_shadow; __builtin_memset(arg, 0, n); } static void kmsan_check_arg(size_t size, const char *hook) { msan_orig_t *orig; msan_td_t *mtd; uint8_t *arg; size_t ctx, i; if (__predict_false(!kmsan_enabled)) return; if (__predict_false(curthread == NULL)) return; mtd = curthread->td_kmsan; ctx = mtd->ctx; arg = mtd->tls[ctx].param_shadow; for (i = 0; i < size; i++) { if (__predict_true(arg[i] == 0)) continue; orig = &mtd->tls[ctx].param_origin[i / sizeof(msan_orig_t)]; kmsan_report_hook((const char *)arg + i, orig, size, i, hook); break; } } void kmsan_thread_alloc(struct thread *td) { msan_td_t *mtd; if (!kmsan_enabled) return; mtd = td->td_kmsan; if (mtd == NULL) { /* We might be recycling a thread. */ kmsan_init_arg(sizeof(size_t) + sizeof(struct malloc_type *) + sizeof(int)); mtd = malloc(sizeof(*mtd), M_KMSAN, M_WAITOK); } __builtin_memset(mtd, 0, sizeof(*mtd)); mtd->ctx = 0; if (td->td_kstack != 0) kmsan_mark((void *)td->td_kstack, ptoa(td->td_kstack_pages), KMSAN_STATE_UNINIT); td->td_kmsan = mtd; } void kmsan_thread_free(struct thread *td) { msan_td_t *mtd; if (!kmsan_enabled) return; if (__predict_false(td == curthread)) kmsan_panic("%s: freeing KMSAN TLS for curthread", __func__); mtd = td->td_kmsan; kmsan_init_arg(sizeof(void *) + sizeof(struct malloc_type *)); free(mtd, M_KMSAN); td->td_kmsan = NULL; } void kmsan_intr_enter(void); void kmsan_intr_leave(void); void kmsan_intr_enter(void) { msan_td_t *mtd; if (__predict_false(!kmsan_enabled)) return; mtd = curthread->td_kmsan; mtd->ctx++; if (__predict_false(mtd->ctx >= MSAN_NCONTEXT)) kmsan_panic("%s: mtd->ctx = %zu", __func__, mtd->ctx); } void kmsan_intr_leave(void) { msan_td_t *mtd; if (__predict_false(!kmsan_enabled)) return; mtd = curthread->td_kmsan; if (__predict_false(mtd->ctx == 0)) kmsan_panic("%s: mtd->ctx = %zu", __func__, mtd->ctx); mtd->ctx--; } /* -------------------------------------------------------------------------- */ void kmsan_shadow_map(vm_offset_t addr, size_t size) { size_t npages, i; vm_offset_t va; MPASS(addr % PAGE_SIZE == 0); MPASS(size % PAGE_SIZE == 0); if (!kmsan_enabled) return; npages = atop(size); va = kmsan_md_addr_to_shad(addr); for (i = 0; i < npages; i++) { pmap_san_enter(va + ptoa(i)); } va = kmsan_md_addr_to_orig(addr); for (i = 0; i < npages; i++) { pmap_san_enter(va + ptoa(i)); } } void kmsan_orig(const void *addr, size_t size, int type, uintptr_t pc) { msan_orig_t orig; orig = kmsan_md_orig_encode(type, pc); kmsan_origin_fill(addr, orig, size); } void kmsan_mark(const void *addr, size_t size, uint8_t c) { kmsan_shadow_fill((uintptr_t)addr, c, size); } void kmsan_mark_bio(const struct bio *bp, uint8_t c) { kmsan_mark(bp->bio_data, bp->bio_length, c); } void kmsan_mark_mbuf(const struct mbuf *m, uint8_t c) { do { if ((m->m_flags & M_EXTPG) == 0) kmsan_mark(m->m_data, m->m_len, c); m = m->m_next; } while (m != NULL); } void kmsan_check(const void *p, size_t sz, const char *descr) { kmsan_shadow_check((uintptr_t)p, sz, descr); } void kmsan_check_bio(const struct bio *bp, const char *descr) { kmsan_shadow_check((uintptr_t)bp->bio_data, bp->bio_length, descr); } void kmsan_check_mbuf(const struct mbuf *m, const char *descr) { do { kmsan_shadow_check((uintptr_t)mtod(m, void *), m->m_len, descr); } while ((m = m->m_next) != NULL); } void kmsan_check_uio(const struct uio *uio, const char *descr) { for (int i = 0; i < uio->uio_iovcnt; i++) { kmsan_check(uio->uio_iov[i].iov_base, uio->uio_iov[i].iov_len, descr); } } void kmsan_init(void) { int disabled; disabled = 0; TUNABLE_INT_FETCH("debug.kmsan.disabled", &disabled); if (disabled) return; /* Initialize the TLS for curthread. */ msan_thread0.ctx = 0; thread0.td_kmsan = &msan_thread0; /* Now officially enabled. */ kmsan_disabled = false; } /* -------------------------------------------------------------------------- */ msan_meta_t __msan_metadata_ptr_for_load_n(void *, size_t); msan_meta_t __msan_metadata_ptr_for_store_n(void *, size_t); msan_meta_t __msan_metadata_ptr_for_load_n(void *addr, size_t size) { return (kmsan_meta_get(addr, size, false)); } msan_meta_t __msan_metadata_ptr_for_store_n(void *addr, size_t size) { return (kmsan_meta_get(addr, size, true)); } #define MSAN_META_FUNC(size) \ msan_meta_t __msan_metadata_ptr_for_load_##size(void *); \ msan_meta_t __msan_metadata_ptr_for_load_##size(void *addr) \ { \ return (kmsan_meta_get(addr, size, false)); \ } \ msan_meta_t __msan_metadata_ptr_for_store_##size(void *); \ msan_meta_t __msan_metadata_ptr_for_store_##size(void *addr) \ { \ return (kmsan_meta_get(addr, size, true)); \ } MSAN_META_FUNC(1) MSAN_META_FUNC(2) MSAN_META_FUNC(4) MSAN_META_FUNC(8) void __msan_instrument_asm_store(const void *, size_t); msan_orig_t __msan_chain_origin(msan_orig_t); void __msan_poison(const void *, size_t); void __msan_unpoison(const void *, size_t); void __msan_poison_alloca(const void *, uint64_t, const char *); void __msan_unpoison_alloca(const void *, uint64_t); void __msan_warning(msan_orig_t); msan_tls_t *__msan_get_context_state(void); void __msan_instrument_asm_store(const void *addr, size_t size) { kmsan_shadow_fill((uintptr_t)addr, KMSAN_STATE_INITED, size); } msan_orig_t __msan_chain_origin(msan_orig_t origin) { return (origin); } void __msan_poison(const void *addr, size_t size) { kmsan_shadow_fill((uintptr_t)addr, KMSAN_STATE_UNINIT, size); } void __msan_unpoison(const void *addr, size_t size) { kmsan_shadow_fill((uintptr_t)addr, KMSAN_STATE_INITED, size); } void __msan_poison_alloca(const void *addr, uint64_t size, const char *descr) { msan_orig_t orig; orig = kmsan_md_orig_encode(KMSAN_TYPE_STACK, (uintptr_t)descr); kmsan_origin_fill(addr, orig, size); kmsan_shadow_fill((uintptr_t)addr, KMSAN_STATE_UNINIT, size); } void __msan_unpoison_alloca(const void *addr, uint64_t size) { kmsan_shadow_fill((uintptr_t)addr, KMSAN_STATE_INITED, size); } void __msan_warning(msan_orig_t origin) { if (__predict_false(!kmsan_enabled)) return; kmsan_report_inline(origin, KMSAN_RET_ADDR); } msan_tls_t * __msan_get_context_state(void) { msan_td_t *mtd; /* * When APs are started, they execute some C code before curthread is * set. We have to handle that here. */ if (__predict_false(!kmsan_enabled || curthread == NULL)) return (&dummy_tls); mtd = curthread->td_kmsan; return (&mtd->tls[mtd->ctx]); } /* -------------------------------------------------------------------------- */ /* * Function hooks. Mostly ASM functions which need KMSAN wrappers to handle * initialized areas properly. */ void * kmsan_memcpy(void *dst, const void *src, size_t len) { /* No kmsan_check_arg, because inlined. */ kmsan_init_ret(sizeof(void *)); if (__predict_true(len != 0)) { kmsan_meta_copy(dst, src, len); } return (__builtin_memcpy(dst, src, len)); } int kmsan_memcmp(const void *b1, const void *b2, size_t len) { const uint8_t *_b1 = b1, *_b2 = b2; size_t i; kmsan_check_arg(sizeof(b1) + sizeof(b2) + sizeof(len), "memcmp():args"); kmsan_init_ret(sizeof(int)); for (i = 0; i < len; i++) { if (*_b1 != *_b2) { kmsan_shadow_check((uintptr_t)b1, i + 1, "memcmp():arg1"); kmsan_shadow_check((uintptr_t)b2, i + 1, "memcmp():arg2"); return (*_b1 - *_b2); } _b1++, _b2++; } return (0); } void * kmsan_memset(void *dst, int c, size_t len) { /* No kmsan_check_arg, because inlined. */ kmsan_shadow_fill((uintptr_t)dst, KMSAN_STATE_INITED, len); kmsan_init_ret(sizeof(void *)); return (__builtin_memset(dst, c, len)); } void * kmsan_memmove(void *dst, const void *src, size_t len) { /* No kmsan_check_arg, because inlined. */ if (__predict_true(len != 0)) { kmsan_meta_copy(dst, src, len); } kmsan_init_ret(sizeof(void *)); return (__builtin_memmove(dst, src, len)); } __strong_reference(kmsan_memcpy, __msan_memcpy); __strong_reference(kmsan_memset, __msan_memset); __strong_reference(kmsan_memmove, __msan_memmove); char * kmsan_strcpy(char *dst, const char *src) { const char *_src = src; char *_dst = dst; size_t len = 0; kmsan_check_arg(sizeof(dst) + sizeof(src), "strcpy():args"); while (1) { len++; *dst = *src; if (*src == '\0') break; src++, dst++; } kmsan_shadow_check((uintptr_t)_src, len, "strcpy():arg2"); kmsan_shadow_fill((uintptr_t)_dst, KMSAN_STATE_INITED, len); kmsan_init_ret(sizeof(char *)); return (_dst); } int kmsan_strcmp(const char *s1, const char *s2) { const char *_s1 = s1, *_s2 = s2; size_t len = 0; kmsan_check_arg(sizeof(s1) + sizeof(s2), "strcmp():args"); kmsan_init_ret(sizeof(int)); while (1) { len++; if (*s1 != *s2) break; if (*s1 == '\0') { kmsan_shadow_check((uintptr_t)_s1, len, "strcmp():arg1"); kmsan_shadow_check((uintptr_t)_s2, len, "strcmp():arg2"); return (0); } s1++, s2++; } kmsan_shadow_check((uintptr_t)_s1, len, "strcmp():arg1"); kmsan_shadow_check((uintptr_t)_s2, len, "strcmp():arg2"); return (*(const unsigned char *)s1 - *(const unsigned char *)s2); } size_t kmsan_strlen(const char *str) { const char *s; kmsan_check_arg(sizeof(str), "strlen():args"); s = str; while (1) { if (*s == '\0') break; s++; } kmsan_shadow_check((uintptr_t)str, (size_t)(s - str) + 1, "strlen():arg1"); kmsan_init_ret(sizeof(size_t)); return (s - str); } int kmsan_copyin(const void *, void *, size_t); int kmsan_copyout(const void *, void *, size_t); int kmsan_copyinstr(const void *, void *, size_t, size_t *); int kmsan_copyin(const void *uaddr, void *kaddr, size_t len) { int ret; kmsan_check_arg(sizeof(uaddr) + sizeof(kaddr) + sizeof(len), "copyin():args"); ret = copyin(uaddr, kaddr, len); if (ret == 0) kmsan_shadow_fill((uintptr_t)kaddr, KMSAN_STATE_INITED, len); kmsan_init_ret(sizeof(int)); return (ret); } int kmsan_copyout(const void *kaddr, void *uaddr, size_t len) { kmsan_check_arg(sizeof(kaddr) + sizeof(uaddr) + sizeof(len), "copyout():args"); kmsan_shadow_check((uintptr_t)kaddr, len, "copyout():arg1"); kmsan_init_ret(sizeof(int)); return (copyout(kaddr, uaddr, len)); } int kmsan_copyinstr(const void *uaddr, void *kaddr, size_t len, size_t *done) { size_t _done; int ret; kmsan_check_arg(sizeof(uaddr) + sizeof(kaddr) + sizeof(len) + sizeof(done), "copyinstr():args"); ret = copyinstr(uaddr, kaddr, len, &_done); if (ret == 0) kmsan_shadow_fill((uintptr_t)kaddr, KMSAN_STATE_INITED, _done); if (done != NULL) { *done = _done; kmsan_shadow_fill((uintptr_t)done, KMSAN_STATE_INITED, sizeof(size_t)); } kmsan_init_ret(sizeof(int)); return (ret); } /* -------------------------------------------------------------------------- */ int kmsan_fubyte(volatile const void *base) { int ret; kmsan_check_arg(sizeof(base), "fubyte(): args"); ret = fubyte(base); kmsan_init_ret(sizeof(int)); return (ret); } int kmsan_fuword16(volatile const void *base) { int ret; kmsan_check_arg(sizeof(base), "fuword16(): args"); ret = fuword16(base); kmsan_init_ret(sizeof(int)); return (ret); } int kmsan_fueword(volatile const void *base, long *val) { int ret; kmsan_check_arg(sizeof(base) + sizeof(val), "fueword(): args"); ret = fueword(base, val); if (ret == 0) kmsan_shadow_fill((uintptr_t)val, KMSAN_STATE_INITED, sizeof(*val)); kmsan_init_ret(sizeof(int)); return (ret); } int kmsan_fueword32(volatile const void *base, int32_t *val) { int ret; kmsan_check_arg(sizeof(base) + sizeof(val), "fueword32(): args"); ret = fueword32(base, val); if (ret == 0) kmsan_shadow_fill((uintptr_t)val, KMSAN_STATE_INITED, sizeof(*val)); kmsan_init_ret(sizeof(int)); return (ret); } int kmsan_fueword64(volatile const void *base, int64_t *val) { int ret; kmsan_check_arg(sizeof(base) + sizeof(val), "fueword64(): args"); ret = fueword64(base, val); if (ret == 0) kmsan_shadow_fill((uintptr_t)val, KMSAN_STATE_INITED, sizeof(*val)); kmsan_init_ret(sizeof(int)); return (ret); } int kmsan_subyte(volatile void *base, int byte) { int ret; kmsan_check_arg(sizeof(base) + sizeof(byte), "subyte():args"); ret = subyte(base, byte); kmsan_init_ret(sizeof(int)); return (ret); } int kmsan_suword(volatile void *base, long word) { int ret; kmsan_check_arg(sizeof(base) + sizeof(word), "suword():args"); ret = suword(base, word); kmsan_init_ret(sizeof(int)); return (ret); } int kmsan_suword16(volatile void *base, int word) { int ret; kmsan_check_arg(sizeof(base) + sizeof(word), "suword16():args"); ret = suword16(base, word); kmsan_init_ret(sizeof(int)); return (ret); } int kmsan_suword32(volatile void *base, int32_t word) { int ret; kmsan_check_arg(sizeof(base) + sizeof(word), "suword32():args"); ret = suword32(base, word); kmsan_init_ret(sizeof(int)); return (ret); } int kmsan_suword64(volatile void *base, int64_t word) { int ret; kmsan_check_arg(sizeof(base) + sizeof(word), "suword64():args"); ret = suword64(base, word); kmsan_init_ret(sizeof(int)); return (ret); } int kmsan_casueword32(volatile uint32_t *base, uint32_t oldval, uint32_t *oldvalp, uint32_t newval) { int ret; kmsan_check_arg(sizeof(base) + sizeof(oldval) + sizeof(oldvalp) + sizeof(newval), "casueword32(): args"); ret = casueword32(base, oldval, oldvalp, newval); kmsan_shadow_fill((uintptr_t)oldvalp, KMSAN_STATE_INITED, sizeof(*oldvalp)); kmsan_init_ret(sizeof(int)); return (ret); } int kmsan_casueword(volatile u_long *base, u_long oldval, u_long *oldvalp, u_long newval) { int ret; kmsan_check_arg(sizeof(base) + sizeof(oldval) + sizeof(oldvalp) + sizeof(newval), "casueword32(): args"); ret = casueword(base, oldval, oldvalp, newval); kmsan_shadow_fill((uintptr_t)oldvalp, KMSAN_STATE_INITED, sizeof(*oldvalp)); kmsan_init_ret(sizeof(int)); return (ret); } /* -------------------------------------------------------------------------- */ #include #include #define _MSAN_ATOMIC_FUNC_ADD(name, type) \ void kmsan_atomic_add_##name(volatile type *ptr, type val) \ { \ kmsan_check_arg(sizeof(ptr) + sizeof(val), \ "atomic_add_" #name "():args"); \ kmsan_shadow_check((uintptr_t)ptr, sizeof(type), \ "atomic_add_" #name "():ptr"); \ atomic_add_##name(ptr, val); \ } #define MSAN_ATOMIC_FUNC_ADD(name, type) \ _MSAN_ATOMIC_FUNC_ADD(name, type) \ _MSAN_ATOMIC_FUNC_ADD(acq_##name, type) \ _MSAN_ATOMIC_FUNC_ADD(rel_##name, type) #define _MSAN_ATOMIC_FUNC_SUBTRACT(name, type) \ void kmsan_atomic_subtract_##name(volatile type *ptr, type val) \ { \ kmsan_check_arg(sizeof(ptr) + sizeof(val), \ "atomic_subtract_" #name "():args"); \ kmsan_shadow_check((uintptr_t)ptr, sizeof(type), \ "atomic_subtract_" #name "():ptr"); \ atomic_subtract_##name(ptr, val); \ } #define MSAN_ATOMIC_FUNC_SUBTRACT(name, type) \ _MSAN_ATOMIC_FUNC_SUBTRACT(name, type) \ _MSAN_ATOMIC_FUNC_SUBTRACT(acq_##name, type) \ _MSAN_ATOMIC_FUNC_SUBTRACT(rel_##name, type) #define _MSAN_ATOMIC_FUNC_SET(name, type) \ void kmsan_atomic_set_##name(volatile type *ptr, type val) \ { \ kmsan_check_arg(sizeof(ptr) + sizeof(val), \ "atomic_set_" #name "():args"); \ kmsan_shadow_check((uintptr_t)ptr, sizeof(type), \ "atomic_set_" #name "():ptr"); \ atomic_set_##name(ptr, val); \ } #define MSAN_ATOMIC_FUNC_SET(name, type) \ _MSAN_ATOMIC_FUNC_SET(name, type) \ _MSAN_ATOMIC_FUNC_SET(acq_##name, type) \ _MSAN_ATOMIC_FUNC_SET(rel_##name, type) #define _MSAN_ATOMIC_FUNC_CLEAR(name, type) \ void kmsan_atomic_clear_##name(volatile type *ptr, type val) \ { \ kmsan_check_arg(sizeof(ptr) + sizeof(val), \ "atomic_clear_" #name "():args"); \ kmsan_shadow_check((uintptr_t)ptr, sizeof(type), \ "atomic_clear_" #name "():ptr"); \ atomic_clear_##name(ptr, val); \ } #define MSAN_ATOMIC_FUNC_CLEAR(name, type) \ _MSAN_ATOMIC_FUNC_CLEAR(name, type) \ _MSAN_ATOMIC_FUNC_CLEAR(acq_##name, type) \ _MSAN_ATOMIC_FUNC_CLEAR(rel_##name, type) #define MSAN_ATOMIC_FUNC_FETCHADD(name, type) \ type kmsan_atomic_fetchadd_##name(volatile type *ptr, type val) \ { \ kmsan_check_arg(sizeof(ptr) + sizeof(val), \ "atomic_fetchadd_" #name "():args"); \ kmsan_shadow_check((uintptr_t)ptr, sizeof(type), \ "atomic_fetchadd_" #name "():ptr"); \ kmsan_init_ret(sizeof(type)); \ return (atomic_fetchadd_##name(ptr, val)); \ } #define MSAN_ATOMIC_FUNC_READANDCLEAR(name, type) \ type kmsan_atomic_readandclear_##name(volatile type *ptr) \ { \ kmsan_check_arg(sizeof(ptr), \ "atomic_readandclear_" #name "():args"); \ kmsan_shadow_check((uintptr_t)ptr, sizeof(type), \ "atomic_readandclear_" #name "():ptr"); \ kmsan_init_ret(sizeof(type)); \ return (atomic_readandclear_##name(ptr)); \ } #define MSAN_ATOMIC_FUNC_TESTANDCLEAR(name, type) \ int kmsan_atomic_testandclear_##name(volatile type *ptr, u_int v) \ { \ kmsan_check_arg(sizeof(ptr) + sizeof(v), \ "atomic_testandclear_" #name "():args"); \ kmsan_shadow_check((uintptr_t)ptr, sizeof(type), \ "atomic_testandclear_" #name "():ptr"); \ kmsan_init_ret(sizeof(int)); \ return (atomic_testandclear_##name(ptr, v)); \ } #define MSAN_ATOMIC_FUNC_TESTANDSET(name, type) \ int kmsan_atomic_testandset_##name(volatile type *ptr, u_int v) \ { \ kmsan_check_arg(sizeof(ptr) + sizeof(v), \ "atomic_testandset_" #name "():args"); \ kmsan_shadow_check((uintptr_t)ptr, sizeof(type), \ "atomic_testandset_" #name "():ptr"); \ kmsan_init_ret(sizeof(int)); \ return (atomic_testandset_##name(ptr, v)); \ } #define MSAN_ATOMIC_FUNC_SWAP(name, type) \ type kmsan_atomic_swap_##name(volatile type *ptr, type val) \ { \ kmsan_check_arg(sizeof(ptr) + sizeof(val), \ "atomic_swap_" #name "():args"); \ kmsan_shadow_check((uintptr_t)ptr, sizeof(type), \ "atomic_swap_" #name "():ptr"); \ kmsan_init_ret(sizeof(type)); \ return (atomic_swap_##name(ptr, val)); \ } #define _MSAN_ATOMIC_FUNC_CMPSET(name, type) \ int kmsan_atomic_cmpset_##name(volatile type *ptr, type oval, \ type nval) \ { \ kmsan_check_arg(sizeof(ptr) + sizeof(oval) + \ sizeof(nval), "atomic_cmpset_" #name "():args"); \ kmsan_shadow_check((uintptr_t)ptr, sizeof(type), \ "atomic_cmpset_" #name "():ptr"); \ kmsan_init_ret(sizeof(int)); \ return (atomic_cmpset_##name(ptr, oval, nval)); \ } #define MSAN_ATOMIC_FUNC_CMPSET(name, type) \ _MSAN_ATOMIC_FUNC_CMPSET(name, type) \ _MSAN_ATOMIC_FUNC_CMPSET(acq_##name, type) \ _MSAN_ATOMIC_FUNC_CMPSET(rel_##name, type) #define _MSAN_ATOMIC_FUNC_FCMPSET(name, type) \ int kmsan_atomic_fcmpset_##name(volatile type *ptr, type *oval, \ type nval) \ { \ kmsan_check_arg(sizeof(ptr) + sizeof(oval) + \ sizeof(nval), "atomic_fcmpset_" #name "():args"); \ kmsan_shadow_check((uintptr_t)ptr, sizeof(type), \ "atomic_fcmpset_" #name "():ptr"); \ kmsan_init_ret(sizeof(int)); \ return (atomic_fcmpset_##name(ptr, oval, nval)); \ } #define MSAN_ATOMIC_FUNC_FCMPSET(name, type) \ _MSAN_ATOMIC_FUNC_FCMPSET(name, type) \ _MSAN_ATOMIC_FUNC_FCMPSET(acq_##name, type) \ _MSAN_ATOMIC_FUNC_FCMPSET(rel_##name, type) #define MSAN_ATOMIC_FUNC_THREAD_FENCE(name) \ void kmsan_atomic_thread_fence_##name(void) \ { \ atomic_thread_fence_##name(); \ } #define _MSAN_ATOMIC_FUNC_LOAD(name, type) \ - type kmsan_atomic_load_##name(volatile type *ptr) \ + type kmsan_atomic_load_##name(const volatile type *ptr) \ { \ kmsan_check_arg(sizeof(ptr), \ "atomic_load_" #name "():args"); \ kmsan_shadow_check((uintptr_t)ptr, sizeof(type), \ "atomic_load_" #name "():ptr"); \ kmsan_init_ret(sizeof(type)); \ return (atomic_load_##name(ptr)); \ } #define MSAN_ATOMIC_FUNC_LOAD(name, type) \ _MSAN_ATOMIC_FUNC_LOAD(name, type) \ _MSAN_ATOMIC_FUNC_LOAD(acq_##name, type) #define _MSAN_ATOMIC_FUNC_STORE(name, type) \ void kmsan_atomic_store_##name(volatile type *ptr, type val) \ { \ kmsan_check_arg(sizeof(ptr) + sizeof(val), \ "atomic_store_" #name "():args"); \ kmsan_shadow_fill((uintptr_t)ptr, KMSAN_STATE_INITED, \ sizeof(type)); \ atomic_store_##name(ptr, val); \ } #define MSAN_ATOMIC_FUNC_STORE(name, type) \ _MSAN_ATOMIC_FUNC_STORE(name, type) \ _MSAN_ATOMIC_FUNC_STORE(rel_##name, type) MSAN_ATOMIC_FUNC_ADD(8, uint8_t); MSAN_ATOMIC_FUNC_ADD(16, uint16_t); MSAN_ATOMIC_FUNC_ADD(32, uint32_t); MSAN_ATOMIC_FUNC_ADD(64, uint64_t); MSAN_ATOMIC_FUNC_ADD(int, u_int); MSAN_ATOMIC_FUNC_ADD(long, u_long); MSAN_ATOMIC_FUNC_ADD(ptr, uintptr_t); MSAN_ATOMIC_FUNC_SUBTRACT(8, uint8_t); MSAN_ATOMIC_FUNC_SUBTRACT(16, uint16_t); MSAN_ATOMIC_FUNC_SUBTRACT(32, uint32_t); MSAN_ATOMIC_FUNC_SUBTRACT(64, uint64_t); MSAN_ATOMIC_FUNC_SUBTRACT(int, u_int); MSAN_ATOMIC_FUNC_SUBTRACT(long, u_long); MSAN_ATOMIC_FUNC_SUBTRACT(ptr, uintptr_t); MSAN_ATOMIC_FUNC_SET(8, uint8_t); MSAN_ATOMIC_FUNC_SET(16, uint16_t); MSAN_ATOMIC_FUNC_SET(32, uint32_t); MSAN_ATOMIC_FUNC_SET(64, uint64_t); MSAN_ATOMIC_FUNC_SET(int, u_int); MSAN_ATOMIC_FUNC_SET(long, u_long); MSAN_ATOMIC_FUNC_SET(ptr, uintptr_t); MSAN_ATOMIC_FUNC_CLEAR(8, uint8_t); MSAN_ATOMIC_FUNC_CLEAR(16, uint16_t); MSAN_ATOMIC_FUNC_CLEAR(32, uint32_t); MSAN_ATOMIC_FUNC_CLEAR(64, uint64_t); MSAN_ATOMIC_FUNC_CLEAR(int, u_int); MSAN_ATOMIC_FUNC_CLEAR(long, u_long); MSAN_ATOMIC_FUNC_CLEAR(ptr, uintptr_t); MSAN_ATOMIC_FUNC_FETCHADD(32, uint32_t); MSAN_ATOMIC_FUNC_FETCHADD(64, uint64_t); MSAN_ATOMIC_FUNC_FETCHADD(int, u_int); MSAN_ATOMIC_FUNC_FETCHADD(long, u_long); MSAN_ATOMIC_FUNC_READANDCLEAR(32, uint32_t); MSAN_ATOMIC_FUNC_READANDCLEAR(64, uint64_t); MSAN_ATOMIC_FUNC_READANDCLEAR(int, u_int); MSAN_ATOMIC_FUNC_READANDCLEAR(long, u_long); MSAN_ATOMIC_FUNC_READANDCLEAR(ptr, uintptr_t); MSAN_ATOMIC_FUNC_TESTANDCLEAR(32, uint32_t); MSAN_ATOMIC_FUNC_TESTANDCLEAR(64, uint64_t); MSAN_ATOMIC_FUNC_TESTANDCLEAR(int, u_int); MSAN_ATOMIC_FUNC_TESTANDCLEAR(long, u_long); MSAN_ATOMIC_FUNC_TESTANDCLEAR(ptr, uintptr_t); MSAN_ATOMIC_FUNC_TESTANDSET(32, uint32_t); MSAN_ATOMIC_FUNC_TESTANDSET(64, uint64_t); MSAN_ATOMIC_FUNC_TESTANDSET(int, u_int); MSAN_ATOMIC_FUNC_TESTANDSET(long, u_long); MSAN_ATOMIC_FUNC_TESTANDSET(ptr, uintptr_t); MSAN_ATOMIC_FUNC_SWAP(32, uint32_t); MSAN_ATOMIC_FUNC_SWAP(64, uint64_t); MSAN_ATOMIC_FUNC_SWAP(int, u_int); MSAN_ATOMIC_FUNC_SWAP(long, u_long); MSAN_ATOMIC_FUNC_SWAP(ptr, uintptr_t); MSAN_ATOMIC_FUNC_CMPSET(8, uint8_t); MSAN_ATOMIC_FUNC_CMPSET(16, uint16_t); MSAN_ATOMIC_FUNC_CMPSET(32, uint32_t); MSAN_ATOMIC_FUNC_CMPSET(64, uint64_t); MSAN_ATOMIC_FUNC_CMPSET(int, u_int); MSAN_ATOMIC_FUNC_CMPSET(long, u_long); MSAN_ATOMIC_FUNC_CMPSET(ptr, uintptr_t); MSAN_ATOMIC_FUNC_FCMPSET(8, uint8_t); MSAN_ATOMIC_FUNC_FCMPSET(16, uint16_t); MSAN_ATOMIC_FUNC_FCMPSET(32, uint32_t); MSAN_ATOMIC_FUNC_FCMPSET(64, uint64_t); MSAN_ATOMIC_FUNC_FCMPSET(int, u_int); MSAN_ATOMIC_FUNC_FCMPSET(long, u_long); MSAN_ATOMIC_FUNC_FCMPSET(ptr, uintptr_t); _MSAN_ATOMIC_FUNC_LOAD(bool, bool); MSAN_ATOMIC_FUNC_LOAD(8, uint8_t); MSAN_ATOMIC_FUNC_LOAD(16, uint16_t); MSAN_ATOMIC_FUNC_LOAD(32, uint32_t); MSAN_ATOMIC_FUNC_LOAD(64, uint64_t); MSAN_ATOMIC_FUNC_LOAD(char, u_char); MSAN_ATOMIC_FUNC_LOAD(short, u_short); MSAN_ATOMIC_FUNC_LOAD(int, u_int); MSAN_ATOMIC_FUNC_LOAD(long, u_long); MSAN_ATOMIC_FUNC_LOAD(ptr, uintptr_t); _MSAN_ATOMIC_FUNC_STORE(bool, bool); MSAN_ATOMIC_FUNC_STORE(8, uint8_t); MSAN_ATOMIC_FUNC_STORE(16, uint16_t); MSAN_ATOMIC_FUNC_STORE(32, uint32_t); MSAN_ATOMIC_FUNC_STORE(64, uint64_t); MSAN_ATOMIC_FUNC_STORE(char, u_char); MSAN_ATOMIC_FUNC_STORE(short, u_short); MSAN_ATOMIC_FUNC_STORE(int, u_int); MSAN_ATOMIC_FUNC_STORE(long, u_long); MSAN_ATOMIC_FUNC_STORE(ptr, uintptr_t); MSAN_ATOMIC_FUNC_THREAD_FENCE(acq); MSAN_ATOMIC_FUNC_THREAD_FENCE(rel); MSAN_ATOMIC_FUNC_THREAD_FENCE(acq_rel); MSAN_ATOMIC_FUNC_THREAD_FENCE(seq_cst); void kmsan_atomic_interrupt_fence(void) { atomic_interrupt_fence(); } /* -------------------------------------------------------------------------- */ #include #include #include int kmsan_bus_space_map(bus_space_tag_t tag, bus_addr_t hnd, bus_size_t size, int flags, bus_space_handle_t *handlep) { return (bus_space_map(tag, hnd, size, flags, handlep)); } void kmsan_bus_space_unmap(bus_space_tag_t tag, bus_space_handle_t hnd, bus_size_t size) { bus_space_unmap(tag, hnd, size); } int kmsan_bus_space_subregion(bus_space_tag_t tag, bus_space_handle_t hnd, bus_size_t offset, bus_size_t size, bus_space_handle_t *handlep) { return (bus_space_subregion(tag, hnd, offset, size, handlep)); } void kmsan_bus_space_free(bus_space_tag_t tag, bus_space_handle_t hnd, bus_size_t size) { bus_space_free(tag, hnd, size); } void kmsan_bus_space_barrier(bus_space_tag_t tag, bus_space_handle_t hnd, bus_size_t offset, bus_size_t size, int flags) { bus_space_barrier(tag, hnd, offset, size, flags); } #if defined(__amd64__) #define BUS_SPACE_IO(tag) ((tag) == X86_BUS_SPACE_IO) #else #define BUS_SPACE_IO(tag) (false) #endif #define MSAN_BUS_READ_FUNC(func, width, type) \ type kmsan_bus_space_read##func##_##width(bus_space_tag_t tag, \ bus_space_handle_t hnd, bus_size_t offset) \ { \ type ret; \ if (!BUS_SPACE_IO(tag)) \ kmsan_shadow_fill((uintptr_t)(hnd + offset), \ KMSAN_STATE_INITED, (width)); \ ret = bus_space_read##func##_##width(tag, hnd, offset); \ kmsan_init_ret(sizeof(type)); \ return (ret); \ } \ #define MSAN_BUS_READ_PTR_FUNC(func, width, type) \ void kmsan_bus_space_read_##func##_##width(bus_space_tag_t tag, \ bus_space_handle_t hnd, bus_size_t size, type *buf, \ bus_size_t count) \ { \ kmsan_shadow_fill((uintptr_t)buf, KMSAN_STATE_INITED, \ (width) * count); \ bus_space_read_##func##_##width(tag, hnd, size, buf, \ count); \ } MSAN_BUS_READ_FUNC(, 1, uint8_t) MSAN_BUS_READ_FUNC(_stream, 1, uint8_t) MSAN_BUS_READ_PTR_FUNC(multi, 1, uint8_t) MSAN_BUS_READ_PTR_FUNC(multi_stream, 1, uint8_t) MSAN_BUS_READ_PTR_FUNC(region, 1, uint8_t) MSAN_BUS_READ_PTR_FUNC(region_stream, 1, uint8_t) MSAN_BUS_READ_FUNC(, 2, uint16_t) MSAN_BUS_READ_FUNC(_stream, 2, uint16_t) MSAN_BUS_READ_PTR_FUNC(multi, 2, uint16_t) MSAN_BUS_READ_PTR_FUNC(multi_stream, 2, uint16_t) MSAN_BUS_READ_PTR_FUNC(region, 2, uint16_t) MSAN_BUS_READ_PTR_FUNC(region_stream, 2, uint16_t) MSAN_BUS_READ_FUNC(, 4, uint32_t) MSAN_BUS_READ_FUNC(_stream, 4, uint32_t) MSAN_BUS_READ_PTR_FUNC(multi, 4, uint32_t) MSAN_BUS_READ_PTR_FUNC(multi_stream, 4, uint32_t) MSAN_BUS_READ_PTR_FUNC(region, 4, uint32_t) MSAN_BUS_READ_PTR_FUNC(region_stream, 4, uint32_t) MSAN_BUS_READ_FUNC(, 8, uint64_t) #ifndef __amd64__ MSAN_BUS_READ_FUNC(_stream, 8, uint64_t) MSAN_BUS_READ_PTR_FUNC(multi, 8, uint64_t) MSAN_BUS_READ_PTR_FUNC(multi_stream, 8, uint64_t) MSAN_BUS_READ_PTR_FUNC(region, 8, uint64_t) MSAN_BUS_READ_PTR_FUNC(region_stream, 8, uint64_t) #endif #define MSAN_BUS_WRITE_FUNC(func, width, type) \ void kmsan_bus_space_write##func##_##width(bus_space_tag_t tag, \ bus_space_handle_t hnd, bus_size_t offset, type value) \ { \ bus_space_write##func##_##width(tag, hnd, offset, value);\ } \ #define MSAN_BUS_WRITE_PTR_FUNC(func, width, type) \ void kmsan_bus_space_write_##func##_##width(bus_space_tag_t tag,\ bus_space_handle_t hnd, bus_size_t size, const type *buf, \ bus_size_t count) \ { \ kmsan_shadow_check((uintptr_t)buf, sizeof(type) * count,\ "bus_space_write()"); \ bus_space_write_##func##_##width(tag, hnd, size, buf, \ count); \ } MSAN_BUS_WRITE_FUNC(, 1, uint8_t) MSAN_BUS_WRITE_FUNC(_stream, 1, uint8_t) MSAN_BUS_WRITE_PTR_FUNC(multi, 1, uint8_t) MSAN_BUS_WRITE_PTR_FUNC(multi_stream, 1, uint8_t) MSAN_BUS_WRITE_PTR_FUNC(region, 1, uint8_t) MSAN_BUS_WRITE_PTR_FUNC(region_stream, 1, uint8_t) MSAN_BUS_WRITE_FUNC(, 2, uint16_t) MSAN_BUS_WRITE_FUNC(_stream, 2, uint16_t) MSAN_BUS_WRITE_PTR_FUNC(multi, 2, uint16_t) MSAN_BUS_WRITE_PTR_FUNC(multi_stream, 2, uint16_t) MSAN_BUS_WRITE_PTR_FUNC(region, 2, uint16_t) MSAN_BUS_WRITE_PTR_FUNC(region_stream, 2, uint16_t) MSAN_BUS_WRITE_FUNC(, 4, uint32_t) MSAN_BUS_WRITE_FUNC(_stream, 4, uint32_t) MSAN_BUS_WRITE_PTR_FUNC(multi, 4, uint32_t) MSAN_BUS_WRITE_PTR_FUNC(multi_stream, 4, uint32_t) MSAN_BUS_WRITE_PTR_FUNC(region, 4, uint32_t) MSAN_BUS_WRITE_PTR_FUNC(region_stream, 4, uint32_t) MSAN_BUS_WRITE_FUNC(, 8, uint64_t) #define MSAN_BUS_SET_FUNC(func, width, type) \ void kmsan_bus_space_set_##func##_##width(bus_space_tag_t tag, \ bus_space_handle_t hnd, bus_size_t offset, type value, \ bus_size_t count) \ { \ bus_space_set_##func##_##width(tag, hnd, offset, value, \ count); \ } MSAN_BUS_SET_FUNC(multi, 1, uint8_t) MSAN_BUS_SET_FUNC(region, 1, uint8_t) MSAN_BUS_SET_FUNC(multi_stream, 1, uint8_t) MSAN_BUS_SET_FUNC(region_stream, 1, uint8_t) MSAN_BUS_SET_FUNC(multi, 2, uint16_t) MSAN_BUS_SET_FUNC(region, 2, uint16_t) MSAN_BUS_SET_FUNC(multi_stream, 2, uint16_t) MSAN_BUS_SET_FUNC(region_stream, 2, uint16_t) MSAN_BUS_SET_FUNC(multi, 4, uint32_t) MSAN_BUS_SET_FUNC(region, 4, uint32_t) MSAN_BUS_SET_FUNC(multi_stream, 4, uint32_t) MSAN_BUS_SET_FUNC(region_stream, 4, uint32_t) #define MSAN_BUS_PEEK_FUNC(width, type) \ int kmsan_bus_space_peek_##width(bus_space_tag_t tag, \ bus_space_handle_t hnd, bus_size_t offset, type *value) \ { \ return (bus_space_peek_##width(tag, hnd, offset, value)); \ } MSAN_BUS_PEEK_FUNC(1, uint8_t) MSAN_BUS_PEEK_FUNC(2, uint16_t) MSAN_BUS_PEEK_FUNC(4, uint32_t) #define MSAN_BUS_POKE_FUNC(width, type) \ int kmsan_bus_space_poke_##width(bus_space_tag_t tag, \ bus_space_handle_t hnd, bus_size_t offset, type value) \ { \ return (bus_space_poke_##width(tag, hnd, offset, value)); \ } MSAN_BUS_POKE_FUNC(1, uint8_t) MSAN_BUS_POKE_FUNC(2, uint16_t) MSAN_BUS_POKE_FUNC(4, uint32_t) /* -------------------------------------------------------------------------- */ void kmsan_bus_dmamap_sync(struct memdesc *desc, bus_dmasync_op_t op) { /* * Some drivers, e.g., nvme, use the same code path for loading device * read and write requests, and will thus specify both flags. In this * case we should not do any checking since it will generally lead to * false positives. */ if ((op & (BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE)) == BUS_DMASYNC_PREWRITE) { switch (desc->md_type) { case MEMDESC_VADDR: kmsan_check(desc->u.md_vaddr, desc->md_len, "dmasync"); break; case MEMDESC_MBUF: kmsan_check_mbuf(desc->u.md_mbuf, "dmasync"); break; case 0: break; default: kmsan_panic("%s: unhandled memdesc type %d", __func__, desc->md_type); } } if ((op & BUS_DMASYNC_POSTREAD) != 0) { switch (desc->md_type) { case MEMDESC_VADDR: kmsan_mark(desc->u.md_vaddr, desc->md_len, KMSAN_STATE_INITED); break; case MEMDESC_MBUF: kmsan_mark_mbuf(desc->u.md_mbuf, KMSAN_STATE_INITED); break; case 0: break; default: kmsan_panic("%s: unhandled memdesc type %d", __func__, desc->md_type); } } } diff --git a/sys/sys/atomic_san.h b/sys/sys/atomic_san.h index e22324b87623..93a9bfcbf593 100644 --- a/sys/sys/atomic_san.h +++ b/sys/sys/atomic_san.h @@ -1,410 +1,410 @@ /*- * SPDX-License-Identifier: BSD-2-Clause * * Copyright (c) 2019 Andrew Turner * Copyright (c) 2021 The FreeBSD Foundation * * This software was developed by SRI International and the University of * Cambridge Computer Laboratory (Department of Computer Science and * Technology) under DARPA contract HR0011-18-C-0016 ("ECATS"), as part of the * DARPA SSITH research programme. * * Portions of this software were written by Mark Johnston under sponsorship * by the FreeBSD Foundation. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #ifndef _SYS_ATOMIC_SAN_H_ #define _SYS_ATOMIC_SAN_H_ #ifndef _MACHINE_ATOMIC_H_ #error do not include this header, use machine/atomic.h #endif #include #define ATOMIC_SAN_FUNC_1(sp, op, name, type) \ void sp##_atomic_##op##_##name(volatile type *, type); \ void sp##_atomic_##op##_acq_##name(volatile type *, type); \ void sp##_atomic_##op##_rel_##name(volatile type *, type) #define ATOMIC_SAN_CMPSET(sp, name, type) \ int sp##_atomic_cmpset_##name(volatile type *, type, type); \ int sp##_atomic_cmpset_acq_##name(volatile type *, type, type); \ int sp##_atomic_cmpset_rel_##name(volatile type *, type, type) #define ATOMIC_SAN_FCMPSET(sp, name, type) \ int sp##_atomic_fcmpset_##name(volatile type *, type *, type); \ int sp##_atomic_fcmpset_acq_##name(volatile type *, type *, type); \ int sp##_atomic_fcmpset_rel_##name(volatile type *, type *, type) #define ATOMIC_SAN_READ(sp, op, name, type) \ type sp##_atomic_##op##_##name(volatile type *, type) #define ATOMIC_SAN_READANDCLEAR(sp, name, type) \ type sp##_atomic_readandclear_##name(volatile type *) #define ATOMIC_SAN_LOAD(sp, name, type) \ - type sp##_atomic_load_##name(volatile type *) + type sp##_atomic_load_##name(const volatile type *) #define ATOMIC_SAN_LOAD_ACQ(sp, name, type) \ - type sp##_atomic_load_acq_##name(volatile type *) + type sp##_atomic_load_acq_##name(const volatile type *) #define ATOMIC_SAN_STORE(sp, name, type) \ void sp##_atomic_store_##name(volatile type *, type) #define ATOMIC_SAN_STORE_REL(sp, name, type) \ void sp##_atomic_store_rel_##name(volatile type *, type) #define ATOMIC_SAN_TEST(sp, op, name, type) \ int sp##_atomic_##op##_##name(volatile type *, u_int); \ int sp##_atomic_##op##_acq_##name(volatile type *, u_int) #define _ATOMIC_SAN_THREAD_FENCE(sp) \ void sp##_atomic_thread_fence_acq(void); \ void sp##_atomic_thread_fence_rel(void); \ void sp##_atomic_thread_fence_acq_rel(void); \ void sp##_atomic_thread_fence_seq_cst(void); \ void sp##_atomic_interrupt_fence(void) #define ATOMIC_SAN_THREAD_FENCE(sp) \ _ATOMIC_SAN_THREAD_FENCE(sp) #define ATOMIC_SAN_LOAD_STORE(sp, name, type) \ ATOMIC_SAN_LOAD(sp, name, type); \ ATOMIC_SAN_STORE(sp, name, type) #define _ATOMIC_SAN_FUNCS(sp, name, type) \ ATOMIC_SAN_FUNC_1(sp, add, name, type); \ ATOMIC_SAN_FUNC_1(sp, clear, name, type); \ ATOMIC_SAN_CMPSET(sp, name, type); \ ATOMIC_SAN_FCMPSET(sp, name, type); \ ATOMIC_SAN_READ(sp, fetchadd, name, type); \ ATOMIC_SAN_LOAD(sp, name, type); \ ATOMIC_SAN_LOAD_ACQ(sp, name, type); \ ATOMIC_SAN_READANDCLEAR(sp, name, type); \ ATOMIC_SAN_FUNC_1(sp, set, name, type); \ ATOMIC_SAN_FUNC_1(sp, subtract, name, type); \ ATOMIC_SAN_STORE(sp, name, type); \ ATOMIC_SAN_STORE_REL(sp, name, type); \ ATOMIC_SAN_READ(sp, swap, name, type); \ ATOMIC_SAN_TEST(sp, testandclear, name, type); \ ATOMIC_SAN_TEST(sp, testandset, name, type) #define ATOMIC_SAN_FUNCS(name, type) \ _ATOMIC_SAN_FUNCS(SAN_INTERCEPTOR_PREFIX, name, type) ATOMIC_SAN_FUNCS(char, uint8_t); ATOMIC_SAN_FUNCS(short, uint16_t); ATOMIC_SAN_FUNCS(int, u_int); ATOMIC_SAN_FUNCS(long, u_long); ATOMIC_SAN_FUNCS(ptr, uintptr_t); ATOMIC_SAN_FUNCS(8, uint8_t); ATOMIC_SAN_FUNCS(16, uint16_t); ATOMIC_SAN_FUNCS(32, uint32_t); ATOMIC_SAN_FUNCS(64, uint64_t); ATOMIC_SAN_LOAD_STORE(SAN_INTERCEPTOR_PREFIX, bool, bool); ATOMIC_SAN_THREAD_FENCE(SAN_INTERCEPTOR_PREFIX); #ifndef SAN_RUNTIME /* * Redirect uses of an atomic(9) function to the sanitizer's interceptor. * For instance, KASAN callers of atomic_add_char() will be redirected to * kasan_atomic_add_char(). */ #define ATOMIC_SAN(func) \ __CONCAT(SAN_INTERCEPTOR_PREFIX, __CONCAT(_atomic_, func)) #define atomic_load_bool ATOMIC_SAN(load_bool) #define atomic_store_bool ATOMIC_SAN(store_bool) #define atomic_add_char ATOMIC_SAN(add_char) #define atomic_add_acq_char ATOMIC_SAN(add_acq_char) #define atomic_add_rel_char ATOMIC_SAN(add_rel_char) #define atomic_clear_char ATOMIC_SAN(clear_char) #define atomic_clear_acq_char ATOMIC_SAN(clear_acq_char) #define atomic_clear_rel_char ATOMIC_SAN(clear_rel_char) #define atomic_cmpset_char ATOMIC_SAN(cmpset_char) #define atomic_cmpset_acq_char ATOMIC_SAN(cmpset_acq_char) #define atomic_cmpset_rel_char ATOMIC_SAN(cmpset_rel_char) #define atomic_fcmpset_char ATOMIC_SAN(fcmpset_char) #define atomic_fcmpset_acq_char ATOMIC_SAN(fcmpset_acq_char) #define atomic_fcmpset_rel_char ATOMIC_SAN(fcmpset_rel_char) #define atomic_fetchadd_char ATOMIC_SAN(fetchadd_char) #define atomic_load_char ATOMIC_SAN(load_char) #define atomic_load_acq_char ATOMIC_SAN(load_acq_char) #define atomic_readandclear_char ATOMIC_SAN(readandclear_char) #define atomic_set_char ATOMIC_SAN(set_char) #define atomic_set_acq_char ATOMIC_SAN(set_acq_char) #define atomic_set_rel_char ATOMIC_SAN(set_rel_char) #define atomic_subtract_char ATOMIC_SAN(subtract_char) #define atomic_subtract_acq_char ATOMIC_SAN(subtract_acq_char) #define atomic_subtract_rel_char ATOMIC_SAN(subtract_rel_char) #define atomic_store_char ATOMIC_SAN(store_char) #define atomic_store_rel_char ATOMIC_SAN(store_rel_char) #define atomic_swap_char ATOMIC_SAN(swap_char) #define atomic_testandclear_char ATOMIC_SAN(testandclear_char) #define atomic_testandset_char ATOMIC_SAN(testandset_char) #define atomic_add_short ATOMIC_SAN(add_short) #define atomic_add_acq_short ATOMIC_SAN(add_acq_short) #define atomic_add_rel_short ATOMIC_SAN(add_rel_short) #define atomic_clear_short ATOMIC_SAN(clear_short) #define atomic_clear_acq_short ATOMIC_SAN(clear_acq_short) #define atomic_clear_rel_short ATOMIC_SAN(clear_rel_short) #define atomic_cmpset_short ATOMIC_SAN(cmpset_short) #define atomic_cmpset_acq_short ATOMIC_SAN(cmpset_acq_short) #define atomic_cmpset_rel_short ATOMIC_SAN(cmpset_rel_short) #define atomic_fcmpset_short ATOMIC_SAN(fcmpset_short) #define atomic_fcmpset_acq_short ATOMIC_SAN(fcmpset_acq_short) #define atomic_fcmpset_rel_short ATOMIC_SAN(fcmpset_rel_short) #define atomic_fetchadd_short ATOMIC_SAN(fetchadd_short) #define atomic_load_short ATOMIC_SAN(load_short) #define atomic_load_acq_short ATOMIC_SAN(load_acq_short) #define atomic_readandclear_short ATOMIC_SAN(readandclear_short) #define atomic_set_short ATOMIC_SAN(set_short) #define atomic_set_acq_short ATOMIC_SAN(set_acq_short) #define atomic_set_rel_short ATOMIC_SAN(set_rel_short) #define atomic_subtract_short ATOMIC_SAN(subtract_short) #define atomic_subtract_acq_short ATOMIC_SAN(subtract_acq_short) #define atomic_subtract_rel_short ATOMIC_SAN(subtract_rel_short) #define atomic_store_short ATOMIC_SAN(store_short) #define atomic_store_rel_short ATOMIC_SAN(store_rel_short) #define atomic_swap_short ATOMIC_SAN(swap_short) #define atomic_testandclear_short ATOMIC_SAN(testandclear_short) #define atomic_testandset_short ATOMIC_SAN(testandset_short) #define atomic_add_int ATOMIC_SAN(add_int) #define atomic_add_acq_int ATOMIC_SAN(add_acq_int) #define atomic_add_rel_int ATOMIC_SAN(add_rel_int) #define atomic_clear_int ATOMIC_SAN(clear_int) #define atomic_clear_acq_int ATOMIC_SAN(clear_acq_int) #define atomic_clear_rel_int ATOMIC_SAN(clear_rel_int) #define atomic_cmpset_int ATOMIC_SAN(cmpset_int) #define atomic_cmpset_acq_int ATOMIC_SAN(cmpset_acq_int) #define atomic_cmpset_rel_int ATOMIC_SAN(cmpset_rel_int) #define atomic_fcmpset_int ATOMIC_SAN(fcmpset_int) #define atomic_fcmpset_acq_int ATOMIC_SAN(fcmpset_acq_int) #define atomic_fcmpset_rel_int ATOMIC_SAN(fcmpset_rel_int) #define atomic_fetchadd_int ATOMIC_SAN(fetchadd_int) #define atomic_load_int ATOMIC_SAN(load_int) #define atomic_load_acq_int ATOMIC_SAN(load_acq_int) #define atomic_readandclear_int ATOMIC_SAN(readandclear_int) #define atomic_set_int ATOMIC_SAN(set_int) #define atomic_set_acq_int ATOMIC_SAN(set_acq_int) #define atomic_set_rel_int ATOMIC_SAN(set_rel_int) #define atomic_subtract_int ATOMIC_SAN(subtract_int) #define atomic_subtract_acq_int ATOMIC_SAN(subtract_acq_int) #define atomic_subtract_rel_int ATOMIC_SAN(subtract_rel_int) #define atomic_store_int ATOMIC_SAN(store_int) #define atomic_store_rel_int ATOMIC_SAN(store_rel_int) #define atomic_swap_int ATOMIC_SAN(swap_int) #define atomic_testandclear_int ATOMIC_SAN(testandclear_int) #define atomic_testandset_int ATOMIC_SAN(testandset_int) #define atomic_add_long ATOMIC_SAN(add_long) #define atomic_add_acq_long ATOMIC_SAN(add_acq_long) #define atomic_add_rel_long ATOMIC_SAN(add_rel_long) #define atomic_clear_long ATOMIC_SAN(clear_long) #define atomic_clear_acq_long ATOMIC_SAN(clear_acq_long) #define atomic_clear_rel_long ATOMIC_SAN(clear_rel_long) #define atomic_cmpset_long ATOMIC_SAN(cmpset_long) #define atomic_cmpset_acq_long ATOMIC_SAN(cmpset_acq_long) #define atomic_cmpset_rel_long ATOMIC_SAN(cmpset_rel_long) #define atomic_fcmpset_long ATOMIC_SAN(fcmpset_long) #define atomic_fcmpset_acq_long ATOMIC_SAN(fcmpset_acq_long) #define atomic_fcmpset_rel_long ATOMIC_SAN(fcmpset_rel_long) #define atomic_fetchadd_long ATOMIC_SAN(fetchadd_long) #define atomic_load_long ATOMIC_SAN(load_long) #define atomic_load_acq_long ATOMIC_SAN(load_acq_long) #define atomic_readandclear_long ATOMIC_SAN(readandclear_long) #define atomic_set_long ATOMIC_SAN(set_long) #define atomic_set_acq_long ATOMIC_SAN(set_acq_long) #define atomic_set_rel_long ATOMIC_SAN(set_rel_long) #define atomic_subtract_long ATOMIC_SAN(subtract_long) #define atomic_subtract_acq_long ATOMIC_SAN(subtract_acq_long) #define atomic_subtract_rel_long ATOMIC_SAN(subtract_rel_long) #define atomic_store_long ATOMIC_SAN(store_long) #define atomic_store_rel_long ATOMIC_SAN(store_rel_long) #define atomic_swap_long ATOMIC_SAN(swap_long) #define atomic_testandclear_long ATOMIC_SAN(testandclear_long) #define atomic_testandset_long ATOMIC_SAN(testandset_long) #define atomic_testandset_acq_long ATOMIC_SAN(testandset_acq_long) #define atomic_add_ptr ATOMIC_SAN(add_ptr) #define atomic_add_acq_ptr ATOMIC_SAN(add_acq_ptr) #define atomic_add_rel_ptr ATOMIC_SAN(add_rel_ptr) #define atomic_clear_ptr ATOMIC_SAN(clear_ptr) #define atomic_clear_acq_ptr ATOMIC_SAN(clear_acq_ptr) #define atomic_clear_rel_ptr ATOMIC_SAN(clear_rel_ptr) #define atomic_cmpset_ptr ATOMIC_SAN(cmpset_ptr) #define atomic_cmpset_acq_ptr ATOMIC_SAN(cmpset_acq_ptr) #define atomic_cmpset_rel_ptr ATOMIC_SAN(cmpset_rel_ptr) #define atomic_fcmpset_ptr ATOMIC_SAN(fcmpset_ptr) #define atomic_fcmpset_acq_ptr ATOMIC_SAN(fcmpset_acq_ptr) #define atomic_fcmpset_rel_ptr ATOMIC_SAN(fcmpset_rel_ptr) #define atomic_fetchadd_ptr ATOMIC_SAN(fetchadd_ptr) #define atomic_load_ptr(x) \ ((__typeof(*x))ATOMIC_SAN(load_ptr)( \ __DECONST(volatile uintptr_t *, (x)))) #define atomic_load_acq_ptr ATOMIC_SAN(load_acq_ptr) #define atomic_load_consume_ptr(x) \ ((__typeof(*x))atomic_load_acq_ptr((volatile uintptr_t *)(x))) #define atomic_readandclear_ptr ATOMIC_SAN(readandclear_ptr) #define atomic_set_ptr ATOMIC_SAN(set_ptr) #define atomic_set_acq_ptr ATOMIC_SAN(set_acq_ptr) #define atomic_set_rel_ptr ATOMIC_SAN(set_rel_ptr) #define atomic_subtract_ptr ATOMIC_SAN(subtract_ptr) #define atomic_subtract_acq_ptr ATOMIC_SAN(subtract_acq_ptr) #define atomic_subtract_rel_ptr ATOMIC_SAN(subtract_rel_ptr) #define atomic_store_ptr(x, v) ({ \ __typeof(*x) __value = (v); \ ATOMIC_SAN(store_ptr)((volatile uintptr_t *)(x), (uintptr_t)(__value));\ }) #define atomic_store_rel_ptr ATOMIC_SAN(store_rel_ptr) #define atomic_swap_ptr ATOMIC_SAN(swap_ptr) #define atomic_testandclear_ptr ATOMIC_SAN(testandclear_ptr) #define atomic_testandset_ptr ATOMIC_SAN(testandset_ptr) #define atomic_add_8 ATOMIC_SAN(add_8) #define atomic_add_acq_8 ATOMIC_SAN(add_acq_8) #define atomic_add_rel_8 ATOMIC_SAN(add_rel_8) #define atomic_clear_8 ATOMIC_SAN(clear_8) #define atomic_clear_acq_8 ATOMIC_SAN(clear_acq_8) #define atomic_clear_rel_8 ATOMIC_SAN(clear_rel_8) #define atomic_cmpset_8 ATOMIC_SAN(cmpset_8) #define atomic_cmpset_acq_8 ATOMIC_SAN(cmpset_acq_8) #define atomic_cmpset_rel_8 ATOMIC_SAN(cmpset_rel_8) #define atomic_fcmpset_8 ATOMIC_SAN(fcmpset_8) #define atomic_fcmpset_acq_8 ATOMIC_SAN(fcmpset_acq_8) #define atomic_fcmpset_rel_8 ATOMIC_SAN(fcmpset_rel_8) #define atomic_fetchadd_8 ATOMIC_SAN(fetchadd_8) #define atomic_load_8 ATOMIC_SAN(load_8) #define atomic_load_acq_8 ATOMIC_SAN(load_acq_8) #define atomic_readandclear_8 ATOMIC_SAN(readandclear_8) #define atomic_set_8 ATOMIC_SAN(set_8) #define atomic_set_acq_8 ATOMIC_SAN(set_acq_8) #define atomic_set_rel_8 ATOMIC_SAN(set_rel_8) #define atomic_subtract_8 ATOMIC_SAN(subtract_8) #define atomic_subtract_acq_8 ATOMIC_SAN(subtract_acq_8) #define atomic_subtract_rel_8 ATOMIC_SAN(subtract_rel_8) #define atomic_store_8 ATOMIC_SAN(store_8) #define atomic_store_rel_8 ATOMIC_SAN(store_rel_8) #define atomic_swap_8 ATOMIC_SAN(swap_8) #define atomic_testandclear_8 ATOMIC_SAN(testandclear_8) #define atomic_testandset_8 ATOMIC_SAN(testandset_8) #define atomic_add_16 ATOMIC_SAN(add_16) #define atomic_add_acq_16 ATOMIC_SAN(add_acq_16) #define atomic_add_rel_16 ATOMIC_SAN(add_rel_16) #define atomic_clear_16 ATOMIC_SAN(clear_16) #define atomic_clear_acq_16 ATOMIC_SAN(clear_acq_16) #define atomic_clear_rel_16 ATOMIC_SAN(clear_rel_16) #define atomic_cmpset_16 ATOMIC_SAN(cmpset_16) #define atomic_cmpset_acq_16 ATOMIC_SAN(cmpset_acq_16) #define atomic_cmpset_rel_16 ATOMIC_SAN(cmpset_rel_16) #define atomic_fcmpset_16 ATOMIC_SAN(fcmpset_16) #define atomic_fcmpset_acq_16 ATOMIC_SAN(fcmpset_acq_16) #define atomic_fcmpset_rel_16 ATOMIC_SAN(fcmpset_rel_16) #define atomic_fetchadd_16 ATOMIC_SAN(fetchadd_16) #define atomic_load_16 ATOMIC_SAN(load_16) #define atomic_load_acq_16 ATOMIC_SAN(load_acq_16) #define atomic_readandclear_16 ATOMIC_SAN(readandclear_16) #define atomic_set_16 ATOMIC_SAN(set_16) #define atomic_set_acq_16 ATOMIC_SAN(set_acq_16) #define atomic_set_rel_16 ATOMIC_SAN(set_rel_16) #define atomic_subtract_16 ATOMIC_SAN(subtract_16) #define atomic_subtract_acq_16 ATOMIC_SAN(subtract_acq_16) #define atomic_subtract_rel_16 ATOMIC_SAN(subtract_rel_16) #define atomic_store_16 ATOMIC_SAN(store_16) #define atomic_store_rel_16 ATOMIC_SAN(store_rel_16) #define atomic_swap_16 ATOMIC_SAN(swap_16) #define atomic_testandclear_16 ATOMIC_SAN(testandclear_16) #define atomic_testandset_16 ATOMIC_SAN(testandset_16) #define atomic_add_32 ATOMIC_SAN(add_32) #define atomic_add_acq_32 ATOMIC_SAN(add_acq_32) #define atomic_add_rel_32 ATOMIC_SAN(add_rel_32) #define atomic_clear_32 ATOMIC_SAN(clear_32) #define atomic_clear_acq_32 ATOMIC_SAN(clear_acq_32) #define atomic_clear_rel_32 ATOMIC_SAN(clear_rel_32) #define atomic_cmpset_32 ATOMIC_SAN(cmpset_32) #define atomic_cmpset_acq_32 ATOMIC_SAN(cmpset_acq_32) #define atomic_cmpset_rel_32 ATOMIC_SAN(cmpset_rel_32) #define atomic_fcmpset_32 ATOMIC_SAN(fcmpset_32) #define atomic_fcmpset_acq_32 ATOMIC_SAN(fcmpset_acq_32) #define atomic_fcmpset_rel_32 ATOMIC_SAN(fcmpset_rel_32) #define atomic_fetchadd_32 ATOMIC_SAN(fetchadd_32) #define atomic_load_32 ATOMIC_SAN(load_32) #define atomic_load_acq_32 ATOMIC_SAN(load_acq_32) #define atomic_readandclear_32 ATOMIC_SAN(readandclear_32) #define atomic_set_32 ATOMIC_SAN(set_32) #define atomic_set_acq_32 ATOMIC_SAN(set_acq_32) #define atomic_set_rel_32 ATOMIC_SAN(set_rel_32) #define atomic_subtract_32 ATOMIC_SAN(subtract_32) #define atomic_subtract_acq_32 ATOMIC_SAN(subtract_acq_32) #define atomic_subtract_rel_32 ATOMIC_SAN(subtract_rel_32) #define atomic_store_32 ATOMIC_SAN(store_32) #define atomic_store_rel_32 ATOMIC_SAN(store_rel_32) #define atomic_swap_32 ATOMIC_SAN(swap_32) #define atomic_testandclear_32 ATOMIC_SAN(testandclear_32) #define atomic_testandset_32 ATOMIC_SAN(testandset_32) #define atomic_add_64 ATOMIC_SAN(add_64) #define atomic_add_acq_64 ATOMIC_SAN(add_acq_64) #define atomic_add_rel_64 ATOMIC_SAN(add_rel_64) #define atomic_clear_64 ATOMIC_SAN(clear_64) #define atomic_clear_acq_64 ATOMIC_SAN(clear_acq_64) #define atomic_clear_rel_64 ATOMIC_SAN(clear_rel_64) #define atomic_cmpset_64 ATOMIC_SAN(cmpset_64) #define atomic_cmpset_acq_64 ATOMIC_SAN(cmpset_acq_64) #define atomic_cmpset_rel_64 ATOMIC_SAN(cmpset_rel_64) #define atomic_fcmpset_64 ATOMIC_SAN(fcmpset_64) #define atomic_fcmpset_acq_64 ATOMIC_SAN(fcmpset_acq_64) #define atomic_fcmpset_rel_64 ATOMIC_SAN(fcmpset_rel_64) #define atomic_fetchadd_64 ATOMIC_SAN(fetchadd_64) #define atomic_load_64 ATOMIC_SAN(load_64) #define atomic_load_acq_64 ATOMIC_SAN(load_acq_64) #define atomic_readandclear_64 ATOMIC_SAN(readandclear_64) #define atomic_set_64 ATOMIC_SAN(set_64) #define atomic_set_acq_64 ATOMIC_SAN(set_acq_64) #define atomic_set_rel_64 ATOMIC_SAN(set_rel_64) #define atomic_subtract_64 ATOMIC_SAN(subtract_64) #define atomic_subtract_acq_64 ATOMIC_SAN(subtract_acq_64) #define atomic_subtract_rel_64 ATOMIC_SAN(subtract_rel_64) #define atomic_store_64 ATOMIC_SAN(store_64) #define atomic_store_rel_64 ATOMIC_SAN(store_rel_64) #define atomic_swap_64 ATOMIC_SAN(swap_64) #define atomic_testandclear_64 ATOMIC_SAN(testandclear_64) #define atomic_testandset_64 ATOMIC_SAN(testandset_64) #define atomic_thread_fence_acq ATOMIC_SAN(thread_fence_acq) #define atomic_thread_fence_acq_rel ATOMIC_SAN(thread_fence_acq_rel) #define atomic_thread_fence_rel ATOMIC_SAN(thread_fence_rel) #define atomic_thread_fence_seq_cst ATOMIC_SAN(thread_fence_seq_cst) #define atomic_interrupt_fence ATOMIC_SAN(interrupt_fence) #endif /* !SAN_RUNTIME */ #endif /* !_SYS_ATOMIC_SAN_H_ */