Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src Add Kernel Concurrency Sanitizer (kCSan) support. This sanit...



details:   https://anonhg.NetBSD.org/src/rev/fd2a77f30f68
branches:  trunk
changeset: 460833:fd2a77f30f68
user:      maxv <maxv%NetBSD.org@localhost>
date:      Tue Nov 05 20:19:17 2019 +0000

description:
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.

diffstat:

 share/mk/bsd.sys.mk                |    5 +-
 sys/arch/amd64/amd64/machdep.c     |    6 +-
 sys/arch/amd64/amd64/mptramp.S     |   15 +-
 sys/arch/amd64/conf/GENERIC        |    9 +-
 sys/arch/amd64/conf/Makefile.amd64 |   11 +-
 sys/arch/amd64/include/csan.h      |  119 +++++
 sys/arch/x86/x86/cpu.c             |    8 +-
 sys/conf/files                     |    4 +-
 sys/kern/files.kern                |    3 +-
 sys/kern/subr_csan.c               |  744 +++++++++++++++++++++++++++++++++++++
 sys/lib/libkern/libkern.h          |   24 +-
 sys/sys/atomic.h                   |   86 ++++-
 sys/sys/bus_proto.h                |   55 ++-
 sys/sys/cdefs.h                    |    9 +-
 sys/sys/csan.h                     |   49 ++
 sys/sys/systm.h                    |   15 +-
 16 files changed, 1143 insertions(+), 19 deletions(-)

diffs (truncated from 1483 to 300 lines):

diff -r b270becd1457 -r fd2a77f30f68 share/mk/bsd.sys.mk
--- a/share/mk/bsd.sys.mk       Tue Nov 05 20:07:20 2019 +0000
+++ b/share/mk/bsd.sys.mk       Tue Nov 05 20:19:17 2019 +0000
@@ -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 @@
 
 .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}}
diff -r b270becd1457 -r fd2a77f30f68 sys/arch/amd64/amd64/machdep.c
--- a/sys/arch/amd64/amd64/machdep.c    Tue Nov 05 20:07:20 2019 +0000
+++ b/sys/arch/amd64/amd64/machdep.c    Tue Nov 05 20:19:17 2019 +0000
@@ -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 @@
 #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 @@
 #ifdef KASAN
        kasan_init();
 #endif
+       kcsan_init();
 
        pmap_growkernel(VM_MIN_KERNEL_ADDRESS + 32 * 1024 * 1024);
 
diff -r b270becd1457 -r fd2a77f30f68 sys/arch/amd64/amd64/mptramp.S
--- a/sys/arch/amd64/amd64/mptramp.S    Tue Nov 05 20:07:20 2019 +0000
+++ b/sys/arch/amd64/amd64/mptramp.S    Tue Nov 05 20:19:17 2019 +0000
@@ -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 @@
        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)
 
diff -r b270becd1457 -r fd2a77f30f68 sys/arch/amd64/conf/GENERIC
--- a/sys/arch/amd64/conf/GENERIC       Tue Nov 05 20:07:20 2019 +0000
+++ b/sys/arch/amd64/conf/GENERIC       Tue Nov 05 20:19:17 2019 +0000
@@ -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 @@
 
 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       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
diff -r b270becd1457 -r fd2a77f30f68 sys/arch/amd64/conf/Makefile.amd64
--- a/sys/arch/amd64/conf/Makefile.amd64        Tue Nov 05 20:07:20 2019 +0000
+++ b/sys/arch/amd64/conf/Makefile.amd64        Tue Nov 05 20:19:17 2019 +0000
@@ -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 @@
 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
 ##
diff -r b270becd1457 -r fd2a77f30f68 sys/arch/amd64/include/csan.h
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/sys/arch/amd64/include/csan.h     Tue Nov 05 20:19:17 2019 +0000
@@ -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;
+               }
+       }
+}
diff -r b270becd1457 -r fd2a77f30f68 sys/arch/x86/x86/cpu.c
--- a/sys/arch/x86/x86/cpu.c    Tue Nov 05 20:07:20 2019 +0000
+++ b/sys/arch/x86/x86/cpu.c    Tue Nov 05 20:19:17 2019 +0000
@@ -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 @@
 #include <sys/idle.h>
 #include <sys/atomic.h>
 #include <sys/reboot.h>
+#include <sys/csan.h>
 
 #include <uvm/uvm.h>
 
@@ -429,6 +430,7 @@
 #endif
                /* Make sure DELAY() is initialized. */
                DELAY(1);
+               kcsan_cpu_init(ci);
                again = true;
        }



Home | Main Index | Thread Index | Old Index