From 1961bb1857d5d3c9a7e196d52b0c7c459bc6e619 Mon Sep 17 00:00:00 2001 From: Alexander Alekhin Date: Wed, 7 Jun 2017 09:07:32 +0000 Subject: [PATCH] cmake: add ENABLE_BUILD_HARDENING option --- CMakeLists.txt | 1 + cmake/OpenCVCompilerDefenses.cmake | 87 ++++++++++++++++++++++++++++++ cmake/OpenCVCompilerOptions.cmake | 11 +++- samples/CMakeLists.txt | 4 +- 4 files changed, 101 insertions(+), 2 deletions(-) create mode 100644 cmake/OpenCVCompilerDefenses.cmake diff --git a/CMakeLists.txt b/CMakeLists.txt index e3765e8b29..657e1a93f3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -306,6 +306,7 @@ OCV_OPTION(ANDROID_EXAMPLES_WITH_LIBS "Build binaries of Android examples with n OCV_OPTION(ENABLE_IMPL_COLLECTION "Collect implementation data on function call" OFF ) OCV_OPTION(ENABLE_INSTRUMENTATION "Instrument functions to collect calls trace and performance" OFF ) OCV_OPTION(ENABLE_GNU_STL_DEBUG "Enable GNU STL Debug mode (defines _GLIBCXX_DEBUG)" OFF IF ((NOT CMAKE_VERSION VERSION_LESS "2.8.11") AND CMAKE_COMPILER_IS_GNUCXX) ) +OCV_OPTION(ENABLE_BUILD_HARDENING "Enable hardening of the resulting binaries (against security attacks, detects memory corruption, etc)" OFF) OCV_OPTION(GENERATE_ABI_DESCRIPTOR "Generate XML file for abi_compliance_checker tool" OFF IF UNIX) OCV_OPTION(CV_ENABLE_INTRINSICS "Use intrinsic-based optimized code" ON ) OCV_OPTION(CV_DISABLE_OPTIMIZATION "Disable explicit optimized code (dispatched code/intrinsics/loop unrolling/etc)" OFF ) diff --git a/cmake/OpenCVCompilerDefenses.cmake b/cmake/OpenCVCompilerDefenses.cmake new file mode 100644 index 0000000000..822c4c1557 --- /dev/null +++ b/cmake/OpenCVCompilerDefenses.cmake @@ -0,0 +1,87 @@ +# Enable build defense flags. +# Performance may be affected. +# More information: +# - https://www.owasp.org/index.php/C-Based_Toolchain_Hardening +# - https://wiki.debian.org/Hardening +# - https://wiki.gentoo.org/wiki/Hardened/Toolchain +# - https://docs.microsoft.com/en-us/cpp/build/reference/sdl-enable-additional-security-checks + + +set(OPENCV_LINKER_DEFENSES_FLAGS_COMMON "") + +macro(ocv_add_defense_compiler_flag option) + ocv_check_flag_support(CXX "${option}" _varname "${ARGN}") + if(${_varname}) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${option}") + endif() + + ocv_check_flag_support(C "${option}" _varname "${ARGN}") + if(${_varname}) + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${option}") + endif() +endmacro() + +macro(ocv_add_defense_compiler_flag_release option) + ocv_check_flag_support(CXX "${option}" _varname "${ARGN}") + if(${_varname}) + set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} ${option}") + endif() + + ocv_check_flag_support(C "${option}" _varname "${ARGN}") + if(${_varname}) + set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} ${option}") + endif() +endmacro() + +# Define flags + +if(MSVC) + ocv_add_defense_compiler_flag("/GS") + ocv_add_defense_compiler_flag("/DynamicBase") + ocv_add_defense_compiler_flag("/SafeSEH") + ocv_add_defense_compiler_flag("/sdl") +elseif(CMAKE_COMPILER_IS_GNUCXX) + if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS "4.9") + ocv_add_defense_compiler_flag("-fstack-protector") + else() + ocv_add_defense_compiler_flag("-fstack-protector-strong") + endif() + + # These flags is added by general options: -Wformat -Wformat-security + if(NOT CMAKE_CXX_FLAGS MATCHES "-Wformat" OR NOT CMAKE_CXX_FLAGS MATCHES "format-security") + message(FATAL_ERROR "Defense flags: uncompatible options") + endif() + + if(ANDROID) + ocv_add_defense_compiler_flag_release("-D_FORTIFY_SOURCE=2") + if(NOT CMAKE_CXX_FLAGS_RELEASE MATCHES "-D_FORTIFY_SOURCE=2") # TODO Check this + ocv_add_defense_compiler_flag_release("-D_FORTIFY_SOURCE=1") + endif() + else() + ocv_add_defense_compiler_flag_release("-D_FORTIFY_SOURCE=2") + endif() + + set(OPENCV_LINKER_DEFENSES_FLAGS_COMMON "${OPENCV_LINKER_DEFENSES_FLAGS_COMMON} -z noexecstack -z relro -z now" ) +else() + # not supported +endif() + +set(CMAKE_POSITION_INDEPENDENT_CODE TRUE) +if(NOT CMAKE_CXX_FLAGS MATCHES "-fPIC") + ocv_add_defense_compiler_flag("-fPIC") +endif() +if(CMAKE_COMPILER_IS_GNUCXX) + set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fPIE -pie") +endif() + +set( CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} ${LINKER_DEFENSES_FLAGS_COMMON}" ) +set( CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} ${LINKER_DEFENSES_FLAGS_COMMON}" ) +set( CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${LINKER_DEFENSES_FLAGS_COMMON}" ) + +if(CMAKE_COMPILER_IS_GNUCXX) + foreach(flags + CMAKE_CXX_FLAGS CMAKE_CXX_FLAGS_RELEASE CMAKE_CXX_FLAGS_DEBUG + CMAKE_C_FLAGS CMAKE_C_FLAGS_RELEASE CMAKE_C_FLAGS_DEBUG) + string(REPLACE "-O3" "-O2" ${flags} "${${flags}}") + endforeach() +endif() diff --git a/cmake/OpenCVCompilerOptions.cmake b/cmake/OpenCVCompilerOptions.cmake index 030837a5d0..d2a1098a8a 100644 --- a/cmake/OpenCVCompilerOptions.cmake +++ b/cmake/OpenCVCompilerOptions.cmake @@ -205,7 +205,11 @@ if(CMAKE_COMPILER_IS_GNUCXX) endif() if(MSVC) - set(OPENCV_EXTRA_FLAGS "${OPENCV_EXTRA_FLAGS} /D _CRT_SECURE_NO_DEPRECATE /D _CRT_NONSTDC_NO_DEPRECATE /D _SCL_SECURE_NO_WARNINGS") + #TODO Code refactoring is required to resolve security warnings + #if(NOT ENABLE_BUILD_HARDENING) + set(OPENCV_EXTRA_FLAGS "${OPENCV_EXTRA_FLAGS} /D _CRT_SECURE_NO_DEPRECATE /D _CRT_NONSTDC_NO_DEPRECATE /D _SCL_SECURE_NO_WARNINGS") + #endif() + # 64-bit portability warnings, in MSVC80 if(MSVC80) set(OPENCV_EXTRA_FLAGS "${OPENCV_EXTRA_FLAGS} /Wp64") @@ -328,3 +332,8 @@ endif() if(APPLE AND NOT CMAKE_CROSSCOMPILING AND NOT DEFINED ENV{LDFLAGS} AND EXISTS "/usr/local/lib") link_directories("/usr/local/lib") endif() + + +if(ENABLE_BUILD_HARDENING) + include(${CMAKE_CURRENT_LIST_DIR}/OpenCVCompilerDefenses.cmake) +endif() diff --git a/samples/CMakeLists.txt b/samples/CMakeLists.txt index b1f98e969d..152d502395 100644 --- a/samples/CMakeLists.txt +++ b/samples/CMakeLists.txt @@ -53,7 +53,9 @@ option(BUILD_EXAMPLES "Build samples" ON) find_package(OpenCV REQUIRED) if(MSVC) - add_definitions(-D_CRT_SECURE_NO_WARNINGS) + if(NOT ENABLE_BUILD_HARDENING) + add_definitions(-D_CRT_SECURE_NO_WARNINGS) + endif() if(NOT OpenCV_SHARED) foreach(flag_var