nixpkgs mirror (for testing)
github.com/NixOS/nixpkgs
nix
1{
2 lib,
3 stdenv,
4 runCommand,
5 runCommandWith,
6 runCommandCC,
7 writeText,
8 bintools,
9 hello,
10 debian-devscripts,
11}:
12
13let
14 # writeCBin from trivial-builders won't let us choose
15 # our own stdenv
16 writeCBinWithStdenv =
17 codePath: stdenv': env:
18 runCommandWith
19 {
20 name = "test-bin";
21 stdenv = stdenv';
22 derivationArgs = {
23 inherit codePath;
24 preferLocalBuild = true;
25 allowSubstitutes = false;
26 }
27 // env;
28 }
29 ''
30 [ -n "$postConfigure" ] && eval "$postConfigure"
31 [ -n "$preBuild" ] && eval "$preBuild"
32 n=$out/bin/test-bin
33 mkdir -p "$(dirname "$n")"
34 cp "$codePath" .
35 NIX_DEBUG=1 $CC -x ''${TEST_SOURCE_LANG:-c} "$(basename $codePath)" -O1 $TEST_EXTRA_FLAGS -o "$n"
36 '';
37
38 f1exampleWithStdEnv = writeCBinWithStdenv ./fortify1-example.c;
39 f2exampleWithStdEnv = writeCBinWithStdenv ./fortify2-example.c;
40 f3exampleWithStdEnv = writeCBinWithStdenv ./fortify3-example.c;
41
42 flexArrF2ExampleWithStdEnv = writeCBinWithStdenv ./flex-arrays-fortify-example.c;
43
44 # we don't really have a reliable property for testing for
45 # libstdc++ we'll just have to check for the absence of libcxx
46 checkGlibcxxassertionsWithStdEnv =
47 expectDefined: stdenv': derivationArgs:
48 brokenIf (stdenv.cc.libcxx != null) (
49 writeCBinWithStdenv
50 (writeText "main.cpp" ''
51 #if${if expectDefined then "n" else ""}def _GLIBCXX_ASSERTIONS
52 #error "Expected _GLIBCXX_ASSERTIONS to be ${if expectDefined then "" else "un"}defined"
53 #endif
54 int main() {}
55 '')
56 stdenv'
57 (
58 derivationArgs
59 // {
60 env = (derivationArgs.env or { }) // {
61 TEST_SOURCE_LANG = derivationArgs.env.TEST_SOURCE_LANG or "c++";
62 };
63 }
64 )
65 );
66
67 checkLibcxxHardeningWithStdEnv =
68 expectValue: stdenv': env:
69 brokenIf (stdenv.cc.libcxx == null) (
70 writeCBinWithStdenv
71 (writeText "main.cpp" (
72 ''
73 #include <limits>
74 #ifndef _LIBCPP_HARDENING_MODE
75 #error "Expected _LIBCPP_HARDENING_MODE to be defined"
76 #endif
77 #ifndef ${expectValue}
78 #error "Expected ${expectValue} to be defined"
79 #endif
80
81 #if _LIBCPP_HARDENING_MODE != ${expectValue}
82 #error "Expected _LIBCPP_HARDENING_MODE to equal ${expectValue}"
83 #endif
84 ''
85 + ''
86 int main() {}
87 ''
88 ))
89 stdenv'
90 (
91 env
92 // {
93 env = (env.env or { }) // {
94 TEST_SOURCE_LANG = env.env.TEST_SOURCE_LANG or "c++";
95 };
96 }
97 )
98 );
99
100 # for when we need a slightly more complicated program
101 helloWithStdEnv =
102 stdenv': env:
103 (hello.override { stdenv = stdenv'; }).overrideAttrs (
104 {
105 preBuild = ''
106 export CFLAGS="$TEST_EXTRA_FLAGS"
107 '';
108 NIX_DEBUG = "1";
109 postFixup = ''
110 cp $out/bin/hello $out/bin/test-bin
111 '';
112 }
113 // env
114 );
115
116 stdenvUnsupport =
117 additionalUnsupported:
118 stdenv.override {
119 cc = stdenv.cc.override {
120 cc = (
121 lib.extendDerivation true rec {
122 # this is ugly - have to cross-reference from
123 # hardeningUnsupportedFlagsByTargetPlatform to hardeningUnsupportedFlags
124 # because the finalAttrs mechanism that hardeningUnsupportedFlagsByTargetPlatform
125 # implementations use to do this won't work with lib.extendDerivation.
126 # but it's simplified by the fact that targetPlatform is already fixed
127 # at this point.
128 hardeningUnsupportedFlagsByTargetPlatform = _: hardeningUnsupportedFlags;
129 hardeningUnsupportedFlags =
130 (
131 if stdenv.cc.cc ? hardeningUnsupportedFlagsByTargetPlatform then
132 stdenv.cc.cc.hardeningUnsupportedFlagsByTargetPlatform stdenv.targetPlatform
133 else
134 (stdenv.cc.cc.hardeningUnsupportedFlags or [ ])
135 )
136 ++ additionalUnsupported;
137 } stdenv.cc.cc
138 );
139 };
140 allowedRequisites = null;
141 };
142
143 checkTestBin =
144 testBin:
145 {
146 # can only test flags that are detectable by hardening-check
147 ignoreBindNow ? true,
148 ignoreFortify ? true,
149 ignorePie ? true,
150 ignoreRelRO ? true,
151 ignoreStackProtector ? true,
152 ignoreStackClashProtection ? true,
153 expectFailure ? false,
154 }:
155 let
156 stackClashStr = "Stack clash protection: yes";
157 expectFailureClause = lib.optionalString expectFailure " && echo 'ERROR: Expected hardening-check to fail, but it passed!' >&2 && false";
158 in
159 runCommandCC "check-test-bin"
160 {
161 nativeBuildInputs = [ debian-devscripts ];
162 buildInputs = [ testBin ];
163 meta = {
164 platforms =
165 if ignoreStackClashProtection then
166 lib.platforms.linux # ELF-reliant
167 else
168 [ "x86_64-linux" ]; # stackclashprotection test looks for x86-specific instructions
169 # musl implementation of fortify undetectable by this means even if present,
170 # static similarly
171 broken = (stdenv.hostPlatform.isMusl || stdenv.hostPlatform.isStatic) && !ignoreFortify;
172 };
173 }
174 (
175 ''
176 if ${lib.optionalString (!expectFailure) "!"} {
177 hardening-check --nocfprotection --nobranchprotection \
178 ${lib.optionalString ignoreBindNow "--nobindnow"} \
179 ${lib.optionalString ignoreFortify "--nofortify"} \
180 ${lib.optionalString ignorePie "--nopie"} \
181 ${lib.optionalString ignoreRelRO "--norelro"} \
182 ${lib.optionalString ignoreStackProtector "--nostackprotector"} \
183 $(PATH=$HOST_PATH type -P test-bin) | tee $out
184 ''
185 + lib.optionalString (!ignoreStackClashProtection) ''
186 # stack clash protection doesn't actually affect the exit code of
187 # hardening-check (likely authors think false negatives too common)
188 { grep -F '${stackClashStr}' $out || { echo "Didn't find '${stackClashStr}' in output" && false ;} ;}
189 ''
190 + ''
191 } ; then
192 ''
193 + lib.optionalString expectFailure ''
194 echo 'ERROR: Expected hardening-check to fail, but it passed!' >&2
195 ''
196 + ''
197 exit 2
198 fi
199 ''
200 );
201
202 nameDrvAfterAttrName = builtins.mapAttrs (
203 name: drv:
204 drv.overrideAttrs (_: {
205 name = "test-${name}";
206 })
207 );
208
209 fortifyExecTest = fortifyExecTestFull true "012345 7" "0123456 7";
210
211 # returning a specific exit code when aborting due to a fortify
212 # check isn't mandated. so it's better to just ensure that a
213 # nonzero exit code is returned when we go a single byte beyond
214 # the buffer, with the example programs being designed to be
215 # unlikely to genuinely segfault for such a small overflow.
216 fortifyExecTestFull =
217 expectProtection: saturatedArgs: oneTooFarArgs: testBin:
218 runCommand "exec-test"
219 {
220 buildInputs = [
221 testBin
222 ];
223 meta.broken = !(stdenv.buildPlatform.canExecute stdenv.hostPlatform);
224 }
225 ''
226 (
227 export PATH=$HOST_PATH
228 echo "Saturated buffer:" # check program isn't completly broken
229 test-bin ${saturatedArgs}
230 echo "One byte too far:" # overflow byte being the null terminator?
231 (
232 ${if expectProtection then "!" else ""} test-bin ${oneTooFarArgs}
233 ) || (
234 echo 'Expected ${if expectProtection then "failure" else "success"}, but ${
235 if expectProtection then "succeeded" else "failed"
236 }!' && exit 1
237 )
238 )
239 echo "Expected behaviour observed"
240 touch $out
241 '';
242
243 brokenIf =
244 cond: drv:
245 if cond then
246 drv.overrideAttrs (old: {
247 meta = old.meta or { } // {
248 broken = true;
249 };
250 })
251 else
252 drv;
253 overridePlatforms =
254 platforms: drv:
255 drv.overrideAttrs (old: {
256 meta = old.meta or { } // {
257 inherit platforms;
258 };
259 });
260
261 instructionPresenceTest =
262 label: mnemonicPattern: testBin: expectFailure:
263 runCommand "${label}-instr-test"
264 {
265 nativeBuildInputs = [
266 bintools
267 ];
268 buildInputs = [
269 testBin
270 ];
271 }
272 ''
273 touch $out
274 if $OBJDUMP -d \
275 --no-addresses \
276 --no-show-raw-insn \
277 "$(PATH=$HOST_PATH type -P test-bin)" \
278 | grep -E '${mnemonicPattern}' > /dev/null ; then
279 echo "Found ${label} instructions" >&2
280 ${lib.optionalString expectFailure "exit 1"}
281 else
282 echo "Did not find ${label} instructions" >&2
283 ${lib.optionalString (!expectFailure) "exit 1"}
284 fi
285 '';
286
287 pacRetTest =
288 testBin: expectFailure:
289 overridePlatforms [ "aarch64-linux" ] (
290 instructionPresenceTest "pacret" "\\bpaciasp\\b" testBin expectFailure
291 );
292
293 elfNoteTest =
294 label: pattern: testBin: expectFailure:
295 runCommand "${label}-elf-note-test"
296 {
297 nativeBuildInputs = [
298 bintools
299 ];
300 buildInputs = [
301 testBin
302 ];
303 }
304 ''
305 touch $out
306 if $READELF -n "$(PATH=$HOST_PATH type -P test-bin)" \
307 | grep -E '${pattern}' > /dev/null ; then
308 echo "Found ${label} note" >&2
309 ${lib.optionalString expectFailure "exit 1"}
310 else
311 echo "Did not find ${label} note" >&2
312 ${lib.optionalString (!expectFailure) "exit 1"}
313 fi
314 '';
315
316 shadowStackTest =
317 testBin: expectFailure:
318 brokenIf stdenv.hostPlatform.isMusl (
319 overridePlatforms [ "x86_64-linux" ] (elfNoteTest "shadowstack" "\\bSHSTK\\b" testBin expectFailure)
320 );
321
322in
323nameDrvAfterAttrName (
324 {
325 bindNowExplicitEnabled = brokenIf stdenv.hostPlatform.isStatic (
326 checkTestBin
327 (f2exampleWithStdEnv stdenv {
328 hardeningEnable = [ "bindnow" ];
329 })
330 {
331 ignoreBindNow = false;
332 }
333 );
334
335 fortifyExplicitEnabled = (
336 checkTestBin
337 (f2exampleWithStdEnv stdenv {
338 hardeningEnable = [ "fortify" ];
339 })
340 {
341 ignoreFortify = false;
342 }
343 );
344
345 fortify1ExplicitEnabledExecTest = fortifyExecTest (
346 f1exampleWithStdEnv stdenv {
347 hardeningEnable = [ "fortify" ];
348 }
349 );
350
351 # musl implementation is effectively FORTIFY_SOURCE=1-only,
352 fortifyExplicitEnabledExecTest = brokenIf stdenv.hostPlatform.isMusl (
353 fortifyExecTest (
354 f2exampleWithStdEnv stdenv {
355 hardeningEnable = [ "fortify" ];
356 }
357 )
358 );
359
360 fortify3ExplicitEnabled = brokenIf (!stdenv.cc.isGNU || lib.versionOlder stdenv.cc.version "12") (
361 checkTestBin
362 (f3exampleWithStdEnv stdenv {
363 hardeningEnable = [ "fortify3" ];
364 })
365 {
366 ignoreFortify = false;
367 }
368 );
369
370 # musl implementation is effectively FORTIFY_SOURCE=1-only
371 fortify3ExplicitEnabledExecTest =
372 brokenIf (stdenv.hostPlatform.isMusl || !stdenv.cc.isGNU || lib.versionOlder stdenv.cc.version "12")
373 (
374 fortifyExecTest (
375 f3exampleWithStdEnv stdenv {
376 hardeningEnable = [ "fortify3" ];
377 }
378 )
379 );
380
381 sfa1explicitEnabled =
382 checkTestBin
383 (flexArrF2ExampleWithStdEnv stdenv {
384 hardeningEnable = [
385 "fortify"
386 "strictflexarrays1"
387 ];
388 env = {
389 TEST_EXTRA_FLAGS = "-DBUFFER_DEF_SIZE=7";
390 };
391 })
392 {
393 ignoreFortify = false;
394 };
395
396 # musl implementation is effectively FORTIFY_SOURCE=1-only
397 sfa1explicitEnabledExecTest = brokenIf stdenv.hostPlatform.isMusl (
398 fortifyExecTestFull true "012345" "0123456" (
399 flexArrF2ExampleWithStdEnv stdenv {
400 hardeningEnable = [
401 "fortify"
402 "strictflexarrays1"
403 ];
404 env = {
405 TEST_EXTRA_FLAGS = "-DBUFFER_DEF_SIZE=7";
406 };
407 }
408 )
409 );
410
411 sfa1explicitEnabledDoesntProtectDefLen1 =
412 checkTestBin
413 (flexArrF2ExampleWithStdEnv stdenv {
414 hardeningEnable = [
415 "fortify"
416 "strictflexarrays1"
417 ];
418 env = {
419 TEST_EXTRA_FLAGS = "-DBUFFER_DEF_SIZE=1";
420 };
421 })
422 {
423 ignoreFortify = false;
424 expectFailure = true;
425 };
426
427 # musl implementation is effectively FORTIFY_SOURCE=1-only
428 sfa1explicitEnabledDoesntProtectDefLen1ExecTest = brokenIf stdenv.hostPlatform.isMusl (
429 fortifyExecTestFull false "''" "0" (
430 flexArrF2ExampleWithStdEnv stdenv {
431 hardeningEnable = [
432 "fortify"
433 "strictflexarrays1"
434 ];
435 env = {
436 TEST_EXTRA_FLAGS = "-DBUFFER_DEF_SIZE=1";
437 };
438 }
439 )
440 );
441
442 sfa3explicitEnabledProtectsDefLen1 =
443 checkTestBin
444 (flexArrF2ExampleWithStdEnv stdenv {
445 hardeningEnable = [
446 "fortify"
447 "strictflexarrays3"
448 ];
449 env = {
450 TEST_EXTRA_FLAGS = "-DBUFFER_DEF_SIZE=1";
451 };
452 })
453 {
454 ignoreFortify = false;
455 };
456
457 # musl implementation is effectively FORTIFY_SOURCE=1-only
458 sfa3explicitEnabledProtectsDefLen1ExecTest = brokenIf stdenv.hostPlatform.isMusl (
459 fortifyExecTestFull true "''" "0" (
460 flexArrF2ExampleWithStdEnv stdenv {
461 hardeningEnable = [
462 "fortify"
463 "strictflexarrays3"
464 ];
465 env = {
466 TEST_EXTRA_FLAGS = "-DBUFFER_DEF_SIZE=1";
467 };
468 }
469 )
470 );
471
472 sfa3explicitEnabledDoesntProtectCorrectFlex =
473 checkTestBin
474 (flexArrF2ExampleWithStdEnv stdenv {
475 hardeningEnable = [
476 "fortify"
477 "strictflexarrays3"
478 ];
479 env = {
480 TEST_EXTRA_FLAGS = "-DBUFFER_DEF_SIZE=";
481 };
482 })
483 {
484 ignoreFortify = false;
485 expectFailure = true;
486 };
487
488 # musl implementation is effectively FORTIFY_SOURCE=1-only
489 sfa3explicitEnabledDoesntProtectCorrectFlexExecTest = brokenIf stdenv.hostPlatform.isMusl (
490 fortifyExecTestFull false "" "0" (
491 flexArrF2ExampleWithStdEnv stdenv {
492 hardeningEnable = [
493 "fortify"
494 "strictflexarrays3"
495 ];
496 env = {
497 TEST_EXTRA_FLAGS = "-DBUFFER_DEF_SIZE=";
498 };
499 }
500 )
501 );
502
503 pieAlwaysEnabled = brokenIf stdenv.hostPlatform.isStatic (
504 checkTestBin (f2exampleWithStdEnv stdenv { }) {
505 ignorePie = false;
506 }
507 );
508
509 relROExplicitEnabled =
510 checkTestBin
511 (f2exampleWithStdEnv stdenv {
512 hardeningEnable = [ "relro" ];
513 })
514 {
515 ignoreRelRO = false;
516 };
517
518 stackProtectorExplicitEnabled = brokenIf stdenv.hostPlatform.isStatic (
519 checkTestBin
520 (f2exampleWithStdEnv stdenv {
521 hardeningEnable = [ "stackprotector" ];
522 })
523 {
524 ignoreStackProtector = false;
525 }
526 );
527
528 # protection patterns generated by clang not detectable?
529 stackClashProtectionExplicitEnabled = brokenIf stdenv.cc.isClang (
530 checkTestBin
531 (helloWithStdEnv stdenv {
532 hardeningEnable = [ "stackclashprotection" ];
533 })
534 {
535 ignoreStackClashProtection = false;
536 }
537 );
538
539 pacRetExplicitEnabled = pacRetTest (helloWithStdEnv stdenv {
540 hardeningEnable = [ "pacret" ];
541 }) false;
542
543 shadowStackExplicitEnabled = shadowStackTest (f1exampleWithStdEnv stdenv {
544 hardeningEnable = [ "shadowstack" ];
545 }) false;
546
547 glibcxxassertionsExplicitEnabled = checkGlibcxxassertionsWithStdEnv true stdenv {
548 hardeningEnable = [ "glibcxxassertions" ];
549 };
550
551 bindNowExplicitDisabled =
552 checkTestBin
553 (f2exampleWithStdEnv stdenv {
554 hardeningDisable = [ "bindnow" ];
555 })
556 {
557 ignoreBindNow = false;
558 expectFailure = true;
559 };
560
561 fortifyExplicitDisabled =
562 checkTestBin
563 (f2exampleWithStdEnv stdenv {
564 hardeningDisable = [ "fortify" ];
565 })
566 {
567 ignoreFortify = false;
568 expectFailure = true;
569 };
570
571 fortify3ExplicitDisabled =
572 checkTestBin
573 (f3exampleWithStdEnv stdenv {
574 hardeningDisable = [ "fortify3" ];
575 })
576 {
577 ignoreFortify = false;
578 expectFailure = true;
579 };
580
581 fortifyExplicitDisabledDisablesFortify3 =
582 checkTestBin
583 (f3exampleWithStdEnv stdenv {
584 hardeningEnable = [ "fortify3" ];
585 hardeningDisable = [ "fortify" ];
586 })
587 {
588 ignoreFortify = false;
589 expectFailure = true;
590 };
591
592 fortify3ExplicitDisabledDoesntDisableFortify =
593 checkTestBin
594 (f2exampleWithStdEnv stdenv {
595 hardeningEnable = [ "fortify" ];
596 hardeningDisable = [ "fortify3" ];
597 })
598 {
599 ignoreFortify = false;
600 };
601
602 # musl implementation is effectively FORTIFY_SOURCE=1-only
603 sfa1explicitDisabled = brokenIf stdenv.hostPlatform.isMusl (
604 checkTestBin
605 (flexArrF2ExampleWithStdEnv stdenv {
606 hardeningEnable = [ "fortify" ];
607 hardeningDisable = [ "strictflexarrays1" ];
608 env = {
609 TEST_EXTRA_FLAGS = "-DBUFFER_DEF_SIZE=7";
610 };
611 })
612 {
613 ignoreFortify = false;
614 expectFailure = true;
615 }
616 );
617
618 sfa1explicitDisabledExecTest = fortifyExecTestFull false "012345" "0123456" (
619 flexArrF2ExampleWithStdEnv stdenv {
620 hardeningEnable = [ "fortify" ];
621 hardeningDisable = [ "strictflexarrays1" ];
622 env = {
623 TEST_EXTRA_FLAGS = "-DBUFFER_DEF_SIZE=7";
624 };
625 }
626 );
627
628 # musl implementation is effectively FORTIFY_SOURCE=1-only
629 sfa1explicitDisabledDisablesSfa3 = brokenIf stdenv.hostPlatform.isMusl (
630 checkTestBin
631 (flexArrF2ExampleWithStdEnv stdenv {
632 hardeningEnable = [
633 "fortify"
634 "strictflexarrays3"
635 ];
636 hardeningDisable = [ "strictflexarrays1" ];
637 env = {
638 TEST_EXTRA_FLAGS = "-DBUFFER_DEF_SIZE=1";
639 };
640 })
641 {
642 ignoreFortify = false;
643 expectFailure = true;
644 }
645 );
646
647 # musl implementation is effectively FORTIFY_SOURCE=1-only
648 sfa1explicitDisabledDisablesSfa3ExecTest = brokenIf stdenv.hostPlatform.isMusl (
649 fortifyExecTestFull false "''" "0" (
650 flexArrF2ExampleWithStdEnv stdenv {
651 hardeningEnable = [
652 "fortify"
653 "strictflexarrays3"
654 ];
655 hardeningDisable = [ "strictflexarrays1" ];
656 env = {
657 TEST_EXTRA_FLAGS = "-DBUFFER_DEF_SIZE=1";
658 };
659 }
660 )
661 );
662
663 sfa3explicitDisabledDoesntDisableSfa1 =
664 checkTestBin
665 (flexArrF2ExampleWithStdEnv stdenv {
666 hardeningEnable = [
667 "fortify"
668 "strictflexarrays1"
669 ];
670 hardeningDisable = [ "strictflexarrays3" ];
671 env = {
672 TEST_EXTRA_FLAGS = "-DBUFFER_DEF_SIZE=7";
673 };
674 })
675 {
676 ignoreFortify = false;
677 };
678
679 # musl implementation is effectively FORTIFY_SOURCE=1-only
680 sfa3explicitDisabledDoesntDisableSfa1ExecTest = brokenIf stdenv.hostPlatform.isMusl (
681 fortifyExecTestFull true "012345" "0123456" (
682 flexArrF2ExampleWithStdEnv stdenv {
683 hardeningEnable = [
684 "fortify"
685 "strictflexarrays1"
686 ];
687 hardeningDisable = [ "strictflexarrays3" ];
688 env = {
689 TEST_EXTRA_FLAGS = "-DBUFFER_DEF_SIZE=7";
690 };
691 }
692 )
693 );
694
695 # can't force-disable ("partial"?) relro
696 relROExplicitDisabled = brokenIf true (
697 checkTestBin
698 (f2exampleWithStdEnv stdenv {
699 })
700 {
701 ignoreRelRO = false;
702 expectFailure = true;
703 }
704 );
705
706 stackProtectorExplicitDisabled =
707 checkTestBin
708 (f2exampleWithStdEnv stdenv {
709 hardeningDisable = [ "stackprotector" ];
710 })
711 {
712 ignoreStackProtector = false;
713 expectFailure = true;
714 };
715
716 stackClashProtectionExplicitDisabled =
717 checkTestBin
718 (helloWithStdEnv stdenv {
719 hardeningDisable = [ "stackclashprotection" ];
720 })
721 {
722 ignoreStackClashProtection = false;
723 expectFailure = true;
724 };
725
726 pacRetExplicitDisabled = pacRetTest (helloWithStdEnv stdenv {
727 hardeningDisable = [ "pacret" ];
728 }) true;
729
730 shadowStackExplicitDisabled = shadowStackTest (f1exampleWithStdEnv stdenv {
731 hardeningDisable = [ "shadowstack" ];
732 }) true;
733
734 glibcxxassertionsExplicitDisabled = checkGlibcxxassertionsWithStdEnv false stdenv {
735 hardeningDisable = [ "glibcxxassertions" ];
736 };
737
738 lchFastExplicitDisabled = checkLibcxxHardeningWithStdEnv "_LIBCPP_HARDENING_MODE_NONE" stdenv {
739 hardeningDisable = [ "libcxxhardeningfast" ];
740 };
741
742 lchExtensiveExplicitEnabled =
743 checkLibcxxHardeningWithStdEnv "_LIBCPP_HARDENING_MODE_EXTENSIVE" stdenv
744 {
745 hardeningEnable = [ "libcxxhardeningextensive" ];
746 };
747
748 lchExtensiveExplicitDisabledDoesntDisableLchFast =
749 checkLibcxxHardeningWithStdEnv "_LIBCPP_HARDENING_MODE_FAST" stdenv
750 {
751 hardeningEnable = [ "libcxxhardeningfast" ];
752 hardeningDisable = [ "libcxxhardeningextensive" ];
753 };
754
755 lchFastExplicitDisabledDisablesLchExtensive =
756 checkLibcxxHardeningWithStdEnv "_LIBCPP_HARDENING_MODE_NONE" stdenv
757 {
758 hardeningEnable = [ "libcxxhardeningextensive" ];
759 hardeningDisable = [ "libcxxhardeningfast" ];
760 };
761
762 lchFastExtensiveExplicitEnabledResultsInLchExtensive =
763 checkLibcxxHardeningWithStdEnv "_LIBCPP_HARDENING_MODE_EXTENSIVE" stdenv
764 {
765 hardeningEnable = [
766 "libcxxhardeningfast"
767 "libcxxhardeningextensive"
768 ];
769 };
770
771 lchFastExtensiveExplicitDisabledDisablesBoth =
772 checkLibcxxHardeningWithStdEnv "_LIBCPP_HARDENING_MODE_NONE" stdenv
773 {
774 hardeningDisable = [
775 "libcxxhardeningfast"
776 "libcxxhardeningextensive"
777 ];
778 };
779
780 # most flags can't be "unsupported" by compiler alone and
781 # binutils doesn't have an accessible hardeningUnsupportedFlags
782 # mechanism, so can only test a couple of flags through altered
783 # stdenv trickery
784
785 fortifyStdenvUnsupp =
786 checkTestBin
787 (f2exampleWithStdEnv
788 (stdenvUnsupport [
789 "fortify"
790 "fortify3"
791 ])
792 {
793 hardeningEnable = [ "fortify" ];
794 }
795 )
796 {
797 ignoreFortify = false;
798 expectFailure = true;
799 };
800
801 fortify3StdenvUnsupp =
802 checkTestBin
803 (f3exampleWithStdEnv (stdenvUnsupport [ "fortify3" ]) {
804 hardeningEnable = [ "fortify3" ];
805 })
806 {
807 ignoreFortify = false;
808 expectFailure = true;
809 };
810
811 fortifyStdenvUnsuppUnsupportsFortify3 =
812 checkTestBin
813 (f3exampleWithStdEnv (stdenvUnsupport [ "fortify" ]) {
814 hardeningEnable = [ "fortify3" ];
815 })
816 {
817 ignoreFortify = false;
818 expectFailure = true;
819 };
820
821 fortify3StdenvUnsuppDoesntUnsuppFortify1 =
822 checkTestBin
823 (f1exampleWithStdEnv (stdenvUnsupport [ "fortify3" ]) {
824 hardeningEnable = [ "fortify" ];
825 })
826 {
827 ignoreFortify = false;
828 };
829
830 fortify3StdenvUnsuppDoesntUnsuppFortify1ExecTest = fortifyExecTest (
831 f1exampleWithStdEnv (stdenvUnsupport [ "fortify3" ]) {
832 hardeningEnable = [ "fortify" ];
833 }
834 );
835
836 sfa1StdenvUnsupp =
837 checkTestBin
838 (flexArrF2ExampleWithStdEnv
839 (stdenvUnsupport [
840 "strictflexarrays1"
841 "strictflexarrays3"
842 ])
843 {
844 hardeningEnable = [
845 "fortify"
846 "strictflexarrays1"
847 ];
848 env = {
849 TEST_EXTRA_FLAGS = "-DBUFFER_DEF_SIZE=7";
850 };
851 }
852 )
853 {
854 ignoreFortify = false;
855 expectFailure = true;
856 };
857
858 sfa3StdenvUnsupp =
859 checkTestBin
860 (flexArrF2ExampleWithStdEnv (stdenvUnsupport [ "strictflexarrays3" ]) {
861 hardeningEnable = [
862 "fortify"
863 "strictflexarrays3"
864 ];
865 env = {
866 TEST_EXTRA_FLAGS = "-DBUFFER_DEF_SIZE=1";
867 };
868 })
869 {
870 ignoreFortify = false;
871 expectFailure = true;
872 };
873
874 sfa1StdenvUnsuppUnsupportsSfa3 =
875 checkTestBin
876 (flexArrF2ExampleWithStdEnv (stdenvUnsupport [ "strictflexarrays1" ]) {
877 hardeningEnable = [
878 "fortify"
879 "strictflexarrays3"
880 ];
881 env = {
882 TEST_EXTRA_FLAGS = "-DBUFFER_DEF_SIZE=1";
883 };
884 })
885 {
886 ignoreFortify = false;
887 expectFailure = true;
888 };
889
890 sfa3StdenvUnsuppDoesntUnsuppSfa1 =
891 checkTestBin
892 (flexArrF2ExampleWithStdEnv (stdenvUnsupport [ "strictflexarrays3" ]) {
893 hardeningEnable = [
894 "fortify"
895 "strictflexarrays1"
896 ];
897 env = {
898 TEST_EXTRA_FLAGS = "-DBUFFER_DEF_SIZE=7";
899 };
900 })
901 {
902 ignoreFortify = false;
903 };
904
905 # musl implementation is effectively FORTIFY_SOURCE=1-only
906 sfa3StdenvUnsuppDoesntUnsuppSfa1ExecTest = brokenIf stdenv.hostPlatform.isMusl (
907 fortifyExecTestFull true "012345" "0123456" (
908 flexArrF2ExampleWithStdEnv (stdenvUnsupport [ "strictflexarrays3" ]) {
909 hardeningEnable = [
910 "fortify"
911 "strictflexarrays1"
912 ];
913 env = {
914 TEST_EXTRA_FLAGS = "-DBUFFER_DEF_SIZE=7";
915 };
916 }
917 )
918 );
919
920 stackProtectorStdenvUnsupp =
921 checkTestBin
922 (f2exampleWithStdEnv (stdenvUnsupport [ "stackprotector" ]) {
923 hardeningEnable = [ "stackprotector" ];
924 })
925 {
926 ignoreStackProtector = false;
927 expectFailure = true;
928 };
929
930 stackClashProtectionStdenvUnsupp =
931 checkTestBin
932 (helloWithStdEnv (stdenvUnsupport [ "stackclashprotection" ]) {
933 hardeningEnable = [ "stackclashprotection" ];
934 })
935 {
936 ignoreStackClashProtection = false;
937 expectFailure = true;
938 };
939
940 # NIX_HARDENING_ENABLE set in the shell overrides hardeningDisable
941 # and hardeningEnable
942
943 stackProtectorReenabledEnv =
944 checkTestBin
945 (f2exampleWithStdEnv stdenv {
946 hardeningDisable = [ "stackprotector" ];
947 postConfigure = ''
948 export NIX_HARDENING_ENABLE="stackprotector"
949 '';
950 })
951 {
952 ignoreStackProtector = false;
953 };
954
955 stackProtectorReenabledFromAllEnv =
956 checkTestBin
957 (f2exampleWithStdEnv stdenv {
958 hardeningDisable = [ "all" ];
959 postConfigure = ''
960 export NIX_HARDENING_ENABLE="stackprotector"
961 '';
962 })
963 {
964 ignoreStackProtector = false;
965 };
966
967 stackProtectorRedisabledEnv =
968 checkTestBin
969 (f2exampleWithStdEnv stdenv {
970 hardeningEnable = [ "stackprotector" ];
971 postConfigure = ''
972 export NIX_HARDENING_ENABLE=""
973 '';
974 })
975 {
976 ignoreStackProtector = false;
977 expectFailure = true;
978 };
979
980 glibcxxassertionsStdenvUnsupp =
981 checkGlibcxxassertionsWithStdEnv false (stdenvUnsupport [ "glibcxxassertions" ])
982 {
983 hardeningEnable = [ "glibcxxassertions" ];
984 };
985
986 lchFastStdenvUnsupp =
987 checkLibcxxHardeningWithStdEnv "_LIBCPP_HARDENING_MODE_NONE"
988 (stdenvUnsupport [ "libcxxhardeningfast" ])
989 {
990 hardeningEnable = [ "libcxxhardeningfast" ];
991 };
992
993 lchFastStdenvUnsuppUnsupportsLchExtensive =
994 checkLibcxxHardeningWithStdEnv "_LIBCPP_HARDENING_MODE_NONE"
995 (stdenvUnsupport [ "libcxxhardeningfast" ])
996 {
997 hardeningEnable = [ "libcxxhardeningextensive" ];
998 };
999
1000 lchExtensiveStdenvUnsuppDoesntUnsupportLchFast =
1001 checkLibcxxHardeningWithStdEnv "_LIBCPP_HARDENING_MODE_FAST"
1002 (stdenvUnsupport [ "libcxxhardeningextensive" ])
1003 {
1004 hardeningEnable = [
1005 "libcxxhardeningfast"
1006 "libcxxhardeningextensive"
1007 ];
1008 };
1009
1010 fortify3EnabledEnvEnablesFortify1 =
1011 checkTestBin
1012 (f1exampleWithStdEnv stdenv {
1013 hardeningDisable = [
1014 "fortify"
1015 "fortify3"
1016 ];
1017 postConfigure = ''
1018 export NIX_HARDENING_ENABLE="fortify3"
1019 '';
1020 })
1021 {
1022 ignoreFortify = false;
1023 };
1024
1025 fortify3EnabledEnvEnablesFortify1ExecTest = fortifyExecTest (
1026 f1exampleWithStdEnv stdenv {
1027 hardeningDisable = [
1028 "fortify"
1029 "fortify3"
1030 ];
1031 postConfigure = ''
1032 export NIX_HARDENING_ENABLE="fortify3"
1033 '';
1034 }
1035 );
1036
1037 fortifyEnabledEnvDoesntEnableFortify3 =
1038 checkTestBin
1039 (f3exampleWithStdEnv stdenv {
1040 hardeningDisable = [
1041 "fortify"
1042 "fortify3"
1043 ];
1044 postConfigure = ''
1045 export NIX_HARDENING_ENABLE="fortify"
1046 '';
1047 })
1048 {
1049 ignoreFortify = false;
1050 expectFailure = true;
1051 };
1052
1053 sfa3EnabledEnvEnablesSfa1 =
1054 checkTestBin
1055 (flexArrF2ExampleWithStdEnv stdenv {
1056 hardeningDisable = [
1057 "strictflexarrays1"
1058 "strictflexarrays3"
1059 ];
1060 postConfigure = ''
1061 export NIX_HARDENING_ENABLE="fortify strictflexarrays3"
1062 '';
1063 env = {
1064 TEST_EXTRA_FLAGS = "-DBUFFER_DEF_SIZE=7";
1065 };
1066 })
1067 {
1068 ignoreFortify = false;
1069 };
1070
1071 sfa3EnabledEnvEnablesSfa1ExecTest = fortifyExecTestFull true "012345" "0123456" (
1072 f1exampleWithStdEnv stdenv {
1073 hardeningDisable = [
1074 "strictflexarrays1"
1075 "strictflexarrays3"
1076 ];
1077 postConfigure = ''
1078 export NIX_HARDENING_ENABLE="fortify strictflexarrays3"
1079 '';
1080 env = {
1081 TEST_EXTRA_FLAGS = "-DBUFFER_DEF_SIZE=7";
1082 };
1083 }
1084 );
1085
1086 sfa1EnabledEnvDoesntEnableSfa3 =
1087 checkTestBin
1088 (flexArrF2ExampleWithStdEnv stdenv {
1089 hardeningDisable = [
1090 "strictflexarrays1"
1091 "strictflexarrays3"
1092 ];
1093 postConfigure = ''
1094 export NIX_HARDENING_ENABLE="fortify strictflexarrays1"
1095 '';
1096 env = {
1097 TEST_EXTRA_FLAGS = "-DBUFFER_DEF_SIZE=1";
1098 };
1099 })
1100 {
1101 ignoreFortify = false;
1102 expectFailure = true;
1103 };
1104
1105 lchFastEnabledEnv = checkLibcxxHardeningWithStdEnv "_LIBCPP_HARDENING_MODE_FAST" stdenv {
1106 hardeningDisable = [
1107 "libcxxhardeningfast"
1108 "libcxxhardeningextensive"
1109 ];
1110 postConfigure = ''
1111 export NIX_HARDENING_ENABLE="libcxxhardeningfast"
1112 '';
1113 };
1114
1115 lchExtensiveEnabledEnv = checkLibcxxHardeningWithStdEnv "_LIBCPP_HARDENING_MODE_EXTENSIVE" stdenv {
1116 hardeningDisable = [
1117 "libcxxhardeningfast"
1118 "libcxxhardeningextensive"
1119 ];
1120 postConfigure = ''
1121 export NIX_HARDENING_ENABLE="libcxxhardeningextensive"
1122 '';
1123 };
1124
1125 lchFastExtensiveEnabledEnvResultsInLchExtensive =
1126 checkLibcxxHardeningWithStdEnv "_LIBCPP_HARDENING_MODE_EXTENSIVE" stdenv
1127 {
1128 hardeningDisable = [
1129 "libcxxhardeningfast"
1130 "libcxxhardeningextensive"
1131 ];
1132 postConfigure = ''
1133 export NIX_HARDENING_ENABLE="libcxxhardeningextensive libcxxhardeningfast"
1134 '';
1135 };
1136
1137 # NIX_HARDENING_ENABLE can't enable an unsupported feature
1138 stackProtectorUnsupportedEnabledEnv =
1139 checkTestBin
1140 (f2exampleWithStdEnv (stdenvUnsupport [ "stackprotector" ]) {
1141 postConfigure = ''
1142 export NIX_HARDENING_ENABLE="stackprotector"
1143 '';
1144 })
1145 {
1146 ignoreStackProtector = false;
1147 expectFailure = true;
1148 };
1149
1150 # current implementation prevents the command-line from disabling
1151 # fortify if cc-wrapper is enabling it.
1152
1153 fortify1ExplicitEnabledCmdlineDisabled =
1154 checkTestBin
1155 (f1exampleWithStdEnv stdenv {
1156 hardeningEnable = [ "fortify" ];
1157 postConfigure = ''
1158 export TEST_EXTRA_FLAGS='-D_FORTIFY_SOURCE=0'
1159 '';
1160 })
1161 {
1162 ignoreFortify = false;
1163 expectFailure = false;
1164 };
1165
1166 # current implementation doesn't force-disable fortify if
1167 # command-line enables it even if we use hardeningDisable.
1168
1169 fortify1ExplicitDisabledCmdlineEnabled =
1170 checkTestBin
1171 (f1exampleWithStdEnv stdenv {
1172 hardeningDisable = [ "fortify" ];
1173 postConfigure = ''
1174 export TEST_EXTRA_FLAGS='-D_FORTIFY_SOURCE=1'
1175 '';
1176 })
1177 {
1178 ignoreFortify = false;
1179 };
1180
1181 fortify1ExplicitDisabledCmdlineEnabledExecTest = fortifyExecTest (
1182 f1exampleWithStdEnv stdenv {
1183 hardeningDisable = [ "fortify" ];
1184 postConfigure = ''
1185 export TEST_EXTRA_FLAGS='-D_FORTIFY_SOURCE=1'
1186 '';
1187 }
1188 );
1189
1190 fortify1ExplicitEnabledCmdlineDisabledNoWarn = f1exampleWithStdEnv stdenv {
1191 hardeningEnable = [ "fortify" ];
1192 postConfigure = ''
1193 export TEST_EXTRA_FLAGS='-D_FORTIFY_SOURCE=0 -Werror'
1194 '';
1195 };
1196
1197 }
1198 // (
1199 let
1200 tb = f2exampleWithStdEnv stdenv {
1201 hardeningDisable = [ "all" ];
1202 hardeningEnable = [
1203 "fortify"
1204 ];
1205 };
1206 in
1207 {
1208
1209 allExplicitDisabledBindNow = checkTestBin tb {
1210 ignoreBindNow = false;
1211 expectFailure = true;
1212 };
1213
1214 allExplicitDisabledFortify = checkTestBin tb {
1215 ignoreFortify = false;
1216 expectFailure = true;
1217 };
1218
1219 # can't force-disable ("partial"?) relro
1220 allExplicitDisabledRelRO = brokenIf true (
1221 checkTestBin tb {
1222 ignoreRelRO = false;
1223 expectFailure = true;
1224 }
1225 );
1226
1227 allExplicitDisabledStackProtector = checkTestBin tb {
1228 ignoreStackProtector = false;
1229 expectFailure = true;
1230 };
1231
1232 allExplicitDisabledStackClashProtection = checkTestBin tb {
1233 ignoreStackClashProtection = false;
1234 expectFailure = true;
1235 };
1236
1237 allExplicitDisabledPacRet = pacRetTest (helloWithStdEnv stdenv {
1238 hardeningDisable = [ "all" ];
1239 }) true;
1240
1241 allExplicitDisabledShadowStack = shadowStackTest (f1exampleWithStdEnv stdenv {
1242 hardeningDisable = [ "all" ];
1243 }) true;
1244
1245 allExplicitDisabledGlibcxxAssertions = checkGlibcxxassertionsWithStdEnv false stdenv {
1246 hardeningDisable = [ "all" ];
1247 };
1248
1249 allExplicitDisabledLibcxxHardening =
1250 checkLibcxxHardeningWithStdEnv "_LIBCPP_HARDENING_MODE_NONE" stdenv
1251 {
1252 hardeningDisable = [ "all" ];
1253 };
1254 }
1255 )
1256)