Module Name: src Committed By: maxv Date: Tue Nov 5 20:19:18 UTC 2019
Modified Files: src/share/mk: bsd.sys.mk src/sys/arch/amd64/amd64: machdep.c mptramp.S src/sys/arch/amd64/conf: GENERIC Makefile.amd64 src/sys/arch/x86/x86: cpu.c src/sys/conf: files src/sys/kern: files.kern src/sys/lib/libkern: libkern.h src/sys/sys: atomic.h bus_proto.h cdefs.h systm.h Added Files: src/sys/arch/amd64/include: csan.h src/sys/kern: subr_csan.c src/sys/sys: csan.h Log Message: Add Kernel Concurrency Sanitizer (kCSan) support. This sanitizer allows us to detect race conditions at runtime. It is a variation of TSan that is easy to implement and more suited to kernel internals, albeit theoretically less precise than TSan's happens-before. We do basically two things: - On every KCSAN_NACCESSES (=2000) memory accesses, we create a cell describing the access, and delay the calling CPU (10ms). - On all memory accesses, we verify if the memory we're reading/writing is referenced in a cell already. The combination of the two means that, if for example cpu0 does a read that is selected and cpu1 does a write at the same address, kCSan will fire, because cpu1's write collides with cpu0's read cell. The coverage of the instrumentation is the same as that of kASan. Also, the code is organized in a way similar to kASan, so it is easy to add support for more architectures than amd64. kCSan is compatible with KCOV. Reviewed by Kamil. To generate a diff of this commit: cvs rdiff -u -r1.294 -r1.295 src/share/mk/bsd.sys.mk cvs rdiff -u -r1.337 -r1.338 src/sys/arch/amd64/amd64/machdep.c cvs rdiff -u -r1.26 -r1.27 src/sys/arch/amd64/amd64/mptramp.S cvs rdiff -u -r1.544 -r1.545 src/sys/arch/amd64/conf/GENERIC cvs rdiff -u -r1.78 -r1.79 src/sys/arch/amd64/conf/Makefile.amd64 cvs rdiff -u -r0 -r1.1 src/sys/arch/amd64/include/csan.h cvs rdiff -u -r1.173 -r1.174 src/sys/arch/x86/x86/cpu.c cvs rdiff -u -r1.1240 -r1.1241 src/sys/conf/files cvs rdiff -u -r1.35 -r1.36 src/sys/kern/files.kern cvs rdiff -u -r0 -r1.1 src/sys/kern/subr_csan.c cvs rdiff -u -r1.132 -r1.133 src/sys/lib/libkern/libkern.h cvs rdiff -u -r1.15 -r1.16 src/sys/sys/atomic.h cvs rdiff -u -r1.9 -r1.10 src/sys/sys/bus_proto.h cvs rdiff -u -r1.147 -r1.148 src/sys/sys/cdefs.h cvs rdiff -u -r0 -r1.1 src/sys/sys/csan.h cvs rdiff -u -r1.287 -r1.288 src/sys/sys/systm.h Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/share/mk/bsd.sys.mk diff -u src/share/mk/bsd.sys.mk:1.294 src/share/mk/bsd.sys.mk:1.295 --- src/share/mk/bsd.sys.mk:1.294 Tue Oct 15 15:05:00 2019 +++ src/share/mk/bsd.sys.mk Tue Nov 5 20:19:17 2019 @@ -1,4 +1,4 @@ -# $NetBSD: bsd.sys.mk,v 1.294 2019/10/15 15:05:00 christos Exp $ +# $NetBSD: bsd.sys.mk,v 1.295 2019/11/05 20:19:17 maxv Exp $ # # Build definitions used for NetBSD source tree builds. @@ -246,7 +246,8 @@ CFLAGS+= ${KLEAKFLAGS.${.IMPSRC:T}:U${KL .if ${KCOV:U0} > 0 KCOVFLAGS= -fsanitize-coverage=trace-pc -.for f in subr_kcov.c subr_lwp_specificdata.c subr_specificdata.c subr_asan.c +.for f in subr_kcov.c subr_lwp_specificdata.c subr_specificdata.c subr_asan.c \ + subr_csan.c KCOVFLAGS.${f}= # empty .endfor CFLAGS+= ${KCOVFLAGS.${.IMPSRC:T}:U${KCOVFLAGS}} Index: src/sys/arch/amd64/amd64/machdep.c diff -u src/sys/arch/amd64/amd64/machdep.c:1.337 src/sys/arch/amd64/amd64/machdep.c:1.338 --- src/sys/arch/amd64/amd64/machdep.c:1.337 Sat Oct 12 06:31:03 2019 +++ src/sys/arch/amd64/amd64/machdep.c Tue Nov 5 20:19:17 2019 @@ -1,4 +1,4 @@ -/* $NetBSD: machdep.c,v 1.337 2019/10/12 06:31:03 maxv Exp $ */ +/* $NetBSD: machdep.c,v 1.338 2019/11/05 20:19:17 maxv Exp $ */ /* * Copyright (c) 1996, 1997, 1998, 2000, 2006, 2007, 2008, 2011 @@ -110,7 +110,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: machdep.c,v 1.337 2019/10/12 06:31:03 maxv Exp $"); +__KERNEL_RCSID(0, "$NetBSD: machdep.c,v 1.338 2019/11/05 20:19:17 maxv Exp $"); #include "opt_modular.h" #include "opt_user_ldt.h" @@ -152,6 +152,7 @@ __KERNEL_RCSID(0, "$NetBSD: machdep.c,v #include <sys/lwp.h> #include <sys/proc.h> #include <sys/asan.h> +#include <sys/csan.h> #ifdef KGDB #include <sys/kgdb.h> @@ -1761,6 +1762,7 @@ init_x86_64(paddr_t first_avail) #ifdef KASAN kasan_init(); #endif + kcsan_init(); pmap_growkernel(VM_MIN_KERNEL_ADDRESS + 32 * 1024 * 1024); Index: src/sys/arch/amd64/amd64/mptramp.S diff -u src/sys/arch/amd64/amd64/mptramp.S:1.26 src/sys/arch/amd64/amd64/mptramp.S:1.27 --- src/sys/arch/amd64/amd64/mptramp.S:1.26 Sun Nov 26 14:54:43 2017 +++ src/sys/arch/amd64/amd64/mptramp.S Tue Nov 5 20:19:17 2019 @@ -1,4 +1,4 @@ -/* $NetBSD: mptramp.S,v 1.26 2017/11/26 14:54:43 maxv Exp $ */ +/* $NetBSD: mptramp.S,v 1.27 2019/11/05 20:19:17 maxv Exp $ */ /* * Copyright (c) 2000, 2016 The NetBSD Foundation, Inc. @@ -75,6 +75,7 @@ */ #include "assym.h" +#include "opt_kcsan.h" #include <machine/asm.h> #include <machine/specialreg.h> #include <machine/segments.h> @@ -244,6 +245,18 @@ _C_LABEL(cpu_spinup_trampoline_end): /* movl PCB_CR0(%rsi),%eax movq %rax,%cr0 +#ifdef KCSAN + /* + * The C instrumentation uses GS.base, so initialize it right now. It + * gets re-initialized later, that's fine. + */ + movl $MSR_GSBASE,%ecx + movq %rdi,%rax + movq %rdi,%rdx + shrq $32,%rdx + wrmsr +#endif + call _C_LABEL(cpu_hatch) END(cpu_spinup_trampoline) Index: src/sys/arch/amd64/conf/GENERIC diff -u src/sys/arch/amd64/conf/GENERIC:1.544 src/sys/arch/amd64/conf/GENERIC:1.545 --- src/sys/arch/amd64/conf/GENERIC:1.544 Fri Nov 1 02:53:23 2019 +++ src/sys/arch/amd64/conf/GENERIC Tue Nov 5 20:19:17 2019 @@ -1,4 +1,4 @@ -# $NetBSD: GENERIC,v 1.544 2019/11/01 02:53:23 msaitoh Exp $ +# $NetBSD: GENERIC,v 1.545 2019/11/05 20:19:17 maxv Exp $ # # GENERIC machine description file # @@ -22,7 +22,7 @@ include "arch/amd64/conf/std.amd64" options INCLUDE_CONFIG_FILE # embed config file in kernel binary -#ident "GENERIC-$Revision: 1.544 $" +#ident "GENERIC-$Revision: 1.545 $" maxusers 64 # estimated number of users @@ -128,6 +128,11 @@ options KDTRACE_HOOKS # kernel DTrace h #options POOL_QUARANTINE # optional #options KASAN_PANIC # optional +# Kernel Concurrency Sanitizer (kCSan). +#makeoptions KCSAN=1 # mandatory +#options KCSAN # mandatory +#options KCSAN_PANIC # optional + # Kernel Info Leak Detector. #makeoptions KLEAK=1 #options KLEAK Index: src/sys/arch/amd64/conf/Makefile.amd64 diff -u src/sys/arch/amd64/conf/Makefile.amd64:1.78 src/sys/arch/amd64/conf/Makefile.amd64:1.79 --- src/sys/arch/amd64/conf/Makefile.amd64:1.78 Sat Sep 7 18:56:01 2019 +++ src/sys/arch/amd64/conf/Makefile.amd64 Tue Nov 5 20:19:17 2019 @@ -1,4 +1,4 @@ -# $NetBSD: Makefile.amd64,v 1.78 2019/09/07 18:56:01 maxv Exp $ +# $NetBSD: Makefile.amd64,v 1.79 2019/11/05 20:19:17 maxv Exp $ # Makefile for NetBSD # @@ -60,6 +60,15 @@ KASANFLAGS.${f}= # empty CFLAGS+= ${KASANFLAGS.${.IMPSRC:T}:U${KASANFLAGS}} .endif +.if ${KCSAN:U0} > 0 && ${HAVE_GCC:U0} > 0 +KCSANFLAGS= -fsanitize=thread +.for f in subr_csan.c clock.c lapic.c subr_kcov.c subr_lwp_specificdata.c \ + subr_specificdata.c +KCSANFLAGS.${f}= # empty +.endfor +CFLAGS+= ${KCSANFLAGS.${.IMPSRC:T}:U${KCSANFLAGS}} +.endif + ## ## (3) libkern and compat ## Index: src/sys/arch/x86/x86/cpu.c diff -u src/sys/arch/x86/x86/cpu.c:1.173 src/sys/arch/x86/x86/cpu.c:1.174 --- src/sys/arch/x86/x86/cpu.c:1.173 Sat Oct 12 06:31:04 2019 +++ src/sys/arch/x86/x86/cpu.c Tue Nov 5 20:19:17 2019 @@ -1,4 +1,4 @@ -/* $NetBSD: cpu.c,v 1.173 2019/10/12 06:31:04 maxv Exp $ */ +/* $NetBSD: cpu.c,v 1.174 2019/11/05 20:19:17 maxv Exp $ */ /* * Copyright (c) 2000-2012 NetBSD Foundation, Inc. @@ -62,7 +62,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: cpu.c,v 1.173 2019/10/12 06:31:04 maxv Exp $"); +__KERNEL_RCSID(0, "$NetBSD: cpu.c,v 1.174 2019/11/05 20:19:17 maxv Exp $"); #include "opt_ddb.h" #include "opt_mpbios.h" /* for MPDEBUG */ @@ -82,6 +82,7 @@ __KERNEL_RCSID(0, "$NetBSD: cpu.c,v 1.17 #include <sys/idle.h> #include <sys/atomic.h> #include <sys/reboot.h> +#include <sys/csan.h> #include <uvm/uvm.h> @@ -429,6 +430,7 @@ cpu_attach(device_t parent, device_t sel #endif /* Make sure DELAY() is initialized. */ DELAY(1); + kcsan_cpu_init(ci); again = true; } @@ -961,6 +963,8 @@ cpu_hatch(void *v) aprint_debug_dev(ci->ci_dev, "running\n"); + kcsan_cpu_init(ci); + idle_loop(NULL); KASSERT(false); } Index: src/sys/conf/files diff -u src/sys/conf/files:1.1240 src/sys/conf/files:1.1241 --- src/sys/conf/files:1.1240 Sun Sep 22 22:59:38 2019 +++ src/sys/conf/files Tue Nov 5 20:19:17 2019 @@ -1,4 +1,4 @@ -# $NetBSD: files,v 1.1240 2019/09/22 22:59:38 christos Exp $ +# $NetBSD: files,v 1.1241 2019/11/05 20:19:17 maxv Exp $ # @(#)files.newconf 7.5 (Berkeley) 5/10/93 version 20171118 @@ -31,6 +31,8 @@ defflag opt_diagnostic.h _DIAGNOSTIC defflag GPROF defflag KASAN defflag opt_kasan.h KASAN_PANIC +defflag KCSAN +defflag opt_kcsan.h KCSAN_PANIC defflag KLEAK defflag KCOV defflag opt_pool.h POOL_QUARANTINE Index: src/sys/kern/files.kern diff -u src/sys/kern/files.kern:1.35 src/sys/kern/files.kern:1.36 --- src/sys/kern/files.kern:1.35 Thu Aug 15 12:24:08 2019 +++ src/sys/kern/files.kern Tue Nov 5 20:19:17 2019 @@ -1,4 +1,4 @@ -# $NetBSD: files.kern,v 1.35 2019/08/15 12:24:08 maxv Exp $ +# $NetBSD: files.kern,v 1.36 2019/11/05 20:19:17 maxv Exp $ # # kernel sources @@ -105,6 +105,7 @@ file kern/subr_callback.c kern file kern/subr_cprng.c kern file kern/subr_cpufreq.c kern file kern/subr_copy.c kern +file kern/subr_csan.c kcsan file kern/subr_debug.c debug file kern/subr_device.c kern file kern/subr_devsw.c kern Index: src/sys/lib/libkern/libkern.h diff -u src/sys/lib/libkern/libkern.h:1.132 src/sys/lib/libkern/libkern.h:1.133 --- src/sys/lib/libkern/libkern.h:1.132 Fri Sep 20 13:38:00 2019 +++ src/sys/lib/libkern/libkern.h Tue Nov 5 20:19:18 2019 @@ -1,4 +1,4 @@ -/* $NetBSD: libkern.h,v 1.132 2019/09/20 13:38:00 maxv Exp $ */ +/* $NetBSD: libkern.h,v 1.133 2019/11/05 20:19:18 maxv Exp $ */ /*- * Copyright (c) 1992, 1993 @@ -37,6 +37,7 @@ #ifdef _KERNEL_OPT #include "opt_diagnostic.h" #include "opt_kasan.h" +#include "opt_kcsan.h" #endif #include <sys/types.h> @@ -376,11 +377,18 @@ void *kasan_memset(void *, int, size_t); #define memcpy(d, s, l) kasan_memcpy(d, s, l) #define memcmp(a, b, l) kasan_memcmp(a, b, l) #define memset(d, v, l) kasan_memset(d, v, l) +#elif defined(_KERNEL) && defined(KCSAN) +void *kcsan_memcpy(void *, const void *, size_t); +int kcsan_memcmp(const void *, const void *, size_t); +void *kcsan_memset(void *, int, size_t); +#define memcpy(d, s, l) kcsan_memcpy(d, s, l) +#define memcmp(a, b, l) kcsan_memcmp(a, b, l) +#define memset(d, v, l) kcsan_memset(d, v, l) #else #define memcpy(d, s, l) __builtin_memcpy(d, s, l) #define memcmp(a, b, l) __builtin_memcmp(a, b, l) #define memset(d, v, l) __builtin_memset(d, v, l) -#endif /* _KERNEL && KASAN */ +#endif #endif char *strcpy(char *, const char *); @@ -396,11 +404,18 @@ size_t kasan_strlen(const char *); #define strcpy(d, s) kasan_strcpy(d, s) #define strcmp(a, b) kasan_strcmp(a, b) #define strlen(a) kasan_strlen(a) +#elif defined(_KERNEL) && defined(KCSAN) +char *kcsan_strcpy(char *, const char *); +int kcsan_strcmp(const char *, const char *); +size_t kcsan_strlen(const char *); +#define strcpy(d, s) kcsan_strcpy(d, s) +#define strcmp(a, b) kcsan_strcmp(a, b) +#define strlen(a) kcsan_strlen(a) #else #define strcpy(d, s) __builtin_strcpy(d, s) #define strcmp(a, b) __builtin_strcmp(a, b) #define strlen(a) __builtin_strlen(a) -#endif /* _KERNEL && KASAN */ +#endif #endif /* Functions for which we always use built-ins. */ @@ -442,6 +457,9 @@ void *memmove(void *, const void *, size #if defined(_KERNEL) && defined(KASAN) void *kasan_memmove(void *, const void *, size_t); #define memmove(d, s, l) kasan_memmove(d, s, l) +#elif defined(_KERNEL) && defined(KCSAN) +void *kcsan_memmove(void *, const void *, size_t); +#define memmove(d, s, l) kcsan_memmove(d, s, l) #endif int pmatch(const char *, const char *, const char **); Index: src/sys/sys/atomic.h diff -u src/sys/sys/atomic.h:1.15 src/sys/sys/atomic.h:1.16 --- src/sys/sys/atomic.h:1.15 Wed Sep 11 14:56:25 2019 +++ src/sys/sys/atomic.h Tue Nov 5 20:19:18 2019 @@ -1,4 +1,4 @@ -/* $NetBSD: atomic.h,v 1.15 2019/09/11 14:56:25 christos Exp $ */ +/* $NetBSD: atomic.h,v 1.16 2019/11/05 20:19:18 maxv Exp $ */ /*- * Copyright (c) 2007, 2008 The NetBSD Foundation, Inc. @@ -39,6 +39,7 @@ #if defined(_KERNEL) && defined(_KERNEL_OPT) #include "opt_kasan.h" +#include "opt_kcsan.h" #endif #if defined(KASAN) @@ -62,6 +63,27 @@ #define ATOMIC_PROTO_INC(name, tret, targ1) \ void kasan_atomic_inc_##name(volatile targ1 *); \ tret kasan_atomic_inc_##name##_nv(volatile targ1 *) +#elif defined(KCSAN) +#define ATOMIC_PROTO_ADD(name, tret, targ1, targ2) \ + void kcsan_atomic_add_##name(volatile targ1 *, targ2); \ + tret kcsan_atomic_add_##name##_nv(volatile targ1 *, targ2) +#define ATOMIC_PROTO_AND(name, tret, targ1, targ2) \ + void kcsan_atomic_and_##name(volatile targ1 *, targ2); \ + tret kcsan_atomic_and_##name##_nv(volatile targ1 *, targ2) +#define ATOMIC_PROTO_OR(name, tret, targ1, targ2) \ + void kcsan_atomic_or_##name(volatile targ1 *, targ2); \ + tret kcsan_atomic_or_##name##_nv(volatile targ1 *, targ2) +#define ATOMIC_PROTO_CAS(name, tret, targ1, targ2) \ + tret kcsan_atomic_cas_##name(volatile targ1 *, targ2, targ2); \ + tret kcsan_atomic_cas_##name##_ni(volatile targ1 *, targ2, targ2) +#define ATOMIC_PROTO_SWAP(name, tret, targ1, targ2) \ + tret kcsan_atomic_swap_##name(volatile targ1 *, targ2) +#define ATOMIC_PROTO_DEC(name, tret, targ1) \ + void kcsan_atomic_dec_##name(volatile targ1 *); \ + tret kcsan_atomic_dec_##name##_nv(volatile targ1 *) +#define ATOMIC_PROTO_INC(name, tret, targ1) \ + void kcsan_atomic_inc_##name(volatile targ1 *); \ + tret kcsan_atomic_inc_##name##_nv(volatile targ1 *) #else #define ATOMIC_PROTO_ADD(name, tret, targ1, targ2) \ void atomic_add_##name(volatile targ1 *, targ2); \ @@ -213,6 +235,68 @@ __END_DECLS #define atomic_inc_ulong_nv kasan_atomic_inc_ulong_nv #define atomic_inc_ptr_nv kasan_atomic_inc_ptr_nv #define atomic_inc_64_nv kasan_atomic_inc_64_nv +#elif defined(KCSAN) +#define atomic_add_32 kcsan_atomic_add_32 +#define atomic_add_int kcsan_atomic_add_int +#define atomic_add_long kcsan_atomic_add_long +#define atomic_add_ptr kcsan_atomic_add_ptr +#define atomic_add_64 kcsan_atomic_add_64 +#define atomic_add_32_nv kcsan_atomic_add_32_nv +#define atomic_add_int_nv kcsan_atomic_add_int_nv +#define atomic_add_long_nv kcsan_atomic_add_long_nv +#define atomic_add_ptr_nv kcsan_atomic_add_ptr_nv +#define atomic_add_64_nv kcsan_atomic_add_64_nv +#define atomic_and_32 kcsan_atomic_and_32 +#define atomic_and_uint kcsan_atomic_and_uint +#define atomic_and_ulong kcsan_atomic_and_ulong +#define atomic_and_64 kcsan_atomic_and_64 +#define atomic_and_32_nv kcsan_atomic_and_32_nv +#define atomic_and_uint_nv kcsan_atomic_and_uint_nv +#define atomic_and_ulong_nv kcsan_atomic_and_ulong_nv +#define atomic_and_64_nv kcsan_atomic_and_64_nv +#define atomic_or_32 kcsan_atomic_or_32 +#define atomic_or_uint kcsan_atomic_or_uint +#define atomic_or_ulong kcsan_atomic_or_ulong +#define atomic_or_64 kcsan_atomic_or_64 +#define atomic_or_32_nv kcsan_atomic_or_32_nv +#define atomic_or_uint_nv kcsan_atomic_or_uint_nv +#define atomic_or_ulong_nv kcsan_atomic_or_ulong_nv +#define atomic_or_64_nv kcsan_atomic_or_64_nv +#define atomic_cas_32 kcsan_atomic_cas_32 +#define atomic_cas_uint kcsan_atomic_cas_uint +#define atomic_cas_ulong kcsan_atomic_cas_ulong +#define atomic_cas_ptr kcsan_atomic_cas_ptr +#define atomic_cas_64 kcsan_atomic_cas_64 +#define atomic_cas_32_ni kcsan_atomic_cas_32_ni +#define atomic_cas_uint_ni kcsan_atomic_cas_uint_ni +#define atomic_cas_ulong_ni kcsan_atomic_cas_ulong_ni +#define atomic_cas_ptr_ni kcsan_atomic_cas_ptr_ni +#define atomic_cas_64_ni kcsan_atomic_cas_64_ni +#define atomic_swap_32 kcsan_atomic_swap_32 +#define atomic_swap_uint kcsan_atomic_swap_uint +#define atomic_swap_ulong kcsan_atomic_swap_ulong +#define atomic_swap_ptr kcsan_atomic_swap_ptr +#define atomic_swap_64 kcsan_atomic_swap_64 +#define atomic_dec_32 kcsan_atomic_dec_32 +#define atomic_dec_uint kcsan_atomic_dec_uint +#define atomic_dec_ulong kcsan_atomic_dec_ulong +#define atomic_dec_ptr kcsan_atomic_dec_ptr +#define atomic_dec_64 kcsan_atomic_dec_64 +#define atomic_dec_32_nv kcsan_atomic_dec_32_nv +#define atomic_dec_uint_nv kcsan_atomic_dec_uint_nv +#define atomic_dec_ulong_nv kcsan_atomic_dec_ulong_nv +#define atomic_dec_ptr_nv kcsan_atomic_dec_ptr_nv +#define atomic_dec_64_nv kcsan_atomic_dec_64_nv +#define atomic_inc_32 kcsan_atomic_inc_32 +#define atomic_inc_uint kcsan_atomic_inc_uint +#define atomic_inc_ulong kcsan_atomic_inc_ulong +#define atomic_inc_ptr kcsan_atomic_inc_ptr +#define atomic_inc_64 kcsan_atomic_inc_64 +#define atomic_inc_32_nv kcsan_atomic_inc_32_nv +#define atomic_inc_uint_nv kcsan_atomic_inc_uint_nv +#define atomic_inc_ulong_nv kcsan_atomic_inc_ulong_nv +#define atomic_inc_ptr_nv kcsan_atomic_inc_ptr_nv +#define atomic_inc_64_nv kcsan_atomic_inc_64_nv #endif #endif /* ! _SYS_ATOMIC_H_ */ Index: src/sys/sys/bus_proto.h diff -u src/sys/sys/bus_proto.h:1.9 src/sys/sys/bus_proto.h:1.10 --- src/sys/sys/bus_proto.h:1.9 Sun Sep 22 10:35:12 2019 +++ src/sys/sys/bus_proto.h Tue Nov 5 20:19:18 2019 @@ -1,4 +1,4 @@ -/* $NetBSD: bus_proto.h,v 1.9 2019/09/22 10:35:12 maxv Exp $ */ +/* $NetBSD: bus_proto.h,v 1.10 2019/11/05 20:19:18 maxv Exp $ */ /*- * Copyright (c) 1996, 1997, 1998, 2001, 2007 The NetBSD Foundation, Inc. @@ -66,6 +66,7 @@ #ifdef _KERNEL_OPT #include "opt_kasan.h" +#include "opt_kcsan.h" #endif /* @@ -158,6 +159,32 @@ void kasan_bus_space_read_region_stream_ #define bus_space_read_region_stream_2 kasan_bus_space_read_region_stream_2 #define bus_space_read_region_stream_4 kasan_bus_space_read_region_stream_4 #define bus_space_read_region_stream_8 kasan_bus_space_read_region_stream_8 +#elif defined(KCSAN) +#define BUS_SPACE_READ_MEM_PROTOS(bytes, bits) \ +void kcsan_bus_space_read_multi_##bytes(bus_space_tag_t, bus_space_handle_t, \ + bus_size_t, uint##bits##_t *, bus_size_t); \ +void kcsan_bus_space_read_multi_stream_##bytes(bus_space_tag_t, \ + bus_space_handle_t, bus_size_t, uint##bits##_t *, bus_size_t); \ +void kcsan_bus_space_read_region_##bytes(bus_space_tag_t, bus_space_handle_t, \ + bus_size_t, uint##bits##_t *, bus_size_t); \ +void kcsan_bus_space_read_region_stream_##bytes(bus_space_tag_t, \ + bus_space_handle_t, bus_size_t, uint##bits##_t *, bus_size_t); +#define bus_space_read_multi_1 kcsan_bus_space_read_multi_1 +#define bus_space_read_multi_2 kcsan_bus_space_read_multi_2 +#define bus_space_read_multi_4 kcsan_bus_space_read_multi_4 +#define bus_space_read_multi_8 kcsan_bus_space_read_multi_8 +#define bus_space_read_multi_stream_1 kcsan_bus_space_read_multi_stream_1 +#define bus_space_read_multi_stream_2 kcsan_bus_space_read_multi_stream_2 +#define bus_space_read_multi_stream_4 kcsan_bus_space_read_multi_stream_4 +#define bus_space_read_multi_stream_8 kcsan_bus_space_read_multi_stream_8 +#define bus_space_read_region_1 kcsan_bus_space_read_region_1 +#define bus_space_read_region_2 kcsan_bus_space_read_region_2 +#define bus_space_read_region_4 kcsan_bus_space_read_region_4 +#define bus_space_read_region_8 kcsan_bus_space_read_region_8 +#define bus_space_read_region_stream_1 kcsan_bus_space_read_region_stream_1 +#define bus_space_read_region_stream_2 kcsan_bus_space_read_region_stream_2 +#define bus_space_read_region_stream_4 kcsan_bus_space_read_region_stream_4 +#define bus_space_read_region_stream_8 kcsan_bus_space_read_region_stream_8 #else #define BUS_SPACE_READ_MEM_PROTOS(bytes, bits) \ void bus_space_read_multi_##bytes(bus_space_tag_t, bus_space_handle_t, \ @@ -221,6 +248,32 @@ void kasan_bus_space_write_region_stream #define bus_space_write_region_stream_2 kasan_bus_space_write_region_stream_2 #define bus_space_write_region_stream_4 kasan_bus_space_write_region_stream_4 #define bus_space_write_region_stream_8 kasan_bus_space_write_region_stream_8 +#elif defined(KCSAN) +#define BUS_SPACE_WRITE_MEM_PROTOS(bytes, bits) \ +void kcsan_bus_space_write_multi_##bytes(bus_space_tag_t, bus_space_handle_t, \ + bus_size_t, const uint##bits##_t *, bus_size_t); \ +void kcsan_bus_space_write_multi_stream_##bytes(bus_space_tag_t, \ + bus_space_handle_t, bus_size_t, const uint##bits##_t *, bus_size_t); \ +void kcsan_bus_space_write_region_##bytes(bus_space_tag_t, bus_space_handle_t, \ + bus_size_t, const uint##bits##_t *, bus_size_t); \ +void kcsan_bus_space_write_region_stream_##bytes(bus_space_tag_t, \ + bus_space_handle_t, bus_size_t, const uint##bits##_t *, bus_size_t); +#define bus_space_write_multi_1 kcsan_bus_space_write_multi_1 +#define bus_space_write_multi_2 kcsan_bus_space_write_multi_2 +#define bus_space_write_multi_4 kcsan_bus_space_write_multi_4 +#define bus_space_write_multi_8 kcsan_bus_space_write_multi_8 +#define bus_space_write_multi_stream_1 kcsan_bus_space_write_multi_stream_1 +#define bus_space_write_multi_stream_2 kcsan_bus_space_write_multi_stream_2 +#define bus_space_write_multi_stream_4 kcsan_bus_space_write_multi_stream_4 +#define bus_space_write_multi_stream_8 kcsan_bus_space_write_multi_stream_8 +#define bus_space_write_region_1 kcsan_bus_space_write_region_1 +#define bus_space_write_region_2 kcsan_bus_space_write_region_2 +#define bus_space_write_region_4 kcsan_bus_space_write_region_4 +#define bus_space_write_region_8 kcsan_bus_space_write_region_8 +#define bus_space_write_region_stream_1 kcsan_bus_space_write_region_stream_1 +#define bus_space_write_region_stream_2 kcsan_bus_space_write_region_stream_2 +#define bus_space_write_region_stream_4 kcsan_bus_space_write_region_stream_4 +#define bus_space_write_region_stream_8 kcsan_bus_space_write_region_stream_8 #else #define BUS_SPACE_WRITE_MEM_PROTOS(bytes, bits) \ void bus_space_write_multi_##bytes(bus_space_tag_t, bus_space_handle_t, \ Index: src/sys/sys/cdefs.h diff -u src/sys/sys/cdefs.h:1.147 src/sys/sys/cdefs.h:1.148 --- src/sys/sys/cdefs.h:1.147 Wed Oct 16 18:29:49 2019 +++ src/sys/sys/cdefs.h Tue Nov 5 20:19:18 2019 @@ -1,4 +1,4 @@ -/* $NetBSD: cdefs.h,v 1.147 2019/10/16 18:29:49 christos Exp $ */ +/* $NetBSD: cdefs.h,v 1.148 2019/11/05 20:19:18 maxv Exp $ */ /* * Copyright (c) 1991, 1993 * The Regents of the University of California. All rights reserved. @@ -39,6 +39,7 @@ #ifdef _KERNEL_OPT #include "opt_diagnostic.h" #include "opt_kasan.h" +#include "opt_kcsan.h" #endif /* @@ -341,6 +342,12 @@ #define __noasan /* nothing */ #endif +#if __GNUC_PREREQ__(4, 9) && defined(KCSAN) +#define __nocsan __attribute__((no_sanitize_thread)) +#else +#define __nocsan /* nothing */ +#endif + #if defined(__clang__) #define __noubsan __attribute__((no_sanitize("undefined"))) #elif __GNUC_PREREQ__(4, 9) Index: src/sys/sys/systm.h diff -u src/sys/sys/systm.h:1.287 src/sys/sys/systm.h:1.288 --- src/sys/sys/systm.h:1.287 Thu Oct 10 13:45:14 2019 +++ src/sys/sys/systm.h Tue Nov 5 20:19:18 2019 @@ -1,4 +1,4 @@ -/* $NetBSD: systm.h,v 1.287 2019/10/10 13:45:14 maxv Exp $ */ +/* $NetBSD: systm.h,v 1.288 2019/11/05 20:19:18 maxv Exp $ */ /*- * Copyright (c) 1982, 1988, 1991, 1993 @@ -44,6 +44,7 @@ #include "opt_multiprocessor.h" #include "opt_gprof.h" #include "opt_kasan.h" +#include "opt_kcsan.h" #include "opt_kleak.h" #include "opt_wsdisplay_compat.h" #endif @@ -267,6 +268,9 @@ void tablefull(const char *, const char #if defined(_KERNEL) && defined(KASAN) int kasan_kcopy(const void *, void *, size_t); #define kcopy kasan_kcopy +#elif defined(_KERNEL) && defined(KCSAN) +int kcsan_kcopy(const void *, void *, size_t); +#define kcopy kcsan_kcopy #else int kcopy(const void *, void *, size_t); #endif @@ -286,6 +290,15 @@ int kasan_copyin(const void *, void *, s #define copyinstr kasan_copyinstr #define copyoutstr kasan_copyoutstr #define copyin kasan_copyin +#elif defined(_KERNEL) && defined(KCSAN) +int kcsan_copystr(const void *, void *, size_t, size_t *); +int kcsan_copyinstr(const void *, void *, size_t, size_t *); +int kcsan_copyoutstr(const void *, void *, size_t, size_t *); +int kcsan_copyin(const void *, void *, size_t); +#define copystr kcsan_copystr +#define copyinstr kcsan_copyinstr +#define copyoutstr kcsan_copyoutstr +#define copyin kcsan_copyin #else int copystr(const void *, void *, size_t, size_t *); int copyinstr(const void *, void *, size_t, size_t *); Added files: Index: src/sys/arch/amd64/include/csan.h diff -u /dev/null src/sys/arch/amd64/include/csan.h:1.1 --- /dev/null Tue Nov 5 20:19:18 2019 +++ src/sys/arch/amd64/include/csan.h Tue Nov 5 20:19:17 2019 @@ -0,0 +1,119 @@ +/* $NetBSD: csan.h,v 1.1 2019/11/05 20:19:17 maxv Exp $ */ + +/* + * Copyright (c) 2019 The NetBSD Foundation, Inc. + * All rights reserved. + * + * 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. + */ + +#include <sys/ksyms.h> +#include <x86/cpufunc.h> + +static inline bool +kcsan_md_is_avail(void) +{ + return (x86_read_psl() & PSL_I) == 0; +} + +static inline void +kcsan_md_disable_intrs(uint64_t *state) +{ + *state = x86_read_psl(); + x86_disable_intr(); +} + +static inline void +kcsan_md_enable_intrs(uint64_t *state) +{ + x86_write_psl(*state); +} + +static inline void +kcsan_md_delay(uint64_t us) +{ + DELAY(us); +} + +static inline bool +__md_unwind_end(const char *name) +{ + if (!strcmp(name, "syscall") || + !strcmp(name, "alltraps") || + !strcmp(name, "handle_syscall") || + !strncmp(name, "Xtrap", 5) || + !strncmp(name, "Xintr", 5) || + !strncmp(name, "Xhandle", 7) || + !strncmp(name, "Xresume", 7) || + !strncmp(name, "Xstray", 6) || + !strncmp(name, "Xhold", 5) || + !strncmp(name, "Xrecurse", 8) || + !strcmp(name, "Xdoreti") || + !strncmp(name, "Xsoft", 5)) { + return true; + } + + return false; +} + +static void +kcsan_md_unwind(void) +{ + uint64_t *rbp, rip; + const char *mod; + const char *sym; + size_t nsym; + int error; + + rbp = (uint64_t *)__builtin_frame_address(0); + nsym = 0; + + while (1) { + /* 8(%rbp) contains the saved %rip. */ + rip = *(rbp + 1); + + if (rip < KERNBASE) { + break; + } + error = ksyms_getname(&mod, &sym, (vaddr_t)rip, KSYMS_PROC); + if (error) { + break; + } + printf("#%zu %p in %s <%s>\n", nsym, (void *)rip, sym, mod); + if (__md_unwind_end(sym)) { + break; + } + + rbp = (uint64_t *)*(rbp); + if (rbp == 0) { + break; + } + nsym++; + + if (nsym >= 15) { + break; + } + } +} Index: src/sys/kern/subr_csan.c diff -u /dev/null src/sys/kern/subr_csan.c:1.1 --- /dev/null Tue Nov 5 20:19:18 2019 +++ src/sys/kern/subr_csan.c Tue Nov 5 20:19:17 2019 @@ -0,0 +1,744 @@ +/* $NetBSD: subr_csan.c,v 1.1 2019/11/05 20:19:17 maxv Exp $ */ + +/* + * Copyright (c) 2019 The NetBSD Foundation, Inc. + * All rights reserved. + * + * 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. + */ + +#include <sys/cdefs.h> +__KERNEL_RCSID(0, "$NetBSD: subr_csan.c,v 1.1 2019/11/05 20:19:17 maxv Exp $"); + +#include "opt_kcsan.h" + +#include <sys/param.h> +#include <sys/device.h> +#include <sys/kernel.h> +#include <sys/param.h> +#include <sys/conf.h> +#include <sys/systm.h> +#include <sys/types.h> +#include <sys/csan.h> +#include <sys/cpu.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[MAXCPUS]; +static bool kcsan_enabled __read_mostly; + +#define __RET_ADDR (uintptr_t)__builtin_return_address(0) + +#define KCSAN_NACCESSES 2000 +#define KCSAN_DELAY 10000 /* 10 milliseconds */ + +/* -------------------------------------------------------------------------- */ + +/* The MD code. */ +#include <machine/csan.h> + +/* -------------------------------------------------------------------------- */ + +void +kcsan_init(void) +{ + kcsan_enabled = true; +} + +void +kcsan_cpu_init(struct cpu_info *ci) +{ + kcsan_cpus[cpu_index(ci)].inited = true; +} + +/* -------------------------------------------------------------------------- */ + +static inline void +kcsan_report(csan_cell_t *new, cpuid_t newcpu, csan_cell_t *old, cpuid_t oldcpu) +{ + const char *newsym, *oldsym; + + if (ksyms_getname(NULL, &newsym, (vaddr_t)new->pc, KSYMS_PROC) != 0) { + newsym = "Unknown"; + } + if (ksyms_getname(NULL, &oldsym, (vaddr_t)old->pc, KSYMS_PROC) != 0) { + oldsym = "Unknown"; + } + REPORT("CSan: Racy Access " + "[Cpu%lu %s%s Addr=%p Size=%u PC=%p<%s>] " + "[Cpu%lu %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; + + new.addr = addr; + new.size = size; + new.write = write; + new.atomic = atomic; + new.pc = pc; + + for (i = 0; i < ncpu; 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, cpu_number(), &old, i); + break; + } + + if (__predict_false(!kcsan_md_is_avail())) + return; + + kcsan_md_disable_intrs(&intr); + + cpu = &kcsan_cpus[cpu_number()]; + 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); \ + } + +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); \ + } + +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); +} + +#undef kcopy +#undef copystr +#undef copyinstr +#undef copyoutstr +#undef copyin + +int kcsan_kcopy(const void *, void *, size_t); +int kcsan_copystr(const void *, void *, size_t, size_t *); +int kcsan_copyinstr(const void *, void *, size_t, size_t *); +int kcsan_copyoutstr(const void *, void *, size_t, size_t *); +int kcsan_copyin(const void *, void *, size_t); +int kcopy(const void *, void *, size_t); +int copystr(const void *, void *, size_t, size_t *); +int copyinstr(const void *, void *, size_t, size_t *); +int copyoutstr(const void *, void *, size_t, size_t *); +int copyin(const void *, void *, size_t); + +int +kcsan_kcopy(const void *src, void *dst, size_t len) +{ + kcsan_access((uintptr_t)src, len, false, false, __RET_ADDR); + kcsan_access((uintptr_t)dst, len, true, false, __RET_ADDR); + return kcopy(src, dst, len); +} + +int +kcsan_copystr(const void *kfaddr, void *kdaddr, size_t len, size_t *done) +{ + kcsan_access((uintptr_t)kdaddr, len, true, false, __RET_ADDR); + return copystr(kfaddr, kdaddr, len, done); +} + +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_copyoutstr(const void *kaddr, void *uaddr, size_t len, size_t *done) +{ + kcsan_access((uintptr_t)kaddr, len, false, false, __RET_ADDR); + return copyoutstr(kaddr, uaddr, len, done); +} + +/* -------------------------------------------------------------------------- */ + +#undef atomic_add_32 +#undef atomic_add_int +#undef atomic_add_long +#undef atomic_add_ptr +#undef atomic_add_64 +#undef atomic_add_32_nv +#undef atomic_add_int_nv +#undef atomic_add_long_nv +#undef atomic_add_ptr_nv +#undef atomic_add_64_nv +#undef atomic_and_32 +#undef atomic_and_uint +#undef atomic_and_ulong +#undef atomic_and_64 +#undef atomic_and_32_nv +#undef atomic_and_uint_nv +#undef atomic_and_ulong_nv +#undef atomic_and_64_nv +#undef atomic_or_32 +#undef atomic_or_uint +#undef atomic_or_ulong +#undef atomic_or_64 +#undef atomic_or_32_nv +#undef atomic_or_uint_nv +#undef atomic_or_ulong_nv +#undef atomic_or_64_nv +#undef atomic_cas_32 +#undef atomic_cas_uint +#undef atomic_cas_ulong +#undef atomic_cas_ptr +#undef atomic_cas_64 +#undef atomic_cas_32_ni +#undef atomic_cas_uint_ni +#undef atomic_cas_ulong_ni +#undef atomic_cas_ptr_ni +#undef atomic_cas_64_ni +#undef atomic_swap_32 +#undef atomic_swap_uint +#undef atomic_swap_ulong +#undef atomic_swap_ptr +#undef atomic_swap_64 +#undef atomic_dec_32 +#undef atomic_dec_uint +#undef atomic_dec_ulong +#undef atomic_dec_ptr +#undef atomic_dec_64 +#undef atomic_dec_32_nv +#undef atomic_dec_uint_nv +#undef atomic_dec_ulong_nv +#undef atomic_dec_ptr_nv +#undef atomic_dec_64_nv +#undef atomic_inc_32 +#undef atomic_inc_uint +#undef atomic_inc_ulong +#undef atomic_inc_ptr +#undef atomic_inc_64 +#undef atomic_inc_32_nv +#undef atomic_inc_uint_nv +#undef atomic_inc_ulong_nv +#undef atomic_inc_ptr_nv +#undef atomic_inc_64_nv + +#define CSAN_ATOMIC_FUNC_ADD(name, tret, targ1, targ2) \ + void atomic_add_##name(volatile targ1 *, targ2); \ + void kcsan_atomic_add_##name(volatile targ1 *, targ2); \ + void kcsan_atomic_add_##name(volatile targ1 *ptr, targ2 val) \ + { \ + kcsan_access((uintptr_t)ptr, sizeof(tret), true, true, \ + __RET_ADDR); \ + atomic_add_##name(ptr, val); \ + } \ + tret atomic_add_##name##_nv(volatile targ1 *, targ2); \ + tret kcsan_atomic_add_##name##_nv(volatile targ1 *, targ2); \ + tret kcsan_atomic_add_##name##_nv(volatile targ1 *ptr, targ2 val) \ + { \ + kcsan_access((uintptr_t)ptr, sizeof(tret), true, true, \ + __RET_ADDR); \ + return atomic_add_##name##_nv(ptr, val); \ + } + +#define CSAN_ATOMIC_FUNC_AND(name, tret, targ1, targ2) \ + void atomic_and_##name(volatile targ1 *, targ2); \ + void kcsan_atomic_and_##name(volatile targ1 *, targ2); \ + void kcsan_atomic_and_##name(volatile targ1 *ptr, targ2 val) \ + { \ + kcsan_access((uintptr_t)ptr, sizeof(tret), true, true, \ + __RET_ADDR); \ + atomic_and_##name(ptr, val); \ + } \ + tret atomic_and_##name##_nv(volatile targ1 *, targ2); \ + tret kcsan_atomic_and_##name##_nv(volatile targ1 *, targ2); \ + tret kcsan_atomic_and_##name##_nv(volatile targ1 *ptr, targ2 val) \ + { \ + kcsan_access((uintptr_t)ptr, sizeof(tret), true, true, \ + __RET_ADDR); \ + return atomic_and_##name##_nv(ptr, val); \ + } + +#define CSAN_ATOMIC_FUNC_OR(name, tret, targ1, targ2) \ + void atomic_or_##name(volatile targ1 *, targ2); \ + void kcsan_atomic_or_##name(volatile targ1 *, targ2); \ + void kcsan_atomic_or_##name(volatile targ1 *ptr, targ2 val) \ + { \ + kcsan_access((uintptr_t)ptr, sizeof(tret), true, true, \ + __RET_ADDR); \ + atomic_or_##name(ptr, val); \ + } \ + tret atomic_or_##name##_nv(volatile targ1 *, targ2); \ + tret kcsan_atomic_or_##name##_nv(volatile targ1 *, targ2); \ + tret kcsan_atomic_or_##name##_nv(volatile targ1 *ptr, targ2 val) \ + { \ + kcsan_access((uintptr_t)ptr, sizeof(tret), true, true, \ + __RET_ADDR); \ + return atomic_or_##name##_nv(ptr, val); \ + } + +#define CSAN_ATOMIC_FUNC_CAS(name, tret, targ1, targ2) \ + tret atomic_cas_##name(volatile targ1 *, targ2, targ2); \ + tret kcsan_atomic_cas_##name(volatile targ1 *, targ2, targ2); \ + tret kcsan_atomic_cas_##name(volatile targ1 *ptr, targ2 exp, targ2 new) \ + { \ + kcsan_access((uintptr_t)ptr, sizeof(tret), true, true, \ + __RET_ADDR); \ + return atomic_cas_##name(ptr, exp, new); \ + } \ + tret atomic_cas_##name##_ni(volatile targ1 *, targ2, targ2); \ + tret kcsan_atomic_cas_##name##_ni(volatile targ1 *, targ2, targ2); \ + tret kcsan_atomic_cas_##name##_ni(volatile targ1 *ptr, targ2 exp, targ2 new) \ + { \ + kcsan_access((uintptr_t)ptr, sizeof(tret), true, true, \ + __RET_ADDR); \ + return atomic_cas_##name##_ni(ptr, exp, new); \ + } + +#define CSAN_ATOMIC_FUNC_SWAP(name, tret, targ1, targ2) \ + tret atomic_swap_##name(volatile targ1 *, targ2); \ + tret kcsan_atomic_swap_##name(volatile targ1 *, targ2); \ + tret kcsan_atomic_swap_##name(volatile targ1 *ptr, targ2 val) \ + { \ + kcsan_access((uintptr_t)ptr, sizeof(tret), true, true, \ + __RET_ADDR); \ + return atomic_swap_##name(ptr, val); \ + } + +#define CSAN_ATOMIC_FUNC_DEC(name, tret, targ1) \ + void atomic_dec_##name(volatile targ1 *); \ + void kcsan_atomic_dec_##name(volatile targ1 *); \ + void kcsan_atomic_dec_##name(volatile targ1 *ptr) \ + { \ + kcsan_access((uintptr_t)ptr, sizeof(tret), true, true, \ + __RET_ADDR); \ + atomic_dec_##name(ptr); \ + } \ + tret atomic_dec_##name##_nv(volatile targ1 *); \ + tret kcsan_atomic_dec_##name##_nv(volatile targ1 *); \ + tret kcsan_atomic_dec_##name##_nv(volatile targ1 *ptr) \ + { \ + kcsan_access((uintptr_t)ptr, sizeof(tret), true, true, \ + __RET_ADDR); \ + return atomic_dec_##name##_nv(ptr); \ + } + +#define CSAN_ATOMIC_FUNC_INC(name, tret, targ1) \ + void atomic_inc_##name(volatile targ1 *); \ + void kcsan_atomic_inc_##name(volatile targ1 *); \ + void kcsan_atomic_inc_##name(volatile targ1 *ptr) \ + { \ + kcsan_access((uintptr_t)ptr, sizeof(tret), true, true, \ + __RET_ADDR); \ + atomic_inc_##name(ptr); \ + } \ + tret atomic_inc_##name##_nv(volatile targ1 *); \ + tret kcsan_atomic_inc_##name##_nv(volatile targ1 *); \ + tret kcsan_atomic_inc_##name##_nv(volatile targ1 *ptr) \ + { \ + kcsan_access((uintptr_t)ptr, sizeof(tret), true, true, \ + __RET_ADDR); \ + return atomic_inc_##name##_nv(ptr); \ + } + +CSAN_ATOMIC_FUNC_ADD(32, uint32_t, uint32_t, int32_t); +CSAN_ATOMIC_FUNC_ADD(64, uint64_t, uint64_t, int64_t); +CSAN_ATOMIC_FUNC_ADD(int, unsigned int, unsigned int, int); +CSAN_ATOMIC_FUNC_ADD(long, unsigned long, unsigned long, long); +CSAN_ATOMIC_FUNC_ADD(ptr, void *, void, ssize_t); + +CSAN_ATOMIC_FUNC_AND(32, uint32_t, uint32_t, uint32_t); +CSAN_ATOMIC_FUNC_AND(64, uint64_t, uint64_t, uint64_t); +CSAN_ATOMIC_FUNC_AND(uint, unsigned int, unsigned int, unsigned int); +CSAN_ATOMIC_FUNC_AND(ulong, unsigned long, unsigned long, unsigned long); + +CSAN_ATOMIC_FUNC_OR(32, uint32_t, uint32_t, uint32_t); +CSAN_ATOMIC_FUNC_OR(64, uint64_t, uint64_t, uint64_t); +CSAN_ATOMIC_FUNC_OR(uint, unsigned int, unsigned int, unsigned int); +CSAN_ATOMIC_FUNC_OR(ulong, unsigned long, unsigned long, unsigned long); + +CSAN_ATOMIC_FUNC_CAS(32, uint32_t, uint32_t, uint32_t); +CSAN_ATOMIC_FUNC_CAS(64, uint64_t, uint64_t, uint64_t); +CSAN_ATOMIC_FUNC_CAS(uint, unsigned int, unsigned int, unsigned int); +CSAN_ATOMIC_FUNC_CAS(ulong, unsigned long, unsigned long, unsigned long); +CSAN_ATOMIC_FUNC_CAS(ptr, void *, void, void *); + +CSAN_ATOMIC_FUNC_SWAP(32, uint32_t, uint32_t, uint32_t); +CSAN_ATOMIC_FUNC_SWAP(64, uint64_t, uint64_t, uint64_t); +CSAN_ATOMIC_FUNC_SWAP(uint, unsigned int, unsigned int, unsigned int); +CSAN_ATOMIC_FUNC_SWAP(ulong, unsigned long, unsigned long, unsigned long); +CSAN_ATOMIC_FUNC_SWAP(ptr, void *, void, void *); + +CSAN_ATOMIC_FUNC_DEC(32, uint32_t, uint32_t) +CSAN_ATOMIC_FUNC_DEC(64, uint64_t, uint64_t) +CSAN_ATOMIC_FUNC_DEC(uint, unsigned int, unsigned int); +CSAN_ATOMIC_FUNC_DEC(ulong, unsigned long, unsigned long); +CSAN_ATOMIC_FUNC_DEC(ptr, void *, void); + +CSAN_ATOMIC_FUNC_INC(32, uint32_t, uint32_t) +CSAN_ATOMIC_FUNC_INC(64, uint64_t, uint64_t) +CSAN_ATOMIC_FUNC_INC(uint, unsigned int, unsigned int); +CSAN_ATOMIC_FUNC_INC(ulong, unsigned long, unsigned long); +CSAN_ATOMIC_FUNC_INC(ptr, void *, void); + +/* -------------------------------------------------------------------------- */ + +#include <sys/bus.h> + +#undef bus_space_read_multi_1 +#undef bus_space_read_multi_2 +#undef bus_space_read_multi_4 +#undef bus_space_read_multi_8 +#undef bus_space_read_multi_stream_1 +#undef bus_space_read_multi_stream_2 +#undef bus_space_read_multi_stream_4 +#undef bus_space_read_multi_stream_8 +#undef bus_space_read_region_1 +#undef bus_space_read_region_2 +#undef bus_space_read_region_4 +#undef bus_space_read_region_8 +#undef bus_space_read_region_stream_1 +#undef bus_space_read_region_stream_2 +#undef bus_space_read_region_stream_4 +#undef bus_space_read_region_stream_8 +#undef bus_space_write_multi_1 +#undef bus_space_write_multi_2 +#undef bus_space_write_multi_4 +#undef bus_space_write_multi_8 +#undef bus_space_write_multi_stream_1 +#undef bus_space_write_multi_stream_2 +#undef bus_space_write_multi_stream_4 +#undef bus_space_write_multi_stream_8 +#undef bus_space_write_region_1 +#undef bus_space_write_region_2 +#undef bus_space_write_region_4 +#undef bus_space_write_region_8 +#undef bus_space_write_region_stream_1 +#undef bus_space_write_region_stream_2 +#undef bus_space_write_region_stream_4 +#undef bus_space_write_region_stream_8 + +#define CSAN_BUS_READ_FUNC(bytes, bits) \ + void bus_space_read_multi_##bytes(bus_space_tag_t, bus_space_handle_t, \ + bus_size_t, uint##bits##_t *, bus_size_t); \ + void kcsan_bus_space_read_multi_##bytes(bus_space_tag_t, \ + bus_space_handle_t, bus_size_t, uint##bits##_t *, bus_size_t); \ + void kcsan_bus_space_read_multi_##bytes(bus_space_tag_t tag, \ + bus_space_handle_t hnd, bus_size_t size, uint##bits##_t *buf, \ + bus_size_t count) \ + { \ + kcsan_access((uintptr_t)buf, sizeof(uint##bits##_t) * count, \ + false, false, __RET_ADDR); \ + bus_space_read_multi_##bytes(tag, hnd, size, buf, count); \ + } \ + void bus_space_read_multi_stream_##bytes(bus_space_tag_t, \ + bus_space_handle_t, bus_size_t, uint##bits##_t *, bus_size_t); \ + void kcsan_bus_space_read_multi_stream_##bytes(bus_space_tag_t, \ + bus_space_handle_t, bus_size_t, uint##bits##_t *, bus_size_t); \ + void kcsan_bus_space_read_multi_stream_##bytes(bus_space_tag_t tag, \ + bus_space_handle_t hnd, bus_size_t size, uint##bits##_t *buf, \ + bus_size_t count) \ + { \ + kcsan_access((uintptr_t)buf, sizeof(uint##bits##_t) * count, \ + false, false, __RET_ADDR); \ + bus_space_read_multi_stream_##bytes(tag, hnd, size, buf, count);\ + } \ + void bus_space_read_region_##bytes(bus_space_tag_t, bus_space_handle_t, \ + bus_size_t, uint##bits##_t *, bus_size_t); \ + void kcsan_bus_space_read_region_##bytes(bus_space_tag_t, \ + bus_space_handle_t, bus_size_t, uint##bits##_t *, bus_size_t); \ + void kcsan_bus_space_read_region_##bytes(bus_space_tag_t tag, \ + bus_space_handle_t hnd, bus_size_t size, uint##bits##_t *buf, \ + bus_size_t count) \ + { \ + kcsan_access((uintptr_t)buf, sizeof(uint##bits##_t) * count, \ + false, false, __RET_ADDR); \ + bus_space_read_region_##bytes(tag, hnd, size, buf, count); \ + } \ + void bus_space_read_region_stream_##bytes(bus_space_tag_t, \ + bus_space_handle_t, bus_size_t, uint##bits##_t *, bus_size_t); \ + void kcsan_bus_space_read_region_stream_##bytes(bus_space_tag_t, \ + bus_space_handle_t, bus_size_t, uint##bits##_t *, bus_size_t); \ + void kcsan_bus_space_read_region_stream_##bytes(bus_space_tag_t tag, \ + bus_space_handle_t hnd, bus_size_t size, uint##bits##_t *buf, \ + bus_size_t count) \ + { \ + kcsan_access((uintptr_t)buf, sizeof(uint##bits##_t) * count, \ + false, false, __RET_ADDR); \ + bus_space_read_region_stream_##bytes(tag, hnd, size, buf, count);\ + } + +#define CSAN_BUS_WRITE_FUNC(bytes, bits) \ + void bus_space_write_multi_##bytes(bus_space_tag_t, bus_space_handle_t, \ + bus_size_t, const uint##bits##_t *, bus_size_t); \ + void kcsan_bus_space_write_multi_##bytes(bus_space_tag_t, \ + bus_space_handle_t, bus_size_t, const uint##bits##_t *, bus_size_t);\ + void kcsan_bus_space_write_multi_##bytes(bus_space_tag_t tag, \ + bus_space_handle_t hnd, bus_size_t size, const uint##bits##_t *buf, \ + bus_size_t count) \ + { \ + kcsan_access((uintptr_t)buf, sizeof(uint##bits##_t) * count, \ + true, false, __RET_ADDR); \ + bus_space_write_multi_##bytes(tag, hnd, size, buf, count); \ + } \ + void bus_space_write_multi_stream_##bytes(bus_space_tag_t, \ + bus_space_handle_t, bus_size_t, const uint##bits##_t *, bus_size_t);\ + void kcsan_bus_space_write_multi_stream_##bytes(bus_space_tag_t, \ + bus_space_handle_t, bus_size_t, const uint##bits##_t *, bus_size_t);\ + void kcsan_bus_space_write_multi_stream_##bytes(bus_space_tag_t tag, \ + bus_space_handle_t hnd, bus_size_t size, const uint##bits##_t *buf, \ + bus_size_t count) \ + { \ + kcsan_access((uintptr_t)buf, sizeof(uint##bits##_t) * count, \ + true, false, __RET_ADDR); \ + bus_space_write_multi_stream_##bytes(tag, hnd, size, buf, count);\ + } \ + void bus_space_write_region_##bytes(bus_space_tag_t, bus_space_handle_t,\ + bus_size_t, const uint##bits##_t *, bus_size_t); \ + void kcsan_bus_space_write_region_##bytes(bus_space_tag_t, \ + bus_space_handle_t, bus_size_t, const uint##bits##_t *, bus_size_t);\ + void kcsan_bus_space_write_region_##bytes(bus_space_tag_t tag, \ + bus_space_handle_t hnd, bus_size_t size, const uint##bits##_t *buf, \ + bus_size_t count) \ + { \ + kcsan_access((uintptr_t)buf, sizeof(uint##bits##_t) * count, \ + true, false, __RET_ADDR); \ + bus_space_write_region_##bytes(tag, hnd, size, buf, count); \ + } \ + void bus_space_write_region_stream_##bytes(bus_space_tag_t, \ + bus_space_handle_t, bus_size_t, const uint##bits##_t *, bus_size_t);\ + void kcsan_bus_space_write_region_stream_##bytes(bus_space_tag_t, \ + bus_space_handle_t, bus_size_t, const uint##bits##_t *, bus_size_t);\ + void kcsan_bus_space_write_region_stream_##bytes(bus_space_tag_t tag, \ + bus_space_handle_t hnd, bus_size_t size, const uint##bits##_t *buf, \ + bus_size_t count) \ + { \ + kcsan_access((uintptr_t)buf, sizeof(uint##bits##_t) * count, \ + true, false, __RET_ADDR); \ + bus_space_write_region_stream_##bytes(tag, hnd, size, buf, count);\ + } + +CSAN_BUS_READ_FUNC(1, 8) +CSAN_BUS_READ_FUNC(2, 16) +CSAN_BUS_READ_FUNC(4, 32) +CSAN_BUS_READ_FUNC(8, 64) + +CSAN_BUS_WRITE_FUNC(1, 8) +CSAN_BUS_WRITE_FUNC(2, 16) +CSAN_BUS_WRITE_FUNC(4, 32) +CSAN_BUS_WRITE_FUNC(8, 64) Index: src/sys/sys/csan.h diff -u /dev/null src/sys/sys/csan.h:1.1 --- /dev/null Tue Nov 5 20:19:18 2019 +++ src/sys/sys/csan.h Tue Nov 5 20:19:18 2019 @@ -0,0 +1,49 @@ +/* $NetBSD: csan.h,v 1.1 2019/11/05 20:19:18 maxv Exp $ */ + +/* + * Copyright (c) 2019 The NetBSD Foundation, Inc. + * All rights reserved. + * + * 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. + */ + +#ifndef _SYS_CSAN_H_ +#define _SYS_CSAN_H_ + +#ifdef _KERNEL_OPT +#include "opt_kcsan.h" +#endif + +#include <sys/types.h> + +#ifdef KCSAN +void kcsan_init(void); +void kcsan_cpu_init(struct cpu_info *); +#else +#define kcsan_init() __nothing +#define kcsan_cpu_init(ci) __nothing +#endif + +#endif /* !_SYS_CSAN_H_ */