From 3f1a00c79d0d0e3b7f0893c7163ab8e821b9bebd Mon Sep 17 00:00:00 2001 From: Robert Scott Date: Mon, 7 Apr 2025 22:04:11 +0100 Subject: [PATCH] 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"