All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v3 1/2] kcsan: Instrument memcpy/memset/memmove with newer Clang
@ 2022-09-12  9:45 Marco Elver
  2022-09-12  9:45 ` [PATCH v3 2/2] objtool, kcsan: Add volatile read/write instrumentation to whitelist Marco Elver
  2022-09-14 12:12 ` [PATCH v3 1/2] kcsan: Instrument memcpy/memset/memmove with newer Clang Paul E. McKenney
  0 siblings, 2 replies; 3+ messages in thread
From: Marco Elver @ 2022-09-12  9:45 UTC (permalink / raw)
  To: elver, Paul E. McKenney
  Cc: Mark Rutland, Dmitry Vyukov, Alexander Potapenko, Boqun Feng,
	kasan-dev, linux-kernel, Nathan Chancellor, Nick Desaulniers,
	llvm, Josh Poimboeuf, Peter Zijlstra, stable

With Clang version 16+, -fsanitize=thread will turn
memcpy/memset/memmove calls in instrumented functions into
__tsan_memcpy/__tsan_memset/__tsan_memmove calls respectively.

Add these functions to the core KCSAN runtime, so that we (a) catch data
races with mem* functions, and (b) won't run into linker errors with
such newer compilers.

Cc: stable@vger.kernel.org # v5.10+
Signed-off-by: Marco Elver <elver@google.com>
---
v3:
* Truncate sizes larger than MAX_ENCODABLE_SIZE, so we still set up
  watchpoints on them. Iterating through MAX_ENCODABLE_SIZE blocks may
  result in pathological cases where performance would seriously suffer.
  So let's avoid that for now.
* Just use memcpy/memset/memmove instead of __mem*() functions. Many
  architectures that already support KCSAN don't define them (mips,
  s390), and having both __mem* and mem versions of the functions
  provides little benefit elsewhere; and backporting would become more
  difficult, too. The compiler should not inline them given all
  parameters are non-constants here.

v2:
* Fix for architectures which do not provide their own
  memcpy/memset/memmove and instead use the generic versions in
  lib/string. In this case we'll just alias the __tsan_ variants.
---
 kernel/kcsan/core.c | 50 +++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 50 insertions(+)

diff --git a/kernel/kcsan/core.c b/kernel/kcsan/core.c
index fe12dfe254ec..54d077e1a2dc 100644
--- a/kernel/kcsan/core.c
+++ b/kernel/kcsan/core.c
@@ -14,10 +14,12 @@
 #include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/list.h>
+#include <linux/minmax.h>
 #include <linux/moduleparam.h>
 #include <linux/percpu.h>
 #include <linux/preempt.h>
 #include <linux/sched.h>
+#include <linux/string.h>
 #include <linux/uaccess.h>
 
 #include "encoding.h"
@@ -1308,3 +1310,51 @@ noinline void __tsan_atomic_signal_fence(int memorder)
 	}
 }
 EXPORT_SYMBOL(__tsan_atomic_signal_fence);
+
+#ifdef __HAVE_ARCH_MEMSET
+void *__tsan_memset(void *s, int c, size_t count);
+noinline void *__tsan_memset(void *s, int c, size_t count)
+{
+	/*
+	 * Instead of not setting up watchpoints where accessed size is greater
+	 * than MAX_ENCODABLE_SIZE, truncate checked size to MAX_ENCODABLE_SIZE.
+	 */
+	size_t check_len = min_t(size_t, count, MAX_ENCODABLE_SIZE);
+
+	check_access(s, check_len, KCSAN_ACCESS_WRITE, _RET_IP_);
+	return memset(s, c, count);
+}
+#else
+void *__tsan_memset(void *s, int c, size_t count) __alias(memset);
+#endif
+EXPORT_SYMBOL(__tsan_memset);
+
+#ifdef __HAVE_ARCH_MEMMOVE
+void *__tsan_memmove(void *dst, const void *src, size_t len);
+noinline void *__tsan_memmove(void *dst, const void *src, size_t len)
+{
+	size_t check_len = min_t(size_t, len, MAX_ENCODABLE_SIZE);
+
+	check_access(dst, check_len, KCSAN_ACCESS_WRITE, _RET_IP_);
+	check_access(src, check_len, 0, _RET_IP_);
+	return memmove(dst, src, len);
+}
+#else
+void *__tsan_memmove(void *dst, const void *src, size_t len) __alias(memmove);
+#endif
+EXPORT_SYMBOL(__tsan_memmove);
+
+#ifdef __HAVE_ARCH_MEMCPY
+void *__tsan_memcpy(void *dst, const void *src, size_t len);
+noinline void *__tsan_memcpy(void *dst, const void *src, size_t len)
+{
+	size_t check_len = min_t(size_t, len, MAX_ENCODABLE_SIZE);
+
+	check_access(dst, check_len, KCSAN_ACCESS_WRITE, _RET_IP_);
+	check_access(src, check_len, 0, _RET_IP_);
+	return memcpy(dst, src, len);
+}
+#else
+void *__tsan_memcpy(void *dst, const void *src, size_t len) __alias(memcpy);
+#endif
+EXPORT_SYMBOL(__tsan_memcpy);
-- 
2.37.2.789.g6183377224-goog


^ permalink raw reply related	[flat|nested] 3+ messages in thread

* [PATCH v3 2/2] objtool, kcsan: Add volatile read/write instrumentation to whitelist
  2022-09-12  9:45 [PATCH v3 1/2] kcsan: Instrument memcpy/memset/memmove with newer Clang Marco Elver
@ 2022-09-12  9:45 ` Marco Elver
  2022-09-14 12:12 ` [PATCH v3 1/2] kcsan: Instrument memcpy/memset/memmove with newer Clang Paul E. McKenney
  1 sibling, 0 replies; 3+ messages in thread
From: Marco Elver @ 2022-09-12  9:45 UTC (permalink / raw)
  To: elver, Paul E. McKenney
  Cc: Mark Rutland, Dmitry Vyukov, Alexander Potapenko, Boqun Feng,
	kasan-dev, linux-kernel, Nathan Chancellor, Nick Desaulniers,
	llvm, Josh Poimboeuf, Peter Zijlstra

Adds KCSAN's volatile instrumentation to objtool's uaccess whitelist.

Recent kernel change have shown that this was missing from the uaccess
whitelist (since the first upstreamed version of KCSAN):

  mm/gup.o: warning: objtool: fault_in_readable+0x101: call to __tsan_volatile_write1() with UACCESS enabled

Fixes: 75d75b7a4d54 ("kcsan: Support distinguishing volatile accesses")
Signed-off-by: Marco Elver <elver@google.com>
Reviewed-by: Dmitry Vyukov <dvyukov@google.com>
---
v2:
* Fix commit message.
---
 tools/objtool/check.c | 10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/tools/objtool/check.c b/tools/objtool/check.c
index e55fdf952a3a..67afdce3421f 100644
--- a/tools/objtool/check.c
+++ b/tools/objtool/check.c
@@ -999,6 +999,16 @@ static const char *uaccess_safe_builtin[] = {
 	"__tsan_read_write4",
 	"__tsan_read_write8",
 	"__tsan_read_write16",
+	"__tsan_volatile_read1",
+	"__tsan_volatile_read2",
+	"__tsan_volatile_read4",
+	"__tsan_volatile_read8",
+	"__tsan_volatile_read16",
+	"__tsan_volatile_write1",
+	"__tsan_volatile_write2",
+	"__tsan_volatile_write4",
+	"__tsan_volatile_write8",
+	"__tsan_volatile_write16",
 	"__tsan_atomic8_load",
 	"__tsan_atomic16_load",
 	"__tsan_atomic32_load",
-- 
2.37.2.789.g6183377224-goog


^ permalink raw reply related	[flat|nested] 3+ messages in thread

* Re: [PATCH v3 1/2] kcsan: Instrument memcpy/memset/memmove with newer Clang
  2022-09-12  9:45 [PATCH v3 1/2] kcsan: Instrument memcpy/memset/memmove with newer Clang Marco Elver
  2022-09-12  9:45 ` [PATCH v3 2/2] objtool, kcsan: Add volatile read/write instrumentation to whitelist Marco Elver
@ 2022-09-14 12:12 ` Paul E. McKenney
  1 sibling, 0 replies; 3+ messages in thread
From: Paul E. McKenney @ 2022-09-14 12:12 UTC (permalink / raw)
  To: Marco Elver
  Cc: Mark Rutland, Dmitry Vyukov, Alexander Potapenko, Boqun Feng,
	kasan-dev, linux-kernel, Nathan Chancellor, Nick Desaulniers,
	llvm, Josh Poimboeuf, Peter Zijlstra, stable

On Mon, Sep 12, 2022 at 11:45:40AM +0200, Marco Elver wrote:
> With Clang version 16+, -fsanitize=thread will turn
> memcpy/memset/memmove calls in instrumented functions into
> __tsan_memcpy/__tsan_memset/__tsan_memmove calls respectively.
> 
> Add these functions to the core KCSAN runtime, so that we (a) catch data
> races with mem* functions, and (b) won't run into linker errors with
> such newer compilers.
> 
> Cc: stable@vger.kernel.org # v5.10+
> Signed-off-by: Marco Elver <elver@google.com>

Queued and pushed, thank you!

							Thanx, Paul

> ---
> v3:
> * Truncate sizes larger than MAX_ENCODABLE_SIZE, so we still set up
>   watchpoints on them. Iterating through MAX_ENCODABLE_SIZE blocks may
>   result in pathological cases where performance would seriously suffer.
>   So let's avoid that for now.
> * Just use memcpy/memset/memmove instead of __mem*() functions. Many
>   architectures that already support KCSAN don't define them (mips,
>   s390), and having both __mem* and mem versions of the functions
>   provides little benefit elsewhere; and backporting would become more
>   difficult, too. The compiler should not inline them given all
>   parameters are non-constants here.
> 
> v2:
> * Fix for architectures which do not provide their own
>   memcpy/memset/memmove and instead use the generic versions in
>   lib/string. In this case we'll just alias the __tsan_ variants.
> ---
>  kernel/kcsan/core.c | 50 +++++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 50 insertions(+)
> 
> diff --git a/kernel/kcsan/core.c b/kernel/kcsan/core.c
> index fe12dfe254ec..54d077e1a2dc 100644
> --- a/kernel/kcsan/core.c
> +++ b/kernel/kcsan/core.c
> @@ -14,10 +14,12 @@
>  #include <linux/init.h>
>  #include <linux/kernel.h>
>  #include <linux/list.h>
> +#include <linux/minmax.h>
>  #include <linux/moduleparam.h>
>  #include <linux/percpu.h>
>  #include <linux/preempt.h>
>  #include <linux/sched.h>
> +#include <linux/string.h>
>  #include <linux/uaccess.h>
>  
>  #include "encoding.h"
> @@ -1308,3 +1310,51 @@ noinline void __tsan_atomic_signal_fence(int memorder)
>  	}
>  }
>  EXPORT_SYMBOL(__tsan_atomic_signal_fence);
> +
> +#ifdef __HAVE_ARCH_MEMSET
> +void *__tsan_memset(void *s, int c, size_t count);
> +noinline void *__tsan_memset(void *s, int c, size_t count)
> +{
> +	/*
> +	 * Instead of not setting up watchpoints where accessed size is greater
> +	 * than MAX_ENCODABLE_SIZE, truncate checked size to MAX_ENCODABLE_SIZE.
> +	 */
> +	size_t check_len = min_t(size_t, count, MAX_ENCODABLE_SIZE);
> +
> +	check_access(s, check_len, KCSAN_ACCESS_WRITE, _RET_IP_);
> +	return memset(s, c, count);
> +}
> +#else
> +void *__tsan_memset(void *s, int c, size_t count) __alias(memset);
> +#endif
> +EXPORT_SYMBOL(__tsan_memset);
> +
> +#ifdef __HAVE_ARCH_MEMMOVE
> +void *__tsan_memmove(void *dst, const void *src, size_t len);
> +noinline void *__tsan_memmove(void *dst, const void *src, size_t len)
> +{
> +	size_t check_len = min_t(size_t, len, MAX_ENCODABLE_SIZE);
> +
> +	check_access(dst, check_len, KCSAN_ACCESS_WRITE, _RET_IP_);
> +	check_access(src, check_len, 0, _RET_IP_);
> +	return memmove(dst, src, len);
> +}
> +#else
> +void *__tsan_memmove(void *dst, const void *src, size_t len) __alias(memmove);
> +#endif
> +EXPORT_SYMBOL(__tsan_memmove);
> +
> +#ifdef __HAVE_ARCH_MEMCPY
> +void *__tsan_memcpy(void *dst, const void *src, size_t len);
> +noinline void *__tsan_memcpy(void *dst, const void *src, size_t len)
> +{
> +	size_t check_len = min_t(size_t, len, MAX_ENCODABLE_SIZE);
> +
> +	check_access(dst, check_len, KCSAN_ACCESS_WRITE, _RET_IP_);
> +	check_access(src, check_len, 0, _RET_IP_);
> +	return memcpy(dst, src, len);
> +}
> +#else
> +void *__tsan_memcpy(void *dst, const void *src, size_t len) __alias(memcpy);
> +#endif
> +EXPORT_SYMBOL(__tsan_memcpy);
> -- 
> 2.37.2.789.g6183377224-goog
> 

^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2022-09-14 12:12 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-09-12  9:45 [PATCH v3 1/2] kcsan: Instrument memcpy/memset/memmove with newer Clang Marco Elver
2022-09-12  9:45 ` [PATCH v3 2/2] objtool, kcsan: Add volatile read/write instrumentation to whitelist Marco Elver
2022-09-14 12:12 ` [PATCH v3 1/2] kcsan: Instrument memcpy/memset/memmove with newer Clang Paul E. McKenney

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.