Commit dfd402a4 authored by Marco Elver's avatar Marco Elver Committed by Paul E. McKenney
Browse files

kcsan: Add Kernel Concurrency Sanitizer infrastructure



Kernel Concurrency Sanitizer (KCSAN) is a dynamic data-race detector for
kernel space. KCSAN is a sampling watchpoint-based data-race detector.
See the included Documentation/dev-tools/kcsan.rst for more details.

This patch adds basic infrastructure, but does not yet enable KCSAN for
any architecture.

Signed-off-by: default avatarMarco Elver <elver@google.com>
Acked-by: default avatarPaul E. McKenney <paulmck@kernel.org>
Signed-off-by: default avatarPaul E. McKenney <paulmck@kernel.org>
parent 31f4f5b4
Loading
Loading
Loading
Loading
+11 −0
Original line number Diff line number Diff line
@@ -8848,6 +8848,17 @@ F: Documentation/kbuild/kconfig*
F:	scripts/kconfig/
F:	scripts/Kconfig.include
KCSAN
M:	Marco Elver <elver@google.com>
R:	Dmitry Vyukov <dvyukov@google.com>
L:	kasan-dev@googlegroups.com
S:	Maintained
F:	Documentation/dev-tools/kcsan.rst
F:	include/linux/kcsan*.h
F:	kernel/kcsan/
F:	lib/Kconfig.kcsan
F:	scripts/Makefile.kcsan
KDUMP
M:	Dave Young <dyoung@redhat.com>
M:	Baoquan He <bhe@redhat.com>
+2 −1
Original line number Diff line number Diff line
@@ -478,7 +478,7 @@ export KBUILD_HOSTCXXFLAGS KBUILD_HOSTLDFLAGS KBUILD_HOSTLDLIBS LDFLAGS_MODULE

export KBUILD_CPPFLAGS NOSTDINC_FLAGS LINUXINCLUDE OBJCOPYFLAGS KBUILD_LDFLAGS
export KBUILD_CFLAGS CFLAGS_KERNEL CFLAGS_MODULE
export CFLAGS_KASAN CFLAGS_KASAN_NOSANITIZE CFLAGS_UBSAN
export CFLAGS_KASAN CFLAGS_KASAN_NOSANITIZE CFLAGS_UBSAN CFLAGS_KCSAN
export KBUILD_AFLAGS AFLAGS_KERNEL AFLAGS_MODULE
export KBUILD_AFLAGS_MODULE KBUILD_CFLAGS_MODULE KBUILD_LDFLAGS_MODULE
export KBUILD_AFLAGS_KERNEL KBUILD_CFLAGS_KERNEL
@@ -900,6 +900,7 @@ endif
include scripts/Makefile.kasan
include scripts/Makefile.extrawarn
include scripts/Makefile.ubsan
include scripts/Makefile.kcsan

# Add user supplied CPPFLAGS, AFLAGS and CFLAGS as the last assignments
KBUILD_CPPFLAGS += $(KCPPFLAGS)
+9 −0
Original line number Diff line number Diff line
@@ -24,6 +24,15 @@
#define __no_sanitize_address
#endif

#if __has_feature(thread_sanitizer)
/* emulate gcc's __SANITIZE_THREAD__ flag */
#define __SANITIZE_THREAD__
#define __no_sanitize_thread \
		__attribute__((no_sanitize("thread")))
#else
#define __no_sanitize_thread
#endif

/*
 * Not all versions of clang implement the the type-generic versions
 * of the builtin overflow checkers. Fortunately, clang implements
+7 −0
Original line number Diff line number Diff line
@@ -145,6 +145,13 @@
#define __no_sanitize_address
#endif

#if defined(__SANITIZE_THREAD__) && __has_attribute(__no_sanitize_thread__)
#define __no_sanitize_thread                                                   \
	__attribute__((__noinline__)) __attribute__((no_sanitize_thread))
#else
#define __no_sanitize_thread
#endif

#if GCC_VERSION >= 50100
#define COMPILER_HAS_GENERIC_BUILTIN_OVERFLOW 1
#endif
+29 −8
Original line number Diff line number Diff line
@@ -178,6 +178,7 @@ void ftrace_likely_update(struct ftrace_likely_data *f, int val,
#endif

#include <uapi/linux/types.h>
#include <linux/kcsan-checks.h>

#define __READ_ONCE_SIZE						\
({									\
@@ -193,12 +194,6 @@ void ftrace_likely_update(struct ftrace_likely_data *f, int val,
	}								\
})

static __always_inline
void __read_once_size(const volatile void *p, void *res, int size)
{
	__READ_ONCE_SIZE;
}

#ifdef CONFIG_KASAN
/*
 * We can't declare function 'inline' because __no_sanitize_address confilcts
@@ -207,18 +202,44 @@ void __read_once_size(const volatile void *p, void *res, int size)
 * '__maybe_unused' allows us to avoid defined-but-not-used warnings.
 */
# define __no_kasan_or_inline __no_sanitize_address notrace __maybe_unused
# define __no_sanitize_or_inline __no_kasan_or_inline
#else
# define __no_kasan_or_inline __always_inline
#endif

static __no_kasan_or_inline
#ifdef __SANITIZE_THREAD__
/*
 * Rely on __SANITIZE_THREAD__ instead of CONFIG_KCSAN, to avoid not inlining in
 * compilation units where instrumentation is disabled.
 */
# define __no_kcsan_or_inline __no_sanitize_thread notrace __maybe_unused
# define __no_sanitize_or_inline __no_kcsan_or_inline
#else
# define __no_kcsan_or_inline __always_inline
#endif

#ifndef __no_sanitize_or_inline
#define __no_sanitize_or_inline __always_inline
#endif

static __no_kcsan_or_inline
void __read_once_size(const volatile void *p, void *res, int size)
{
	kcsan_check_atomic_read(p, size);
	__READ_ONCE_SIZE;
}

static __no_sanitize_or_inline
void __read_once_size_nocheck(const volatile void *p, void *res, int size)
{
	__READ_ONCE_SIZE;
}

static __always_inline void __write_once_size(volatile void *p, void *res, int size)
static __no_kcsan_or_inline
void __write_once_size(volatile void *p, void *res, int size)
{
	kcsan_check_atomic_write(p, size);

	switch (size) {
	case 1: *(volatile __u8 *)p = *(__u8 *)res; break;
	case 2: *(volatile __u16 *)p = *(__u16 *)res; break;
Loading