Apply hash-pinned generated edits for CVE-2025-14942 while keeping wolfSSH 1.4.20 managed sources unchanged. Add the ABI header overlay, provenance records, and real state-machine interoperability contracts.
151 lines
7.6 KiB
CMake
151 lines
7.6 KiB
CMake
# SPDX-License-Identifier: GPL-3.0-only
|
|
# Include after project(): IDF component targets and their final source lists exist.
|
|
if(CMAKE_VERSION VERSION_LESS 3.18)
|
|
message(FATAL_ERROR "Security overrides need CMake 3.18 source-property directory support")
|
|
endif()
|
|
|
|
set(_sak_security_script "${CMAKE_CURRENT_LIST_DIR}/../tools/security_overrides.py")
|
|
get_filename_component(_sak_security_script "${_sak_security_script}" REALPATH)
|
|
if(NOT PYTHON)
|
|
find_package(Python3 REQUIRED COMPONENTS Interpreter)
|
|
set(_sak_security_python "${Python3_EXECUTABLE}")
|
|
else()
|
|
set(_sak_security_python "${PYTHON}")
|
|
endif()
|
|
idf_build_get_property(_sak_security_idf IDF_PATH)
|
|
execute_process(
|
|
COMMAND "${_sak_security_python}" "${_sak_security_script}"
|
|
--idf-path "${_sak_security_idf}"
|
|
--project-dir "${PROJECT_SOURCE_DIR}"
|
|
--binary-dir "${CMAKE_BINARY_DIR}"
|
|
RESULT_VARIABLE _sak_security_result
|
|
OUTPUT_VARIABLE _sak_security_stdout
|
|
ERROR_VARIABLE _sak_security_stderr
|
|
)
|
|
if(NOT _sak_security_result EQUAL 0)
|
|
message(FATAL_ERROR "SDK security override generation failed:\n${_sak_security_stdout}${_sak_security_stderr}")
|
|
endif()
|
|
include("${CMAKE_BINARY_DIR}/security_overrides/manifest.cmake")
|
|
set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS
|
|
"${_sak_security_script}" "${SAK_SECURITY_VERSION_HEADER}")
|
|
if(SAK_SECURITY_HEADER_IDS)
|
|
get_filename_component(_sak_security_tools "${_sak_security_script}" DIRECTORY)
|
|
set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS
|
|
"${_sak_security_tools}/wolfssh_order/delta.json")
|
|
endif()
|
|
|
|
# Public extension point: the Python Entry registry supplies the mapping. This
|
|
# function is backend-agnostic; a later pinned project/vendor source uses it too.
|
|
function(sak_security_replace_source component original generated nested_target)
|
|
idf_component_get_property(_target "${component}" COMPONENT_LIB)
|
|
if(NOT TARGET "${_target}")
|
|
message(FATAL_ERROR "Security override: missing component target ${component}")
|
|
endif()
|
|
if(NOT "${nested_target}" STREQUAL "")
|
|
if(NOT component STREQUAL "mbedtls" OR
|
|
NOT nested_target MATCHES "^(mbedtls|mbedx509|mbedcrypto)$")
|
|
message(FATAL_ERROR "Security override: invalid nested target ${component}/${nested_target}")
|
|
endif()
|
|
if(NOT TARGET "${nested_target}")
|
|
message(FATAL_ERROR "Security override: missing nested target ${nested_target}")
|
|
endif()
|
|
set(_target "${nested_target}")
|
|
get_target_property(_imported "${_target}" IMPORTED)
|
|
get_target_property(_alias "${_target}" ALIASED_TARGET)
|
|
get_target_property(_owner_dir "${_target}" SOURCE_DIR)
|
|
get_filename_component(_owner_dir "${_owner_dir}" REALPATH)
|
|
get_filename_component(_expected_owner "${_sak_security_idf}/components/mbedtls/mbedtls/library" REALPATH)
|
|
if(_imported OR _alias OR NOT _owner_dir STREQUAL _expected_owner)
|
|
message(FATAL_ERROR "Security override: unexpected nested target owner ${_target}: ${_owner_dir}")
|
|
endif()
|
|
endif()
|
|
get_target_property(_source_dir "${_target}" SOURCE_DIR)
|
|
get_target_property(_sources "${_target}" SOURCES)
|
|
get_filename_component(_expected "${original}" REALPATH)
|
|
set(_matches 0)
|
|
set(_replaced)
|
|
foreach(_source IN LISTS _sources)
|
|
if(_source MATCHES "\\$<")
|
|
# An expression could hide an additional copy of the protected source.
|
|
message(FATAL_ERROR "Security override: unaudited source expression in ${component}: ${_source}")
|
|
endif()
|
|
get_filename_component(_absolute "${_source}" ABSOLUTE BASE_DIR "${_source_dir}")
|
|
get_filename_component(_absolute "${_absolute}" REALPATH)
|
|
if(_absolute STREQUAL _expected)
|
|
math(EXPR _matches "${_matches} + 1")
|
|
|
|
list(APPEND _replaced "${generated}")
|
|
else()
|
|
list(APPEND _replaced "${_source}")
|
|
endif()
|
|
endforeach()
|
|
if(NOT _matches EQUAL 1)
|
|
message(FATAL_ERROR "Security override: ${component} needs exactly one ${original}; found ${_matches}")
|
|
endif()
|
|
|
|
# Target flags/includes/definitions are retained because the target is not
|
|
# replaced. Preserve source-specific properties in the owning directory too.
|
|
set(_properties COMPILE_FLAGS COMPILE_OPTIONS COMPILE_DEFINITIONS
|
|
INCLUDE_DIRECTORIES OBJECT_DEPENDS OBJECT_OUTPUTS LANGUAGE
|
|
SKIP_PRECOMPILE_HEADERS SKIP_UNITY_BUILD_INCLUSION
|
|
SKIP_LINTING HEADER_FILE_ONLY)
|
|
set(_configs DEBUG RELEASE RELWITHDEBINFO MINSIZEREL
|
|
${CMAKE_CONFIGURATION_TYPES} ${CMAKE_BUILD_TYPE})
|
|
foreach(_config IN LISTS _configs)
|
|
string(TOUPPER "${_config}" _config)
|
|
list(APPEND _properties "COMPILE_DEFINITIONS_${_config}")
|
|
endforeach()
|
|
foreach(_property IN LISTS _properties)
|
|
get_property(_is_set SOURCE "${_expected}" DIRECTORY "${_source_dir}"
|
|
PROPERTY "${_property}" SET)
|
|
if(_is_set)
|
|
get_property(_value SOURCE "${_expected}" DIRECTORY "${_source_dir}"
|
|
PROPERTY "${_property}")
|
|
set_property(SOURCE "${generated}" DIRECTORY "${_source_dir}"
|
|
PROPERTY "${_property}" "${_value}")
|
|
endif()
|
|
endforeach()
|
|
get_filename_component(_original_dir "${original}" DIRECTORY)
|
|
get_property(_includes SOURCE "${generated}" DIRECTORY "${_source_dir}"
|
|
PROPERTY INCLUDE_DIRECTORIES)
|
|
# Restore the implicit quoted-include search directory lost by relocating C.
|
|
set_property(SOURCE "${generated}" DIRECTORY "${_source_dir}"
|
|
PROPERTY INCLUDE_DIRECTORIES "${_original_dir};${_includes}")
|
|
set_property(TARGET "${_target}" PROPERTY SOURCES "${_replaced}")
|
|
set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS
|
|
"${original}" "${generated}")
|
|
message(STATUS "Security override: ${component}: ${original} -> ${generated}")
|
|
endfunction()
|
|
|
|
# HandshakeInfo and WOLFSSH are ABI-sensitive. Force the same generated header
|
|
# into the library AND every transitive consumer, even if a consumer adds a
|
|
# vendor include directory ahead of the overlay. The original include guard
|
|
# then prevents a second, stale definition. This also creates compiler deps.
|
|
foreach(_sak_security_id IN LISTS SAK_SECURITY_HEADER_IDS)
|
|
if(NOT _sak_security_id STREQUAL "wolfssh_internal_header" OR
|
|
NOT SAK_SECURITY_${_sak_security_id}_COMPONENT STREQUAL "wolfssl__wolfssh")
|
|
message(FATAL_ERROR "Security override: unaudited header overlay")
|
|
endif()
|
|
idf_component_get_property(_sak_security_wolfssh wolfssl__wolfssh COMPONENT_LIB)
|
|
if(NOT TARGET "${_sak_security_wolfssh}")
|
|
message(FATAL_ERROR "Security override: missing wolfSSH overlay target")
|
|
endif()
|
|
target_include_directories("${_sak_security_wolfssh}" BEFORE PUBLIC
|
|
"${SAK_SECURITY_WOLFSSH_INCLUDE}")
|
|
# PlatformIO's ESP-IDF adapter sorts app flags and deduplicates component
|
|
# flags. Keep option+operand atomic, as with wolf_crypto_policy.h.
|
|
target_compile_options("${_sak_security_wolfssh}" PUBLIC
|
|
"-include${SAK_SECURITY_${_sak_security_id}_GENERATED}")
|
|
set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS
|
|
"${SAK_SECURITY_${_sak_security_id}_ORIGINAL}"
|
|
"${SAK_SECURITY_${_sak_security_id}_GENERATED}")
|
|
endforeach()
|
|
|
|
foreach(_sak_security_id IN LISTS SAK_SECURITY_OVERRIDE_IDS)
|
|
sak_security_replace_source(
|
|
"${SAK_SECURITY_${_sak_security_id}_COMPONENT}"
|
|
"${SAK_SECURITY_${_sak_security_id}_ORIGINAL}"
|
|
"${SAK_SECURITY_${_sak_security_id}_GENERATED}"
|
|
"${SAK_SECURITY_${_sak_security_id}_TARGET}")
|
|
endforeach()
|