From c68739f4f0c3d1b3d3278da299865d8be772a0be Mon Sep 17 00:00:00 2001 From: Robert Scott Date: Thu, 11 Jul 2024 23:10:19 +0100 Subject: [PATCH 1/9] bootstrap-tools-musl: match bootstrap-tools hardeningUnsupportedFlags seems we missed adding stackclashprotection --- pkgs/stdenv/linux/bootstrap-tools-musl/default.nix | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/pkgs/stdenv/linux/bootstrap-tools-musl/default.nix b/pkgs/stdenv/linux/bootstrap-tools-musl/default.nix index 6d2490acfa47..4450679983ff 100644 --- a/pkgs/stdenv/linux/bootstrap-tools-musl/default.nix +++ b/pkgs/stdenv/linux/bootstrap-tools-musl/default.nix @@ -15,5 +15,10 @@ derivation ({ langC = true; langCC = true; isGNU = true; - hardeningUnsupportedFlags = [ "fortify3" "zerocallusedregs" "trivialautovarinit" ]; + hardeningUnsupportedFlags = [ + "fortify3" + "stackclashprotection" + "trivialautovarinit" + "zerocallusedregs" + ]; } // extraAttrs) From b207b6ef740dd402cfa96dac681c0523996835ae Mon Sep 17 00:00:00 2001 From: Robert Scott Date: Thu, 11 Jul 2024 23:11:13 +0100 Subject: [PATCH 2/9] cc-wrapper: add support for shadowstack hardening flag --- nixos/doc/manual/release-notes/rl-2411.section.md | 2 ++ pkgs/build-support/cc-wrapper/add-hardening.sh | 6 +++++- pkgs/development/compilers/gcc/default.nix | 6 ++++++ pkgs/development/compilers/llvm/common/clang/default.nix | 5 +++++ pkgs/stdenv/darwin/default.nix | 1 + pkgs/stdenv/generic/make-derivation.nix | 1 + pkgs/stdenv/linux/bootstrap-tools-musl/default.nix | 1 + pkgs/stdenv/linux/bootstrap-tools/default.nix | 1 + pkgs/top-level/stage.nix | 1 + 9 files changed, 23 insertions(+), 1 deletion(-) diff --git a/nixos/doc/manual/release-notes/rl-2411.section.md b/nixos/doc/manual/release-notes/rl-2411.section.md index c27d948be4c2..7ca984a8eef4 100644 --- a/nixos/doc/manual/release-notes/rl-2411.section.md +++ b/nixos/doc/manual/release-notes/rl-2411.section.md @@ -242,6 +242,8 @@ - Nemo is now built with gtk-layer-shell support, note that for now it will be expected to see nemo-desktop listed as a regular entry in Cinnamon Wayland session's window list applet. +- The `shadowstack` hardening flag has been added, though disabled by default. + - Support for *runner registration tokens* has been [deprecated](https://gitlab.com/gitlab-org/gitlab/-/issues/380872) in `gitlab-runner` 15.6 and is expected to be removed in `gitlab-runner` 18.0. Configuration of existing runners should be changed to using *runner authentication tokens* by configuring diff --git a/pkgs/build-support/cc-wrapper/add-hardening.sh b/pkgs/build-support/cc-wrapper/add-hardening.sh index 0dca3b3347e5..fc457ed0134a 100644 --- a/pkgs/build-support/cc-wrapper/add-hardening.sh +++ b/pkgs/build-support/cc-wrapper/add-hardening.sh @@ -32,7 +32,7 @@ if [[ -n "${hardeningEnableMap[fortify3]-}" ]]; then fi if (( "${NIX_DEBUG:-0}" >= 1 )); then - declare -a allHardeningFlags=(fortify fortify3 stackprotector stackclashprotection pie pic strictoverflow format trivialautovarinit zerocallusedregs) + declare -a allHardeningFlags=(fortify fortify3 shadowstack stackprotector stackclashprotection pie pic strictoverflow format trivialautovarinit zerocallusedregs) declare -A hardeningDisableMap=() # Determine which flags were effectively disabled so we can report below. @@ -75,6 +75,10 @@ for flag in "${!hardeningEnableMap[@]}"; do ;; esac ;; + shadowstack) + if (( "${NIX_DEBUG:-0}" >= 1 )); then echo HARDENING: enabling shadowstack >&2; fi + hardeningCFlagsBefore+=('-fcf-protection=return') + ;; stackprotector) if (( "${NIX_DEBUG:-0}" >= 1 )); then echo HARDENING: enabling stackprotector >&2; fi hardeningCFlagsBefore+=('-fstack-protector-strong' '--param' 'ssp-buffer-size=4') diff --git a/pkgs/development/compilers/gcc/default.nix b/pkgs/development/compilers/gcc/default.nix index 5eb92fd701da..e5dcb1e0b331 100644 --- a/pkgs/development/compilers/gcc/default.nix +++ b/pkgs/development/compilers/gcc/default.nix @@ -430,6 +430,12 @@ pipe ((callFile ./common/builder.nix {}) ({ ) "stackclashprotection" ++ optional (!atLeast11) "zerocallusedregs" ++ optionals (!atLeast12) [ "fortify3" "trivialautovarinit" ] + ++ optional (!( + atLeast8 + && targetPlatform.isLinux + && targetPlatform.isx86_64 + && targetPlatform.libc == "glibc" + )) "shadowstack" ++ optionals (langFortran) [ "fortify" "format" ]; }; diff --git a/pkgs/development/compilers/llvm/common/clang/default.nix b/pkgs/development/compilers/llvm/common/clang/default.nix index 922eb8657cee..862c5cbb1178 100644 --- a/pkgs/development/compilers/llvm/common/clang/default.nix +++ b/pkgs/development/compilers/llvm/common/clang/default.nix @@ -138,6 +138,11 @@ let isClang = true; hardeningUnsupportedFlagsByTargetPlatform = targetPlatform: [ "fortify3" ] + ++ lib.optional ( + (lib.versionOlder release_version "7") + || !targetPlatform.isLinux + || !targetPlatform.isx86_64 + ) "shadowstack" ++ lib.optional ( (lib.versionOlder release_version "11") || (targetPlatform.isAarch64 && (lib.versionOlder release_version "18.1")) diff --git a/pkgs/stdenv/darwin/default.nix b/pkgs/stdenv/darwin/default.nix index 5e5f2be12ba6..dcab951fdfcc 100644 --- a/pkgs/stdenv/darwin/default.nix +++ b/pkgs/stdenv/darwin/default.nix @@ -416,6 +416,7 @@ in isFromBootstrapFiles = true; hardeningUnsupportedFlags = [ "fortify3" + "shadowstack" "stackclashprotection" "zerocallusedregs" ]; diff --git a/pkgs/stdenv/generic/make-derivation.nix b/pkgs/stdenv/generic/make-derivation.nix index 952b8b66c10c..bda0060900dd 100644 --- a/pkgs/stdenv/generic/make-derivation.nix +++ b/pkgs/stdenv/generic/make-derivation.nix @@ -115,6 +115,7 @@ let "format" "fortify" "fortify3" + "shadowstack" "pic" "pie" "relro" diff --git a/pkgs/stdenv/linux/bootstrap-tools-musl/default.nix b/pkgs/stdenv/linux/bootstrap-tools-musl/default.nix index 4450679983ff..3b69f7c53194 100644 --- a/pkgs/stdenv/linux/bootstrap-tools-musl/default.nix +++ b/pkgs/stdenv/linux/bootstrap-tools-musl/default.nix @@ -17,6 +17,7 @@ derivation ({ isGNU = true; hardeningUnsupportedFlags = [ "fortify3" + "shadowstack" "stackclashprotection" "trivialautovarinit" "zerocallusedregs" diff --git a/pkgs/stdenv/linux/bootstrap-tools/default.nix b/pkgs/stdenv/linux/bootstrap-tools/default.nix index 4450679983ff..3b69f7c53194 100644 --- a/pkgs/stdenv/linux/bootstrap-tools/default.nix +++ b/pkgs/stdenv/linux/bootstrap-tools/default.nix @@ -17,6 +17,7 @@ derivation ({ isGNU = true; hardeningUnsupportedFlags = [ "fortify3" + "shadowstack" "stackclashprotection" "trivialautovarinit" "zerocallusedregs" diff --git a/pkgs/top-level/stage.nix b/pkgs/top-level/stage.nix index b0c7ec03827b..648b81f95a5c 100644 --- a/pkgs/top-level/stage.nix +++ b/pkgs/top-level/stage.nix @@ -292,6 +292,7 @@ let pkgsExtraHardening = super'; stdenv = super'.withDefaultHardeningFlags ( super'.stdenv.cc.defaultHardeningFlags ++ [ + "shadowstack" "stackclashprotection" "trivialautovarinit" ] From 3ebc7bbf61dfd9b0fa2bc65d6484ea9a44adb3e4 Mon Sep 17 00:00:00 2001 From: Robert Scott Date: Thu, 11 Jul 2024 22:52:23 +0100 Subject: [PATCH 3/9] glibc: add option enableCETRuntimeDefault to runtime-enable CET by default this appears to have been added to glibc because of the number of packages in some distributions that were built with CET enabled before a CET enabled machine was available to test for breakage with. we don't have that problem to such an extent and users of hardened systems will likely want to enable this by default. --- .../2.39-revert-cet-default-disable.patch | 49 +++++++++++++++++++ pkgs/development/libraries/glibc/common.nix | 5 +- pkgs/development/libraries/glibc/default.nix | 3 +- 3 files changed, 55 insertions(+), 2 deletions(-) create mode 100644 pkgs/development/libraries/glibc/2.39-revert-cet-default-disable.patch diff --git a/pkgs/development/libraries/glibc/2.39-revert-cet-default-disable.patch b/pkgs/development/libraries/glibc/2.39-revert-cet-default-disable.patch new file mode 100644 index 000000000000..8590581daf0b --- /dev/null +++ b/pkgs/development/libraries/glibc/2.39-revert-cet-default-disable.patch @@ -0,0 +1,49 @@ +Revert 55d63e731253de82e96ed4ddca2e294076cd0bc5 + +--- b/sysdeps/x86/cpu-features.c ++++ a/sysdeps/x86/cpu-features.c +@@ -110,7 +110,7 @@ + if (!CPU_FEATURES_CPU_P (cpu_features, RTM_ALWAYS_ABORT)) + CPU_FEATURE_SET_ACTIVE (cpu_features, RTM); + ++#if CET_ENABLED +-#if CET_ENABLED && 0 + CPU_FEATURE_SET_ACTIVE (cpu_features, IBT); + CPU_FEATURE_SET_ACTIVE (cpu_features, SHSTK); + #endif +reverted: +--- b/sysdeps/x86/cpu-tunables.c ++++ a/sysdeps/x86/cpu-tunables.c +@@ -35,17 +35,6 @@ + break; \ + } + +-#define CHECK_GLIBC_IFUNC_CPU_BOTH(f, cpu_features, name, len) \ +- _Static_assert (sizeof (#name) - 1 == len, #name " != " #len); \ +- if (tunable_str_comma_strcmp_cte (&f, #name)) \ +- { \ +- if (f.disable) \ +- CPU_FEATURE_UNSET (cpu_features, name) \ +- else \ +- CPU_FEATURE_SET_ACTIVE (cpu_features, name) \ +- break; \ +- } +- + /* Disable a preferred feature NAME. We don't enable a preferred feature + which isn't available. */ + #define CHECK_GLIBC_IFUNC_PREFERRED_OFF(f, cpu_features, name, len) \ +@@ -142,13 +131,11 @@ + } + break; + case 5: +- { +- CHECK_GLIBC_IFUNC_CPU_BOTH (n, cpu_features, SHSTK, 5); +- } + if (n.disable) + { + CHECK_GLIBC_IFUNC_CPU_OFF (n, cpu_features, LZCNT, 5); + CHECK_GLIBC_IFUNC_CPU_OFF (n, cpu_features, MOVBE, 5); ++ CHECK_GLIBC_IFUNC_CPU_OFF (n, cpu_features, SHSTK, 5); + CHECK_GLIBC_IFUNC_CPU_OFF (n, cpu_features, SSSE3, 5); + CHECK_GLIBC_IFUNC_CPU_OFF (n, cpu_features, XSAVE, 5); + } diff --git a/pkgs/development/libraries/glibc/common.nix b/pkgs/development/libraries/glibc/common.nix index 25a83b1dc6d2..382a1eea076d 100644 --- a/pkgs/development/libraries/glibc/common.nix +++ b/pkgs/development/libraries/glibc/common.nix @@ -37,6 +37,7 @@ , profilingLibraries ? false , withGd ? false , enableCET ? false +, enableCETRuntimeDefault ? false , extraBuildInputs ? [] , extraNativeBuildInputs ? [] , ... @@ -50,6 +51,7 @@ in assert withLinuxHeaders -> linuxHeaders != null; assert withGd -> gd != null && libpng != null; +assert enableCET == false -> !enableCETRuntimeDefault; stdenv.mkDerivation ({ version = version + patchSuffix; @@ -114,7 +116,8 @@ stdenv.mkDerivation ({ lib.optional (isAarch64 && isLinux) ./0001-aarch64-math-vector.h-add-NVCC-include-guard.patch ) ++ lib.optional stdenv.hostPlatform.isMusl ./fix-rpc-types-musl-conflicts.patch - ++ lib.optional stdenv.buildPlatform.isDarwin ./darwin-cross-build.patch; + ++ lib.optional stdenv.buildPlatform.isDarwin ./darwin-cross-build.patch + ++ lib.optional enableCETRuntimeDefault ./2.39-revert-cet-default-disable.patch; postPatch = '' diff --git a/pkgs/development/libraries/glibc/default.nix b/pkgs/development/libraries/glibc/default.nix index 96a08178637d..490f29e99cfb 100644 --- a/pkgs/development/libraries/glibc/default.nix +++ b/pkgs/development/libraries/glibc/default.nix @@ -3,6 +3,7 @@ , profilingLibraries ? false , withGd ? false , enableCET ? if stdenv.hostPlatform.isx86_64 then "permissive" else false +, enableCETRuntimeDefault ? false , pkgsBuildBuild , libgcc }: @@ -16,7 +17,7 @@ let in (callPackage ./common.nix { inherit stdenv; } { - inherit withLinuxHeaders withGd profilingLibraries enableCET; + inherit withLinuxHeaders withGd profilingLibraries enableCET enableCETRuntimeDefault; pname = "glibc" + lib.optionalString withGd "-gd" + lib.optionalString (stdenv.cc.isGNU && libgcc==null) "-nolibgcc"; }).overrideAttrs(previousAttrs: { From 41cae89e6b8a7f1f6fffd0e965c8db43e3e47db4 Mon Sep 17 00:00:00 2001 From: Robert Scott Date: Wed, 19 Jun 2024 20:01:41 +0100 Subject: [PATCH 4/9] glibc: enableCETRuntimeDefault for pkgsExtraHardening --- pkgs/top-level/stage.nix | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/pkgs/top-level/stage.nix b/pkgs/top-level/stage.nix index 648b81f95a5c..fbd7ea458ba9 100644 --- a/pkgs/top-level/stage.nix +++ b/pkgs/top-level/stage.nix @@ -297,6 +297,10 @@ let "trivialautovarinit" ] ) super'.stdenv; + glibc = super'.glibc.override rec { + enableCET = if self'.stdenv.hostPlatform.isx86_64 then "permissive" else false; + enableCETRuntimeDefault = enableCET != false; + }; }) ] ++ overlays; }; From 5ce990eb576e6539fee662b510adf93bd1cc22ee Mon Sep 17 00:00:00 2001 From: Robert Scott Date: Sat, 13 Jul 2024 13:44:12 +0100 Subject: [PATCH 5/9] doc/stdenv: add section on shadowstack hardening flag --- doc/stdenv/stdenv.chapter.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/doc/stdenv/stdenv.chapter.md b/doc/stdenv/stdenv.chapter.md index a2c69ba6bd14..f219b9eb4185 100644 --- a/doc/stdenv/stdenv.chapter.md +++ b/doc/stdenv/stdenv.chapter.md @@ -1538,6 +1538,16 @@ 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`. +#### `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. + +For the Shadow Stack to be enabled at runtime, all code linked into a process must be built with Shadow Stack enabled, so this is probably only useful to enable on a wide scale, so that all of a packages dependencies also have the feature enabled. + +This is currently only supported on some newer Intel and AMD processors as part of the Intel CET set of features. However, the generated code should continue to work on older processors which will simply omit any of this checking. + +This breaks some code that does advanced stack management or exception handling. If enabling this hardening flag it is important to test the result on a system that has known working and enabled CET support, so that any such breakage can be discovered. + #### `trivialautovarinit` {#trivialautovarinit} Adds the `-ftrivial-auto-var-init=pattern` compiler option. This causes "trivially-initializable" uninitialized stack variables to be forcibly initialized with a nonzero value that is likely to cause a crash (and therefore be noticed). Uninitialized variables generally take on their values based on fragments of previous program state, and attackers can carefully manipulate that state to craft malicious initial values for these variables. From a30f794865e77b6fc3a9a6474970173b18356b45 Mon Sep 17 00:00:00 2001 From: Robert Scott Date: Sun, 14 Jul 2024 12:54:44 +0100 Subject: [PATCH 6/9] pcre: expose enableJit argument, disable shadowstack when enabled --- pkgs/development/libraries/pcre/default.nix | 9 ++++++--- pkgs/top-level/stage.nix | 5 +++++ 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/pkgs/development/libraries/pcre/default.nix b/pkgs/development/libraries/pcre/default.nix index 52a4ba32315e..4ba68535c08d 100644 --- a/pkgs/development/libraries/pcre/default.nix +++ b/pkgs/development/libraries/pcre/default.nix @@ -1,5 +1,7 @@ { lib, stdenv, fetchurl, fetchpatch , pcre, windows ? null + # Disable jit on Apple Silicon, https://github.com/zherczeg/sljit/issues/51 +, enableJit ? !(stdenv.hostPlatform.isDarwin && stdenv.hostPlatform.isAarch64) , variant ? null }: @@ -18,11 +20,12 @@ stdenv.mkDerivation rec { outputs = [ "bin" "dev" "out" "doc" "man" ]; - # Disable jit on Apple Silicon, https://github.com/zherczeg/sljit/issues/51 - configureFlags = lib.optional (!(stdenv.hostPlatform.isDarwin && stdenv.hostPlatform.isAarch64)) "--enable-jit=auto" ++ [ + hardeningDisable = lib.optional enableJit "shadowstack"; + + configureFlags = [ "--enable-unicode-properties" "--disable-cpp" - ] + ] ++ lib.optional enableJit "--enable-jit=auto" ++ lib.optional (variant != null) "--enable-${variant}"; patches = [ diff --git a/pkgs/top-level/stage.nix b/pkgs/top-level/stage.nix index fbd7ea458ba9..72b055c0ec82 100644 --- a/pkgs/top-level/stage.nix +++ b/pkgs/top-level/stage.nix @@ -301,6 +301,11 @@ let enableCET = if self'.stdenv.hostPlatform.isx86_64 then "permissive" else false; enableCETRuntimeDefault = enableCET != false; }; + } // lib.optionalAttrs (with super'.stdenv.hostPlatform; isx86_64 && isLinux) { + # causes shadowstack disablement + pcre = super'.pcre.override { enableJit = false; }; + pcre-cpp = super'.pcre-cpp.override { enableJit = false; }; + pcre16 = super'.pcre16.override { enableJit = false; }; }) ] ++ overlays; }; From 7a4736e1ef32baa85208cd08bf2a146f15659142 Mon Sep 17 00:00:00 2001 From: Robert Scott Date: Sun, 14 Jul 2024 21:26:50 +0100 Subject: [PATCH 7/9] llvm: disable shadowstack hardening flag --- pkgs/development/compilers/llvm/common/llvm/default.nix | 1 + 1 file changed, 1 insertion(+) diff --git a/pkgs/development/compilers/llvm/common/llvm/default.nix b/pkgs/development/compilers/llvm/common/llvm/default.nix index a59c704ebbcb..2043c9b7e9e2 100644 --- a/pkgs/development/compilers/llvm/common/llvm/default.nix +++ b/pkgs/development/compilers/llvm/common/llvm/default.nix @@ -104,6 +104,7 @@ stdenv.mkDerivation (rec { hardeningDisable = [ "trivialautovarinit" + "shadowstack" ]; nativeBuildInputs = [ cmake ] From b84da125d0021cb350b486b254a1649093a17e71 Mon Sep 17 00:00:00 2001 From: Robert Scott Date: Wed, 17 Jul 2024 23:25:29 +0100 Subject: [PATCH 8/9] lix: disable shadowstack hardening flag --- pkgs/tools/package-management/lix/common.nix | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/pkgs/tools/package-management/lix/common.nix b/pkgs/tools/package-management/lix/common.nix index b01b381d1491..203ff91ba449 100644 --- a/pkgs/tools/package-management/lix/common.nix +++ b/pkgs/tools/package-management/lix/common.nix @@ -245,8 +245,11 @@ stdenv.mkDerivation { meson test --no-rebuild "''${flagsArray[@]}" runHook postInstallCheck ''; - # strictoverflow is disabled because we trap on signed overflow instead - hardeningDisable = [ "strictoverflow" ] ++ lib.optional stdenv.hostPlatform.isStatic "pie"; + hardeningDisable = [ + "shadowstack" + # strictoverflow is disabled because we trap on signed overflow instead + "strictoverflow" + ] ++ lib.optional stdenv.hostPlatform.isStatic "pie"; # hardeningEnable = lib.optionals (!stdenv.isDarwin) [ "pie" ]; # hardeningDisable = lib.optional stdenv.hostPlatform.isMusl "fortify"; separateDebugInfo = stdenv.isLinux && !enableStatic; From 0dacfda0af4dfcad051341e6e2dd47b3bbd4407b Mon Sep 17 00:00:00 2001 From: Robert Scott Date: Sat, 20 Jul 2024 11:45:48 +0100 Subject: [PATCH 9/9] nix: disable shadowstack hardening flag --- pkgs/tools/package-management/nix/common.nix | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/pkgs/tools/package-management/nix/common.nix b/pkgs/tools/package-management/nix/common.nix index e98371a1e757..50874fef5c6c 100644 --- a/pkgs/tools/package-management/nix/common.nix +++ b/pkgs/tools/package-management/nix/common.nix @@ -101,7 +101,9 @@ self = stdenv.mkDerivation { hardeningEnable = lib.optionals (!stdenv.isDarwin) [ "pie" ]; - hardeningDisable = lib.optional stdenv.hostPlatform.isMusl "fortify"; + hardeningDisable = [ + "shadowstack" + ] ++ lib.optional stdenv.hostPlatform.isMusl "fortify"; nativeBuildInputs = [ pkg-config