From 64ca4eb070e33b721ac99fcd6d1a2f68b4edad21 Mon Sep 17 00:00:00 2001 From: Ross Brunton Date: Fri, 13 Sep 2024 15:38:40 +0100 Subject: [PATCH] Enable hardening flags on Linux --- .github/workflows/cmake.yml | 7 ++++ CMakeLists.txt | 12 ++++++ cmake/helpers.cmake | 46 +++++++++++++++++++++-- scripts/check-hardening.sh | 42 +++++++++++++++++++++ source/adapters/level_zero/CMakeLists.txt | 11 ++++++ source/mock/CMakeLists.txt | 2 +- test/adapters/level_zero/CMakeLists.txt | 2 +- test/adapters/level_zero/zeCallMap.cpp | 3 +- 8 files changed, 119 insertions(+), 6 deletions(-) create mode 100755 scripts/check-hardening.sh diff --git a/.github/workflows/cmake.yml b/.github/workflows/cmake.yml index 6662f7833d..7ae4c6015a 100644 --- a/.github/workflows/cmake.yml +++ b/.github/workflows/cmake.yml @@ -94,6 +94,8 @@ jobs: -DCMAKE_BUILD_TYPE=${{matrix.build_type}} -DUR_BUILD_TESTS=ON -DUR_FORMAT_CPP_STYLE=ON + -DUR_WEXTRA=ON + -DUR_HARDEN=ON -DUR_DPCXX=${{github.workspace}}/dpcpp_compiler/bin/clang++ ${{matrix.libbacktrace}} ${{matrix.pool_tracking}} @@ -110,6 +112,8 @@ jobs: -DCMAKE_BUILD_TYPE=${{matrix.build_type}} -DUR_BUILD_TESTS=ON -DUR_FORMAT_CPP_STYLE=ON + -DUR_WEXTRA=ON + -DUR_HARDEN=OFF ${{matrix.libbacktrace}} ${{matrix.pool_tracking}} ${{matrix.latency_tracking}} @@ -121,6 +125,9 @@ jobs: - name: Verify that each source file contains a license run: cmake --build ${{github.workspace}}/build --target verify-licenses + - name: Verify hardening flags have been set + run: cmake --build ${{github.workspace}}/build --target verify-licenses + - name: Build run: cmake --build ${{github.workspace}}/build -j $(nproc) diff --git a/CMakeLists.txt b/CMakeLists.txt index a908a22d80..b5cb0b5ebf 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -60,6 +60,8 @@ option(UR_BUILD_XPTI_LIBS "Build the XPTI libraries when tracing is enabled" ON) option(UR_STATIC_LOADER "Build loader as a static library" OFF) option(UR_FORCE_LIBSTDCXX "Force use of libstdc++ in a build using libc++ on Linux" OFF) option(UR_ENABLE_LATENCY_HISTOGRAM "Enable latncy histogram" OFF) +option(UR_WEXTRA "Enable -Wextra on all build targets" OFF) +option(UR_HARDEN "Enable additional hardening flags" ON) set(UR_DPCXX "" CACHE FILEPATH "Path of the DPC++ compiler executable") set(UR_DPCXX_BUILD_FLAGS "" CACHE STRING "Build flags to pass to DPC++ when compiling device programs") set(UR_SYCL_LIBRARY_DIR "" CACHE PATH @@ -160,6 +162,8 @@ if(UR_ENABLE_TRACING) set_target_properties(xptifw PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${CMAKE_LIBRARY_OUTPUT_DIRECTORY} ) + add_ur_target_compile_options(xptifw) + add_ur_target_link_options(xptifw) if (UR_STATIC_LOADER) install(TARGETS xpti xptifw @@ -269,6 +273,14 @@ add_custom_target(verify-licenses COMMENT "Verify all files contain a license." ) +# Add hardening check +list(FILTER license_src EXCLUDE REGEX "registry.yml") +add_custom_target(verify-hardening + COMMAND "${PROJECT_SOURCE_DIR}/scripts/check-hardening.sh" + ${CMAKE_BINARY_DIR} + COMMENT "Check hardening settings on built binaries and libraries" +) + # Add code formatter target add_custom_target(cppformat) # ... and all source files to the formatter diff --git a/cmake/helpers.cmake b/cmake/helpers.cmake index 6a5700da8b..4241c3ca23 100644 --- a/cmake/helpers.cmake +++ b/cmake/helpers.cmake @@ -42,6 +42,10 @@ endfunction() include(CheckCXXCompilerFlag) +if (CMAKE_COMPILER_IS_GNUCC AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS 8.0) + set(OLD_GCC_VERSION ON) +endif() + macro(add_sanitizer_flag flag) set(SAVED_CMAKE_REQUIRED_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES}) set(CMAKE_REQUIRED_LIBRARIES "${CMAKE_REQUIRED_LIBRARIES} -fsanitize=${flag}") @@ -59,6 +63,7 @@ endmacro() function(add_ur_target_compile_options name) if(NOT MSVC) + target_compile_definitions(${name} PRIVATE -D_FORTIFY_SOURCE=2) target_compile_options(${name} PRIVATE -fPIC -Wall @@ -68,9 +73,26 @@ function(add_ur_target_compile_options name) $<$:-fdiagnostics-color=always> $<$:-fcolor-diagnostics> ) + if (UR_HARDEN) + target_compile_options(${name} PRIVATE + -fstack-protector + -fstack-clash-protection + -fcf-protection=none + -flto + -fstack-protector-strong + -fvisibility=hidden # Required for -fsanitize=cfi + $<$:-mfunction-return=thunk> + $<$:-mindirect-branch=thunk> + $<$:-mindirect-branch-register> + $<$:-mretpoline> + $<$:-fsanitize=cfi> + ) + endif() if (CMAKE_BUILD_TYPE STREQUAL "Release") - target_compile_definitions(${name} PRIVATE -D_FORTIFY_SOURCE=2) - target_compile_options(${name} PRIVATE -fvisibility=hidden) + target_compile_options(${name} PRIVATE + -Werror + -fvisibility=hidden + ) endif() if(UR_DEVELOPER_MODE) target_compile_options(${name} PRIVATE @@ -79,6 +101,18 @@ function(add_ur_target_compile_options name) -fstack-protector-strong ) endif() + if(UR_WEXTRA) + target_compile_options(${name} PRIVATE + -Wextra + -Wformat + -Wformat-security + ) + if (CMAKE_BUILD_TYPE STREQUAL "Release") + target_compile_options(${name} PRIVATE + -Werror=format-security + ) + endif() + endif() elseif(MSVC) target_compile_options(${name} PRIVATE $<$:/MP> # clang-cl.exe does not support /MP @@ -102,7 +136,13 @@ endfunction() function(add_ur_target_link_options name) if(NOT MSVC) if (NOT APPLE) - target_link_options(${name} PRIVATE "LINKER:-z,relro,-z,now") + target_link_options(${name} PRIVATE "LINKER:-z,relro,-z,now,-z,noexecstack") + if (CMAKE_BUILD_TYPE STREQUAL "Release") + target_link_options(${name} PRIVATE + -Werror + $<$:-pie> + ) + endif() endif() elseif(MSVC) target_link_options(${name} PRIVATE diff --git a/scripts/check-hardening.sh b/scripts/check-hardening.sh new file mode 100755 index 0000000000..781651744f --- /dev/null +++ b/scripts/check-hardening.sh @@ -0,0 +1,42 @@ +#!/bin/sh +if [ -z $1 ]; then + echo "Usage: $0 builddir" >&2; + exit; +fi + +which hardening-check >> /dev/null; +if [ $? != "0" ]; then + echo "hardening-check not found - on Ubuntu it is from the 'devscripts' package." >&2; + exit; +fi + +RET=0; + +for file in $1/bin/*; do + case "$file" in + */urtrace) + # This is a python script + true;; + *) + hardening-check -q --nocfprotection --nofortify $file;; + esac + RET=$(($RET + $?)) +done; + +for file in $1/lib/*.so; do + case "$file" in + */libOpenCL*) + # This is not built as part of UR + true;; + */libzeCallMap.so | */libur_mock_headers.so) + # Only used in testing, and are too simple for many of the hardening flags to have an effect. + true;; + *) + hardening-check -q --nocfprotection --nofortify $file;; + esac + RET=$(($RET + $?)) +done; + +if [ $RET != "0" ]; then + exit 1; +fi diff --git a/source/adapters/level_zero/CMakeLists.txt b/source/adapters/level_zero/CMakeLists.txt index cc05d36084..d60ad8918d 100644 --- a/source/adapters/level_zero/CMakeLists.txt +++ b/source/adapters/level_zero/CMakeLists.txt @@ -155,6 +155,17 @@ if(UR_BUILD_ADAPTER_L0) ) endif() + # Ensure UR flags are propogated to level zero + # TODO: https://github.com/oneapi-src/unified-runtime/issues/2105 + #foreach(TARGET IN ITEMS ze_loader ze_validation_layer ze_tracing_layer ze_null) + # add_ur_target_compile_options(${TARGET}) + # add_ur_target_link_options(${TARGET}) + # target_compile_options(${TARGET} PRIVATE + # $<$,GNU;Clang;Intel;IntelLLVM>:-Wno-error -Wno-unused-parameter> + # $<$:/WX- /UUNICODE> + # ) + #endforeach() + if(NOT WIN32) target_sources(ur_adapter_level_zero PRIVATE diff --git a/source/mock/CMakeLists.txt b/source/mock/CMakeLists.txt index f3933fbef1..0c5d506294 100644 --- a/source/mock/CMakeLists.txt +++ b/source/mock/CMakeLists.txt @@ -3,7 +3,7 @@ # See LICENSE.TXT # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -add_library (ur_mock_headers SHARED +add_ur_library (ur_mock_headers SHARED "${CMAKE_CURRENT_SOURCE_DIR}/ur_mock_helpers.cpp") target_include_directories(ur_mock_headers diff --git a/test/adapters/level_zero/CMakeLists.txt b/test/adapters/level_zero/CMakeLists.txt index b1c34b8916..6e4cd4874b 100644 --- a/test/adapters/level_zero/CMakeLists.txt +++ b/test/adapters/level_zero/CMakeLists.txt @@ -43,7 +43,7 @@ if(UR_BUILD_ADAPTER_L0) if(NOT WIN32 AND NOT UR_STATIC_ADAPTER_L0) # Make L0 use CallMap from a seprate shared lib so that we can access the map # from the tests. This only seems to work on linux - add_library(zeCallMap SHARED zeCallMap.cpp) + add_ur_library(zeCallMap SHARED zeCallMap.cpp) target_compile_definitions(ur_adapter_level_zero PRIVATE UR_L0_CALL_COUNT_IN_TESTS) # TODO: stop exporting internals like this for tests... target_link_libraries(ur_adapter_level_zero PRIVATE zeCallMap) diff --git a/test/adapters/level_zero/zeCallMap.cpp b/test/adapters/level_zero/zeCallMap.cpp index 3c6487f36d..c2e47b856d 100644 --- a/test/adapters/level_zero/zeCallMap.cpp +++ b/test/adapters/level_zero/zeCallMap.cpp @@ -9,4 +9,5 @@ // Map used by L0 adapter to count the number of calls to each L0 function // Lifetime is managed by the adapter, this variable is defined here // only so that we can read it from the tests. -std::map *ZeCallCount = nullptr; +__attribute__((visibility("default"))) std::map *ZeCallCount = + nullptr;