a90d053b84
KASAN and KCSAN implement interceptors for various primitive operations that are not instrumented by the compiler. KMSAN requires them as well. Rather than adding new cases for each sanitizer which requires interceptors, implement the following protocol: - When interceptor definitions are required, define SAN_NEEDS_INTERCEPTORS and SANITIZER_INTERCEPTOR_PREFIX. - In headers that declare functions which need to be intercepted by a sanitizer runtime, use SANITIZER_INTERCEPTOR_PREFIX to provide declarations. - When SAN_RUNTIME is defined, do not redefine the names of intercepted functions. This is typically the case in files which implement sanitizer runtimes but is also needed in, for example, files which define ifunc selectors for intercepted operations. MFC after: 2 weeks Sponsored by: The FreeBSD Foundation
911 lines
25 KiB
C
911 lines
25 KiB
C
/* $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 <sys/cdefs.h>
|
|
__FBSDID("$FreeBSD$");
|
|
|
|
#include <sys/param.h>
|
|
#include <sys/kernel.h>
|
|
#include <sys/bus.h>
|
|
#include <sys/conf.h>
|
|
#include <sys/cpu.h>
|
|
#include <sys/csan.h>
|
|
#include <sys/proc.h>
|
|
#include <sys/smp.h>
|
|
#include <sys/systm.h>
|
|
|
|
#include <ddb/ddb.h>
|
|
#include <ddb/db_sym.h>
|
|
|
|
#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 <machine/csan.h>
|
|
|
|
/* -------------------------------------------------------------------------- */
|
|
|
|
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);
|
|
}
|
|
|
|
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 <machine/atomic.h>
|
|
#include <sys/atomic_san.h>
|
|
|
|
#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) \
|
|
{ \
|
|
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_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)
|
|
#if !defined(__aarch64__)
|
|
CSAN_ATOMIC_FUNC_TESTANDCLEAR(32, uint32_t)
|
|
CSAN_ATOMIC_FUNC_TESTANDSET(32, uint32_t)
|
|
#endif
|
|
|
|
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)
|
|
#if !defined(__aarch64__)
|
|
CSAN_ATOMIC_FUNC_TESTANDCLEAR(64, uint64_t)
|
|
CSAN_ATOMIC_FUNC_TESTANDSET(64, uint64_t)
|
|
#endif
|
|
|
|
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)
|
|
#if !defined(__aarch64__)
|
|
CSAN_ATOMIC_FUNC_TESTANDCLEAR(int, u_int)
|
|
CSAN_ATOMIC_FUNC_TESTANDSET(int, u_int)
|
|
#endif
|
|
|
|
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)
|
|
#if !defined(__aarch64__)
|
|
CSAN_ATOMIC_FUNC_TESTANDCLEAR(long, u_long)
|
|
CSAN_ATOMIC_FUNC_TESTANDSET(long, u_long)
|
|
CSAN_ATOMIC_FUNC_TESTANDSET(acq_long, u_long)
|
|
#endif
|
|
|
|
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)
|
|
#if 0
|
|
CSAN_ATOMIC_FUNC_TESTANDCLEAR(ptr, uintptr_t)
|
|
CSAN_ATOMIC_FUNC_TESTANDSET(ptr, uintptr_t)
|
|
#endif
|
|
|
|
#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 <sys/bus.h>
|
|
#include <machine/bus.h>
|
|
#include <sys/bus_san.h>
|
|
|
|
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
|