svn commit: r354942 - in head/sys: amd64/amd64 amd64/conf amd64/include arm64/arm64 arm64/conf arm64/include conf kern libkern modules sys x86/include x86/x86
Andrew Turner
andrew at FreeBSD.org
Thu Nov 21 11:22:12 UTC 2019
Author: andrew
Date: Thu Nov 21 11:22:08 2019
New Revision: 354942
URL: https://svnweb.freebsd.org/changeset/base/354942
Log:
Port the NetBSD KCSAN runtime to FreeBSD.
Update the NetBSD Kernel Concurrency Sanitizer (KCSAN) runtime to work in
the FreeBSD kernel. It is a useful tool for finding data races between
threads executing on different CPUs.
This can be enabled by enabling KCSAN in the kernel config, or by using the
GENERIC-KCSAN amd64 kernel. It works on amd64 and arm64, however the later
needs a compiler change to allow -fsanitize=thread that KCSAN uses.
Sponsored by: DARPA, AFRL
Differential Revision: https://reviews.freebsd.org/D22315
Added:
head/sys/amd64/conf/GENERIC-KCSAN (contents, props changed)
head/sys/amd64/include/csan.h (contents, props changed)
head/sys/arm64/include/csan.h (contents, props changed)
head/sys/sys/_cscan_atomic.h (contents, props changed)
head/sys/sys/_cscan_bus.h (contents, props changed)
Modified:
head/sys/amd64/amd64/copyout.c
head/sys/amd64/amd64/machdep.c
head/sys/amd64/conf/GENERIC
head/sys/amd64/include/atomic.h
head/sys/arm64/arm64/bus_machdep.c
head/sys/arm64/arm64/copystr.c
head/sys/arm64/arm64/machdep.c
head/sys/arm64/arm64/mp_machdep.c
head/sys/arm64/conf/GENERIC
head/sys/arm64/include/atomic.h
head/sys/arm64/include/bus.h
head/sys/conf/files
head/sys/conf/files.arm64
head/sys/conf/kern.post.mk
head/sys/conf/kern.pre.mk
head/sys/conf/options
head/sys/kern/subr_csan.c (contents, props changed)
head/sys/kern/vfs_aio.c
head/sys/libkern/strcmp.c
head/sys/libkern/strcpy.c
head/sys/libkern/strlen.c
head/sys/modules/Makefile
head/sys/sys/csan.h (contents, props changed)
head/sys/sys/libkern.h
head/sys/sys/systm.h
head/sys/x86/include/bus.h
head/sys/x86/x86/bus_machdep.c
head/sys/x86/x86/mp_x86.c
Modified: head/sys/amd64/amd64/copyout.c
==============================================================================
--- head/sys/amd64/amd64/copyout.c Thu Nov 21 08:20:05 2019 (r354941)
+++ head/sys/amd64/amd64/copyout.c Thu Nov 21 11:22:08 2019 (r354942)
@@ -146,6 +146,10 @@ DEFINE_IFUNC(, int, casueword, (volatile u_long *, u_l
casueword_smap : casueword_nosmap);
}
+#undef copyinstr
+#undef copyin
+#undef copyout
+
int copyinstr_nosmap(const void *udaddr, void *kaddr, size_t len,
size_t *lencopied);
int copyinstr_smap(const void *udaddr, void *kaddr, size_t len,
Modified: head/sys/amd64/amd64/machdep.c
==============================================================================
--- head/sys/amd64/amd64/machdep.c Thu Nov 21 08:20:05 2019 (r354941)
+++ head/sys/amd64/amd64/machdep.c Thu Nov 21 11:22:08 2019 (r354942)
@@ -64,6 +64,7 @@ __FBSDID("$FreeBSD$");
#include <sys/callout.h>
#include <sys/cons.h>
#include <sys/cpu.h>
+#include <sys/csan.h>
#include <sys/efi.h>
#include <sys/eventhandler.h>
#include <sys/exec.h>
@@ -1899,6 +1900,8 @@ hammer_time(u_int64_t modulep, u_int64_t physfree)
cpu_probe_amdc1e();
+ kcsan_cpu_init(0);
+
#ifdef FDT
x86_init_fdt();
#endif
@@ -2722,6 +2725,40 @@ outb_(u_short port, u_char data)
void *memset_std(void *buf, int c, size_t len);
void *memset_erms(void *buf, int c, size_t len);
+void *memmove_std(void * _Nonnull dst, const void * _Nonnull src,
+ size_t len);
+void *memmove_erms(void * _Nonnull dst, const void * _Nonnull src,
+ size_t len);
+void *memcpy_std(void * _Nonnull dst, const void * _Nonnull src,
+ size_t len);
+void *memcpy_erms(void * _Nonnull dst, const void * _Nonnull src,
+ size_t len);
+
+#ifdef KCSAN
+/*
+ * These fail to build as ifuncs when used with KCSAN.
+ */
+void *
+memset(void *buf, int c, size_t len)
+{
+
+ return memset_std(buf, c, len);
+}
+
+void *
+memmove(void * _Nonnull dst, const void * _Nonnull src, size_t len)
+{
+
+ return memmove_std(dst, src, len);
+}
+
+void *
+memcpy(void * _Nonnull dst, const void * _Nonnull src, size_t len)
+{
+
+ return memcpy_std(dst, src, len);
+}
+#else
DEFINE_IFUNC(, void *, memset, (void *, int, size_t))
{
@@ -2729,10 +2766,6 @@ DEFINE_IFUNC(, void *, memset, (void *, int, size_t))
memset_erms : memset_std);
}
-void *memmove_std(void * _Nonnull dst, const void * _Nonnull src,
- size_t len);
-void *memmove_erms(void * _Nonnull dst, const void * _Nonnull src,
- size_t len);
DEFINE_IFUNC(, void *, memmove, (void * _Nonnull, const void * _Nonnull,
size_t))
{
@@ -2741,16 +2774,13 @@ DEFINE_IFUNC(, void *, memmove, (void * _Nonnull, cons
memmove_erms : memmove_std);
}
-void *memcpy_std(void * _Nonnull dst, const void * _Nonnull src,
- size_t len);
-void *memcpy_erms(void * _Nonnull dst, const void * _Nonnull src,
- size_t len);
DEFINE_IFUNC(, void *, memcpy, (void * _Nonnull, const void * _Nonnull,size_t))
{
return ((cpu_stdext_feature & CPUID_STDEXT_ERMS) != 0 ?
memcpy_erms : memcpy_std);
}
+#endif
void pagezero_std(void *addr);
void pagezero_erms(void *addr);
Modified: head/sys/amd64/conf/GENERIC
==============================================================================
--- head/sys/amd64/conf/GENERIC Thu Nov 21 08:20:05 2019 (r354941)
+++ head/sys/amd64/conf/GENERIC Thu Nov 21 11:22:08 2019 (r354942)
@@ -106,6 +106,7 @@ options VERBOSE_SYSINIT=0 # Support debug.verbose_sys
#options KCOV # Kernel Coverage Sanitizer
# Warning: KUBSAN can result in a kernel too large for loader to load
#options KUBSAN # Kernel Undefined Behavior Sanitizer
+#options KCSAN # Kernel Concurrency Sanitizer
# Kernel dump features.
options EKCD # Support for encrypted kernel dumps
Added: head/sys/amd64/conf/GENERIC-KCSAN
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++ head/sys/amd64/conf/GENERIC-KCSAN Thu Nov 21 11:22:08 2019 (r354942)
@@ -0,0 +1,33 @@
+#
+# GENERIC-KCSAN -- Kernel Concurrency Sanitizer kernel configuration file
+# for FreeBSD/amd64
+#
+# This configuration file removes several debugging options, including
+# WITNESS and INVARIANTS checking, which are known to have significant
+# performance impact on running systems. When benchmarking new features
+# this kernel should be used instead of the standard GENERIC.
+# This kernel configuration should never appear outside of the HEAD
+# of the FreeBSD tree.
+#
+# For more information on this file, please read the config(5) manual page,
+# and/or the handbook section on Kernel Configuration Files:
+#
+# https://www.FreeBSD.org/doc/en_US.ISO8859-1/books/handbook/kernelconfig-config.html
+#
+# The handbook is also available locally in /usr/share/doc/handbook
+# if you've installed the doc distribution, otherwise always see the
+# FreeBSD World Wide Web server (https://www.FreeBSD.org/) for the
+# latest information.
+#
+# An exhaustive list of options and more detailed explanations of the
+# device lines is also present in the ../../conf/NOTES and NOTES files.
+# If you are in doubt as to the purpose or necessity of a line, check first
+# in NOTES.
+#
+# $FreeBSD$
+
+include GENERIC
+
+ident GENERIC-KCSAN
+
+options KCSAN
Modified: head/sys/amd64/include/atomic.h
==============================================================================
--- head/sys/amd64/include/atomic.h Thu Nov 21 08:20:05 2019 (r354941)
+++ head/sys/amd64/include/atomic.h Thu Nov 21 11:22:08 2019 (r354942)
@@ -57,6 +57,20 @@
#define wmb() __asm __volatile("sfence;" : : : "memory")
#define rmb() __asm __volatile("lfence;" : : : "memory")
+#ifdef _KERNEL
+/*
+ * OFFSETOF_MONITORBUF == __pcpu_offset(pc_monitorbuf).
+ *
+ * The open-coded number is used instead of the symbolic expression to
+ * avoid a dependency on sys/pcpu.h in machine/atomic.h consumers.
+ * An assertion in amd64/vm_machdep.c ensures that the value is correct.
+ */
+#define OFFSETOF_MONITORBUF 0x100
+#endif
+
+#if defined(KCSAN) && !defined(KCSAN_RUNTIME)
+#include <sys/_cscan_atomic.h>
+#else
#include <sys/atomic_common.h>
/*
@@ -345,15 +359,6 @@ atomic_testandclear_long(volatile u_long *p, u_int v)
#if defined(_KERNEL)
-/*
- * OFFSETOF_MONITORBUF == __pcpu_offset(pc_monitorbuf).
- *
- * The open-coded number is used instead of the symbolic expression to
- * avoid a dependency on sys/pcpu.h in machine/atomic.h consumers.
- * An assertion in amd64/vm_machdep.c ensures that the value is correct.
- */
-#define OFFSETOF_MONITORBUF 0x100
-
#if defined(SMP) || defined(KLD_MODULE)
static __inline void
__storeload_barrier(void)
@@ -678,5 +683,7 @@ u_long atomic_swap_long(volatile u_long *p, u_long v);
#define atomic_readandclear_ptr atomic_readandclear_long
#endif /* !WANT_FUNCTIONS */
+
+#endif /* KCSAN && !KCSAN_RUNTIME */
#endif /* !_MACHINE_ATOMIC_H_ */
Added: head/sys/amd64/include/csan.h
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++ head/sys/amd64/include/csan.h Thu Nov 21 11:22:08 2019 (r354942)
@@ -0,0 +1,67 @@
+/* $NetBSD: csan.h,v 1.2 2019/11/06 06:57:22 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.
+ *
+ * $FreeBSD$
+ */
+
+#include <machine/cpufunc.h>
+#include <machine/stack.h>
+#include <machine/vmparam.h>
+
+static inline bool
+kcsan_md_is_avail(void)
+{
+ return true;
+}
+
+static inline void
+kcsan_md_disable_intrs(uint64_t *state)
+{
+
+ *state = intr_disable();
+}
+
+static inline void
+kcsan_md_enable_intrs(uint64_t *state)
+{
+
+ intr_restore(*state);
+}
+
+static inline void
+kcsan_md_delay(uint64_t us)
+{
+ DELAY(us);
+}
+
+static void
+kcsan_md_unwind(void)
+{
+}
Modified: head/sys/arm64/arm64/bus_machdep.c
==============================================================================
--- head/sys/arm64/arm64/bus_machdep.c Thu Nov 21 08:20:05 2019 (r354941)
+++ head/sys/arm64/arm64/bus_machdep.c Thu Nov 21 11:22:08 2019 (r354942)
@@ -25,6 +25,8 @@
*
*/
+#define KCSAN_RUNTIME
+
#include "opt_platform.h"
#include <sys/param.h>
Modified: head/sys/arm64/arm64/copystr.c
==============================================================================
--- head/sys/arm64/arm64/copystr.c Thu Nov 21 08:20:05 2019 (r354941)
+++ head/sys/arm64/arm64/copystr.c Thu Nov 21 11:22:08 2019 (r354942)
@@ -32,7 +32,7 @@ __FBSDID("$FreeBSD$");
#include <sys/systm.h>
int
-copystr(const void * __restrict kfaddr, void * __restrict kdaddr, size_t len,
+(copystr)(const void * __restrict kfaddr, void * __restrict kdaddr, size_t len,
size_t * __restrict lencopied)
{
const char *src;
Modified: head/sys/arm64/arm64/machdep.c
==============================================================================
--- head/sys/arm64/arm64/machdep.c Thu Nov 21 08:20:05 2019 (r354941)
+++ head/sys/arm64/arm64/machdep.c Thu Nov 21 11:22:08 2019 (r354942)
@@ -38,6 +38,7 @@ __FBSDID("$FreeBSD$");
#include <sys/bus.h>
#include <sys/cons.h>
#include <sys/cpu.h>
+#include <sys/csan.h>
#include <sys/devmap.h>
#include <sys/efi.h>
#include <sys/exec.h>
@@ -1208,6 +1209,8 @@ initarm(struct arm64_bootparams *abp)
dbg_init();
kdb_init();
pan_enable();
+
+ kcsan_cpu_init(0);
env = kern_getenv("kernelname");
if (env != NULL)
Modified: head/sys/arm64/arm64/mp_machdep.c
==============================================================================
--- head/sys/arm64/arm64/mp_machdep.c Thu Nov 21 08:20:05 2019 (r354941)
+++ head/sys/arm64/arm64/mp_machdep.c Thu Nov 21 11:22:08 2019 (r354942)
@@ -40,6 +40,7 @@ __FBSDID("$FreeBSD$");
#include <sys/systm.h>
#include <sys/bus.h>
#include <sys/cpu.h>
+#include <sys/csan.h>
#include <sys/kernel.h>
#include <sys/ktr.h>
#include <sys/malloc.h>
@@ -252,6 +253,8 @@ init_secondary(uint64_t cpu)
}
mtx_unlock_spin(&ap_boot_mtx);
+
+ kcsan_cpu_init(cpu);
/* Enter the scheduler */
sched_throw(NULL);
Modified: head/sys/arm64/conf/GENERIC
==============================================================================
--- head/sys/arm64/conf/GENERIC Thu Nov 21 08:20:05 2019 (r354941)
+++ head/sys/arm64/conf/GENERIC Thu Nov 21 11:22:08 2019 (r354942)
@@ -100,6 +100,7 @@ options VERBOSE_SYSINIT=0 # Support debug.verbose_sys
#options KCOV # Kernel Coverage Sanitizer
# Warning: KUBSAN can result in a kernel too large for loader to load
#options KUBSAN # Kernel Undefined Behavior Sanitizer
+#options KCSAN # Kernel Concurrency Sanitizer
# Kernel dump features.
options EKCD # Support for encrypted kernel dumps
Modified: head/sys/arm64/include/atomic.h
==============================================================================
--- head/sys/arm64/include/atomic.h Thu Nov 21 08:20:05 2019 (r354941)
+++ head/sys/arm64/include/atomic.h Thu Nov 21 11:22:08 2019 (r354942)
@@ -29,8 +29,6 @@
#ifndef _MACHINE_ATOMIC_H_
#define _MACHINE_ATOMIC_H_
-#include <sys/atomic_common.h>
-
#define isb() __asm __volatile("isb" : : : "memory")
/*
@@ -55,6 +53,12 @@
#define wmb() dmb(st) /* Full system memory barrier store */
#define rmb() dmb(ld) /* Full system memory barrier load */
+#if defined(KCSAN) && !defined(KCSAN_RUNTIME)
+#include <sys/_cscan_atomic.h>
+#else
+
+#include <sys/atomic_common.h>
+
#define ATOMIC_OP(op, asm_op, bar, a, l) \
static __inline void \
atomic_##op##_##bar##8(volatile uint8_t *p, uint8_t val) \
@@ -600,6 +604,8 @@ atomic_thread_fence_seq_cst(void)
dmb(sy);
}
+
+#endif /* KCSAN && !KCSAN_RUNTIME */
#endif /* _MACHINE_ATOMIC_H_ */
Modified: head/sys/arm64/include/bus.h
==============================================================================
--- head/sys/arm64/include/bus.h Thu Nov 21 08:20:05 2019 (r354941)
+++ head/sys/arm64/include/bus.h Thu Nov 21 11:22:08 2019 (r354942)
@@ -89,6 +89,9 @@
#define BUS_SPACE_BARRIER_READ 0x01
#define BUS_SPACE_BARRIER_WRITE 0x02
+#if defined(KCSAN) && !defined(KCSAN_RUNTIME)
+#include <sys/_cscan_bus.h>
+#else
struct bus_space {
/* cookie */
@@ -463,6 +466,8 @@ struct bus_space {
__bs_copy(4, t, h1, o1, h2, o2, c)
#define bus_space_copy_region_8(t, h1, o1, h2, o2, c) \
__bs_copy(8, t, h1, o1, h2, o2, c)
+
+#endif
#include <machine/bus_dma.h>
Added: head/sys/arm64/include/csan.h
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++ head/sys/arm64/include/csan.h Thu Nov 21 11:22:08 2019 (r354942)
@@ -0,0 +1,104 @@
+/* $NetBSD: csan.h,v 1.2 2019/11/06 06:57:22 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.
+ *
+ * $FreeBSD$
+ */
+
+#include <machine/cpufunc.h>
+#include <machine/stack.h>
+#include <machine/vmparam.h>
+
+static inline bool
+kcsan_md_is_avail(void)
+{
+ return true;
+}
+
+static inline void
+kcsan_md_disable_intrs(uint64_t *state)
+{
+
+ *state = intr_disable();
+}
+
+static inline void
+kcsan_md_enable_intrs(uint64_t *state)
+{
+
+ intr_restore(*state);
+}
+
+static inline void
+kcsan_md_delay(uint64_t us)
+{
+ DELAY(us);
+}
+
+static void
+kcsan_md_unwind(void)
+{
+#ifdef DDB
+ c_db_sym_t sym;
+ db_expr_t offset;
+ const char *symname;
+#endif
+ struct unwind_state frame;
+ uint64_t sp;
+ int nsym;
+
+ __asm __volatile("mov %0, sp" : "=&r" (sp));
+
+ frame.sp = sp;
+ frame.fp = (uint64_t)__builtin_frame_address(0);
+ frame.pc = (uint64_t)kcsan_md_unwind;
+ nsym = 0;
+
+ while (1) {
+ unwind_frame(&frame);
+ if (!INKERNEL((vm_offset_t)frame.fp) ||
+ !INKERNEL((vm_offset_t)frame.pc))
+ break;
+
+#ifdef DDB
+ sym = db_search_symbol((vm_offset_t)frame.pc, DB_STGY_PROC,
+ &offset);
+ db_symbol_values(sym, &symname, NULL);
+ printf("#%d %p in %s+%#lx\n", nsym, (void *)frame.pc,
+ symname, offset);
+#else
+ printf("#%d %p\n", nsym, (void *)frame.pc);
+#endif
+ nsym++;
+
+ if (nsym >= 15) {
+ break;
+ }
+ }
+}
Modified: head/sys/conf/files
==============================================================================
--- head/sys/conf/files Thu Nov 21 08:20:05 2019 (r354941)
+++ head/sys/conf/files Thu Nov 21 11:22:08 2019 (r354942)
@@ -3805,6 +3805,8 @@ kern/subr_compressor.c standard \
kern/subr_coverage.c optional coverage \
compile-with "${NORMAL_C:N-fsanitize*}"
kern/subr_counter.c standard
+kern/subr_csan.c optional kcsan \
+ compile-with "${NORMAL_C:N-fsanitize*}"
kern/subr_devstat.c standard
kern/subr_disk.c standard
kern/subr_early.c standard
Modified: head/sys/conf/files.arm64
==============================================================================
--- head/sys/conf/files.arm64 Thu Nov 21 08:20:05 2019 (r354941)
+++ head/sys/conf/files.arm64 Thu Nov 21 11:22:08 2019 (r354942)
@@ -286,8 +286,10 @@ kern/pic_if.m optional intrng
kern/subr_devmap.c standard
kern/subr_intr.c optional intrng
libkern/bcmp.c standard
-libkern/memcmp.c standard
-libkern/memset.c standard
+libkern/memcmp.c standard \
+ compile-with "${NORMAL_C:N-fsanitize*}"
+libkern/memset.c standard \
+ compile-with "${NORMAL_C:N-fsanitize*}"
libkern/arm64/crc32c_armv8.S standard
cddl/dev/dtrace/aarch64/dtrace_asm.S optional dtrace compile-with "${DTRACE_S}"
cddl/dev/dtrace/aarch64/dtrace_subr.c optional dtrace compile-with "${DTRACE_C}"
Modified: head/sys/conf/kern.post.mk
==============================================================================
--- head/sys/conf/kern.post.mk Thu Nov 21 08:20:05 2019 (r354941)
+++ head/sys/conf/kern.post.mk Thu Nov 21 11:22:08 2019 (r354942)
@@ -38,6 +38,10 @@ MKMODULESENV+= WITH_CTF="${WITH_CTF}"
MKMODULESENV+= WITH_EXTRA_TCP_STACKS="${WITH_EXTRA_TCP_STACKS}"
.endif
+.if defined(KCSAN_ENABLED)
+MKMODULESENV+= KCSAN_ENABLED="yes"
+.endif
+
.if defined(SAN_CFLAGS)
MKMODULESENV+= SAN_CFLAGS="${SAN_CFLAGS}"
.endif
Modified: head/sys/conf/kern.pre.mk
==============================================================================
--- head/sys/conf/kern.pre.mk Thu Nov 21 08:20:05 2019 (r354941)
+++ head/sys/conf/kern.pre.mk Thu Nov 21 11:22:08 2019 (r354942)
@@ -117,6 +117,11 @@ PROF= -pg
.endif
DEFINED_PROF= ${PROF}
+KCSAN_ENABLED!= grep KCSAN opt_global.h || true ; echo
+.if !empty(KCSAN_ENABLED)
+SAN_CFLAGS+= -fsanitize=thread
+.endif
+
KUBSAN_ENABLED!= grep KUBSAN opt_global.h || true ; echo
.if !empty(KUBSAN_ENABLED)
SAN_CFLAGS+= -fsanitize=undefined
Modified: head/sys/conf/options
==============================================================================
--- head/sys/conf/options Thu Nov 21 08:20:05 2019 (r354941)
+++ head/sys/conf/options Thu Nov 21 11:22:08 2019 (r354942)
@@ -230,6 +230,7 @@ ZSTDIO opt_zstdio.h
# Sanitizers
COVERAGE opt_global.h
KCOV
+KCSAN opt_global.h
KUBSAN opt_global.h
# POSIX kernel options
Modified: head/sys/kern/subr_csan.c
==============================================================================
--- head/sys/kern/subr_csan.c Thu Nov 21 08:20:05 2019 (r354941)
+++ head/sys/kern/subr_csan.c Thu Nov 21 11:22:08 2019 (r354942)
@@ -3,6 +3,7 @@
/*
* 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.
@@ -29,19 +30,26 @@
* POSSIBILITY OF SUCH DAMAGE.
*/
+#define KCSAN_RUNTIME
+
+#include "opt_ddb.h"
+
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: subr_csan.c,v 1.5 2019/11/15 08:11:37 maxv Exp $");
+__FBSDID("$FreeBSD$");
#include <sys/param.h>
-#include <sys/device.h>
#include <sys/kernel.h>
-#include <sys/param.h>
+#include <sys/bus.h>
#include <sys/conf.h>
-#include <sys/systm.h>
-#include <sys/types.h>
-#include <sys/csan.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
@@ -62,7 +70,7 @@ typedef struct {
csan_cell_t cell;
} csan_cpu_t;
-static csan_cpu_t kcsan_cpus[MAXCPUS];
+static csan_cpu_t kcsan_cpus[MAXCPU];
static bool kcsan_enabled __read_mostly;
#define __RET_ADDR (uintptr_t)__builtin_return_address(0)
@@ -77,34 +85,43 @@ static bool kcsan_enabled __read_mostly;
/* -------------------------------------------------------------------------- */
-void
-kcsan_init(void)
+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(struct cpu_info *ci)
+kcsan_cpu_init(u_int cpu)
{
- kcsan_cpus[cpu_index(ci)].inited = true;
+ kcsan_cpus[cpu].inited = true;
}
/* -------------------------------------------------------------------------- */
static inline void
-kcsan_report(csan_cell_t *new, cpuid_t newcpu, csan_cell_t *old, cpuid_t oldcpu)
+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;
- 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";
- }
+ 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%lu %s%s Addr=%p Size=%u PC=%p<%s>] "
- "[Cpu%lu %s%s Addr=%p Size=%u PC=%p<%s>]\n",
+ "[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,
@@ -134,8 +151,6 @@ kcsan_access(uintptr_t addr, size_t size, bool write,
if (__predict_false(!kcsan_enabled))
return;
- if (__predict_false(kcsan_md_unsupported((vaddr_t)addr)))
- return;
new.addr = addr;
new.size = size;
@@ -143,7 +158,7 @@ kcsan_access(uintptr_t addr, size_t size, bool write,
new.atomic = atomic;
new.pc = pc;
- for (i = 0; i < ncpu; i++) {
+ CPU_FOREACH(i) {
__builtin_memcpy(&old, &kcsan_cpus[i].cell, sizeof(old));
if (old.addr + old.size <= new.addr)
@@ -155,7 +170,7 @@ kcsan_access(uintptr_t addr, size_t size, bool write,
if (__predict_true(kcsan_access_is_atomic(&new, &old)))
continue;
- kcsan_report(&new, cpu_number(), &old, i);
+ kcsan_report(&new, PCPU_GET(cpuid), &old, i);
break;
}
@@ -164,7 +179,7 @@ kcsan_access(uintptr_t addr, size_t size, bool write,
kcsan_md_disable_intrs(&intr);
- cpu = &kcsan_cpus[cpu_number()];
+ cpu = &kcsan_cpus[PCPU_GET(cpuid)];
if (__predict_false(!cpu->inited))
goto out;
cpu->cnt = (cpu->cnt + 1) % KCSAN_NACCESSES;
@@ -184,6 +199,11 @@ out:
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)
@@ -197,6 +217,11 @@ CSAN_READ(16)
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)
@@ -321,35 +346,14 @@ kcsan_strlen(const char *str)
return (s - str);
}
-#undef kcopy
#undef copystr
-#undef copyinstr
-#undef copyoutstr
#undef copyin
+#undef copyin_nofault
+#undef copyinstr
#undef copyout
+#undef copyout_nofault
-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 kcsan_copyout(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 copyout(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);
@@ -364,13 +368,6 @@ kcsan_copyin(const void *uaddr, void *kaddr, size_t le
}
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);
-}
-
-int
kcsan_copyinstr(const void *uaddr, void *kaddr, size_t len, size_t *done)
{
kcsan_access((uintptr_t)kaddr, len, true, false, __RET_ADDR);
@@ -378,377 +375,477 @@ kcsan_copyinstr(const void *uaddr, void *kaddr, size_t
}
int
-kcsan_copyoutstr(const void *kaddr, void *uaddr, size_t len, size_t *done)
+kcsan_copyout(const void *kaddr, void *uaddr, size_t len)
{
kcsan_access((uintptr_t)kaddr, len, false, false, __RET_ADDR);
- return copyoutstr(kaddr, uaddr, len, done);
+ return copyout(kaddr, uaddr, len);
}
/* -------------------------------------------------------------------------- */
-#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
+#include <machine/atomic.h>
+#include <sys/_cscan_atomic.h>
-#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_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_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_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_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_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_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_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_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_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_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); \
*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***
More information about the svn-src-head
mailing list