mirror of
https://github.com/espressif/esp-idf.git
synced 2026-10-02 11:10:54 +03:00
feat(build): support KASAN in the build system v2 (cmakev2)
Mirror Kernel Address Sanitizer support into cmakev2 so that CONFIG_COMPILER_KASAN instruments application code the same way build system v1 does.
This commit is contained in:
@@ -7,6 +7,8 @@ include(utilities)
|
||||
include(CheckCCompilerFlag)
|
||||
include(CheckCXXCompilerFlag)
|
||||
include(component_validation)
|
||||
# Shared with the Build system v1: single definition of the KASAN exclusion set.
|
||||
include(${CMAKE_CURRENT_LIST_DIR}/../cmake/kasan.cmake)
|
||||
|
||||
#[[api
|
||||
.. cmakev2:function:: idf_build_set_property
|
||||
@@ -317,6 +319,57 @@ function(__idf_build_link_whole_archive target scope library)
|
||||
target_link_libraries(${target} ${scope} ${library})
|
||||
endfunction()
|
||||
|
||||
#[[
|
||||
__kasan_exclude_components(<library>)
|
||||
|
||||
Compile the low-level components linked to ``library`` without Kernel
|
||||
Address Sanitizer instrumentation.
|
||||
|
||||
The exclusion set is defined once in ``tools/cmake/kasan.cmake`` and shared
|
||||
with the Build system v1. Called from ``idf_build_library`` once
|
||||
LIBRARY_COMPONENTS_LINKED is populated, so every component target already
|
||||
exists and ``-fno-sanitize`` is appended after the global ``-fsanitize``
|
||||
added while the component was processed, which is what makes it win.
|
||||
|
||||
A subproject that opted out of instrumentation altogether by setting the
|
||||
SET_COMPILER_KASAN build property to NO never had ``-fsanitize`` applied, so
|
||||
there is nothing to undo and this is a no-op there.
|
||||
#]]
|
||||
function(__kasan_exclude_components library)
|
||||
idf_build_get_property(set_compiler_kasan SET_COMPILER_KASAN)
|
||||
if(NOT DEFINED set_compiler_kasan OR set_compiler_kasan STREQUAL "")
|
||||
set(set_compiler_kasan YES)
|
||||
endif()
|
||||
if(NOT CONFIG_COMPILER_KASAN OR NOT set_compiler_kasan)
|
||||
return()
|
||||
endif()
|
||||
|
||||
idf_library_get_property(components_linked "${library}" LIBRARY_COMPONENTS_LINKED)
|
||||
kasan_filter_excluded_components(excluded ${components_linked})
|
||||
|
||||
foreach(component_name IN LISTS excluded)
|
||||
idf_component_get_property(component_real_target "${component_name}" COMPONENT_REAL_TARGET)
|
||||
idf_component_get_property(component_real_target_type "${component_name}" COMPONENT_REAL_TARGET_TYPE)
|
||||
|
||||
# Components that created no target, and INTERFACE libraries, have no
|
||||
# sources to de-instrument. Adding an INTERFACE compile option would
|
||||
# also propagate -fno-sanitize to every consumer, including the
|
||||
# application under test.
|
||||
if(NOT component_real_target OR "${component_real_target}" STREQUAL "NOTFOUND")
|
||||
continue()
|
||||
endif()
|
||||
if(NOT "${component_real_target_type}" STREQUAL "STATIC_LIBRARY")
|
||||
continue()
|
||||
endif()
|
||||
|
||||
# idf_build_library may run more than once per configure. Appending the
|
||||
# option again is harmless: CMake de-duplicates compile options, and
|
||||
# every copy lands after the global -fsanitize added while the component
|
||||
# was processed, so the surviving one still wins.
|
||||
target_compile_options("${component_real_target}" PRIVATE "-fno-sanitize=kernel-address")
|
||||
endforeach()
|
||||
endfunction()
|
||||
|
||||
#[[api
|
||||
.. cmakev2:function:: idf_build_library
|
||||
|
||||
@@ -433,6 +486,13 @@ function(idf_build_library library)
|
||||
idf_library_set_property("${library}" LIBRARY_COMPONENT_INTERFACES_LINKED "${component_interface}" APPEND)
|
||||
endforeach()
|
||||
|
||||
# Kernel Address Sanitizer (CONFIG_COMPILER_KASAN): de-instrument the
|
||||
# low-level components. Applied here, once the set of components linked to
|
||||
# the library is known and every component target already exists, so that
|
||||
# -fno-sanitize lands after the global -fsanitize added while the component
|
||||
# was processed and therefore wins.
|
||||
__kasan_exclude_components("${library}")
|
||||
|
||||
# Collect linker fragment files from all components linked to the library
|
||||
# interface and store them in the __LDGEN_FRAGMENT_FILES files. This
|
||||
# property is used by ldgen to generate template-based linker scripts.
|
||||
|
||||
@@ -861,6 +861,18 @@ endfunction()
|
||||
|
||||
List of linker script files added to the link command (with ``-T``) for the
|
||||
component.
|
||||
|
||||
.. cmakev2:component_property:: NO_KASAN
|
||||
|
||||
When set to a true value, the component is compiled without Kernel Address
|
||||
Sanitizer instrumentation (``-fno-sanitize=kernel-address``) while
|
||||
``CONFIG_COMPILER_KASAN`` is enabled. Set it on a component that runs before
|
||||
the sanitizer shadow is initialised, executes with the flash cache disabled,
|
||||
or is otherwise too low-level to instrument.
|
||||
|
||||
The low-level ESP-IDF components are excluded already; the built-in set is
|
||||
defined in ``tools/cmake/kasan.cmake`` and shared with the CMake-based build
|
||||
system v1, which honours this property as well.
|
||||
#]]
|
||||
|
||||
#[[api
|
||||
|
||||
@@ -356,6 +356,31 @@ function(__init_project_configuration)
|
||||
list(APPEND compile_options "-fstack-protector-all")
|
||||
endif()
|
||||
|
||||
# Kernel Address Sanitizer (CONFIG_COMPILER_KASAN): instrument every memory
|
||||
# load and store with a shadow-memory check. The flag goes into the C and C++
|
||||
# options rather than the language-agnostic list because the assembler does
|
||||
# not accept -fsanitize. Low-level components are de-instrumented again in
|
||||
# idf_build_library(), see __kasan_exclude_components().
|
||||
#
|
||||
# A subproject that must never be instrumented (for example the bootloader,
|
||||
# which runs before the sanitizer shadow is initialised) sets the
|
||||
# SET_COMPILER_KASAN build property to NO before idf_project_init(), the
|
||||
# same way it uses SET_COMPILER_LTO and SET_COMPILER_OPTIMIZATION; an unset
|
||||
# property means instrumentation is allowed.
|
||||
idf_build_get_property(set_compiler_kasan SET_COMPILER_KASAN)
|
||||
if(NOT DEFINED set_compiler_kasan OR set_compiler_kasan STREQUAL "")
|
||||
set(set_compiler_kasan YES)
|
||||
endif()
|
||||
if(CONFIG_COMPILER_KASAN AND set_compiler_kasan)
|
||||
list(APPEND c_compile_options "-fsanitize=kernel-address")
|
||||
list(APPEND cxx_compile_options "-fsanitize=kernel-address")
|
||||
if(NOT CONFIG_KASAN_STACK)
|
||||
list(APPEND c_compile_options "--param" "asan-stack=0")
|
||||
list(APPEND cxx_compile_options "--param" "asan-stack=0")
|
||||
endif()
|
||||
list(APPEND link_options "-fsanitize=kernel-address")
|
||||
endif()
|
||||
|
||||
if(CONFIG_COMPILER_DUMP_RTL_FILES)
|
||||
list(APPEND compile_options "-fdump-rtl-expand")
|
||||
endif()
|
||||
|
||||
Reference in New Issue
Block a user