From 3f1a00c79d0d0e3b7f0893c7163ab8e821b9bebd Mon Sep 17 00:00:00 2001 From: Robert Scott Date: Mon, 7 Apr 2025 22:04:11 +0100 Subject: [PATCH 01/15] cc-wrapper: add support for strictflexarrays1 & strictflexarrays3 hardening flags adding strictflexarrays1 to pkgsExtraHardening --- doc/release-notes/rl-2511.section.md | 2 +- doc/stdenv/stdenv.chapter.md | 16 +++++++++ .../build-support/cc-wrapper/add-hardening.sh | 34 ++++++++++++++++++- pkgs/development/compilers/gcc/default.nix | 4 +++ .../compilers/llvm/common/clang/default.nix | 2 ++ pkgs/stdenv/generic/make-derivation.nix | 23 ++++++++----- pkgs/top-level/variants.nix | 1 + 7 files changed, 72 insertions(+), 10 deletions(-) diff --git a/doc/release-notes/rl-2511.section.md b/doc/release-notes/rl-2511.section.md index ba2d9f256d34..b921e3e08d8b 100644 --- a/doc/release-notes/rl-2511.section.md +++ b/doc/release-notes/rl-2511.section.md @@ -15,7 +15,7 @@ -- Create the first release note entry in this section! +- New hardening flags, `strictflexarrays1` and `strictflexarrays3` were made available, corresponding to the gcc/clang options `-fstrict-flex-arrays=1` and `-fstrict-flex-arrays=3` respectively. ## Nixpkgs Library {#sec-nixpkgs-release-25.11-lib} diff --git a/doc/stdenv/stdenv.chapter.md b/doc/stdenv/stdenv.chapter.md index 6851294ddf96..7b4f901f58a7 100644 --- a/doc/stdenv/stdenv.chapter.md +++ b/doc/stdenv/stdenv.chapter.md @@ -1620,6 +1620,22 @@ Adds the `-fPIE` compiler and `-pie` linker options. Position Independent Execut Static libraries need to be compiled with `-fPIE` so that executables can link them in with the `-pie` linker option. If the libraries lack `-fPIE`, you will get the error `recompile with -fPIE`. +#### `strictflexarrays1` {#strictflexarrays1} + +This flag adds the `-fstrict-flex-arrays=1` compiler option, which reduces the cases the compiler treats as "flexible arrays" to those declared with length `[1]`, `[0]` or (the correct) `[]`. This increases the coverage of fortify checks, because such arrays declared as the trailing element of a structure can normally not have their intended length determined by the compiler. + +Enabling this flag on packages that still use length declarations of flexible arrays >1 may cause the package to fail to compile citing accesses beyond the bounds of an array or even crash at runtime by detecting an array access as an "overrun". Few projects still use length declarations of flexible arrays >1. + +Disabling `strictflexarrays1` implies disablement of `strictflexarrays3`. + +#### `strictflexarrays3` {#strictflexarrays3} + +This flag adds the `-fstrict-flex-arrays=3` compiler option, which reduces the cases the compiler treats as "flexible arrays" to only those declared with length as (the correct) `[]`. This increases the coverage of fortify checks, because such arrays declared as the trailing element of a structure can normally not have their intended length determined by the compiler. + +Enabling this flag on packages that still use non-empty length declarations for flexible arrays may cause the package to fail to compile citing accesses beyond the bounds of an array or even crash at runtime by detecting an array access as an "overrun". Many projects still use such non-empty length declarations for flexible arrays. + +Enabling this flag implies enablement of `strictflexarrays1`. Disabling this flag does not imply disablement of `strictflexarrays1`. + #### `shadowstack` {#shadowstack} Adds the `-fcf-protection=return` compiler option. This enables the Shadow Stack feature supported by some newer processors, which maintains a user-inaccessible copy of the program's stack containing only return-addresses. When returning from a function, the processor compares the return-address value on the two stacks and throws an error if they do not match, considering it a sign of corruption and possible tampering. This should significantly increase the difficulty of ROP attacks. diff --git a/pkgs/build-support/cc-wrapper/add-hardening.sh b/pkgs/build-support/cc-wrapper/add-hardening.sh index 9fed30303ab8..2dcf1516d2de 100644 --- a/pkgs/build-support/cc-wrapper/add-hardening.sh +++ b/pkgs/build-support/cc-wrapper/add-hardening.sh @@ -10,6 +10,7 @@ for flag in ${NIX_HARDENING_ENABLE_@suffixSalt@-}; do hardeningEnableMap["$flag"]=1 done + # fortify3 implies fortify enablement - make explicit before # we filter unsupported flags because unsupporting fortify3 # doesn't mean we should unsupport fortify too @@ -31,8 +32,31 @@ if [[ -n "${hardeningEnableMap[fortify3]-}" ]]; then unset -v "hardeningEnableMap['fortify']" fi + +# strictflexarrays3 implies strictflexarrays1 enablement - make explicit before +# we filter unsupported flags because unsupporting strictflexarrays3 +# doesn't mean we should unsupport strictflexarrays1 too +if [[ -n "${hardeningEnableMap[strictflexarrays3]-}" ]]; then + hardeningEnableMap["strictflexarrays1"]=1 +fi + +# Remove unsupported flags. +for flag in @hardening_unsupported_flags@; do + unset -v "hardeningEnableMap[$flag]" + # strictflexarrays1 being unsupported implies strictflexarrays3 is unsupported + if [[ "$flag" = 'strictflexarrays1' ]] ; then + unset -v "hardeningEnableMap['strictflexarrays3']" + fi +done + +# now make strictflexarrays1 and strictflexarrays3 mutually exclusive +if [[ -n "${hardeningEnableMap[strictflexarrays3]-}" ]]; then + unset -v "hardeningEnableMap['strictflexarrays1']" +fi + + if (( "${NIX_DEBUG:-0}" >= 1 )); then - declare -a allHardeningFlags=(fortify fortify3 shadowstack stackprotector stackclashprotection nostrictaliasing pacret pie pic strictoverflow format trivialautovarinit zerocallusedregs) + declare -a allHardeningFlags=(fortify fortify3 shadowstack stackprotector stackclashprotection nostrictaliasing pacret strictflexarrays1 strictflexarrays3 pie pic strictoverflow format trivialautovarinit zerocallusedregs) declare -A hardeningDisableMap=() # Determine which flags were effectively disabled so we can report below. @@ -79,6 +103,14 @@ for flag in "${!hardeningEnableMap[@]}"; do if (( "${NIX_DEBUG:-0}" >= 1 )); then echo HARDENING: enabling shadowstack >&2; fi hardeningCFlagsBefore+=('-fcf-protection=return') ;; + strictflexarrays1) + if (( "${NIX_DEBUG:-0}" >= 1 )); then echo HARDENING: enabling strictflexarrays1 >&2; fi + hardeningCFlagsBefore+=('-fstrict-flex-arrays=1') + ;; + strictflexarrays3) + if (( "${NIX_DEBUG:-0}" >= 1 )); then echo HARDENING: enabling strictflexarrays3 >&2; fi + hardeningCFlagsBefore+=('-fstrict-flex-arrays=3') + ;; pacret) if (( "${NIX_DEBUG:-0}" >= 1 )); then echo HARDENING: enabling pacret >&2; fi hardeningCFlagsBefore+=('-mbranch-protection=pac-ret') diff --git a/pkgs/development/compilers/gcc/default.nix b/pkgs/development/compilers/gcc/default.nix index 38f17692cefa..22a80416d022 100644 --- a/pkgs/development/compilers/gcc/default.nix +++ b/pkgs/development/compilers/gcc/default.nix @@ -428,6 +428,10 @@ pipe "fortify3" "trivialautovarinit" ] + ++ optionals (!atLeast13) [ + "strictflexarrays1" + "strictflexarrays3" + ] ++ optional ( !(targetPlatform.isLinux && targetPlatform.isx86_64 && targetPlatform.libc == "glibc") ) "shadowstack" diff --git a/pkgs/development/compilers/llvm/common/clang/default.nix b/pkgs/development/compilers/llvm/common/clang/default.nix index f3d434b6ac57..a34746b8e079 100644 --- a/pkgs/development/compilers/llvm/common/clang/default.nix +++ b/pkgs/development/compilers/llvm/common/clang/default.nix @@ -299,6 +299,8 @@ stdenv.mkDerivation ( ++ lib.optional ( (lib.versionOlder release_version "15") || !(targetPlatform.isx86_64 || targetPlatform.isAarch64) ) "zerocallusedregs" + ++ lib.optional (lib.versionOlder release_version "15") "strictflexarrays1" + ++ lib.optional (lib.versionOlder release_version "16") "strictflexarrays3" ++ (finalAttrs.passthru.hardeningUnsupportedFlags or [ ]); }; diff --git a/pkgs/stdenv/generic/make-derivation.nix b/pkgs/stdenv/generic/make-derivation.nix index cf7917f366a9..0a8ea03f41b1 100644 --- a/pkgs/stdenv/generic/make-derivation.nix +++ b/pkgs/stdenv/generic/make-derivation.nix @@ -33,6 +33,7 @@ let optionalAttrs optionalString optionals + pipe remove splitString subtractLists @@ -159,6 +160,8 @@ let "format" "fortify" "fortify3" + "strictflexarrays1" + "strictflexarrays3" "shadowstack" "nostrictaliasing" "pacret" @@ -356,14 +359,18 @@ let ) == 0; dontAddHostSuffix = attrs ? outputHash && !noNonNativeDeps || !stdenv.hasCC; - hardeningDisable' = - if - any (x: x == "fortify") hardeningDisable - # disabling fortify implies fortify3 should also be disabled - then - unique (hardeningDisable ++ [ "fortify3" ]) - else - hardeningDisable; + concretizeFlagImplications = + flag: impliesFlags: list: + if any (x: x == flag) list then (list ++ impliesFlags) else list; + + hardeningDisable' = unique ( + pipe hardeningDisable [ + # disabling fortify implies fortify3 should also be disabled + (concretizeFlagImplications "fortify" [ "fortify3" ]) + # disabling strictflexarrays1 implies strictflexarrays3 should also be disabled + (concretizeFlagImplications "strictflexarrays1" [ "strictflexarrays3" ]) + ] + ); defaultHardeningFlags = (if stdenv.hasCC then stdenv.cc else { }).defaultHardeningFlags or # fallback safe-ish set of flags diff --git a/pkgs/top-level/variants.nix b/pkgs/top-level/variants.nix index 8465c61da529..337860895764 100644 --- a/pkgs/top-level/variants.nix +++ b/pkgs/top-level/variants.nix @@ -104,6 +104,7 @@ self: super: { stdenv = super'.withDefaultHardeningFlags ( super'.stdenv.cc.defaultHardeningFlags ++ [ + "strictflexarrays1" "shadowstack" "nostrictaliasing" "pacret" From a3d6882c67f72dca3142d5fd5373140f97c12958 Mon Sep 17 00:00:00 2001 From: Robert Scott Date: Sun, 13 Apr 2025 14:45:49 +0100 Subject: [PATCH 02/15] tests.hardeningFlags: refactor, moving musl brokenness into checkTestBin --- pkgs/test/cc-wrapper/hardening.nix | 80 ++++++++++++++---------------- 1 file changed, 36 insertions(+), 44 deletions(-) diff --git a/pkgs/test/cc-wrapper/hardening.nix b/pkgs/test/cc-wrapper/hardening.nix index d7cd60134652..eb5074e07d43 100644 --- a/pkgs/test/cc-wrapper/hardening.nix +++ b/pkgs/test/cc-wrapper/hardening.nix @@ -100,11 +100,16 @@ let { nativeBuildInputs = [ debian-devscripts ]; buildInputs = [ testBin ]; - meta.platforms = - if ignoreStackClashProtection then - lib.platforms.linux # ELF-reliant - else - [ "x86_64-linux" ]; # stackclashprotection test looks for x86-specific instructions + meta = { + platforms = + if ignoreStackClashProtection then + lib.platforms.linux # ELF-reliant + else + [ "x86_64-linux" ]; # stackclashprotection test looks for x86-specific instructions + # musl implementation of fortify undetectable by this means even if present, + # static similarly + broken = (stdenv.hostPlatform.isMusl || stdenv.hostPlatform.isStatic) && !ignoreFortify; + }; } ( '' @@ -259,8 +264,7 @@ nameDrvAfterAttrName ( } ); - # musl implementation undetectable by this means even if present - fortifyExplicitEnabled = brokenIf stdenv.hostPlatform.isMusl ( + fortifyExplicitEnabled = ( checkTestBin (f2exampleWithStdEnv stdenv { hardeningEnable = [ "fortify" ]; @@ -288,17 +292,15 @@ nameDrvAfterAttrName ( ) ); - fortify3ExplicitEnabled = - brokenIf (stdenv.hostPlatform.isMusl || !stdenv.cc.isGNU || lib.versionOlder stdenv.cc.version "12") - ( - checkTestBin - (f3exampleWithStdEnv stdenv { - hardeningEnable = [ "fortify3" ]; - }) - { - ignoreFortify = false; - } - ); + fortify3ExplicitEnabled = brokenIf (!stdenv.cc.isGNU || lib.versionOlder stdenv.cc.version "12") ( + checkTestBin + (f3exampleWithStdEnv stdenv { + hardeningEnable = [ "fortify3" ]; + }) + { + ignoreFortify = false; + } + ); # musl implementation is effectively FORTIFY_SOURCE=1-only fortify3ExplicitEnabledExecTest = @@ -513,16 +515,14 @@ nameDrvAfterAttrName ( expectFailure = true; }; - # musl implementation undetectable by this means even if present - fortify3StdenvUnsuppDoesntUnsuppFortify1 = brokenIf stdenv.hostPlatform.isMusl ( + fortify3StdenvUnsuppDoesntUnsuppFortify1 = checkTestBin (f1exampleWithStdEnv (stdenvUnsupport [ "fortify3" ]) { hardeningEnable = [ "fortify" ]; }) { ignoreFortify = false; - } - ); + }; fortify3StdenvUnsuppDoesntUnsuppFortify1ExecTest = fortifyExecTest ( f1exampleWithStdEnv (stdenvUnsupport [ "fortify3" ]) { @@ -590,8 +590,7 @@ nameDrvAfterAttrName ( expectFailure = true; }; - # musl implementation undetectable by this means even if present - fortify3EnabledEnvEnablesFortify1 = brokenIf stdenv.hostPlatform.isMusl ( + fortify3EnabledEnvEnablesFortify1 = checkTestBin (f1exampleWithStdEnv stdenv { hardeningDisable = [ @@ -604,8 +603,7 @@ nameDrvAfterAttrName ( }) { ignoreFortify = false; - } - ); + }; fortify3EnabledEnvEnablesFortify1ExecTest = fortifyExecTest ( f1exampleWithStdEnv stdenv { @@ -651,8 +649,7 @@ nameDrvAfterAttrName ( # current implementation prevents the command-line from disabling # fortify if cc-wrapper is enabling it. - # undetectable by this means on static even if present - fortify1ExplicitEnabledCmdlineDisabled = brokenIf stdenv.hostPlatform.isStatic ( + fortify1ExplicitEnabledCmdlineDisabled = checkTestBin (f1exampleWithStdEnv stdenv { hardeningEnable = [ "fortify" ]; @@ -663,27 +660,22 @@ nameDrvAfterAttrName ( { ignoreFortify = false; expectFailure = false; - } - ); + }; # current implementation doesn't force-disable fortify if # command-line enables it even if we use hardeningDisable. - # musl implementation undetectable by this means even if present fortify1ExplicitDisabledCmdlineEnabled = - brokenIf (stdenv.hostPlatform.isMusl || stdenv.hostPlatform.isStatic) - ( - checkTestBin - (f1exampleWithStdEnv stdenv { - hardeningDisable = [ "fortify" ]; - postConfigure = '' - export TEST_EXTRA_FLAGS='-D_FORTIFY_SOURCE=1' - ''; - }) - { - ignoreFortify = false; - } - ); + checkTestBin + (f1exampleWithStdEnv stdenv { + hardeningDisable = [ "fortify" ]; + postConfigure = '' + export TEST_EXTRA_FLAGS='-D_FORTIFY_SOURCE=1' + ''; + }) + { + ignoreFortify = false; + }; fortify1ExplicitDisabledCmdlineEnabledExecTest = fortifyExecTest ( f1exampleWithStdEnv stdenv { From 2c0c7045c9f29cb243ff7a4ef7f64f3187eeb8d9 Mon Sep 17 00:00:00 2001 From: Robert Scott Date: Sun, 20 Apr 2025 18:58:52 +0100 Subject: [PATCH 03/15] tests.hardeningFlags: enable fortifyExplicitEnabledExecTest for clang/glibc this appears to work now --- pkgs/test/cc-wrapper/hardening.nix | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/pkgs/test/cc-wrapper/hardening.nix b/pkgs/test/cc-wrapper/hardening.nix index eb5074e07d43..4bb304e4b49e 100644 --- a/pkgs/test/cc-wrapper/hardening.nix +++ b/pkgs/test/cc-wrapper/hardening.nix @@ -281,16 +281,13 @@ nameDrvAfterAttrName ( ); # musl implementation is effectively FORTIFY_SOURCE=1-only, - # clang-on-glibc also only appears to support FORTIFY_SOURCE=1 (!) - fortifyExplicitEnabledExecTest = - brokenIf (stdenv.hostPlatform.isMusl || (stdenv.cc.isClang && stdenv.hostPlatform.libc == "glibc")) - ( - fortifyExecTest ( - f2exampleWithStdEnv stdenv { - hardeningEnable = [ "fortify" ]; - } - ) - ); + fortifyExplicitEnabledExecTest = brokenIf stdenv.hostPlatform.isMusl ( + fortifyExecTest ( + f2exampleWithStdEnv stdenv { + hardeningEnable = [ "fortify" ]; + } + ) + ); fortify3ExplicitEnabled = brokenIf (!stdenv.cc.isGNU || lib.versionOlder stdenv.cc.version "12") ( checkTestBin From 31e6de5f70a69a60cfb0fb143220ffda39060e45 Mon Sep 17 00:00:00 2001 From: Robert Scott Date: Sun, 20 Apr 2025 18:58:04 +0100 Subject: [PATCH 04/15] tests.hardeningFlags: add tests for strictflexarrays1 & 3 flags --- .../cc-wrapper/flex-arrays-fortify-example.c | 33 ++ pkgs/test/cc-wrapper/hardening.nix | 371 +++++++++++++++++- 2 files changed, 399 insertions(+), 5 deletions(-) create mode 100644 pkgs/test/cc-wrapper/flex-arrays-fortify-example.c diff --git a/pkgs/test/cc-wrapper/flex-arrays-fortify-example.c b/pkgs/test/cc-wrapper/flex-arrays-fortify-example.c new file mode 100644 index 000000000000..3be34eca3aad --- /dev/null +++ b/pkgs/test/cc-wrapper/flex-arrays-fortify-example.c @@ -0,0 +1,33 @@ +/* an example that should be protected by FORTIFY_SOURCE=2 but + * only if the appropriate -fstrict-flex-arrays= argument is used + * for the corresponding value used for BUFFER_DEF_SIZE + */ +#include +#include +#include + +struct buffer_with_header { + char header[1]; + char buffer[BUFFER_DEF_SIZE]; +}; + +int main(int argc, char *argv[]) { + /* use volatile pointer to prevent compiler + * using the outer allocation length with a + * fortified strcpy, which would throw off + * the function-name-sniffing fortify-detecting + * approaches + */ + struct buffer_with_header *volatile b = \ + (struct buffer_with_header *)malloc(sizeof(struct buffer_with_header)+1); + + /* if there are no arguments, skip the write to allow + * builds with BUFFER_DEF_SIZE=0 to have a case where + * the program passes even with strict protection. + */ + if (argc > 1) { + strcpy(b->buffer, argv[1]); + puts(b->buffer); + } + return 0; +} diff --git a/pkgs/test/cc-wrapper/hardening.nix b/pkgs/test/cc-wrapper/hardening.nix index 4bb304e4b49e..2124b58d340d 100644 --- a/pkgs/test/cc-wrapper/hardening.nix +++ b/pkgs/test/cc-wrapper/hardening.nix @@ -37,6 +37,8 @@ let f2exampleWithStdEnv = writeCBinWithStdenv ./fortify2-example.c; f3exampleWithStdEnv = writeCBinWithStdenv ./fortify3-example.c; + flexArrF2ExampleWithStdEnv = writeCBinWithStdenv ./flex-arrays-fortify-example.c; + # for when we need a slightly more complicated program helloWithStdEnv = stdenv': env: @@ -146,13 +148,15 @@ let }) ); + fortifyExecTest = fortifyExecTestFull true "012345 7" "0123456 7"; + # returning a specific exit code when aborting due to a fortify # check isn't mandated. so it's better to just ensure that a # nonzero exit code is returned when we go a single byte beyond # the buffer, with the example programs being designed to be # unlikely to genuinely segfault for such a small overflow. - fortifyExecTest = - testBin: + fortifyExecTestFull = + expectProtection: saturatedArgs: oneTooFarArgs: testBin: runCommand "exec-test" { buildInputs = [ @@ -164,9 +168,15 @@ let ( export PATH=$HOST_PATH echo "Saturated buffer:" # check program isn't completly broken - test-bin 012345 7 - echo "One byte too far:" # eighth byte being the null terminator - (! test-bin 0123456 7) || (echo 'Expected failure, but succeeded!' && exit 1) + test-bin ${saturatedArgs} + echo "One byte too far:" # overflow byte being the null terminator? + ( + ${if expectProtection then "!" else ""} test-bin ${oneTooFarArgs} + ) || ( + echo 'Expected ${if expectProtection then "failure" else "success"}, but ${ + if expectProtection then "succeeded" else "failed" + }!' && exit 1 + ) ) echo "Expected behaviour observed" touch $out @@ -310,6 +320,128 @@ nameDrvAfterAttrName ( ) ); + sfa1explicitEnabled = + checkTestBin + (flexArrF2ExampleWithStdEnv stdenv { + hardeningEnable = [ + "fortify" + "strictflexarrays1" + ]; + env = { + TEST_EXTRA_FLAGS = "-DBUFFER_DEF_SIZE=7"; + }; + }) + { + ignoreFortify = false; + }; + + # musl implementation is effectively FORTIFY_SOURCE=1-only + sfa1explicitEnabledExecTest = brokenIf stdenv.hostPlatform.isMusl ( + fortifyExecTestFull true "012345" "0123456" ( + flexArrF2ExampleWithStdEnv stdenv { + hardeningEnable = [ + "fortify" + "strictflexarrays1" + ]; + env = { + TEST_EXTRA_FLAGS = "-DBUFFER_DEF_SIZE=7"; + }; + } + ) + ); + + sfa1explicitEnabledDoesntProtectDefLen1 = + checkTestBin + (flexArrF2ExampleWithStdEnv stdenv { + hardeningEnable = [ + "fortify" + "strictflexarrays1" + ]; + env = { + TEST_EXTRA_FLAGS = "-DBUFFER_DEF_SIZE=1"; + }; + }) + { + ignoreFortify = false; + expectFailure = true; + }; + + # musl implementation is effectively FORTIFY_SOURCE=1-only + sfa1explicitEnabledDoesntProtectDefLen1ExecTest = brokenIf stdenv.hostPlatform.isMusl ( + fortifyExecTestFull false "''" "0" ( + flexArrF2ExampleWithStdEnv stdenv { + hardeningEnable = [ + "fortify" + "strictflexarrays1" + ]; + env = { + TEST_EXTRA_FLAGS = "-DBUFFER_DEF_SIZE=1"; + }; + } + ) + ); + + sfa3explicitEnabledProtectsDefLen1 = + checkTestBin + (flexArrF2ExampleWithStdEnv stdenv { + hardeningEnable = [ + "fortify" + "strictflexarrays3" + ]; + env = { + TEST_EXTRA_FLAGS = "-DBUFFER_DEF_SIZE=1"; + }; + }) + { + ignoreFortify = false; + }; + + # musl implementation is effectively FORTIFY_SOURCE=1-only + sfa3explicitEnabledProtectsDefLen1ExecTest = brokenIf stdenv.hostPlatform.isMusl ( + fortifyExecTestFull true "''" "0" ( + flexArrF2ExampleWithStdEnv stdenv { + hardeningEnable = [ + "fortify" + "strictflexarrays3" + ]; + env = { + TEST_EXTRA_FLAGS = "-DBUFFER_DEF_SIZE=1"; + }; + } + ) + ); + + sfa3explicitEnabledDoesntProtectCorrectFlex = + checkTestBin + (flexArrF2ExampleWithStdEnv stdenv { + hardeningEnable = [ + "fortify" + "strictflexarrays3" + ]; + env = { + TEST_EXTRA_FLAGS = "-DBUFFER_DEF_SIZE="; + }; + }) + { + ignoreFortify = false; + expectFailure = true; + }; + + # musl implementation is effectively FORTIFY_SOURCE=1-only + sfa3explicitEnabledDoesntProtectCorrectFlexExecTest = brokenIf stdenv.hostPlatform.isMusl ( + fortifyExecTestFull false "" "0" ( + flexArrF2ExampleWithStdEnv stdenv { + hardeningEnable = [ + "fortify" + "strictflexarrays3" + ]; + env = { + TEST_EXTRA_FLAGS = "-DBUFFER_DEF_SIZE="; + }; + } + ) + ); + pieExplicitEnabled = brokenIf stdenv.hostPlatform.isStatic ( checkTestBin (f2exampleWithStdEnv stdenv { @@ -420,6 +552,99 @@ nameDrvAfterAttrName ( ignoreFortify = false; }; + # musl implementation is effectively FORTIFY_SOURCE=1-only + sfa1explicitDisabled = brokenIf stdenv.hostPlatform.isMusl ( + checkTestBin + (flexArrF2ExampleWithStdEnv stdenv { + hardeningEnable = [ "fortify" ]; + hardeningDisable = [ "strictflexarrays1" ]; + env = { + TEST_EXTRA_FLAGS = "-DBUFFER_DEF_SIZE=7"; + }; + }) + { + ignoreFortify = false; + expectFailure = true; + } + ); + + sfa1explicitDisabledExecTest = fortifyExecTestFull false "012345" "0123456" ( + flexArrF2ExampleWithStdEnv stdenv { + hardeningEnable = [ "fortify" ]; + hardeningDisable = [ "strictflexarrays1" ]; + env = { + TEST_EXTRA_FLAGS = "-DBUFFER_DEF_SIZE=7"; + }; + } + ); + + # musl implementation is effectively FORTIFY_SOURCE=1-only + sfa1explicitDisabledDisablesSfa3 = brokenIf stdenv.hostPlatform.isMusl ( + checkTestBin + (flexArrF2ExampleWithStdEnv stdenv { + hardeningEnable = [ + "fortify" + "strictflexarrays3" + ]; + hardeningDisable = [ "strictflexarrays1" ]; + env = { + TEST_EXTRA_FLAGS = "-DBUFFER_DEF_SIZE=1"; + }; + }) + { + ignoreFortify = false; + expectFailure = true; + } + ); + + # musl implementation is effectively FORTIFY_SOURCE=1-only + sfa1explicitDisabledDisablesSfa3ExecTest = brokenIf stdenv.hostPlatform.isMusl ( + fortifyExecTestFull false "''" "0" ( + flexArrF2ExampleWithStdEnv stdenv { + hardeningEnable = [ + "fortify" + "strictflexarrays3" + ]; + hardeningDisable = [ "strictflexarrays1" ]; + env = { + TEST_EXTRA_FLAGS = "-DBUFFER_DEF_SIZE=1"; + }; + } + ) + ); + + sfa3explicitDisabledDoesntDisableSfa1 = + checkTestBin + (flexArrF2ExampleWithStdEnv stdenv { + hardeningEnable = [ + "fortify" + "strictflexarrays1" + ]; + hardeningDisable = [ "strictflexarrays3" ]; + env = { + TEST_EXTRA_FLAGS = "-DBUFFER_DEF_SIZE=7"; + }; + }) + { + ignoreFortify = false; + }; + + # musl implementation is effectively FORTIFY_SOURCE=1-only + sfa3explicitDisabledDoesntDisableSfa1ExecTest = brokenIf stdenv.hostPlatform.isMusl ( + fortifyExecTestFull true "012345" "0123456" ( + flexArrF2ExampleWithStdEnv stdenv { + hardeningEnable = [ + "fortify" + "strictflexarrays1" + ]; + hardeningDisable = [ "strictflexarrays3" ]; + env = { + TEST_EXTRA_FLAGS = "-DBUFFER_DEF_SIZE=7"; + }; + } + ) + ); + pieExplicitDisabled = brokenIf (stdenv.hostPlatform.isMusl && stdenv.cc.isClang) ( checkTestBin (f2exampleWithStdEnv stdenv { @@ -527,6 +752,90 @@ nameDrvAfterAttrName ( } ); + sfa1StdenvUnsupp = + checkTestBin + (flexArrF2ExampleWithStdEnv + (stdenvUnsupport [ + "strictflexarrays1" + "strictflexarrays3" + ]) + { + hardeningEnable = [ + "fortify" + "strictflexarrays1" + ]; + env = { + TEST_EXTRA_FLAGS = "-DBUFFER_DEF_SIZE=7"; + }; + } + ) + { + ignoreFortify = false; + expectFailure = true; + }; + + sfa3StdenvUnsupp = + checkTestBin + (flexArrF2ExampleWithStdEnv (stdenvUnsupport [ "strictflexarrays3" ]) { + hardeningEnable = [ + "fortify" + "strictflexarrays3" + ]; + env = { + TEST_EXTRA_FLAGS = "-DBUFFER_DEF_SIZE=1"; + }; + }) + { + ignoreFortify = false; + expectFailure = true; + }; + + sfa1StdenvUnsuppUnsupportsSfa3 = + checkTestBin + (flexArrF2ExampleWithStdEnv (stdenvUnsupport [ "strictflexarrays1" ]) { + hardeningEnable = [ + "fortify" + "strictflexarrays3" + ]; + env = { + TEST_EXTRA_FLAGS = "-DBUFFER_DEF_SIZE=1"; + }; + }) + { + ignoreFortify = false; + expectFailure = true; + }; + + sfa3StdenvUnsuppDoesntUnsuppSfa1 = + checkTestBin + (flexArrF2ExampleWithStdEnv (stdenvUnsupport [ "strictflexarrays3" ]) { + hardeningEnable = [ + "fortify" + "strictflexarrays1" + ]; + env = { + TEST_EXTRA_FLAGS = "-DBUFFER_DEF_SIZE=7"; + }; + }) + { + ignoreFortify = false; + }; + + # musl implementation is effectively FORTIFY_SOURCE=1-only + sfa3StdenvUnsuppDoesntUnsuppSfa1ExecTest = brokenIf stdenv.hostPlatform.isMusl ( + fortifyExecTestFull true "012345" "0123456" ( + flexArrF2ExampleWithStdEnv (stdenvUnsupport [ "strictflexarrays3" ]) { + hardeningEnable = [ + "fortify" + "strictflexarrays1" + ]; + env = { + TEST_EXTRA_FLAGS = "-DBUFFER_DEF_SIZE=7"; + }; + } + ) + ); + stackProtectorStdenvUnsupp = checkTestBin (f2exampleWithStdEnv (stdenvUnsupport [ "stackprotector" ]) { @@ -630,6 +939,58 @@ nameDrvAfterAttrName ( expectFailure = true; }; + sfa3EnabledEnvEnablesSfa1 = + checkTestBin + (flexArrF2ExampleWithStdEnv stdenv { + hardeningDisable = [ + "strictflexarrays1" + "strictflexarrays3" + ]; + postConfigure = '' + export NIX_HARDENING_ENABLE="fortify strictflexarrays3" + ''; + env = { + TEST_EXTRA_FLAGS = "-DBUFFER_DEF_SIZE=7"; + }; + }) + { + ignoreFortify = false; + }; + + sfa3EnabledEnvEnablesSfa1ExecTest = fortifyExecTestFull true "012345" "0123456" ( + f1exampleWithStdEnv stdenv { + hardeningDisable = [ + "strictflexarrays1" + "strictflexarrays3" + ]; + postConfigure = '' + export NIX_HARDENING_ENABLE="fortify strictflexarrays3" + ''; + env = { + TEST_EXTRA_FLAGS = "-DBUFFER_DEF_SIZE=7"; + }; + } + ); + + sfa1EnabledEnvDoesntEnableSfa3 = + checkTestBin + (flexArrF2ExampleWithStdEnv stdenv { + hardeningDisable = [ + "strictflexarrays1" + "strictflexarrays3" + ]; + postConfigure = '' + export NIX_HARDENING_ENABLE="fortify strictflexarrays1" + ''; + env = { + TEST_EXTRA_FLAGS = "-DBUFFER_DEF_SIZE=1"; + }; + }) + { + ignoreFortify = false; + expectFailure = true; + }; + # NIX_HARDENING_ENABLE can't enable an unsupported feature stackProtectorUnsupportedEnabledEnv = checkTestBin From c4bc9401957e4ee1c773c1e7d670ce34c95f9780 Mon Sep 17 00:00:00 2001 From: Robert Scott Date: Sat, 24 May 2025 01:37:21 +0100 Subject: [PATCH 05/15] tests.hardeningFlags: use --nobranchprotection for hardening-check introduced with new debian-devscripts --- pkgs/test/cc-wrapper/hardening.nix | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkgs/test/cc-wrapper/hardening.nix b/pkgs/test/cc-wrapper/hardening.nix index 2124b58d340d..5ae8a0196873 100644 --- a/pkgs/test/cc-wrapper/hardening.nix +++ b/pkgs/test/cc-wrapper/hardening.nix @@ -116,7 +116,7 @@ let ( '' if ${lib.optionalString (!expectFailure) "!"} { - hardening-check --nocfprotection \ + hardening-check --nocfprotection --nobranchprotection \ ${lib.optionalString ignoreBindNow "--nobindnow"} \ ${lib.optionalString ignoreFortify "--nofortify"} \ ${lib.optionalString ignorePie "--nopie"} \ From e7faa8bad7bcaa9b74fe79e886cea7bc8d5cb5ae Mon Sep 17 00:00:00 2001 From: Robert Scott Date: Sun, 6 Apr 2025 17:03:38 +0100 Subject: [PATCH 06/15] glibc: disable strictflexarrays3 hardening flag --- pkgs/development/libraries/glibc/default.nix | 1 + 1 file changed, 1 insertion(+) diff --git a/pkgs/development/libraries/glibc/default.nix b/pkgs/development/libraries/glibc/default.nix index d165cb8fff62..f4d49d8ec533 100644 --- a/pkgs/development/libraries/glibc/default.nix +++ b/pkgs/development/libraries/glibc/default.nix @@ -64,6 +64,7 @@ in "fortify" "pie" "stackprotector" + "strictflexarrays3" ]; env = (previousAttrs.env or { }) // { From 3d49f61e8acba7dece6828465972521e79f32dcc Mon Sep 17 00:00:00 2001 From: Robert Scott Date: Sun, 6 Apr 2025 17:18:40 +0100 Subject: [PATCH 07/15] gdbm: disable strictflexarrays3 hardening flag --- pkgs/by-name/gd/gdbm/package.nix | 2 ++ 1 file changed, 2 insertions(+) diff --git a/pkgs/by-name/gd/gdbm/package.nix b/pkgs/by-name/gd/gdbm/package.nix index 45707a5a4d4b..c707a23cfeaf 100644 --- a/pkgs/by-name/gd/gdbm/package.nix +++ b/pkgs/by-name/gd/gdbm/package.nix @@ -24,6 +24,8 @@ stdenv.mkDerivation (finalAttrs: { nativeBuildInputs = [ updateAutotoolsGnuConfigScriptsHook ]; + hardeningDisable = [ "strictflexarrays3" ]; + configureFlags = [ (lib.enableFeature true "libgdbm-compat") ]; outputs = [ From ea933260d4ea090613e60e6f6966118796d3b098 Mon Sep 17 00:00:00 2001 From: Robert Scott Date: Sun, 6 Apr 2025 19:02:33 +0100 Subject: [PATCH 08/15] unzip: disable strictflexarrays3 hardening flag --- pkgs/by-name/un/unzip/package.nix | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/pkgs/by-name/un/unzip/package.nix b/pkgs/by-name/un/unzip/package.nix index a5b84b813538..7a2f8fc8bd33 100644 --- a/pkgs/by-name/un/unzip/package.nix +++ b/pkgs/by-name/un/unzip/package.nix @@ -16,7 +16,10 @@ stdenv.mkDerivation rec { sha256 = "0dxx11knh3nk95p2gg2ak777dd11pr7jx5das2g49l262scrcv83"; }; - hardeningDisable = [ "format" ]; + hardeningDisable = [ + "format" + "strictflexarrays3" + ]; patchFlags = [ "-p1" From 79c3782ef848c05fea8a8c9ce351842f1e18ac78 Mon Sep 17 00:00:00 2001 From: Robert Scott Date: Sun, 6 Apr 2025 20:06:34 +0100 Subject: [PATCH 09/15] libgpg-error: disable strictflexarrays3 hardening flag --- pkgs/by-name/li/libgpg-error/package.nix | 2 ++ 1 file changed, 2 insertions(+) diff --git a/pkgs/by-name/li/libgpg-error/package.nix b/pkgs/by-name/li/libgpg-error/package.nix index 140d15a2c380..562da12a0de7 100644 --- a/pkgs/by-name/li/libgpg-error/package.nix +++ b/pkgs/by-name/li/libgpg-error/package.nix @@ -36,6 +36,8 @@ stdenv.mkDerivation ( sed '/BUILD_TIMESTAMP=/s/=.*/=1970-01-01T00:01+0000/' -i ./configure ''; + hardeningDisable = [ "strictflexarrays3" ]; + configureFlags = [ # See https://dev.gnupg.org/T6257#164567 "--enable-install-gpg-error-config" From 185f5f70bc3c3e2cd98befd03139983cc3e6ae99 Mon Sep 17 00:00:00 2001 From: Robert Scott Date: Sun, 6 Apr 2025 20:10:10 +0100 Subject: [PATCH 10/15] libtpms: disable strictflexarrays3 hardening flag --- pkgs/by-name/li/libtpms/package.nix | 2 ++ 1 file changed, 2 insertions(+) diff --git a/pkgs/by-name/li/libtpms/package.nix b/pkgs/by-name/li/libtpms/package.nix index 4deb7b7e261e..744277555714 100644 --- a/pkgs/by-name/li/libtpms/package.nix +++ b/pkgs/by-name/li/libtpms/package.nix @@ -19,6 +19,8 @@ stdenv.mkDerivation rec { sha256 = "sha256-YKs/XYJ8UItOtSinl28/G9XFVzobFd4ZDKtClQDLXFk="; }; + hardeningDisable = [ "strictflexarrays3" ]; + nativeBuildInputs = [ autoreconfHook pkg-config From 6e7b7ac6ecd04f38d42969ea8aa4be32a44422e9 Mon Sep 17 00:00:00 2001 From: Robert Scott Date: Sun, 6 Apr 2025 20:52:21 +0100 Subject: [PATCH 11/15] libgcrypt: disable strictflexarrays3 hardening flag --- pkgs/by-name/li/libgcrypt/package.nix | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/pkgs/by-name/li/libgcrypt/package.nix b/pkgs/by-name/li/libgcrypt/package.nix index 4ac7d48213e2..040fba50592b 100644 --- a/pkgs/by-name/li/libgcrypt/package.nix +++ b/pkgs/by-name/li/libgcrypt/package.nix @@ -32,10 +32,16 @@ stdenv.mkDerivation rec { "out" ]; - # The CPU Jitter random number generator must not be compiled with - # optimizations and the optimize -O0 pragma only works for gcc. - # The build enables -O2 by default for everything else. - hardeningDisable = lib.optional stdenv.cc.isClang "fortify"; + hardeningDisable = + [ + "strictflexarrays3" + ] + ++ lib.optionals stdenv.cc.isClang [ + # The CPU Jitter random number generator must not be compiled with + # optimizations and the optimize -O0 pragma only works for gcc. + # The build enables -O2 by default for everything else. + "fortify" + ]; depsBuildBuild = [ buildPackages.stdenv.cc ]; From 43929ac9ccf00c092cde97507c8ebc11e9d752c8 Mon Sep 17 00:00:00 2001 From: Robert Scott Date: Sun, 6 Apr 2025 20:59:17 +0100 Subject: [PATCH 12/15] libksba: disable strictflexarrays3 hardening flag --- pkgs/by-name/li/libksba/package.nix | 2 ++ 1 file changed, 2 insertions(+) diff --git a/pkgs/by-name/li/libksba/package.nix b/pkgs/by-name/li/libksba/package.nix index e45be78cae0a..f606ba680f63 100644 --- a/pkgs/by-name/li/libksba/package.nix +++ b/pkgs/by-name/li/libksba/package.nix @@ -26,6 +26,8 @@ stdenv.mkDerivation rec { propagatedBuildInputs = [ libgpg-error ]; depsBuildBuild = [ buildPackages.stdenv.cc ]; + hardeningDisable = [ "strictflexarrays3" ]; + configureFlags = [ "--with-libgpg-error-prefix=${libgpg-error.dev}" ]; postInstall = '' From 339c93697ffa4c159aefbb88600abfe3ebb4e508 Mon Sep 17 00:00:00 2001 From: Robert Scott Date: Sun, 6 Apr 2025 21:25:36 +0100 Subject: [PATCH 13/15] libarchive: disable strictflexarrays3 hardening flag --- pkgs/by-name/li/libarchive/package.nix | 2 ++ 1 file changed, 2 insertions(+) diff --git a/pkgs/by-name/li/libarchive/package.nix b/pkgs/by-name/li/libarchive/package.nix index bf43230d9333..83360768cc45 100644 --- a/pkgs/by-name/li/libarchive/package.nix +++ b/pkgs/by-name/li/libarchive/package.nix @@ -123,6 +123,8 @@ stdenv.mkDerivation (finalAttrs: { acl ]; + hardeningDisable = [ "strictflexarrays3" ]; + configureFlags = lib.optional (!xarSupport) "--without-xml2"; preBuild = lib.optionalString stdenv.hostPlatform.isCygwin '' From 5da561c2ec4465a7a17e5fd509985c79e2e0bb5c Mon Sep 17 00:00:00 2001 From: Robert Scott Date: Sun, 6 Apr 2025 22:07:52 +0100 Subject: [PATCH 14/15] elfutils: disable strictflexarrays3 hardening flag --- pkgs/by-name/el/elfutils/package.nix | 2 ++ 1 file changed, 2 insertions(+) diff --git a/pkgs/by-name/el/elfutils/package.nix b/pkgs/by-name/el/elfutils/package.nix index f07ab5b6aebc..594f6f3499b4 100644 --- a/pkgs/by-name/el/elfutils/package.nix +++ b/pkgs/by-name/el/elfutils/package.nix @@ -117,6 +117,8 @@ stdenv.mkDerivation rec { propagatedNativeBuildInputs = [ setupDebugInfoDirs ]; + hardeningDisable = [ "strictflexarrays3" ]; + configureFlags = [ "--program-prefix=eu-" # prevent collisions with binutils From b7771e10fca3014de26e876bcc2d39418f1d75ed Mon Sep 17 00:00:00 2001 From: Robert Scott Date: Sun, 6 Apr 2025 22:10:49 +0100 Subject: [PATCH 15/15] dash: disable strictflexarrays3 hardening flag --- pkgs/by-name/da/dash/package.nix | 2 ++ 1 file changed, 2 insertions(+) diff --git a/pkgs/by-name/da/dash/package.nix b/pkgs/by-name/da/dash/package.nix index 6fe83258a58a..6c21d4edeff1 100644 --- a/pkgs/by-name/da/dash/package.nix +++ b/pkgs/by-name/da/dash/package.nix @@ -25,6 +25,8 @@ stdenv.mkDerivation (finalAttrs: { depsBuildBuild = [ buildPackages.stdenv.cc ]; buildInputs = [ libedit ]; + hardeningDisable = [ "strictflexarrays3" ]; + configureFlags = [ "--with-libedit" ]; preConfigure = lib.optional stdenv.hostPlatform.isStatic '' export LIBS="$(''${PKG_CONFIG:-pkg-config} --libs --static libedit)"