From 6c38bde6ca467829b172cbdab30a1698e95e288e Mon Sep 17 00:00:00 2001 From: Cameron Bytheway Date: Fri, 2 Jun 2023 14:28:50 -0600 Subject: [PATCH] build: make feature flags consistent (#3921) --- CMakeLists.txt | 322 ++++++------------ bindings/rust/s2n-tls-sys/build.rs | 147 ++++---- .../rust/s2n-tls-sys/templates/Cargo.template | 2 + s2n.mk | 87 +---- .../{clone.c => S2N_CLONE_SUPPORTED.c} | 0 tests/features/S2N_CLONE_SUPPORTED.flags | 1 + .../{cpuid.c => S2N_CPUID_AVAILABLE.c} | 0 tests/features/S2N_CPUID_AVAILABLE.flags | 0 .../{execinfo.c => S2N_EXECINFO_AVAILABLE.c} | 0 tests/features/S2N_EXECINFO_AVAILABLE.flags | 0 ...through.c => S2N_FALL_THROUGH_SUPPORTED.c} | 0 .../features/S2N_FALL_THROUGH_SUPPORTED.flags | 1 + .../{features.c => S2N_FEATURES_AVAILABLE.c} | 0 tests/features/S2N_FEATURES_AVAILABLE.flags | 0 ...c => S2N_KYBER512R3_AVX2_BMI2_SUPPORTED.c} | 0 .../S2N_KYBER512R3_AVX2_BMI2_SUPPORTED.flags | 1 + ...2N_KYBER512R3_M256_INTRINSICS_SUPPORTED.c} | 0 ...KYBER512R3_M256_INTRINSICS_SUPPORTED.flags | 0 ...2N_LIBCRYPTO_SUPPORTS_EVP_MD5_SHA1_HASH.c} | 0 ...LIBCRYPTO_SUPPORTS_EVP_MD5_SHA1_HASH.flags | 0 ...CRYPTO_SUPPORTS_EVP_MD_CTX_SET_PKEY_CTX.c} | 0 ...PTO_SUPPORTS_EVP_MD_CTX_SET_PKEY_CTX.flags | 0 ...rc4.c => S2N_LIBCRYPTO_SUPPORTS_EVP_RC4.c} | 0 .../S2N_LIBCRYPTO_SUPPORTS_EVP_RC4.flags | 0 ...12.c => S2N_LIBCRYPTO_SUPPORTS_KYBER512.c} | 0 .../S2N_LIBCRYPTO_SUPPORTS_KYBER512.flags | 0 .../{madvise.c => S2N_MADVISE_SUPPORTED.c} | 0 tests/features/S2N_MADVISE_SUPPORTED.flags | 1 + .../{minherit.c => S2N_MINHERIT_SUPPORTED.c} | 0 tests/features/S2N_MINHERIT_SUPPORTED.flags | 1 + .../{ktls.c => S2N_PLATFORM_SUPPORTS_KTLS.c} | 0 .../features/S2N_PLATFORM_SUPPORTS_KTLS.flags | 0 ...strict__.c => S2N___RESTRICT__SUPPORTED.c} | 0 .../features/S2N___RESTRICT__SUPPORTED.flags | 1 + 34 files changed, 201 insertions(+), 363 deletions(-) rename tests/features/{clone.c => S2N_CLONE_SUPPORTED.c} (100%) create mode 100644 tests/features/S2N_CLONE_SUPPORTED.flags rename tests/features/{cpuid.c => S2N_CPUID_AVAILABLE.c} (100%) create mode 100644 tests/features/S2N_CPUID_AVAILABLE.flags rename tests/features/{execinfo.c => S2N_EXECINFO_AVAILABLE.c} (100%) create mode 100644 tests/features/S2N_EXECINFO_AVAILABLE.flags rename tests/features/{fallthrough.c => S2N_FALL_THROUGH_SUPPORTED.c} (100%) create mode 100644 tests/features/S2N_FALL_THROUGH_SUPPORTED.flags rename tests/features/{features.c => S2N_FEATURES_AVAILABLE.c} (100%) create mode 100644 tests/features/S2N_FEATURES_AVAILABLE.flags rename tests/features/{noop_main.c => S2N_KYBER512R3_AVX2_BMI2_SUPPORTED.c} (100%) create mode 100644 tests/features/S2N_KYBER512R3_AVX2_BMI2_SUPPORTED.flags rename tests/features/{m256_intrinsics.c => S2N_KYBER512R3_M256_INTRINSICS_SUPPORTED.c} (100%) create mode 100644 tests/features/S2N_KYBER512R3_M256_INTRINSICS_SUPPORTED.flags rename tests/features/{evp_md5_sha1.c => S2N_LIBCRYPTO_SUPPORTS_EVP_MD5_SHA1_HASH.c} (100%) create mode 100644 tests/features/S2N_LIBCRYPTO_SUPPORTS_EVP_MD5_SHA1_HASH.flags rename tests/features/{evp_md_ctx_set_pkey_ctx.c => S2N_LIBCRYPTO_SUPPORTS_EVP_MD_CTX_SET_PKEY_CTX.c} (100%) create mode 100644 tests/features/S2N_LIBCRYPTO_SUPPORTS_EVP_MD_CTX_SET_PKEY_CTX.flags rename tests/features/{evp_rc4.c => S2N_LIBCRYPTO_SUPPORTS_EVP_RC4.c} (100%) create mode 100644 tests/features/S2N_LIBCRYPTO_SUPPORTS_EVP_RC4.flags rename tests/features/{evp_kem_kyber_512.c => S2N_LIBCRYPTO_SUPPORTS_KYBER512.c} (100%) create mode 100644 tests/features/S2N_LIBCRYPTO_SUPPORTS_KYBER512.flags rename tests/features/{madvise.c => S2N_MADVISE_SUPPORTED.c} (100%) create mode 100644 tests/features/S2N_MADVISE_SUPPORTED.flags rename tests/features/{minherit.c => S2N_MINHERIT_SUPPORTED.c} (100%) create mode 100644 tests/features/S2N_MINHERIT_SUPPORTED.flags rename tests/features/{ktls.c => S2N_PLATFORM_SUPPORTS_KTLS.c} (100%) create mode 100644 tests/features/S2N_PLATFORM_SUPPORTS_KTLS.flags rename tests/features/{__restrict__.c => S2N___RESTRICT__SUPPORTED.c} (100%) create mode 100644 tests/features/S2N___RESTRICT__SUPPORTED.flags diff --git a/CMakeLists.txt b/CMakeLists.txt index c58c28871d7..d0585ef5d0f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -32,7 +32,8 @@ option(S2N_INTERN_LIBCRYPTO "This ensures that s2n-tls is compiled and deployed version of libcrypto by interning the code and hiding symbols. This also enables s2n-tls to be loaded in an application with an otherwise conflicting libcrypto version." OFF) option(S2N_LTO, "Enables link time optimizations when building s2n-tls." OFF) -option(S2N_STACKTRACE "Enables stacktrace functionality in s2n-tls." ON) +option(S2N_STACKTRACE "Enables stacktrace functionality in s2n-tls. Note that this functionality is +only available on platforms that support execinfo." ON) option(COVERAGE "Enable profiling collection for code coverage calculation" OFF) option(S2N_INTEG_TESTS "Enable the integrationv2 tests" OFF) option(S2N_FAST_INTEG_TESTS "Enable the integrationv2 with more parallelism, only has effect if S2N_INTEG_TESTS=ON" OFF) @@ -112,114 +113,6 @@ else() find_package(Threads REQUIRED) endif() -if(S2N_NO_PQ_ASM) - message(STATUS "S2N_NO_PQ_ASM flag was detected - disabling PQ crypto assembly code") -else() - enable_language(ASM) - - # Kyber Round-3 code has several different optimizations which require - # specific compiler flags to be supported by the compiler. - # So for each needed instruction set extension we check if the compiler - # supports it and set proper compiler flags to be added later to the - # Kyber compilation units. - if(${CMAKE_SYSTEM_PROCESSOR} MATCHES "^(x86_64|amd64|AMD64)$") - - set(KYBER512R3_AVX2_BMI2_FLAGS "-mavx2 -mavx -mbmi2") - try_compile(KYBER512R3_AVX2_BMI2_SUPPORTED - ${CMAKE_BINARY_DIR} - "${CMAKE_CURRENT_LIST_DIR}/tests/features/noop_main.c" - COMPILE_DEFINITIONS ${KYBER512R3_AVX2_BMI2_FLAGS}) - - try_compile(KYBER512R3_M256_INTRINSICS_SUPPORTED - ${CMAKE_BINARY_DIR} - "${CMAKE_CURRENT_LIST_DIR}/tests/features/m256_intrinsics.c") - - # Some platforms support -mavx2 flag but not m256 intrinsics required to use them. Only enable Kyber assembly - # optimizations if both are supported. See https://github.com/aws/s2n-tls/pull/3005 for more info. - if(KYBER512R3_AVX2_BMI2_SUPPORTED AND KYBER512R3_M256_INTRINSICS_SUPPORTED) - set(KYBER512R3_AVX2_BMI2_OPT_SUPPORTED ON) - endif() - endif() -endif() - -if(KYBER512R3_AVX2_BMI2_OPT_SUPPORTED) - FILE(GLOB KYBER512R3_AVX2_BMI2_ASM_SRCS "pq-crypto/kyber_r3/*_avx2.S") - list(APPEND PQ_SRC ${KYBER512R3_AVX2_BMI2_ASM_SRCS}) -endif() - -# Probe for execinfo.h extensions (not present on some systems, notably android) -include(CheckCSourceCompiles) - -# Determine if execinfo.h is available -if(CMAKE_SYSTEM_NAME STREQUAL "FreeBSD") -try_compile( - S2N_HAVE_EXECINFO - ${CMAKE_BINARY_DIR} - SOURCES "${CMAKE_CURRENT_LIST_DIR}/tests/features/execinfo.c" - LINK_LIBRARIES execinfo -) -else() -try_compile( - S2N_HAVE_EXECINFO - ${CMAKE_BINARY_DIR} - SOURCES "${CMAKE_CURRENT_LIST_DIR}/tests/features/execinfo.c" -) -endif() - -# Determine if cpuid.h is available -try_compile( - S2N_CPUID_AVAILABLE - ${CMAKE_BINARY_DIR} - SOURCES "${CMAKE_CURRENT_LIST_DIR}/tests/features/cpuid.c" -) - -# Determine if features.h is available -try_compile( - S2N_FEATURES_AVAILABLE - ${CMAKE_BINARY_DIR} - SOURCES "${CMAKE_CURRENT_LIST_DIR}/tests/features/features.c" -) - -# Determine if __attribute__((fallthrough)) is available -try_compile( - FALL_THROUGH_SUPPORTED - ${CMAKE_BINARY_DIR} - SOURCES "${CMAKE_CURRENT_LIST_DIR}/tests/features/fallthrough.c" - COMPILE_DEFINITIONS "-Werror" -) - -# Determine if __restrict__ is available -try_compile( - __RESTRICT__SUPPORTED - ${CMAKE_BINARY_DIR} - SOURCES "${CMAKE_CURRENT_LIST_DIR}/tests/features/__restrict__.c" - COMPILE_DEFINITIONS "-Werror" -) - -# Determine if madvise() is available -try_compile( - MADVISE_SUPPORTED - ${CMAKE_BINARY_DIR} - SOURCES "${CMAKE_CURRENT_LIST_DIR}/tests/features/madvise.c" - COMPILE_DEFINITIONS "-Werror" -) - -# Determine if minherit() is available -try_compile( - MINHERIT_SUPPORTED - ${CMAKE_BINARY_DIR} - SOURCES "${CMAKE_CURRENT_LIST_DIR}/tests/features/minherit.c" - COMPILE_DEFINITIONS "-Werror" -) - -# Determine if clone() is available -try_compile( - CLONE_SUPPORTED - ${CMAKE_BINARY_DIR} - SOURCES "${CMAKE_CURRENT_LIST_DIR}/tests/features/clone.c" - COMPILE_DEFINITIONS "-Werror" -) - if(APPLE) set(OS_LIBS c Threads::Threads) elseif(CMAKE_SYSTEM_NAME STREQUAL "FreeBSD") @@ -300,7 +193,7 @@ if(NOT APPLE) endif() if(S2N_NO_PQ) - target_compile_options(${PROJECT_NAME} PUBLIC -DS2N_NO_PQ) + add_definitions(-DS2N_NO_PQ) endif() # Whether to fail the build when compiling s2n's portable C code with non-portable assembly optimizations. Doing this @@ -312,33 +205,11 @@ if(S2N_BLOCK_NONPORTABLE_OPTIMIZATIONS) target_compile_options(${PROJECT_NAME} PUBLIC -DS2N_BLOCK_NONPORTABLE_OPTIMIZATIONS=1) endif() -if(KYBER512R3_AVX2_BMI2_OPT_SUPPORTED) - FILE(GLOB KYBER512R3_AVX2_BMI2_SRCS "pq-crypto/kyber_r3/*_avx2.c") - set_source_files_properties(${KYBER512R3_AVX2_BMI2_SRCS} PROPERTIES COMPILE_FLAGS ${KYBER512R3_AVX2_BMI2_FLAGS}) - target_compile_options(${PROJECT_NAME} PUBLIC -DS2N_KYBER512R3_AVX2_BMI2) - - message(STATUS "Enabling Kyber_R3 x86_64 optimizations") -endif() - -if(S2N_HAVE_EXECINFO AND S2N_STACKTRACE) - target_compile_options(${PROJECT_NAME} PUBLIC -DS2N_STACKTRACE) -else() - message(STATUS "Disabling stacktrace functionality") -endif() - -if(S2N_CPUID_AVAILABLE) - target_compile_options(${PROJECT_NAME} PUBLIC -DS2N_CPUID_AVAILABLE) -endif() - -if(S2N_FEATURES_AVAILABLE) - target_compile_options(${PROJECT_NAME} PUBLIC -DS2N_FEATURES_AVAILABLE) -endif() - target_compile_options(${PROJECT_NAME} PUBLIC -fPIC) -target_compile_definitions(${PROJECT_NAME} PRIVATE -D_POSIX_C_SOURCE=200809L) +add_definitions(-D_POSIX_C_SOURCE=200809L) if(CMAKE_BUILD_TYPE MATCHES Release) - target_compile_definitions(${PROJECT_NAME} PRIVATE -D_FORTIFY_SOURCE=2) + add_definitions(-D_FORTIFY_SOURCE=2) endif() if(NO_STACK_PROTECTOR) @@ -349,29 +220,6 @@ if(S2N_UNSAFE_FUZZING_MODE) target_compile_options(${PROJECT_NAME} PRIVATE -fsanitize-coverage=trace-pc-guard -fsanitize=address,undefined,leak -fuse-ld=gold -DS2N_ADDRESS_SANITIZER=1) endif() -if (FALL_THROUGH_SUPPORTED) - target_compile_options(${PROJECT_NAME} PUBLIC -DS2N_FALL_THROUGH_SUPPORTED) -endif() - -if (__RESTRICT__SUPPORTED) - target_compile_options(${PROJECT_NAME} PUBLIC -DS2N___RESTRICT__SUPPORTED) -endif() - -if (MADVISE_SUPPORTED) - target_compile_options(${PROJECT_NAME} PUBLIC -DS2N_MADVISE_SUPPORTED) - message(STATUS "madvise() support detected") -endif() - -if (MINHERIT_SUPPORTED) - target_compile_options(${PROJECT_NAME} PUBLIC -DS2N_MINHERIT_SUPPORTED) - message(STATUS "minherit() support detected") -endif() - -if (CLONE_SUPPORTED) - target_compile_options(${PROJECT_NAME} PUBLIC -DS2N_CLONE_SUPPORTED) - message(STATUS "clone() support detected") -endif() - list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake/modules") if (NOT $ENV{S2N_LIBCRYPTO} MATCHES "awslc") @@ -416,86 +264,118 @@ if (S2N_INTERN_LIBCRYPTO) message(STATUS "Enabling libcrypto interning") endif() -# Determine if EVP_md5_sha1 is available in libcrypto -try_compile( - LIBCRYPTO_SUPPORTS_EVP_MD5_SHA1_HASH - ${CMAKE_BINARY_DIR} - SOURCES "${CMAKE_CURRENT_LIST_DIR}/tests/features/evp_md5_sha1.c" - LINK_LIBRARIES ${LINK_LIB} ${OS_LIBS} -) -if (LIBCRYPTO_SUPPORTS_EVP_MD5_SHA1_HASH) - target_compile_options(${PROJECT_NAME} PUBLIC -DS2N_LIBCRYPTO_SUPPORTS_EVP_MD5_SHA1_HASH) +if (NOT DEFINED CMAKE_AR) + message(STATUS "CMAKE_AR undefined, setting to `ar` by default") + SET(CMAKE_AR ar) +else() + message(STATUS "CMAKE_AR found: ${CMAKE_AR}") endif() -# Determine if RC4 is available in libcrypto -try_compile( - LIBCRYPTO_SUPPORTS_EVP_RC4 - ${CMAKE_BINARY_DIR} - SOURCES "${CMAKE_CURRENT_LIST_DIR}/tests/features/evp_rc4.c" - LINK_LIBRARIES ${LINK_LIB} ${OS_LIBS} -) +if (NOT DEFINED CMAKE_RANLIB) + message(STATUS "CMAKE_RANLIB undefined, setting to `ranlib` by default") + SET(CMAKE_RANLIB ranlib) +else() + message(STATUS "CMAKE_RANLIB found: ${CMAKE_RANLIB}") +endif() -if (LIBCRYPTO_SUPPORTS_EVP_RC4) - target_compile_options(${PROJECT_NAME} PUBLIC -DS2N_LIBCRYPTO_SUPPORTS_EVP_RC4) +if (NOT DEFINED CMAKE_OBJCOPY) + message(STATUS "CMAKE_OBJCOPY undefined, setting to `objcopy` by default") + SET(CMAKE_OBJCOPY objcopy) +else() + message(STATUS "CMAKE_OBJCOPY found: ${CMAKE_OBJCOPY}") endif() -# Determine if EVP_MD_CTX_set_pkey_ctx is available in libcrypto -try_compile( - LIBCRYPTO_SUPPORTS_EVP_MD_CTX_SET_PKEY_CTX +# Sets the result of the feature probe to `IS_AVAILABLE` +function(feature_probe_result PROBE_NAME IS_AVAILABLE) + # normalize the boolean value + if(IS_AVAILABLE) + set(NORMALIZED TRUE) + else() + set(NORMALIZED FALSE) + endif() + + # indicate the status of the probe + message(STATUS "feature ${PROBE_NAME}: ${NORMALIZED}") + # set the probe result in the parent scope for other probes + set(${PROBE_NAME} ${NORMALIZED} PARENT_SCOPE) + + # define the probe if available + if(NORMALIZED) + add_definitions(-D${PROBE_NAME}) + endif() +endfunction() + +# Tries to compile a feature probe and initializes the corresponding flags +function(feature_probe PROBE_NAME) + # Load the probe's flags + file(READ "${CMAKE_CURRENT_LIST_DIR}/tests/features/${PROBE_NAME}.flags" PROBE_FILE) + string(REPLACE "\n" "" PROBE_FLAGS "${PROBE_FILE}") + + # Try to compile the probe with the given flags + try_compile( + IS_AVAILABLE ${CMAKE_BINARY_DIR} - SOURCES "${CMAKE_CURRENT_LIST_DIR}/tests/features/evp_md_ctx_set_pkey_ctx.c" + SOURCES "${CMAKE_CURRENT_LIST_DIR}/tests/features/${PROBE_NAME}.c" LINK_LIBRARIES ${LINK_LIB} ${OS_LIBS} CMAKE_FLAGS ${ADDITIONAL_FLAGS} -) + COMPILE_DEFINITIONS -c ${PROBE_FLAGS} + ${ARGN} + ) -if (LIBCRYPTO_SUPPORTS_EVP_MD_CTX_SET_PKEY_CTX) - target_compile_options(${PROJECT_NAME} PUBLIC -DS2N_LIBCRYPTO_SUPPORTS_EVP_MD_CTX_SET_PKEY_CTX) -endif() + # Set the result of the probe + feature_probe_result(${PROBE_NAME} ${IS_AVAILABLE}) -# Determine if KEM Kyber512 implementation from AWS-LC is available -try_compile( - LIBCRYPTO_SUPPORTS_EVP_KEM_KYBER_512 - ${CMAKE_BINARY_DIR} - SOURCES "${CMAKE_CURRENT_LIST_DIR}/tests/features/evp_kem_kyber_512.c" - LINK_LIBRARIES ${LINK_LIB} ${OS_LIBS} - COMPILE_DEFINITIONS "-Werror" -) + # Make sure the variable is set in the parent scope + set(${PROBE_NAME} ${IS_AVAILABLE} PARENT_SCOPE) -if(LIBCRYPTO_SUPPORTS_EVP_KEM_KYBER_512) - target_compile_options(${PROJECT_NAME} PUBLIC -DS2N_LIBCRYPTO_SUPPORTS_KYBER512) -endif() + # Set the flags that we used for the probe + set(${PROBE_NAME}_FLAGS ${PROBE_FLAGS} PARENT_SCOPE) +endfunction() -# Determine if kTLS is supported -try_compile( - PLATFORM_SUPPORTS_KTLS - ${CMAKE_BINARY_DIR} - SOURCES "${CMAKE_CURRENT_LIST_DIR}/tests/features/ktls.c" -) -if(PLATFORM_SUPPORTS_KTLS) - message(STATUS "feature probe: kTLS supported") - target_compile_options(${PROJECT_NAME} PUBLIC -DS2N_PLATFORM_SUPPORTS_KTLS) -endif() +# Iterate over all of the features and try to compile them +FILE(GLOB FEATURE_SRCS "${CMAKE_CURRENT_LIST_DIR}/tests/features/*.c") +list(SORT FEATURE_SRCS) +foreach(file ${FEATURE_SRCS}) + get_filename_component(feature_name ${file} NAME_WE) + feature_probe(${feature_name}) +endforeach() -if (NOT DEFINED CMAKE_AR) - message(STATUS "CMAKE_AR undefined, setting to `ar` by default") - SET(CMAKE_AR ar) -else() - message(STATUS "CMAKE_AR found: ${CMAKE_AR}") +# FreeBSD might need to link to execinfo explicitly +if(NOT S2N_EXECINFO_AVAILABLE AND CMAKE_SYSTEM_NAME STREQUAL "FreeBSD") + feature_probe(S2N_EXECINFO_AVAILABLE LINK_LIBRARIES execinfo) endif() -if (NOT DEFINED CMAKE_RANLIB) - message(STATUS "CMAKE_RANLIB undefined, setting to `ranlib` by default") - SET(CMAKE_RANLIB ranlib) -else() - message(STATUS "CMAKE_RANLIB found: ${CMAKE_RANLIB}") +# Stack traces are only available if execinfo is +if (NOT S2N_EXECINFO_AVAILABLE) + set(S2N_STACKTRACE FALSE) endif() +feature_probe_result(S2N_STACKTRACE ${S2N_STACKTRACE}) -if (NOT DEFINED CMAKE_OBJCOPY) - message(STATUS "CMAKE_OBJCOPY undefined, setting to `objcopy` by default") - SET(CMAKE_OBJCOPY objcopy) -else() - message(STATUS "CMAKE_OBJCOPY found: ${CMAKE_OBJCOPY}") +set(S2N_KYBER512R3_AVX2_BMI2 FALSE) +if(NOT S2N_NO_PQ_ASM) + # Kyber Round-3 code has several different optimizations which require + # specific compiler flags to be supported by the compiler. + # So for each needed instruction set extension we check if the compiler + # supports it and set proper compiler flags to be added later to the + # Kyber compilation units. + if(${CMAKE_SYSTEM_PROCESSOR} MATCHES "^(x86_64|amd64|AMD64)$") + # Some platforms support -mavx2 flag but not m256 intrinsics required to use them. Only enable Kyber assembly + # optimizations if both are supported. See https://github.com/aws/s2n-tls/pull/3005 for more info. + if(S2N_KYBER512R3_AVX2_BMI2_SUPPORTED AND S2N_KYBER512R3_M256_INTRINSICS_SUPPORTED) + set(S2N_KYBER512R3_AVX2_BMI2 TRUE) + enable_language(ASM) + + # add the assembly files to the project + FILE(GLOB KYBER512R3_AVX2_BMI2_ASM_SRCS "pq-crypto/kyber_r3/*_avx2.S") + target_sources(${PROJECT_NAME} PRIVATE ${KYBER512R3_AVX2_BMI2_ASM_SRCS}) + + # compile the C files with avx flags + FILE(GLOB KYBER512R3_AVX2_BMI2_SRCS "pq-crypto/kyber_r3/*_avx2.c") + set_source_files_properties(${KYBER512R3_AVX2_BMI2_SRCS} PROPERTIES COMPILE_FLAGS ${S2N_KYBER512R3_AVX2_BMI2_SUPPORTED_FLAGS}) + endif() + endif() endif() +feature_probe_result(S2N_KYBER512R3_AVX2_BMI2 ${S2N_KYBER512R3_AVX2_BMI2}) if (S2N_INTERN_LIBCRYPTO) @@ -658,14 +538,14 @@ if (BUILD_TESTING) target_link_libraries(s2nc ${PROJECT_NAME}) target_include_directories(s2nc PRIVATE api) - target_compile_options(s2nc PRIVATE -std=gnu99 -D_POSIX_C_SOURCE=200112L) + target_compile_options(s2nc PRIVATE -std=gnu99) add_executable(s2nd "bin/s2nd.c" "bin/echo.c" "bin/https.c" "bin/common.c") target_link_libraries(s2nd ${PROJECT_NAME}) target_include_directories(s2nd PRIVATE api) - target_compile_options(s2nd PRIVATE -std=gnu99 -D_POSIX_C_SOURCE=200112L) + target_compile_options(s2nd PRIVATE -std=gnu99) if(S2N_LTO) target_compile_options(s2nc PRIVATE -flto) diff --git a/bindings/rust/s2n-tls-sys/build.rs b/bindings/rust/s2n-tls-sys/build.rs index b1098c66bbb..f2e11ff8813 100644 --- a/bindings/rust/s2n-tls-sys/build.rs +++ b/bindings/rust/s2n-tls-sys/build.rs @@ -34,38 +34,46 @@ fn option_env>(name: N) -> Option { } struct FeatureDetector<'a> { - out_dir: &'a std::path::Path, + builder: cc::Build, + out_dir: &'a Path, } impl<'a> FeatureDetector<'a> { pub fn new(out_dir: &'a Path) -> Self { - Self { out_dir } + let builder = builder(); + Self { builder, out_dir } } pub fn supports(&self, name: &str) -> bool { - let out = self.out_dir.join("features").join(name); - let out = out.to_str().unwrap(); - - cc::Build::new() - .file( - std::path::Path::new("lib/tests/features") - .join(name) - .with_extension("c"), - ) - // don't print anything - .cargo_metadata(false) - // make sure it doesn't warn - .warnings(true) - .debug(false) - // set the archiver to the `true` program, since we don't actually link anything - .archiver("true") - .try_compile(out) - .is_ok() + let mut build = self.builder.get_compiler().to_command(); + + let base = std::path::Path::new("lib/tests/features").join(name); + + let file = base.with_extension("c"); + assert!(file.exists(), "missing feature file: {:?}", file.display()); + + let flags = base.with_extension("flags"); + assert!(file.exists(), "missing flags file: {:?}", flags.display()); + + let flags = std::fs::read_to_string(flags).unwrap(); + for flag in flags.trim().split(' ').filter(|f| !f.is_empty()) { + build.arg(flag); + } + + build + // just compile the file and don't link + .arg("-c") + .arg("-o") + .arg(self.out_dir.join(name).with_extension("o")) + .arg(&file); + + eprintln!("=== Testing feature {name} ==="); + build.status().unwrap().success() } } fn build_vendored() { - let mut build = cc::Build::new(); + let mut build = builder(); let pq = option_env("CARGO_FEATURE_PQ").is_some(); @@ -86,21 +94,6 @@ fn build_vendored() { true })); - build - // pull the include path from the openssl-sys dependency - .include(env("DEP_OPENSSL_INCLUDE")) - .include("lib") - .include("lib/api") - .flag("-std=c11") - .flag("-fgnu89-inline") - // make sure the stack is non-executable - .flag_if_supported("-z relro") - .flag_if_supported("-z now") - .flag_if_supported("-z noexecstack") - // we use some deprecated libcrypto features so don't warn here - .flag_if_supported("-Wno-deprecated-declarations") - .define("_POSIX_C_SOURCE", "200112L"); - if env("PROFILE") == "release" { // fortify source is only available in release mode build.define("_FORTIFY_SOURCE", "2"); @@ -122,36 +115,37 @@ fn build_vendored() { let features = FeatureDetector::new(&out_dir); - if features.supports("execinfo") { - build.define("S2N_HAVE_EXECINFO", "1"); - } - - if features.supports("cpuid") { - build.define("S2N_CPUID_AVAILABLE", "1"); - } - - if features.supports("features") { - build.define("S2N_FEATURES_AVAILABLE", "1"); - } - - if features.supports("fallthrough") { - build.define("FALL_THROUGH_SUPPORTED", "1"); - } - - if features.supports("__restrict__") { - build.define("__RESTRICT__SUPPORTED", "1"); - } - - if features.supports("madvise") { - build.define("MADVISE_SUPPORTED", "1"); - } - - if features.supports("minherit") { - build.define("MINHERIT_SUPPORTED", "1"); - } - - if features.supports("clone") { - build.define("CLONE_SUPPORTED", "1"); + let mut feature_names = std::fs::read_dir("lib/tests/features") + .expect("missing features directory") + .flatten() + .filter(|file| { + let file = file.path(); + file.extension().map_or(false, |ext| ext == "c") + }) + .map(|file| { + file.path() + .file_stem() + .unwrap() + .to_str() + .unwrap() + .to_string() + }) + .collect::>(); + + feature_names.sort(); + + for name in &feature_names { + let is_supported = features.supports(name); + eprintln!("{name}: {is_supported}"); + if is_supported { + build.define(name, "1"); + + // stacktraces are only available if execinfo is + if name == "S2N_EXECINFO_AVAILABLE" && option_env("CARGO_FEATURE_STACKTRACE").is_some() + { + build.define("S2N_STACKTRACE", "1"); + } + } } // don't spit out a bunch of warnings to the end user, since they won't really be able @@ -170,6 +164,27 @@ fn build_vendored() { println!("cargo:include={}", include_dir.display()); } +fn builder() -> cc::Build { + let mut build = cc::Build::new(); + + build + // pull the include path from the openssl-sys dependency + .include(env("DEP_OPENSSL_INCLUDE")) + .include("lib") + .include("lib/api") + .flag("-std=c11") + .flag("-fgnu89-inline") + // make sure the stack is non-executable + .flag_if_supported("-z relro") + .flag_if_supported("-z now") + .flag_if_supported("-z noexecstack") + // we use some deprecated libcrypto features so don't warn here + .flag_if_supported("-Wno-deprecated-declarations") + .define("_POSIX_C_SOURCE", "200112L"); + + build +} + #[cfg(feature = "cmake")] fn build_cmake() { let mut config = cmake::Config::new("lib"); diff --git a/bindings/rust/s2n-tls-sys/templates/Cargo.template b/bindings/rust/s2n-tls-sys/templates/Cargo.template index eafdceeaa3f..956ac839ce5 100644 --- a/bindings/rust/s2n-tls-sys/templates/Cargo.template +++ b/bindings/rust/s2n-tls-sys/templates/Cargo.template @@ -17,6 +17,7 @@ include = [ "lib/**/*.S", "lib/CMakeLists.txt", "lib/**/*.cmake", + "lib/**/*.flags", # for feature probes "src/**/*.rs", "tests/**/*.rs", ] @@ -26,6 +27,7 @@ default = [] quic = [] pq = ["cmake"] # the pq build logic is complicated so just use cmake instead internal = [] +stacktrace = [] # e.g. something like # unstable-foo = [] diff --git a/s2n.mk b/s2n.mk index b91148b4837..98cd92e2eb8 100644 --- a/s2n.mk +++ b/s2n.mk @@ -181,84 +181,19 @@ bindir ?= $(exec_prefix)/bin libdir ?= $(exec_prefix)/lib64 includedir ?= $(exec_prefix)/include -try_compile = $(shell $(CC) $(CFLAGS) -c -o tmp.o $(1) > /dev/null 2>&1; echo $$?; rm tmp.o > /dev/null 2>&1) +feature_probe = $(shell $(CC) $(CFLAGS) $(shell cat $(S2N_ROOT)/tests/features/$(1).flags) -c -o tmp.o $(S2N_ROOT)/tests/features/$(1).c > /dev/null 2>&1 && echo "-D$(1)"; rm tmp.o > /dev/null 2>&1) -# Determine if execinfo.h is available -TRY_COMPILE_EXECINFO := $(call try_compile,$(S2N_ROOT)/tests/features/execinfo.c) -ifeq ($(TRY_COMPILE_EXECINFO), 0) - DEFAULT_CFLAGS += -DS2N_STACKTRACE -endif - -# Determine if cpuid.h is available -TRY_COMPILE_CPUID := $(call try_compile,$(S2N_ROOT)/tests/features/cpuid.c) -ifeq ($(TRY_COMPILE_CPUID), 0) - DEFAULT_CFLAGS += -DS2N_CPUID_AVAILABLE -endif +FEATURES := $(notdir $(patsubst %.c,%,$(wildcard $(S2N_ROOT)/tests/features/*.c))) +SUPPORTED_FEATURES := $(foreach feature,$(FEATURES),$(call feature_probe,$(feature))) +CFLAGS += $(SUPPORTED_FEATURES) +DEFAULT_CFLAGS += $(SUPPORTED_FEATURES) +CPPCFLAGS += $(SUPPORTED_FEATURES) -# Determine if features.h is availabe -TRY_COMPILE_FEATURES := $(call try_compile,$(S2N_ROOT)/tests/features/features.c) -ifeq ($(TRY_COMPILE_FEATURES), 0) - DEFAULT_CFLAGS += -DS2N_FEATURES_AVAILABLE -endif - -# Determine if __attribute__((fallthrough)) is available -TRY_COMPILE_FALL_THROUGH := $(call try_compile,$(S2N_ROOT)/tests/features/fallthrough.c) -ifeq ($(TRY_COMPILE_FALL_THROUGH), 0) - DEFAULT_CFLAGS += -DS2N_FALL_THROUGH_SUPPORTED -endif - -# Determine if __restrict__ is available -TRY_COMPILE__RESTRICT__ := $(call try_compile,$(S2N_ROOT)/tests/features/__restrict__.c) -ifeq ($(TRY_COMPILE__RESTRICT__), 0) - DEFAULT_CFLAGS += -DS2N___RESTRICT__SUPPORTED -endif - -# Determine if EVP_md5_sha1 is available -TRY_EVP_MD5_SHA1_HASH := $(call try_compile,$(S2N_ROOT)/tests/features/evp_md5_sha1.c) -ifeq ($(TRY_EVP_MD5_SHA1_HASH), 0) - DEFAULT_CFLAGS += -DS2N_LIBCRYPTO_SUPPORTS_EVP_MD5_SHA1_HASH -endif - -# Determine if EVP_RC4 is available -TRY_EVP_RC4 := $(call try_compile,$(S2N_ROOT)/tests/features/evp_rc4.c) -ifeq ($(TRY_EVP_RC4), 0) - DEFAULT_CFLAGS += -DS2N_LIBCRYPTO_SUPPORTS_EVP_RC4 -endif - -# Determine if EVP_MD_CTX_set_pkey_ctx is available -TRY_EVP_MD_CTX_SET_PKEY_CTX := $(call try_compile,$(S2N_ROOT)/tests/features/evp_md_ctx_set_pkey_ctx.c) -ifeq ($(TRY_EVP_MD_CTX_SET_PKEY_CTX), 0) - DEFAULT_CFLAGS += -DS2N_LIBCRYPTO_SUPPORTS_EVP_MD_CTX_SET_PKEY_CTX -endif - -# Determine if the Kyber 512 KEM API is available in libcrypto -TRY_LIBCRYPTO_SUPPORTS_KYBER512 := $(call try_compile,$(S2N_ROOT)/tests/features/evp_kem_kyber_512.c) -ifeq ($(TRY_LIBCRYPTO_SUPPORTS_KYBER512), 0) - DEFAULT_CFLAGS += -DS2N_LIBCRYPTO_SUPPORTS_KYBER512 -endif - -# Determine if madvise() is available -TRY_COMPILE_MADVISE := $(call try_compile,$(S2N_ROOT)/tests/features/madvise.c) -ifeq ($(TRY_COMPILE_MADVISE), 0) - DEFAULT_CFLAGS += -DS2N_MADVISE_SUPPORTED -endif - -# Determine if minherit() is available -TRY_COMPILE_MINHERIT:= $(call try_compile,$(S2N_ROOT)/tests/features/minherit.c) -ifeq ($(TRY_COMPILE_MINHERIT), 0) - DEFAULT_CFLAGS += -DS2N_MINHERIT_SUPPORTED -endif - -# Determine if clone() is available -TRY_COMPILE_CLONE := $(call try_compile,$(S2N_ROOT)/tests/features/clone.c) -ifeq ($(TRY_COMPILE_CLONE), 0) - DEFAULT_CFLAGS += -DS2N_CLONE_SUPPORTED -endif - -# Determine if kTLS is available -TRY_COMPILE_KTLS := $(call try_compile,$(S2N_ROOT)/tests/features/ktls.c) -ifeq ($(TRY_COMPILE_KTLS), 0) - DEFAULT_CFLAGS += -DS2N_PLATFORM_SUPPORTS_KTLS +# only enable stacktraces if execinfo is available +ifneq ("$(call feature_probe,S2N_EXECINFO_AVAILABLE)","") + CFLAGS += -DS2N_STACKTRACE + DEFAULT_CFLAGS += -DS2N_STACKTRACE + CPPCFLAGS += -DS2N_STACKTRACE endif CFLAGS_LLVM = ${DEFAULT_CFLAGS} -emit-llvm -c -g -O1 diff --git a/tests/features/clone.c b/tests/features/S2N_CLONE_SUPPORTED.c similarity index 100% rename from tests/features/clone.c rename to tests/features/S2N_CLONE_SUPPORTED.c diff --git a/tests/features/S2N_CLONE_SUPPORTED.flags b/tests/features/S2N_CLONE_SUPPORTED.flags new file mode 100644 index 00000000000..2f41be663b2 --- /dev/null +++ b/tests/features/S2N_CLONE_SUPPORTED.flags @@ -0,0 +1 @@ +-Werror diff --git a/tests/features/cpuid.c b/tests/features/S2N_CPUID_AVAILABLE.c similarity index 100% rename from tests/features/cpuid.c rename to tests/features/S2N_CPUID_AVAILABLE.c diff --git a/tests/features/S2N_CPUID_AVAILABLE.flags b/tests/features/S2N_CPUID_AVAILABLE.flags new file mode 100644 index 00000000000..e69de29bb2d diff --git a/tests/features/execinfo.c b/tests/features/S2N_EXECINFO_AVAILABLE.c similarity index 100% rename from tests/features/execinfo.c rename to tests/features/S2N_EXECINFO_AVAILABLE.c diff --git a/tests/features/S2N_EXECINFO_AVAILABLE.flags b/tests/features/S2N_EXECINFO_AVAILABLE.flags new file mode 100644 index 00000000000..e69de29bb2d diff --git a/tests/features/fallthrough.c b/tests/features/S2N_FALL_THROUGH_SUPPORTED.c similarity index 100% rename from tests/features/fallthrough.c rename to tests/features/S2N_FALL_THROUGH_SUPPORTED.c diff --git a/tests/features/S2N_FALL_THROUGH_SUPPORTED.flags b/tests/features/S2N_FALL_THROUGH_SUPPORTED.flags new file mode 100644 index 00000000000..2f41be663b2 --- /dev/null +++ b/tests/features/S2N_FALL_THROUGH_SUPPORTED.flags @@ -0,0 +1 @@ +-Werror diff --git a/tests/features/features.c b/tests/features/S2N_FEATURES_AVAILABLE.c similarity index 100% rename from tests/features/features.c rename to tests/features/S2N_FEATURES_AVAILABLE.c diff --git a/tests/features/S2N_FEATURES_AVAILABLE.flags b/tests/features/S2N_FEATURES_AVAILABLE.flags new file mode 100644 index 00000000000..e69de29bb2d diff --git a/tests/features/noop_main.c b/tests/features/S2N_KYBER512R3_AVX2_BMI2_SUPPORTED.c similarity index 100% rename from tests/features/noop_main.c rename to tests/features/S2N_KYBER512R3_AVX2_BMI2_SUPPORTED.c diff --git a/tests/features/S2N_KYBER512R3_AVX2_BMI2_SUPPORTED.flags b/tests/features/S2N_KYBER512R3_AVX2_BMI2_SUPPORTED.flags new file mode 100644 index 00000000000..c72920f1597 --- /dev/null +++ b/tests/features/S2N_KYBER512R3_AVX2_BMI2_SUPPORTED.flags @@ -0,0 +1 @@ +-mavx2 -mavx -mbmi2 diff --git a/tests/features/m256_intrinsics.c b/tests/features/S2N_KYBER512R3_M256_INTRINSICS_SUPPORTED.c similarity index 100% rename from tests/features/m256_intrinsics.c rename to tests/features/S2N_KYBER512R3_M256_INTRINSICS_SUPPORTED.c diff --git a/tests/features/S2N_KYBER512R3_M256_INTRINSICS_SUPPORTED.flags b/tests/features/S2N_KYBER512R3_M256_INTRINSICS_SUPPORTED.flags new file mode 100644 index 00000000000..e69de29bb2d diff --git a/tests/features/evp_md5_sha1.c b/tests/features/S2N_LIBCRYPTO_SUPPORTS_EVP_MD5_SHA1_HASH.c similarity index 100% rename from tests/features/evp_md5_sha1.c rename to tests/features/S2N_LIBCRYPTO_SUPPORTS_EVP_MD5_SHA1_HASH.c diff --git a/tests/features/S2N_LIBCRYPTO_SUPPORTS_EVP_MD5_SHA1_HASH.flags b/tests/features/S2N_LIBCRYPTO_SUPPORTS_EVP_MD5_SHA1_HASH.flags new file mode 100644 index 00000000000..e69de29bb2d diff --git a/tests/features/evp_md_ctx_set_pkey_ctx.c b/tests/features/S2N_LIBCRYPTO_SUPPORTS_EVP_MD_CTX_SET_PKEY_CTX.c similarity index 100% rename from tests/features/evp_md_ctx_set_pkey_ctx.c rename to tests/features/S2N_LIBCRYPTO_SUPPORTS_EVP_MD_CTX_SET_PKEY_CTX.c diff --git a/tests/features/S2N_LIBCRYPTO_SUPPORTS_EVP_MD_CTX_SET_PKEY_CTX.flags b/tests/features/S2N_LIBCRYPTO_SUPPORTS_EVP_MD_CTX_SET_PKEY_CTX.flags new file mode 100644 index 00000000000..e69de29bb2d diff --git a/tests/features/evp_rc4.c b/tests/features/S2N_LIBCRYPTO_SUPPORTS_EVP_RC4.c similarity index 100% rename from tests/features/evp_rc4.c rename to tests/features/S2N_LIBCRYPTO_SUPPORTS_EVP_RC4.c diff --git a/tests/features/S2N_LIBCRYPTO_SUPPORTS_EVP_RC4.flags b/tests/features/S2N_LIBCRYPTO_SUPPORTS_EVP_RC4.flags new file mode 100644 index 00000000000..e69de29bb2d diff --git a/tests/features/evp_kem_kyber_512.c b/tests/features/S2N_LIBCRYPTO_SUPPORTS_KYBER512.c similarity index 100% rename from tests/features/evp_kem_kyber_512.c rename to tests/features/S2N_LIBCRYPTO_SUPPORTS_KYBER512.c diff --git a/tests/features/S2N_LIBCRYPTO_SUPPORTS_KYBER512.flags b/tests/features/S2N_LIBCRYPTO_SUPPORTS_KYBER512.flags new file mode 100644 index 00000000000..e69de29bb2d diff --git a/tests/features/madvise.c b/tests/features/S2N_MADVISE_SUPPORTED.c similarity index 100% rename from tests/features/madvise.c rename to tests/features/S2N_MADVISE_SUPPORTED.c diff --git a/tests/features/S2N_MADVISE_SUPPORTED.flags b/tests/features/S2N_MADVISE_SUPPORTED.flags new file mode 100644 index 00000000000..2f41be663b2 --- /dev/null +++ b/tests/features/S2N_MADVISE_SUPPORTED.flags @@ -0,0 +1 @@ +-Werror diff --git a/tests/features/minherit.c b/tests/features/S2N_MINHERIT_SUPPORTED.c similarity index 100% rename from tests/features/minherit.c rename to tests/features/S2N_MINHERIT_SUPPORTED.c diff --git a/tests/features/S2N_MINHERIT_SUPPORTED.flags b/tests/features/S2N_MINHERIT_SUPPORTED.flags new file mode 100644 index 00000000000..2f41be663b2 --- /dev/null +++ b/tests/features/S2N_MINHERIT_SUPPORTED.flags @@ -0,0 +1 @@ +-Werror diff --git a/tests/features/ktls.c b/tests/features/S2N_PLATFORM_SUPPORTS_KTLS.c similarity index 100% rename from tests/features/ktls.c rename to tests/features/S2N_PLATFORM_SUPPORTS_KTLS.c diff --git a/tests/features/S2N_PLATFORM_SUPPORTS_KTLS.flags b/tests/features/S2N_PLATFORM_SUPPORTS_KTLS.flags new file mode 100644 index 00000000000..e69de29bb2d diff --git a/tests/features/__restrict__.c b/tests/features/S2N___RESTRICT__SUPPORTED.c similarity index 100% rename from tests/features/__restrict__.c rename to tests/features/S2N___RESTRICT__SUPPORTED.c diff --git a/tests/features/S2N___RESTRICT__SUPPORTED.flags b/tests/features/S2N___RESTRICT__SUPPORTED.flags new file mode 100644 index 00000000000..2f41be663b2 --- /dev/null +++ b/tests/features/S2N___RESTRICT__SUPPORTED.flags @@ -0,0 +1 @@ +-Werror