diff --git a/README.md b/README.md index 8df8d17..9f8f2b9 100644 --- a/README.md +++ b/README.md @@ -28,7 +28,7 @@ find_package(Sanitizers) ## Usage -You can enable the sanitizers with ``SANITIZE_ADDRESS``, ``SANITIZE_MEMORY``, ``SANITIZE_THREAD`` or ``SANITIZE_UNDEFINED`` options in your CMake configuration. You can do this by passing e.g. ``-DSANITIZE_ADDRESS=On`` on your command line or with your graphical interface. +You can enable the sanitizers with ``SANITIZE_ADDRESS``, ``SANITIZE_MEMORY``, ``SANITIZE_THREAD``, ``SANITIZE_UNDEFINED``, ``SANITIZE_CFI`` or ``SANITIZE_SS`` options in your CMake configuration. You can do this by passing e.g. ``-DSANITIZE_ADDRESS=On`` on your command line or with your graphical interface. If sanitizers are supported by your compiler, the specified targets will be build with sanitizer support. If your compiler has no sanitizing capabilities (I asume intel compiler doesn't) you'll get a warning but CMake will continue processing and sanitizing will simply just be ignored. diff --git a/cmake/FindCFI.cmake b/cmake/FindCFI.cmake new file mode 100644 index 0000000..e6a974f --- /dev/null +++ b/cmake/FindCFI.cmake @@ -0,0 +1,31 @@ +option(SANITIZE_CFI "Enable Control Flow Integrity (CFI) for sanitized targets." OFF) + +# FIXME: Might also want to add the variants of the CFI options + +set(FLAG_CANDIDATES + # FIXME: Brief comment on why the additional flags + # In this case you need a + # linker that does optimization at + # linking time such as LLVM lld or GNU gold. + "-g -fsanitize=cfi -fvisibility=hidden -flto -fuse-ld=lld" + ) + +# There might be some conflict with the other sanitizer +# hence it might need an if statement here. + +# add some handy functions +include(sanitize-helpers) + +if(SANITIZE_CFI) + sanitizer_check_compiler_flags("${FLAG_CANDIDATES}" "ControlFlowIntegrity" + "CFI") +endif() + +function (add_sanitize_cfi TARGET) + if (NOT SANITIZE_CFI) + return() + endif() + + sanitizer_add_flags(${TARGET} "ControlFlowIntegrity" "CFI") +endfunction() + diff --git a/cmake/FindMSan.cmake b/cmake/FindMSan.cmake index 77f45ae..9b2c3cd 100644 --- a/cmake/FindMSan.cmake +++ b/cmake/FindMSan.cmake @@ -39,12 +39,12 @@ endif() if (SANITIZE_MEMORY) if (NOT ${CMAKE_SYSTEM_NAME} STREQUAL "Linux") - message(WARNING "MemorySanitizer disabled for target ${TARGET} because " + message(STATUS "MemorySanitizer disabled for target ${TARGET} because " "MemorySanitizer is supported for Linux systems only.") set(SANITIZE_MEMORY Off CACHE BOOL "Enable MemorySanitizer for sanitized targets." FORCE) elseif (NOT ${CMAKE_SIZEOF_VOID_P} EQUAL 8) - message(WARNING "MemorySanitizer disabled for target ${TARGET} because " + message(STATUS "MemorySanitizer disabled for target ${TARGET} because " "MemorySanitizer is supported for 64bit systems only.") set(SANITIZE_MEMORY Off CACHE BOOL "Enable MemorySanitizer for sanitized targets." FORCE) diff --git a/cmake/FindSS.cmake b/cmake/FindSS.cmake new file mode 100644 index 0000000..5ec85f4 --- /dev/null +++ b/cmake/FindSS.cmake @@ -0,0 +1,24 @@ +option(SANITIZE_SS "Enable SafeStack for sanitized targets." OFF) + +set(FLAG_CANDIDATES + "-g -fsanitize=safe-stack" + ) + +# There might be some conflict with the other sanitizer +# hence it might need an if statement here. + +# add some handy functions +include(sanitize-helpers) + +if(SANITIZE_SS) + sanitizer_check_compiler_flags("${FLAG_CANDIDATES}" "SafeStack" + "SS") +endif() + +function (add_sanitize_ss TARGET) + if (NOT SANITIZE_SS) + return() + endif() + + sanitizer_add_flags(${TARGET} "SafeStack" "SS") +endfunction() diff --git a/cmake/FindSanitizers.cmake b/cmake/FindSanitizers.cmake index 94b1253..81acc9a 100644 --- a/cmake/FindSanitizers.cmake +++ b/cmake/FindSanitizers.cmake @@ -39,7 +39,8 @@ find_package(TSan ${FIND_QUIETLY_FLAG}) find_package(MSan ${FIND_QUIETLY_FLAG}) find_package(UBSan ${FIND_QUIETLY_FLAG}) find_package(LeakSan ${FIND_QUIETLY_FLAG}) - +find_package(CFI ${FIND_QUIETLY_FLAG}) +find_package(SS ${FIND_QUIETLY_FLAG}) set(Sanitizers_COMPONENTS "") @@ -87,7 +88,8 @@ endfunction() function(add_sanitizers ...) # If no sanitizer is enabled, return immediately. if (NOT (SANITIZE_ADDRESS OR SANITIZE_MEMORY OR SANITIZE_THREAD OR - SANITIZE_UNDEFINED)) + SANITIZE_UNDEFINED OR SANITIZE_CFI OR SANITIZE_SS)) + message(STATUS "No sanitizer selected.") return() endif () @@ -96,7 +98,7 @@ function(add_sanitizers ...) # wise sanitizers can't be used and a warning should be printed once. get_target_property(TARGET_TYPE ${TARGET} TYPE) if (TARGET_TYPE STREQUAL "INTERFACE_LIBRARY") - message(WARNING "Can't use any sanitizers for target ${TARGET}, " + message(STATUS "Can't use any sanitizers for target ${TARGET}, " "because it is an interface library and cannot be " "compiled directly.") return() @@ -104,14 +106,14 @@ function(add_sanitizers ...) sanitizer_target_compilers(${TARGET} TARGET_COMPILER) list(LENGTH TARGET_COMPILER NUM_COMPILERS) if (NUM_COMPILERS GREATER 1) - message(WARNING "Can't use any sanitizers for target ${TARGET}, " + message(STATUS "Can't use any sanitizers for target ${TARGET}, " "because it will be compiled by incompatible compilers. " "Target will be compiled without sanitizers.") return() # If the target is compiled by no or no known compiler, give a warning. elseif (NUM_COMPILERS EQUAL 0) - message(WARNING "Sanitizers for target ${TARGET} may not be" + message(STATUS "Sanitizers for target ${TARGET} may not be" " usable, because it uses no or an unknown compiler. " "This is a false warning for targets using only " "object lib(s) as input.") @@ -123,5 +125,7 @@ function(add_sanitizers ...) add_sanitize_memory(${TARGET}) add_sanitize_undefined(${TARGET}) add_sanitize_leak(${TARGET}) + add_sanitize_cfi(${TARGET}) + add_sanitize_ss(${TARGET}) endforeach () endfunction(add_sanitizers) diff --git a/cmake/FindTSan.cmake b/cmake/FindTSan.cmake index c560ab4..92718b4 100644 --- a/cmake/FindTSan.cmake +++ b/cmake/FindTSan.cmake @@ -47,12 +47,12 @@ endif() if (SANITIZE_THREAD) if (NOT ${CMAKE_SYSTEM_NAME} STREQUAL "Linux" AND NOT ${CMAKE_SYSTEM_NAME} STREQUAL "Darwin") - message(WARNING "ThreadSanitizer disabled for target ${TARGET} because " + message(STATUS "ThreadSanitizer disabled for target ${TARGET} because " "ThreadSanitizer is supported for Linux systems and macOS only.") set(SANITIZE_THREAD Off CACHE BOOL "Enable ThreadSanitizer for sanitized targets." FORCE) elseif (NOT ${CMAKE_SIZEOF_VOID_P} EQUAL 8) - message(WARNING "ThreadSanitizer disabled for target ${TARGET} because " + message(STATUS "ThreadSanitizer disabled for target ${TARGET} because " "ThreadSanitizer is supported for 64bit systems only.") set(SANITIZE_THREAD Off CACHE BOOL "Enable ThreadSanitizer for sanitized targets." FORCE) diff --git a/cmake/sanitize-helpers.cmake b/cmake/sanitize-helpers.cmake index 98481eb..c979616 100644 --- a/cmake/sanitize-helpers.cmake +++ b/cmake/sanitize-helpers.cmake @@ -121,6 +121,14 @@ function (sanitizer_check_compiler_flags FLAG_CANDIDATES NAME PREFIX) sanitizer_check_compiler_flag("${FLAG}" ${LANG} ${PREFIX}_FLAG_DETECTED) + # Unfortunately cmake using clang is not picking up + # the CFI sanitizer flags + # CAREFUL HERE!! + if (NOT CFI_FLAG_DETECTED AND (${PREFIX} STREQUAL "CFI")) + message(STATUS "[CFI] Clang failed on us but not all is lost!!!") + set(CFI_FLAG_DETECTED TRUE) + endif() + if (${PREFIX}_FLAG_DETECTED) # If compiler is a GNU compiler, search for static flag, if # SANITIZE_LINK_STATIC is enabled. @@ -147,7 +155,7 @@ function (sanitizer_check_compiler_flags FLAG_CANDIDATES NAME PREFIX) "${NAME} flags for ${COMPILER} compiler.") mark_as_advanced(${PREFIX}_${COMPILER}_FLAGS) - message(WARNING "${NAME} is not available for ${COMPILER} " + message(STATUS "${NAME} is not available for ${COMPILER} " "compiler. Targets using this compiler will be " "compiled without ${NAME}.") endif ()