Fix some issues uncovered by UBSAN and enable UBSAN for nolibc-test to avoid regressions.
Signed-off-by: Thomas Weißschuh linux@weissschuh.net --- Thomas Weißschuh (6): tools/nolibc: add __nolibc_has_feature() tools/nolibc: disable function sanitizer for _start_c() tools/nolibc: properly align dirent buffer tools/nolibc: fix integer overflow in i{64,}toa_r() and selftests/nolibc: disable ubsan for smash_stack() selftests/nolibc: enable UBSAN if available
tools/include/nolibc/compiler.h | 6 ++++++ tools/include/nolibc/crt.h | 5 +++++ tools/include/nolibc/dirent.h | 1 + tools/include/nolibc/stdlib.h | 24 ++++++++---------------- tools/testing/selftests/nolibc/Makefile | 3 ++- tools/testing/selftests/nolibc/nolibc-test.c | 1 + 6 files changed, 23 insertions(+), 17 deletions(-) --- base-commit: 7c73c10b906778384843b9d3ac6c2224727bbf5c change-id: 20250416-nolibc-ubsan-028401698654
Best regards,
Certain compiler features are signaled via the __has_feature() preprocessor builtin.
Add a nolibc wrapper for it, similar to __nolibc_has_attribute().
Signed-off-by: Thomas Weißschuh linux@weissschuh.net --- tools/include/nolibc/compiler.h | 6 ++++++ 1 file changed, 6 insertions(+)
diff --git a/tools/include/nolibc/compiler.h b/tools/include/nolibc/compiler.h index fa1f547e7f13d151ea98b9c585b36659d2d27324..e6d6dc116e43aa69b37eca02ed1590fc09486bdb 100644 --- a/tools/include/nolibc/compiler.h +++ b/tools/include/nolibc/compiler.h @@ -12,6 +12,12 @@ # define __nolibc_has_attribute(attr) 0 #endif
+#if defined(__has_feature) +# define __nolibc_has_feature(feature) __has_feature(feature) +#else +# define __nolibc_has_feature(feature) 0 +#endif + #if __nolibc_has_attribute(naked) # define __nolibc_entrypoint __attribute__((naked)) # define __nolibc_entrypoint_epilogue()
Both constructors and main() may be executed with different function signatures than they are actually using. This is intentional but trips up UBSAN.
Disable the function sanitizer of UBSAN in _start_c().
Signed-off-by: Thomas Weißschuh linux@weissschuh.net --- tools/include/nolibc/crt.h | 5 +++++ 1 file changed, 5 insertions(+)
diff --git a/tools/include/nolibc/crt.h b/tools/include/nolibc/crt.h index c4b10103bbec50f1a3a0a4562e34fdbd1b43ce6f..961cfe777c3564e705dfdd581de828b374d05b0b 100644 --- a/tools/include/nolibc/crt.h +++ b/tools/include/nolibc/crt.h @@ -7,6 +7,8 @@ #ifndef _NOLIBC_CRT_H #define _NOLIBC_CRT_H
+#include "compiler.h" + char **environ __attribute__((weak)); const unsigned long *_auxv __attribute__((weak));
@@ -25,6 +27,9 @@ extern void (*const __fini_array_end[])(void) __attribute__((weak));
void _start_c(long *sp); __attribute__((weak,used)) +#if __nolibc_has_feature(undefined_behavior_sanitizer) + __attribute__((no_sanitize("function"))) +#endif void _start_c(long *sp) { long argc;
As byte buffer is overlaid with a 'struct dirent64'. it has to satisfy the structs alignment requirements.
Fixes: 665fa8dea90d ("tools/nolibc: add support for directory access") Signed-off-by: Thomas Weißschuh linux@weissschuh.net --- tools/include/nolibc/dirent.h | 1 + 1 file changed, 1 insertion(+)
diff --git a/tools/include/nolibc/dirent.h b/tools/include/nolibc/dirent.h index c5c30d0dd6806b1bec2fa8120a3df29aaa201393..cd0ddff86c360b14913a809c8696d89d8a356e9e 100644 --- a/tools/include/nolibc/dirent.h +++ b/tools/include/nolibc/dirent.h @@ -58,6 +58,7 @@ int closedir(DIR *dirp) static __attribute__((unused)) int readdir_r(DIR *dirp, struct dirent *entry, struct dirent **result) { + __attribute__((aligned(__alignof__(struct linux_dirent64)))) char buf[sizeof(struct linux_dirent64) + NAME_MAX + 1]; struct linux_dirent64 *ldir = (void *)buf; intptr_t i = (intptr_t)dirp;
In twos complement the most negative number can not be negated.
Fixes: b1c21e7d99cd ("tools/nolibc/stdlib: add i64toa() and u64toa()") Fixes: 66c397c4d2e1 ("tools/nolibc/stdlib: replace the ltoa() function with more efficient ones") Signed-off-by: Thomas Weißschuh linux@weissschuh.net --- tools/include/nolibc/stdlib.h | 24 ++++++++---------------- 1 file changed, 8 insertions(+), 16 deletions(-)
diff --git a/tools/include/nolibc/stdlib.h b/tools/include/nolibc/stdlib.h index 86ad378ab1ea220559d5ab1adc4bb9972977ba9e..5e4b97810d49ac1b1bd79d6f779f6a748f188a39 100644 --- a/tools/include/nolibc/stdlib.h +++ b/tools/include/nolibc/stdlib.h @@ -271,16 +271,12 @@ int utoa_r(unsigned long in, char *buffer) static __attribute__((unused)) int itoa_r(long in, char *buffer) { - char *ptr = buffer; - int len = 0; - if (in < 0) { - in = -in; - *(ptr++) = '-'; - len++; + *(buffer++) = '-'; + return 1 + utoa_r(-(unsigned long)in, buffer); } - len += utoa_r(in, ptr); - return len; + + return utoa_r(in, buffer); }
/* for historical compatibility, same as above but returns the pointer to the @@ -407,16 +403,12 @@ int u64toa_r(uint64_t in, char *buffer) static __attribute__((unused)) int i64toa_r(int64_t in, char *buffer) { - char *ptr = buffer; - int len = 0; - if (in < 0) { - in = -in; - *(ptr++) = '-'; - len++; + *(buffer++) = '-'; + return 1 + u64toa_r(-(unsigned long long)in, buffer); } - len += u64toa_r(in, ptr); - return len; + + return u64toa_r(in, buffer); }
/* converts int64_t <in> to a string using the static itoa_buffer and returns
smash_stack() intentionally crashes.
Prevent UBSAN from tripping over it.
Signed-off-by: Thomas Weißschuh linux@weissschuh.net --- tools/testing/selftests/nolibc/nolibc-test.c | 1 + 1 file changed, 1 insertion(+)
diff --git a/tools/testing/selftests/nolibc/nolibc-test.c b/tools/testing/selftests/nolibc/nolibc-test.c index 7a60b6ac1457e8d862ab1a6a26c9e46abec92111..b176a706609b7641dd1d743c8a02b6b6e7a4c746 100644 --- a/tools/testing/selftests/nolibc/nolibc-test.c +++ b/tools/testing/selftests/nolibc/nolibc-test.c @@ -1438,6 +1438,7 @@ static int run_vfprintf(int min, int max) return ret; }
+__attribute__((no_sanitize("undefined"))) static int smash_stack(void) { char buf[100];
UBSAN detects undefined behaviour at runtime. To avoid introduction of new UB, enable UBSAN for nolibc-test.
By signalling detected errors through traps no runtime dependency is necessary.
Signed-off-by: Thomas Weißschuh linux@weissschuh.net --- tools/testing/selftests/nolibc/Makefile | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/tools/testing/selftests/nolibc/Makefile b/tools/testing/selftests/nolibc/Makefile index aa05c1faac20d3054b231090b939d050b0231d40..94f3e8be7a68f63ecd639c4f283b3cd10764ce74 100644 --- a/tools/testing/selftests/nolibc/Makefile +++ b/tools/testing/selftests/nolibc/Makefile @@ -189,9 +189,10 @@ ifeq ($(origin XARCH),command line) CFLAGS_XARCH = $(CFLAGS_$(XARCH)) endif CFLAGS_STACKPROTECTOR ?= $(call cc-option,-mstack-protector-guard=global $(call cc-option,-fstack-protector-all)) +CFLAGS_SANITIZER ?= $(call cc-option,-fsanitize=undefined -fsanitize-trap=all) CFLAGS ?= -Os -fno-ident -fno-asynchronous-unwind-tables -std=c89 -W -Wall -Wextra \ $(call cc-option,-fno-stack-protector) $(call cc-option,-Wmissing-prototypes) \ - $(CFLAGS_XARCH) $(CFLAGS_STACKPROTECTOR) $(CFLAGS_EXTRA) + $(CFLAGS_XARCH) $(CFLAGS_STACKPROTECTOR) $(CFLAGS_SANITIZER) $(CFLAGS_EXTRA) LDFLAGS :=
LIBGCC := -lgcc
On Wed, Apr 16, 2025 at 08:40:15PM +0200, Thomas Weißschuh wrote:
Fix some issues uncovered by UBSAN and enable UBSAN for nolibc-test to avoid regressions.
Signed-off-by: Thomas Weißschuh linux@weissschuh.net
Thank you, Thomas! Are these intended to go into the current v6.15 release, or are you instead thinking in terms of the v6.16 merge window? Either works for me, but left to myself, I would assume the v6.16 merge window. ;-)
Thanx, Paul
Thomas Weißschuh (6): tools/nolibc: add __nolibc_has_feature() tools/nolibc: disable function sanitizer for _start_c() tools/nolibc: properly align dirent buffer tools/nolibc: fix integer overflow in i{64,}toa_r() and selftests/nolibc: disable ubsan for smash_stack() selftests/nolibc: enable UBSAN if available
tools/include/nolibc/compiler.h | 6 ++++++ tools/include/nolibc/crt.h | 5 +++++ tools/include/nolibc/dirent.h | 1 + tools/include/nolibc/stdlib.h | 24 ++++++++---------------- tools/testing/selftests/nolibc/Makefile | 3 ++- tools/testing/selftests/nolibc/nolibc-test.c | 1 + 6 files changed, 23 insertions(+), 17 deletions(-)
base-commit: 7c73c10b906778384843b9d3ac6c2224727bbf5c change-id: 20250416-nolibc-ubsan-028401698654
Best regards,
Thomas Weißschuh linux@weissschuh.net
Hi Paul,
On 2025-04-18 10:32:27-0700, Paul E. McKenney wrote:
On Wed, Apr 16, 2025 at 08:40:15PM +0200, Thomas Weißschuh wrote:
Fix some issues uncovered by UBSAN and enable UBSAN for nolibc-test to avoid regressions.
Signed-off-by: Thomas Weißschuh linux@weissschuh.net
Thank you, Thomas! Are these intended to go into the current v6.15 release, or are you instead thinking in terms of the v6.16 merge window? Either works for me, but left to myself, I would assume the v6.16 merge window. ;-)
They are intended for v6.16 through the normal process.
Thomas
Thomas Weißschuh (6): tools/nolibc: add __nolibc_has_feature() tools/nolibc: disable function sanitizer for _start_c() tools/nolibc: properly align dirent buffer tools/nolibc: fix integer overflow in i{64,}toa_r() and selftests/nolibc: disable ubsan for smash_stack() selftests/nolibc: enable UBSAN if available
tools/include/nolibc/compiler.h | 6 ++++++ tools/include/nolibc/crt.h | 5 +++++ tools/include/nolibc/dirent.h | 1 + tools/include/nolibc/stdlib.h | 24 ++++++++---------------- tools/testing/selftests/nolibc/Makefile | 3 ++- tools/testing/selftests/nolibc/nolibc-test.c | 1 + 6 files changed, 23 insertions(+), 17 deletions(-)
base-commit: 7c73c10b906778384843b9d3ac6c2224727bbf5c change-id: 20250416-nolibc-ubsan-028401698654
Best regards,
Thomas Weißschuh linux@weissschuh.net
On Fri, Apr 18, 2025 at 11:20:29PM +0200, Thomas Weißschuh wrote:
Hi Paul,
On 2025-04-18 10:32:27-0700, Paul E. McKenney wrote:
On Wed, Apr 16, 2025 at 08:40:15PM +0200, Thomas Weißschuh wrote:
Fix some issues uncovered by UBSAN and enable UBSAN for nolibc-test to avoid regressions.
Signed-off-by: Thomas Weißschuh linux@weissschuh.net
Thank you, Thomas! Are these intended to go into the current v6.15 release, or are you instead thinking in terms of the v6.16 merge window? Either works for me, but left to myself, I would assume the v6.16 merge window. ;-)
They are intended for v6.16 through the normal process.
Sounds good, and thank you for the clarification. Plus good show on getting them out early. ;-)
Thanx, Paul
Thomas
Thomas Weißschuh (6): tools/nolibc: add __nolibc_has_feature() tools/nolibc: disable function sanitizer for _start_c() tools/nolibc: properly align dirent buffer tools/nolibc: fix integer overflow in i{64,}toa_r() and selftests/nolibc: disable ubsan for smash_stack() selftests/nolibc: enable UBSAN if available
tools/include/nolibc/compiler.h | 6 ++++++ tools/include/nolibc/crt.h | 5 +++++ tools/include/nolibc/dirent.h | 1 + tools/include/nolibc/stdlib.h | 24 ++++++++---------------- tools/testing/selftests/nolibc/Makefile | 3 ++- tools/testing/selftests/nolibc/nolibc-test.c | 1 + 6 files changed, 23 insertions(+), 17 deletions(-)
base-commit: 7c73c10b906778384843b9d3ac6c2224727bbf5c change-id: 20250416-nolibc-ubsan-028401698654
Best regards,
Thomas Weißschuh linux@weissschuh.net
linux-kselftest-mirror@lists.linaro.org