Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions doc/redirects.json
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,12 @@
"inkscape-plugins": [
"index.html#inkscape-plugins"
],
"libcxxhardeningextensive": [
"index.html#libcxxhardeningextensive"
],
"libcxxhardeningfast": [
"index.html#libcxxhardeningfast"
],
"major-ghc-deprecation": [
"index.html#major-ghc-deprecation"
],
Expand Down
4 changes: 1 addition & 3 deletions doc/release-notes/rl-2511.section.md
Original file line number Diff line number Diff line change
Expand Up @@ -245,7 +245,7 @@

- `installShellCompletion`: now supports Nushell completion files

- 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.
- New hardening flags `strictflexarrays1`, `strictflexarrays3`, `glibcxxassertions`, `libcxxhardeningfast` and `libcxxhardeningextensive` were made available.

- `gramps` has been updated to 6.0.0
Upstream recommends [backing up your Family Trees](https://gramps-project.org/wiki/index.php/Gramps_6.0_Wiki_Manual_-_Manage_Family_Trees#Backing_up_a_Family_Tree) before upgrading.
Expand All @@ -261,8 +261,6 @@
- `searx` was updated to use `envsubst` instead of `sed` for parsing secrets from environment variables.
If your previous configuration included a secret reference like `server.secret_key = "@SEARX_SECRET_KEY@"`, you must migrate to the new envsubst syntax: `server.secret_key = "$SEARX_SECRET_KEY"`.

- A new hardening flag, `glibcxxassertions` was made available, corresponding to the glibc `_GLIBCXX_ASSERTIONS` option.

- `versionCheckHook`: Packages that previously relied solely on `pname` to locate the program used to version check, but have a differing `meta.mainProgram` entry, might now fail.


Expand Down
12 changes: 12 additions & 0 deletions doc/stdenv/stdenv.chapter.md
Original file line number Diff line number Diff line change
Expand Up @@ -1675,6 +1675,18 @@ Adds the `-D_GLIBCXX_ASSERTIONS` compiler flag. This flag only has an effect on

These checks may have an impact on performance in some cases.

#### `libcxxhardeningfast` {#libcxxhardeningfast}

Adds the `-D_LIBCPP_HARDENING_MODE=_LIBCPP_HARDENING_MODE_FAST` compiler flag. This flag only has an effect on libc++ targets, and when defined, enables a set of assertions that prevent undefined behavior caused by violating preconditions of the standard library. libc++ provides several hardening modes, and this "fast" mode contains a set of security-critical checks that can be done with relatively little overhead in constant time.

Disabling `libcxxhardeningfast` implies disablement of checks from `libcxxhardeningextensive`.

#### `libcxxhardeningextensive` {#libcxxhardeningextensive}

Adds the `-D_LIBCPP_HARDENING_MODE=_LIBCPP_HARDENING_MODE_EXTENSIVE` compiler flag. This flag only has an effect on libc++ targets, and when defined, enables a set of assertions that prevent undefined behavior caused by violating preconditions of the standard library. libc++ provides several hardening modes, and this "extensive" mode adds checks for undefined behavior that incur relatively little overhead but aren’t security-critical. The additional rigour impacts performance more than fast mode: benchmarking is recommended to determine if it is acceptable for a particular application.

Enabling this flag implies enablement of checks from `libcxxhardeningfast`. Disabling this flag does not imply disablement of checks from `libcxxhardeningfast`.

#### `pacret` {#pacret}

This flag adds the `-mbranch-protection=pac-ret` compiler option on aarch64-linux targets. This uses ARM v8.3's Pointer Authentication feature to sign function return pointers before adding them to the stack. The pointer's authenticity is then validated before returning to its destination. This dramatically increases the difficulty of ROP exploitation techniques.
Expand Down
2 changes: 2 additions & 0 deletions pkgs/build-support/bintools-wrapper/default.nix
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@
"format"
"fortify"
"fortify3"
"libcxxhardeningextensive"
"libcxxhardeningfast"
"pic"
"relro"
"stackclashprotection"
Expand Down
26 changes: 25 additions & 1 deletion pkgs/build-support/cc-wrapper/add-hardening.sh
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,13 @@ if [[ -n "${hardeningEnableMap[strictflexarrays3]-}" ]]; then
hardeningEnableMap["strictflexarrays1"]=1
fi

# libcxxhardeningextensive implies libcxxhardeningfast enablement - make explicit before
# we filter unsupported flags because unsupporting libcxxhardeningextensive
# doesn't mean we should unsupport libcxxhardeningfast too
if [[ -n "${hardeningEnableMap[libcxxhardeningextensive]-}" ]]; then
hardeningEnableMap["libcxxhardeningfast"]=1
fi


# Remove unsupported flags.
for flag in @hardening_unsupported_flags@; do
Expand All @@ -37,6 +44,10 @@ for flag in @hardening_unsupported_flags@; do
if [[ "$flag" = 'strictflexarrays1' ]] ; then
unset -v "hardeningEnableMap['strictflexarrays3']"
fi
# libcxxhardeningfast being unsupported implies libcxxhardeningextensive is unsupported
if [[ "$flag" = 'libcxxhardeningfast' ]] ; then
unset -v "hardeningEnableMap['libcxxhardeningextensive']"
fi
done


Expand All @@ -50,9 +61,14 @@ if [[ -n "${hardeningEnableMap[strictflexarrays3]-}" ]]; then
unset -v "hardeningEnableMap['strictflexarrays1']"
fi

# now make libcxxhardeningfast and libcxxhardeningextensive mutually exclusive
if [[ -n "${hardeningEnableMap[libcxxhardeningextensive]-}" ]]; then
unset -v "hardeningEnableMap['libcxxhardeningfast']"
fi


if (( "${NIX_DEBUG:-0}" >= 1 )); then
declare -a allHardeningFlags=(fortify fortify3 shadowstack stackprotector stackclashprotection nostrictaliasing pacret strictflexarrays1 strictflexarrays3 pic strictoverflow glibcxxassertions format trivialautovarinit zerocallusedregs)
declare -a allHardeningFlags=(fortify fortify3 shadowstack stackprotector stackclashprotection nostrictaliasing pacret strictflexarrays1 strictflexarrays3 pic strictoverflow libcxxhardeningfast libcxxhardeningextensive glibcxxassertions format trivialautovarinit zerocallusedregs)
declare -A hardeningDisableMap=()

# Determine which flags were effectively disabled so we can report below.
Expand Down Expand Up @@ -115,6 +131,14 @@ for flag in "${!hardeningEnableMap[@]}"; do
if (( "${NIX_DEBUG:-0}" >= 1 )); then echo HARDENING: enabling glibcxxassertions >&2; fi
hardeningCFlagsBefore+=('-D_GLIBCXX_ASSERTIONS')
;;
libcxxhardeningfast)
if (( "${NIX_DEBUG:-0}" >= 1 )); then echo HARDENING: enabling libcxxhardeningfast >&2; fi
hardeningCFlagsBefore+=('-D_LIBCPP_HARDENING_MODE=_LIBCPP_HARDENING_MODE_FAST')
;;
libcxxhardeningextensive)
if (( "${NIX_DEBUG:-0}" >= 1 )); then echo HARDENING: enabling libcxxhardeningextensive >&2; fi
hardeningCFlagsBefore+=('-D_LIBCPP_HARDENING_MODE=_LIBCPP_HARDENING_MODE_EXTENSIVE')
;;
stackprotector)
if (( "${NIX_DEBUG:-0}" >= 1 )); then echo HARDENING: enabling stackprotector >&2; fi
hardeningCFlagsBefore+=('-fstack-protector-strong' '--param' 'ssp-buffer-size=4')
Expand Down
3 changes: 3 additions & 0 deletions pkgs/by-name/ld/ld64/package.nix
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,9 @@ stdenv.mkDerivation (finalAttrs: {
xar
];

# ld built with this fails to link glib's gio on x86_64 darwin
hardeningDisable = [ "libcxxhardeningfast" ];

dontUseCmakeConfigure = true; # CMake is only needed because it’s used by Meson to find LLVM.

# Note for overrides: ld64 cannot be built as a debug build because of UB in its iteration implementations,
Expand Down
4 changes: 4 additions & 0 deletions pkgs/stdenv/generic/make-derivation.nix
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,8 @@ let
"relro"
"stackprotector"
"glibcxxassertions"
"libcxxhardeningfast"
"libcxxhardeningextensive"
"stackclashprotection"
"strictoverflow"
"trivialautovarinit"
Expand Down Expand Up @@ -427,6 +429,8 @@ let
(concretizeFlagImplications "fortify" [ "fortify3" ])
# disabling strictflexarrays1 implies strictflexarrays3 should also be disabled
(concretizeFlagImplications "strictflexarrays1" [ "strictflexarrays3" ])
# disabling libcxxhardeningfast implies libcxxhardeningextensive should also be disabled
(concretizeFlagImplications "libcxxhardeningfast" [ "libcxxhardeningextensive" ])
]
);
enabledHardeningOptions =
Expand Down
171 changes: 160 additions & 11 deletions pkgs/test/cc-wrapper/hardening.nix
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,8 @@ let
[ -n "$preBuild" ] && eval "$preBuild"
n=$out/bin/test-bin
mkdir -p "$(dirname "$n")"
cp "$codePath" code.c
NIX_DEBUG=1 $CC -x c code.c -O1 $TEST_EXTRA_FLAGS -o "$n"
cp "$codePath" .
NIX_DEBUG=1 $CC -x ''${TEST_SOURCE_LANG:-c} "$(basename $codePath)" -O1 $TEST_EXTRA_FLAGS -o "$n"
'';

f1exampleWithStdEnv = writeCBinWithStdenv ./fortify1-example.c;
Expand All @@ -41,15 +41,60 @@ let

flexArrF2ExampleWithStdEnv = writeCBinWithStdenv ./flex-arrays-fortify-example.c;

# we don't really have a reliable property for testing for
# libstdc++ we'll just have to check for the absence of libcxx
checkGlibcxxassertionsWithStdEnv =
expectDefined:
writeCBinWithStdenv (
writeText "main.cpp" ''
#if${if expectDefined then "n" else ""}def _GLIBCXX_ASSERTIONS
#error "Expected _GLIBCXX_ASSERTIONS to be ${if expectDefined then "" else "un"}defined"
#endif
int main() {}
''
expectDefined: stdenv': derivationArgs:
brokenIf (stdenv.cc.libcxx != null) (
writeCBinWithStdenv
(writeText "main.cpp" ''
#if${if expectDefined then "n" else ""}def _GLIBCXX_ASSERTIONS
#error "Expected _GLIBCXX_ASSERTIONS to be ${if expectDefined then "" else "un"}defined"
#endif
int main() {}
'')
stdenv'
(
derivationArgs
// {
env = (derivationArgs.env or { }) // {
TEST_SOURCE_LANG = derivationArgs.env.TEST_SOURCE_LANG or "c++";
};
}
)
);

checkLibcxxHardeningWithStdEnv =
expectValue: stdenv': env:
brokenIf (stdenv.cc.libcxx == null) (
writeCBinWithStdenv
(writeText "main.cpp" (
''
#include <limits>
#ifndef _LIBCPP_HARDENING_MODE
#error "Expected _LIBCPP_HARDENING_MODE to be defined"
#endif
#ifndef ${expectValue}
#error "Expected ${expectValue} to be defined"
#endif

#if _LIBCPP_HARDENING_MODE != ${expectValue}
#error "Expected _LIBCPP_HARDENING_MODE to equal ${expectValue}"
#endif
''
+ ''
int main() {}
''
))
stdenv'
(
env
// {
env = (env.env or { }) // {
TEST_SOURCE_LANG = env.env.TEST_SOURCE_LANG or "c++";
};
}
)
);

# for when we need a slightly more complicated program
Expand Down Expand Up @@ -691,6 +736,48 @@ nameDrvAfterAttrName (
hardeningDisable = [ "glibcxxassertions" ];
};

lchFastExplicitDisabled = checkLibcxxHardeningWithStdEnv "_LIBCPP_HARDENING_MODE_NONE" stdenv {
hardeningDisable = [ "libcxxhardeningfast" ];
};

lchExtensiveExplicitEnabled =
checkLibcxxHardeningWithStdEnv "_LIBCPP_HARDENING_MODE_EXTENSIVE" stdenv
{
hardeningEnable = [ "libcxxhardeningextensive" ];
};

lchExtensiveExplicitDisabledDoesntDisableLchFast =
checkLibcxxHardeningWithStdEnv "_LIBCPP_HARDENING_MODE_FAST" stdenv
{
hardeningEnable = [ "libcxxhardeningfast" ];
hardeningDisable = [ "libcxxhardeningextensive" ];
};

lchFastExplicitDisabledDisablesLchExtensive =
checkLibcxxHardeningWithStdEnv "_LIBCPP_HARDENING_MODE_NONE" stdenv
{
hardeningEnable = [ "libcxxhardeningextensive" ];
hardeningDisable = [ "libcxxhardeningfast" ];
};

lchFastExtensiveExplicitEnabledResultsInLchExtensive =
checkLibcxxHardeningWithStdEnv "_LIBCPP_HARDENING_MODE_EXTENSIVE" stdenv
{
hardeningEnable = [
"libcxxhardeningfast"
"libcxxhardeningextensive"
];
};

lchFastExtensiveExplicitDisabledDisablesBoth =
checkLibcxxHardeningWithStdEnv "_LIBCPP_HARDENING_MODE_NONE" stdenv
{
hardeningDisable = [
"libcxxhardeningfast"
"libcxxhardeningextensive"
];
};

# most flags can't be "unsupported" by compiler alone and
# binutils doesn't have an accessible hardeningUnsupportedFlags
# mechanism, so can only test a couple of flags through altered
Expand Down Expand Up @@ -897,6 +984,30 @@ nameDrvAfterAttrName (
hardeningEnable = [ "glibcxxassertions" ];
};

lchFastStdenvUnsupp =
checkLibcxxHardeningWithStdEnv "_LIBCPP_HARDENING_MODE_NONE"
(stdenvUnsupport [ "libcxxhardeningfast" ])
{
hardeningEnable = [ "libcxxhardeningfast" ];
};

lchFastStdenvUnsuppUnsupportsLchExtensive =
checkLibcxxHardeningWithStdEnv "_LIBCPP_HARDENING_MODE_NONE"
(stdenvUnsupport [ "libcxxhardeningfast" ])
{
hardeningEnable = [ "libcxxhardeningextensive" ];
};

lchExtensiveStdenvUnsuppDoesntUnsupportLchFast =
checkLibcxxHardeningWithStdEnv "_LIBCPP_HARDENING_MODE_FAST"
(stdenvUnsupport [ "libcxxhardeningextensive" ])
{
hardeningEnable = [
"libcxxhardeningfast"
"libcxxhardeningextensive"
];
};

fortify3EnabledEnvEnablesFortify1 =
checkTestBin
(f1exampleWithStdEnv stdenv {
Expand Down Expand Up @@ -992,6 +1103,38 @@ nameDrvAfterAttrName (
expectFailure = true;
};

lchFastEnabledEnv = checkLibcxxHardeningWithStdEnv "_LIBCPP_HARDENING_MODE_FAST" stdenv {
hardeningDisable = [
"libcxxhardeningfast"
"libcxxhardeningextensive"
];
postConfigure = ''
export NIX_HARDENING_ENABLE="libcxxhardeningfast"
'';
};

lchExtensiveEnabledEnv = checkLibcxxHardeningWithStdEnv "_LIBCPP_HARDENING_MODE_EXTENSIVE" stdenv {
hardeningDisable = [
"libcxxhardeningfast"
"libcxxhardeningextensive"
];
postConfigure = ''
export NIX_HARDENING_ENABLE="libcxxhardeningextensive"
'';
};

lchFastExtensiveEnabledEnvResultsInLchExtensive =
checkLibcxxHardeningWithStdEnv "_LIBCPP_HARDENING_MODE_EXTENSIVE" stdenv
{
hardeningDisable = [
"libcxxhardeningfast"
"libcxxhardeningextensive"
];
postConfigure = ''
export NIX_HARDENING_ENABLE="libcxxhardeningextensive libcxxhardeningfast"
'';
};

# NIX_HARDENING_ENABLE can't enable an unsupported feature
stackProtectorUnsupportedEnabledEnv =
checkTestBin
Expand Down Expand Up @@ -1101,9 +1244,15 @@ nameDrvAfterAttrName (
hardeningDisable = [ "all" ];
}) true;

glibcxxassertionsExplicitDisabled = checkGlibcxxassertionsWithStdEnv false stdenv {
allExplicitDisabledGlibcxxAssertions = checkGlibcxxassertionsWithStdEnv false stdenv {
hardeningDisable = [ "all" ];
};

allExplicitDisabledLibcxxHardening =
checkLibcxxHardeningWithStdEnv "_LIBCPP_HARDENING_MODE_NONE" stdenv
{
hardeningDisable = [ "all" ];
};
}
)
)
1 change: 1 addition & 0 deletions pkgs/top-level/variants.nix
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,7 @@ self: super: {
"nostrictaliasing"
"pacret"
"glibcxxassertions"
"libcxxhardeningfast"
"trivialautovarinit"
]
) super'.stdenv;
Expand Down
Loading