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 <andyross@google.com>
This commit is contained in:
Andy Ross 2022-08-09 17:57:42 -07:00 committed by Alberto Escolar
commit 74cc534758
13 changed files with 61 additions and 43 deletions

View file

@ -28,15 +28,6 @@ if (CONFIG_GPROF)
zephyr_compile_options($<TARGET_PROPERTY:compiler,gprof>) zephyr_compile_options($<TARGET_PROPERTY:compiler,gprof>)
zephyr_link_libraries($<TARGET_PROPERTY:linker,gprof>) zephyr_link_libraries($<TARGET_PROPERTY:linker,gprof>)
endif() endif()
if (CONFIG_ASAN)
zephyr_compile_options($<TARGET_PROPERTY:compiler,sanitize_address>)
zephyr_link_libraries($<TARGET_PROPERTY:linker,sanitize_address>)
endif ()
if (CONFIG_UBSAN)
zephyr_compile_options($<TARGET_PROPERTY:compiler,sanitize_undefined>)
zephyr_link_libraries($<TARGET_PROPERTY:linker,sanitize_undefined>)
endif ()
zephyr_compile_definitions(_POSIX_C_SOURCE=200809 _XOPEN_SOURCE=600 _XOPEN_SOURCE_EXTENDED) 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 # Zephyr which will clash with the native POSIX API] . It would also need to
# be included in a few zephyr kernel files. # 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) add_subdirectory(core)

View file

@ -162,11 +162,6 @@ set_compiler_property(PROPERTY coverage "")
# mwdt compiler flags for imacros. The specific header must be appended by user. # mwdt compiler flags for imacros. The specific header must be appended by user.
set_compiler_property(PROPERTY imacros -imacros) 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. # Security canaries.
#no support of -mstack-protector-guard=global" #no support of -mstack-protector-guard=global"
set_compiler_property(PROPERTY security_canaries -fstack-protector-all) set_compiler_property(PROPERTY security_canaries -fstack-protector-all)

View file

@ -101,11 +101,6 @@ set_compiler_property(PROPERTY no_common)
# Flags for imacros. The specific header must be appended by user. # Flags for imacros. The specific header must be appended by user.
set_compiler_property(PROPERTY imacros) 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 # Compiler flag for turning off thread-safe initialization of local statics
set_property(TARGET compiler-cpp PROPERTY no_threadsafe_statics) set_property(TARGET compiler-cpp PROPERTY no_threadsafe_statics)

View file

@ -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. # GCC compiler flags for imacros. The specific header must be appended by user.
set_compiler_property(PROPERTY imacros -imacros) 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 gprof -pg)
set_compiler_property(PROPERTY sanitize_undefined -fsanitize=undefined)
# GCC compiler flag for turning off thread-safe initialization of local statics # GCC compiler flag for turning off thread-safe initialization of local statics
set_property(TARGET compiler-cpp PROPERTY no_threadsafe_statics "-fno-threadsafe-statics") set_property(TARGET compiler-cpp PROPERTY no_threadsafe_statics "-fno-threadsafe-statics")

View file

@ -2,8 +2,3 @@
if (NOT CONFIG_COVERAGE_GCOV) if (NOT CONFIG_COVERAGE_GCOV)
set_property(TARGET linker PROPERTY coverage --coverage) set_property(TARGET linker PROPERTY coverage --coverage)
endif() 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)

View file

@ -7,9 +7,4 @@ if (NOT CONFIG_COVERAGE_GCOV)
set_property(TARGET linker PROPERTY coverage -lgcov) set_property(TARGET linker PROPERTY coverage -lgcov)
endif() 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) check_set_linker_property(TARGET linker APPEND PROPERTY gprof -pg)

View file

@ -3,11 +3,6 @@
# Set the property for the corresponding flags of the given toolchain. # Set the property for the corresponding flags of the given toolchain.
set_property(TARGET linker PROPERTY coverage) 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. # Linker flag for printing of memusage.
# Set this flag if the linker supports reporting of memusage as part of link, # Set this flag if the linker supports reporting of memusage as part of link,
# such as ls --print-memory-usage flag. # such as ls --print-memory-usage flag.

View file

@ -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) \ #define Z_INIT_ENTRY_DEFINE(_entry_name, _init_fn, _device, _level, _prio) \
static const Z_DECL_ALIGN(struct init_entry) \ 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)"_"))) = { \ __attribute__((__section__(".z_init_" #_level STRINGIFY(_prio)"_"))) = { \
.init = (_init_fn), \ .init = (_init_fn), \
.dev = (_device), \ .dev = (_device), \

View file

@ -52,6 +52,21 @@
#error "Invalid/unknown toolchain configuration" #error "Invalid/unknown toolchain configuration"
#endif #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 * @def GCC_VERSION
* @brief GCC version in xxyyzz for xx.yy.zz. Zero if not GCC compatible. * @brief GCC version in xxyyzz for xx.yy.zz. Zero if not GCC compatible.

View file

@ -209,7 +209,7 @@
*/ */
#define STRUCT_SECTION_ITERABLE(struct_type, name) \ #define STRUCT_SECTION_ITERABLE(struct_type, name) \
Z_DECL_ALIGN(struct 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. * @brief Defines an alternate data type iterable section.
@ -221,7 +221,7 @@
*/ */
#define STRUCT_SECTION_ITERABLE_ALTERNATE(out_type, struct_type, name) \ #define STRUCT_SECTION_ITERABLE_ALTERNATE(out_type, struct_type, name) \
Z_DECL_ALIGN(struct 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. * @brief Iterate over a specified iterable section.

View file

@ -618,5 +618,11 @@ do { \
*/ */
#define Z_IS_POW2(x) (((x) != 0) && (((x) & ((x)-1)) == 0)) #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 /* !_LINKER */
#endif /* ZEPHYR_INCLUDE_TOOLCHAIN_GCC_H_ */ #endif /* ZEPHYR_INCLUDE_TOOLCHAIN_GCC_H_ */

View file

@ -43,7 +43,7 @@ void posix_soc_clean_up(void);
* any Zephyr thread are running. * any Zephyr thread are running.
*/ */
#define NATIVE_TASK(fn, level, prio) \ #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")))\ __attribute__((__section__(".native_" #level STRINGIFY(prio) "_task")))\
= fn = fn

View file

@ -120,6 +120,18 @@ config ASAN
This behavior can be changes by adding leak_check_at_exit=1 to the This behavior can be changes by adding leak_check_at_exit=1 to the
environment variable ASAN_OPTIONS. 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 config ASAN_NOP_DLCLOSE
bool "Override host OS dlclose() with a NOP" bool "Override host OS dlclose() with a NOP"
default y if HAS_SDL default y if HAS_SDL