From 74cc5347587624ded3ad9c2cc5266909e864cad9 Mon Sep 17 00:00:00 2001 From: Andy Ross Date: Tue, 9 Aug 2022 17:57:42 -0700 Subject: [PATCH] cmake: Update CONFIG_ASAN support This had bitrotten a bit, and didn't build as shipped. Current libasan implementations want -fsanitize=address passed as a linker argument too. We have grown a "lld" linker variant that needs the same cmake treatment as the "ld" binutils one, but never got it. But the various flags had been cut/pasted around to different places, with slightly different forms. That's really sort of a mess, as sanitizer support was only ever support with host toolchains for native_posix (and AFAICT no one anywhere has made this work on cross compilers in an embedded environment). And the separate "gcc" vs. "llvm" layers were silly, as there has only ever been one API for this feature (from LLVM, then picked up compatibly by gcc). Pull this stuff out and just do it in one place in the posix arch for simplicity. Also recent sanitizers are trying to add instrumentation padding around data that we use linker trickery to pack tightly (c.f. SYS_INIT, STRUCT_SECTION_ITERABLE) and we need a way ("__noasan") to turn that off. Actually for gcc, it was enough to just make the records const (already true for most of them, except a native_posix init struct), but clang apparently isn't smart enough. Finally, add an ASAN_RECOVER kconfig that enables the use of "halt_on_error=0" in $ASAN_OPTIONS, which continues execution past the first error. Signed-off-by: Andy Ross --- arch/posix/CMakeLists.txt | 33 ++++++++++++++------ cmake/compiler/arcmwdt/compiler_flags.cmake | 5 --- cmake/compiler/compiler_flags_template.cmake | 5 --- cmake/compiler/gcc/compiler_flags.cmake | 5 --- cmake/linker/ld/clang/linker_flags.cmake | 5 --- cmake/linker/ld/gcc/linker_flags.cmake | 5 --- cmake/linker/linker_flags_template.cmake | 5 --- include/zephyr/init.h | 2 +- include/zephyr/toolchain.h | 15 +++++++++ include/zephyr/toolchain/common.h | 4 +-- include/zephyr/toolchain/gcc.h | 6 ++++ soc/posix/inf_clock/soc.h | 2 +- subsys/debug/Kconfig | 12 +++++++ 13 files changed, 61 insertions(+), 43 deletions(-) diff --git a/arch/posix/CMakeLists.txt b/arch/posix/CMakeLists.txt index 4dfcb9a28245..4ad249e60bd3 100644 --- a/arch/posix/CMakeLists.txt +++ b/arch/posix/CMakeLists.txt @@ -28,15 +28,6 @@ if (CONFIG_GPROF) zephyr_compile_options($) zephyr_link_libraries($) endif() -if (CONFIG_ASAN) - zephyr_compile_options($) - zephyr_link_libraries($) -endif () - -if (CONFIG_UBSAN) - zephyr_compile_options($) - zephyr_link_libraries($) -endif () zephyr_compile_definitions(_POSIX_C_SOURCE=200809 _XOPEN_SOURCE=600 _XOPEN_SOURCE_EXTENDED) @@ -53,5 +44,29 @@ zephyr_ld_options( # Zephyr which will clash with the native POSIX API] . It would also need to # be included in a few zephyr kernel files. +# +# Support for the LLVM Sanitizer toolchain instrumentation frameworks +# (supported by current gcc's as well) +# + +if(CONFIG_ASAN) + list(APPEND LLVM_SANITIZERS "address") +endif() + +if(CONFIG_UBSAN) + list(APPEND LLVM_SANITIZERS "undefined") +endif() + +if(CONFIG_ASAN_RECOVER) + zephyr_compile_options(-fsanitize-recover=all) +endif() + +list(JOIN LLVM_SANITIZERS "," LLVM_SANITIZERS_ARG) +if(NOT ${LLVM_SANITIZERS_ARG} STREQUAL "") + set(LLVM_SANITIZERS_ARG "-fsanitize=${LLVM_SANITIZERS_ARG}") + zephyr_compile_options("${LLVM_SANITIZERS_ARG}") + zephyr_link_libraries("${LLVM_SANITIZERS_ARG}") +endif() + add_subdirectory(core) diff --git a/cmake/compiler/arcmwdt/compiler_flags.cmake b/cmake/compiler/arcmwdt/compiler_flags.cmake index ed2e6179618b..341256ec10ee 100644 --- a/cmake/compiler/arcmwdt/compiler_flags.cmake +++ b/cmake/compiler/arcmwdt/compiler_flags.cmake @@ -162,11 +162,6 @@ set_compiler_property(PROPERTY coverage "") # mwdt compiler flags for imacros. The specific header must be appended by user. set_compiler_property(PROPERTY imacros -imacros) -#no support of -fsanitize=address and -lasan -set_compiler_property(PROPERTY sanitize_address "") - -set_compiler_property(PROPERTY sanitize_undefined "") - # Security canaries. #no support of -mstack-protector-guard=global" set_compiler_property(PROPERTY security_canaries -fstack-protector-all) diff --git a/cmake/compiler/compiler_flags_template.cmake b/cmake/compiler/compiler_flags_template.cmake index 28b2e7a805a0..44bca0324d95 100644 --- a/cmake/compiler/compiler_flags_template.cmake +++ b/cmake/compiler/compiler_flags_template.cmake @@ -101,11 +101,6 @@ set_compiler_property(PROPERTY no_common) # Flags for imacros. The specific header must be appended by user. set_compiler_property(PROPERTY imacros) -# Compiler flags for sanitizing. -set_compiler_property(PROPERTY sanitize_address) - -set_compiler_property(PROPERTY sanitize_undefined) - # Compiler flag for turning off thread-safe initialization of local statics set_property(TARGET compiler-cpp PROPERTY no_threadsafe_statics) diff --git a/cmake/compiler/gcc/compiler_flags.cmake b/cmake/compiler/gcc/compiler_flags.cmake index b051e15b2216..ac0724022b8f 100644 --- a/cmake/compiler/gcc/compiler_flags.cmake +++ b/cmake/compiler/gcc/compiler_flags.cmake @@ -177,13 +177,8 @@ set_compiler_property(PROPERTY no_common -fno-common) # GCC compiler flags for imacros. The specific header must be appended by user. set_compiler_property(PROPERTY imacros -imacros) -# GCC compiler flags for sanitizing. -set_compiler_property(PROPERTY sanitize_address -fsanitize=address) - set_compiler_property(PROPERTY gprof -pg) -set_compiler_property(PROPERTY sanitize_undefined -fsanitize=undefined) - # GCC compiler flag for turning off thread-safe initialization of local statics set_property(TARGET compiler-cpp PROPERTY no_threadsafe_statics "-fno-threadsafe-statics") diff --git a/cmake/linker/ld/clang/linker_flags.cmake b/cmake/linker/ld/clang/linker_flags.cmake index 5f4c036b68c8..fd4f6f2b48ef 100644 --- a/cmake/linker/ld/clang/linker_flags.cmake +++ b/cmake/linker/ld/clang/linker_flags.cmake @@ -2,8 +2,3 @@ if (NOT CONFIG_COVERAGE_GCOV) set_property(TARGET linker PROPERTY coverage --coverage) endif() - -# ld/clang linker flags for sanitizing. -check_set_linker_property(TARGET linker APPEND PROPERTY sanitize_address -fsanitize=address) - -check_set_linker_property(TARGET linker APPEND PROPERTY sanitize_undefined -fsanitize=undefined) diff --git a/cmake/linker/ld/gcc/linker_flags.cmake b/cmake/linker/ld/gcc/linker_flags.cmake index 7a2ffdf4c0cc..4a816a78fcca 100644 --- a/cmake/linker/ld/gcc/linker_flags.cmake +++ b/cmake/linker/ld/gcc/linker_flags.cmake @@ -7,9 +7,4 @@ if (NOT CONFIG_COVERAGE_GCOV) set_property(TARGET linker PROPERTY coverage -lgcov) endif() -# ld/gcc linker flags for sanitizing. -check_set_linker_property(TARGET linker APPEND PROPERTY sanitize_address -lasan) -check_set_linker_property(TARGET linker APPEND PROPERTY sanitize_address -fsanitize=address) -check_set_linker_property(TARGET linker APPEND PROPERTY sanitize_undefined -fsanitize=undefined) - check_set_linker_property(TARGET linker APPEND PROPERTY gprof -pg) diff --git a/cmake/linker/linker_flags_template.cmake b/cmake/linker/linker_flags_template.cmake index 7b7c3cca7922..910515c31196 100644 --- a/cmake/linker/linker_flags_template.cmake +++ b/cmake/linker/linker_flags_template.cmake @@ -3,11 +3,6 @@ # Set the property for the corresponding flags of the given toolchain. set_property(TARGET linker PROPERTY coverage) -# Linker flags for sanitizing. -check_set_linker_property(TARGET linker APPEND PROPERTY sanitize_address) - -check_set_linker_property(TARGET linker APPEND PROPERTY sanitize_undefined) - # Linker flag for printing of memusage. # Set this flag if the linker supports reporting of memusage as part of link, # such as ls --print-memory-usage flag. diff --git a/include/zephyr/init.h b/include/zephyr/init.h index 11780c5e20bf..1abadcdbc193 100644 --- a/include/zephyr/init.h +++ b/include/zephyr/init.h @@ -91,7 +91,7 @@ void z_sys_init_run_level(int32_t level); */ #define Z_INIT_ENTRY_DEFINE(_entry_name, _init_fn, _device, _level, _prio) \ static const Z_DECL_ALIGN(struct init_entry) \ - Z_INIT_ENTRY_NAME(_entry_name) __used \ + Z_INIT_ENTRY_NAME(_entry_name) __used __noasan \ __attribute__((__section__(".z_init_" #_level STRINGIFY(_prio)"_"))) = { \ .init = (_init_fn), \ .dev = (_device), \ diff --git a/include/zephyr/toolchain.h b/include/zephyr/toolchain.h index 6e8deefe3d77..ca348fea60e7 100644 --- a/include/zephyr/toolchain.h +++ b/include/zephyr/toolchain.h @@ -52,6 +52,21 @@ #error "Invalid/unknown toolchain configuration" #endif +/** + * @def __noasan + * @brief Disable address sanitizer + * + * When used in the definiton of a symbol, prevents that symbol (be it + * a function or data) from being instrumented by the address + * sanitizer feature of the compiler. Most commonly, this is used to + * prevent padding around data that will be treated specially by the + * Zephyr link (c.f. SYS_INIT records, STRUCT_SECTION_ITERABLE + * definitions) in ways that don't understand the guard padding. + */ +#ifndef __noasan +#define __noasan /**/ +#endif + /** * @def GCC_VERSION * @brief GCC version in xxyyzz for xx.yy.zz. Zero if not GCC compatible. diff --git a/include/zephyr/toolchain/common.h b/include/zephyr/toolchain/common.h index e7b58a5ac564..cf2dce5676dc 100644 --- a/include/zephyr/toolchain/common.h +++ b/include/zephyr/toolchain/common.h @@ -209,7 +209,7 @@ */ #define STRUCT_SECTION_ITERABLE(struct_type, name) \ Z_DECL_ALIGN(struct struct_type) name \ - __in_section(_##struct_type, static, name) __used + __in_section(_##struct_type, static, name) __used __noasan /** * @brief Defines an alternate data type iterable section. @@ -221,7 +221,7 @@ */ #define STRUCT_SECTION_ITERABLE_ALTERNATE(out_type, struct_type, name) \ Z_DECL_ALIGN(struct struct_type) name \ - __in_section(_##out_type, static, name) __used + __in_section(_##out_type, static, name) __used __noasan /** * @brief Iterate over a specified iterable section. diff --git a/include/zephyr/toolchain/gcc.h b/include/zephyr/toolchain/gcc.h index 756830c4d964..f3cef4d12a8e 100644 --- a/include/zephyr/toolchain/gcc.h +++ b/include/zephyr/toolchain/gcc.h @@ -618,5 +618,11 @@ do { \ */ #define Z_IS_POW2(x) (((x) != 0) && (((x) & ((x)-1)) == 0)) +#ifdef CONFIG_ASAN +#define __noasan __attribute__((no_sanitize("address"))) +#else +#define __noasan /**/ +#endif + #endif /* !_LINKER */ #endif /* ZEPHYR_INCLUDE_TOOLCHAIN_GCC_H_ */ diff --git a/soc/posix/inf_clock/soc.h b/soc/posix/inf_clock/soc.h index fb79b7e1bee9..5805ba3218e7 100644 --- a/soc/posix/inf_clock/soc.h +++ b/soc/posix/inf_clock/soc.h @@ -43,7 +43,7 @@ void posix_soc_clean_up(void); * any Zephyr thread are running. */ #define NATIVE_TASK(fn, level, prio) \ - static void (*_CONCAT(__native_task_, fn)) __used \ + static const void (*_CONCAT(__native_task_, fn)) __used __noasan \ __attribute__((__section__(".native_" #level STRINGIFY(prio) "_task")))\ = fn diff --git a/subsys/debug/Kconfig b/subsys/debug/Kconfig index 60a3dc9a1c25..19abfc5b0c51 100644 --- a/subsys/debug/Kconfig +++ b/subsys/debug/Kconfig @@ -120,6 +120,18 @@ config ASAN This behavior can be changes by adding leak_check_at_exit=1 to the environment variable ASAN_OPTIONS. +config ASAN_RECOVER + bool "Continue after sanitizer errors" + depends on ASAN + default y + help + The default behavior of compiler sanitizers is to exit after + the first error. Set this to y to enable the code to + continue, which can be useful if a code base has known + unsuppressed errors. You will also need to set + "halt_on_error=0" in your ASAN_OPTIONS environment variable + at runtime. + config ASAN_NOP_DLCLOSE bool "Override host OS dlclose() with a NOP" default y if HAS_SDL