mirror of
https://github.com/NixOS/nixpkgs.git
synced 2024-09-29 15:43:00 +00:00
Merge pull request #253186 from risicle/ris-hardening-tests-fixups
cc-wrapper hardeningFlags tests: fix expected behaviour in corner cases, add tests for `stackclashprotection`
This commit is contained in:
commit
4c89bb901d
@ -3,6 +3,7 @@
|
||||
, runCommand
|
||||
, runCommandWith
|
||||
, runCommandCC
|
||||
, hello
|
||||
, debian-devscripts
|
||||
}:
|
||||
|
||||
@ -18,6 +19,7 @@ let
|
||||
allowSubstitutes = false;
|
||||
} // env;
|
||||
} ''
|
||||
[ -n "$postConfigure" ] && eval "$postConfigure"
|
||||
[ -n "$preBuild" ] && eval "$preBuild"
|
||||
n=$out/bin/test-bin
|
||||
mkdir -p "$(dirname "$n")"
|
||||
@ -29,10 +31,32 @@ let
|
||||
f2exampleWithStdEnv = writeCBinWithStdenv ./fortify2-example.c;
|
||||
f3exampleWithStdEnv = writeCBinWithStdenv ./fortify3-example.c;
|
||||
|
||||
# for when we need a slightly more complicated program
|
||||
helloWithStdEnv = stdenv': env: (hello.override { stdenv = stdenv'; }).overrideAttrs ({
|
||||
preBuild = ''
|
||||
export CFLAGS="$TEST_EXTRA_FLAGS"
|
||||
'';
|
||||
NIX_DEBUG = "1";
|
||||
postFixup = ''
|
||||
cp $out/bin/hello $out/bin/test-bin
|
||||
'';
|
||||
} // env);
|
||||
|
||||
stdenvUnsupport = additionalUnsupported: stdenv.override {
|
||||
cc = stdenv.cc.override {
|
||||
cc = (lib.extendDerivation true {
|
||||
hardeningUnsupportedFlags = (stdenv.cc.cc.hardeningUnsupportedFlags or []) ++ additionalUnsupported;
|
||||
cc = (lib.extendDerivation true rec {
|
||||
# this is ugly - have to cross-reference from
|
||||
# hardeningUnsupportedFlagsByTargetPlatform to hardeningUnsupportedFlags
|
||||
# because the finalAttrs mechanism that hardeningUnsupportedFlagsByTargetPlatform
|
||||
# implementations use to do this won't work with lib.extendDerivation.
|
||||
# but it's simplified by the fact that targetPlatform is already fixed
|
||||
# at this point.
|
||||
hardeningUnsupportedFlagsByTargetPlatform = _: hardeningUnsupportedFlags;
|
||||
hardeningUnsupportedFlags = (
|
||||
if stdenv.cc.cc ? hardeningUnsupportedFlagsByTargetPlatform
|
||||
then stdenv.cc.cc.hardeningUnsupportedFlagsByTargetPlatform stdenv.targetPlatform
|
||||
else (stdenv.cc.cc.hardeningUnsupportedFlags or [])
|
||||
) ++ additionalUnsupported;
|
||||
} stdenv.cc.cc);
|
||||
};
|
||||
allowedRequisites = null;
|
||||
@ -45,24 +69,39 @@ let
|
||||
ignorePie ? true,
|
||||
ignoreRelRO ? true,
|
||||
ignoreStackProtector ? true,
|
||||
ignoreStackClashProtection ? true,
|
||||
expectFailure ? false,
|
||||
}: let
|
||||
stackClashStr = "Stack clash protection: yes";
|
||||
expectFailureClause = lib.optionalString expectFailure
|
||||
" && echo 'ERROR: Expected hardening-check to fail, but it passed!' >&2 && exit 1";
|
||||
" && echo 'ERROR: Expected hardening-check to fail, but it passed!' >&2 && false";
|
||||
in runCommandCC "check-test-bin" {
|
||||
nativeBuildInputs = [ debian-devscripts ];
|
||||
buildInputs = [ testBin ];
|
||||
meta.platforms = lib.platforms.linux; # ELF-reliant
|
||||
} ''
|
||||
hardening-check --nocfprotection \
|
||||
${lib.optionalString ignoreBindNow "--nobindnow"} \
|
||||
${lib.optionalString ignoreFortify "--nofortify"} \
|
||||
${lib.optionalString ignorePie "--nopie"} \
|
||||
${lib.optionalString ignoreRelRO "--norelro"} \
|
||||
${lib.optionalString ignoreStackProtector "--nostackprotector"} \
|
||||
$(PATH=$HOST_PATH type -P test-bin) ${expectFailureClause}
|
||||
touch $out
|
||||
'';
|
||||
meta.platforms = if ignoreStackClashProtection
|
||||
then lib.platforms.linux # ELF-reliant
|
||||
else [ "x86_64-linux" ]; # stackclashprotection test looks for x86-specific instructions
|
||||
} (''
|
||||
if ${lib.optionalString (!expectFailure) "!"} {
|
||||
hardening-check --nocfprotection \
|
||||
${lib.optionalString ignoreBindNow "--nobindnow"} \
|
||||
${lib.optionalString ignoreFortify "--nofortify"} \
|
||||
${lib.optionalString ignorePie "--nopie"} \
|
||||
${lib.optionalString ignoreRelRO "--norelro"} \
|
||||
${lib.optionalString ignoreStackProtector "--nostackprotector"} \
|
||||
$(PATH=$HOST_PATH type -P test-bin) | tee $out
|
||||
'' + lib.optionalString (!ignoreStackClashProtection) ''
|
||||
# stack clash protection doesn't actually affect the exit code of
|
||||
# hardening-check (likely authors think false negatives too common)
|
||||
{ grep -F '${stackClashStr}' $out || { echo "Didn't find '${stackClashStr}' in output" && false ;} ;}
|
||||
'' + ''
|
||||
} ; then
|
||||
'' + lib.optionalString expectFailure ''
|
||||
echo 'ERROR: Expected hardening-check to fail, but it passed!' >&2
|
||||
'' + ''
|
||||
exit 2
|
||||
fi
|
||||
'');
|
||||
|
||||
nameDrvAfterAttrName = builtins.mapAttrs (name: drv:
|
||||
drv.overrideAttrs (_: { name = "test-${name}"; })
|
||||
@ -151,6 +190,13 @@ in nameDrvAfterAttrName ({
|
||||
ignoreStackProtector = false;
|
||||
});
|
||||
|
||||
# protection patterns generated by clang not detectable?
|
||||
stackClashProtectionExplicitEnabled = brokenIf stdenv.cc.isClang (checkTestBin (helloWithStdEnv stdenv {
|
||||
hardeningEnable = [ "stackclashprotection" ];
|
||||
}) {
|
||||
ignoreStackClashProtection = false;
|
||||
});
|
||||
|
||||
bindNowExplicitDisabled = checkTestBin (f2exampleWithStdEnv stdenv {
|
||||
hardeningDisable = [ "bindnow" ];
|
||||
}) {
|
||||
@ -211,12 +257,19 @@ in nameDrvAfterAttrName ({
|
||||
expectFailure = true;
|
||||
};
|
||||
|
||||
stackClashProtectionExplicitDisabled = checkTestBin (helloWithStdEnv stdenv {
|
||||
hardeningDisable = [ "stackclashprotection" ];
|
||||
}) {
|
||||
ignoreStackClashProtection = false;
|
||||
expectFailure = true;
|
||||
};
|
||||
|
||||
# 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
|
||||
# stdenv trickery
|
||||
|
||||
fortifyStdenvUnsupp = checkTestBin (f2exampleWithStdEnv (stdenvUnsupport ["fortify"]) {
|
||||
fortifyStdenvUnsupp = checkTestBin (f2exampleWithStdEnv (stdenvUnsupport ["fortify" "fortify3"]) {
|
||||
hardeningEnable = [ "fortify" ];
|
||||
}) {
|
||||
ignoreFortify = false;
|
||||
@ -237,13 +290,14 @@ in nameDrvAfterAttrName ({
|
||||
expectFailure = true;
|
||||
};
|
||||
|
||||
fortify3StdenvUnsuppDoesntUnsuppFortify = brokenIf stdenv.hostPlatform.isMusl (checkTestBin (f2exampleWithStdEnv (stdenvUnsupport ["fortify3"]) {
|
||||
# musl implementation undetectable by this means even if present
|
||||
fortify3StdenvUnsuppDoesntUnsuppFortify1 = brokenIf stdenv.hostPlatform.isMusl (checkTestBin (f1exampleWithStdEnv (stdenvUnsupport ["fortify3"]) {
|
||||
hardeningEnable = [ "fortify" ];
|
||||
}) {
|
||||
ignoreFortify = false;
|
||||
});
|
||||
|
||||
fortify3StdenvUnsuppDoesntUnsuppFortifyExecTest = fortifyExecTest (f2exampleWithStdEnv (stdenvUnsupport ["fortify3"]) {
|
||||
fortify3StdenvUnsuppDoesntUnsuppFortify1ExecTest = fortifyExecTest (f1exampleWithStdEnv (stdenvUnsupport ["fortify3"]) {
|
||||
hardeningEnable = [ "fortify" ];
|
||||
});
|
||||
|
||||
@ -254,12 +308,19 @@ in nameDrvAfterAttrName ({
|
||||
expectFailure = true;
|
||||
};
|
||||
|
||||
stackClashProtectionStdenvUnsupp = checkTestBin (helloWithStdEnv (stdenvUnsupport ["stackclashprotection"]) {
|
||||
hardeningEnable = [ "stackclashprotection" ];
|
||||
}) {
|
||||
ignoreStackClashProtection = false;
|
||||
expectFailure = true;
|
||||
};
|
||||
|
||||
# NIX_HARDENING_ENABLE set in the shell overrides hardeningDisable
|
||||
# and hardeningEnable
|
||||
|
||||
stackProtectorReenabledEnv = checkTestBin (f2exampleWithStdEnv stdenv {
|
||||
hardeningDisable = [ "stackprotector" ];
|
||||
preBuild = ''
|
||||
postConfigure = ''
|
||||
export NIX_HARDENING_ENABLE="stackprotector"
|
||||
'';
|
||||
}) {
|
||||
@ -268,7 +329,7 @@ in nameDrvAfterAttrName ({
|
||||
|
||||
stackProtectorReenabledFromAllEnv = checkTestBin (f2exampleWithStdEnv stdenv {
|
||||
hardeningDisable = [ "all" ];
|
||||
preBuild = ''
|
||||
postConfigure = ''
|
||||
export NIX_HARDENING_ENABLE="stackprotector"
|
||||
'';
|
||||
}) {
|
||||
@ -277,7 +338,7 @@ in nameDrvAfterAttrName ({
|
||||
|
||||
stackProtectorRedisabledEnv = checkTestBin (f2exampleWithStdEnv stdenv {
|
||||
hardeningEnable = [ "stackprotector" ];
|
||||
preBuild = ''
|
||||
postConfigure = ''
|
||||
export NIX_HARDENING_ENABLE=""
|
||||
'';
|
||||
}) {
|
||||
@ -285,25 +346,26 @@ in nameDrvAfterAttrName ({
|
||||
expectFailure = true;
|
||||
};
|
||||
|
||||
fortify3EnabledEnvEnablesFortify = brokenIf stdenv.hostPlatform.isMusl (checkTestBin (f2exampleWithStdEnv stdenv {
|
||||
# musl implementation undetectable by this means even if present
|
||||
fortify3EnabledEnvEnablesFortify1 = brokenIf stdenv.hostPlatform.isMusl (checkTestBin (f1exampleWithStdEnv stdenv {
|
||||
hardeningDisable = [ "fortify" "fortify3" ];
|
||||
preBuild = ''
|
||||
postConfigure = ''
|
||||
export NIX_HARDENING_ENABLE="fortify3"
|
||||
'';
|
||||
}) {
|
||||
ignoreFortify = false;
|
||||
});
|
||||
|
||||
fortify3EnabledEnvEnablesFortifyExecTest = fortifyExecTest (f2exampleWithStdEnv stdenv {
|
||||
fortify3EnabledEnvEnablesFortify1ExecTest = fortifyExecTest (f1exampleWithStdEnv stdenv {
|
||||
hardeningDisable = [ "fortify" "fortify3" ];
|
||||
preBuild = ''
|
||||
postConfigure = ''
|
||||
export NIX_HARDENING_ENABLE="fortify3"
|
||||
'';
|
||||
});
|
||||
|
||||
fortifyEnabledEnvDoesntEnableFortify3 = checkTestBin (f3exampleWithStdEnv stdenv {
|
||||
hardeningDisable = [ "fortify" "fortify3" ];
|
||||
preBuild = ''
|
||||
postConfigure = ''
|
||||
export NIX_HARDENING_ENABLE="fortify"
|
||||
'';
|
||||
}) {
|
||||
@ -312,9 +374,8 @@ in nameDrvAfterAttrName ({
|
||||
};
|
||||
|
||||
# NIX_HARDENING_ENABLE can't enable an unsupported feature
|
||||
|
||||
stackProtectorUnsupportedEnabledEnv = checkTestBin (f2exampleWithStdEnv (stdenvUnsupport ["stackprotector"]) {
|
||||
preBuild = ''
|
||||
postConfigure = ''
|
||||
export NIX_HARDENING_ENABLE="stackprotector"
|
||||
'';
|
||||
}) {
|
||||
@ -322,23 +383,29 @@ in nameDrvAfterAttrName ({
|
||||
expectFailure = true;
|
||||
};
|
||||
|
||||
# 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 (checkTestBin (f1exampleWithStdEnv stdenv {
|
||||
hardeningEnable = [ "fortify" ];
|
||||
preBuild = ''
|
||||
postConfigure = ''
|
||||
export TEST_EXTRA_FLAGS='-D_FORTIFY_SOURCE=0'
|
||||
'';
|
||||
}) {
|
||||
ignoreFortify = false;
|
||||
expectFailure = true;
|
||||
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" ];
|
||||
preBuild = ''
|
||||
postConfigure = ''
|
||||
export TEST_EXTRA_FLAGS='-D_FORTIFY_SOURCE=1'
|
||||
'';
|
||||
}) {
|
||||
@ -347,14 +414,14 @@ in nameDrvAfterAttrName ({
|
||||
|
||||
fortify1ExplicitDisabledCmdlineEnabledExecTest = fortifyExecTest (f1exampleWithStdEnv stdenv {
|
||||
hardeningDisable = [ "fortify" ];
|
||||
preBuild = ''
|
||||
postConfigure = ''
|
||||
export TEST_EXTRA_FLAGS='-D_FORTIFY_SOURCE=1'
|
||||
'';
|
||||
});
|
||||
|
||||
fortify1ExplicitEnabledCmdlineDisabledNoWarn = f1exampleWithStdEnv stdenv {
|
||||
hardeningEnable = [ "fortify" ];
|
||||
preBuild = ''
|
||||
postConfigure = ''
|
||||
export TEST_EXTRA_FLAGS='-D_FORTIFY_SOURCE=0 -Werror'
|
||||
'';
|
||||
};
|
||||
@ -393,4 +460,9 @@ in {
|
||||
ignoreStackProtector = false;
|
||||
expectFailure = true;
|
||||
};
|
||||
|
||||
allExplicitDisabledStackClashProtection = checkTestBin tb {
|
||||
ignoreStackClashProtection = false;
|
||||
expectFailure = true;
|
||||
};
|
||||
}))
|
||||
|
Loading…
Reference in New Issue
Block a user