Skip to content

cc-wrapper: add support for strictflexarrays1 & strictflexarrays3 hardening flags#400408

Merged
philiptaron merged 15 commits intoNixOS:stagingfrom
risicle:ris-hardening-strictflexarrays1-3
May 26, 2025
Merged

cc-wrapper: add support for strictflexarrays1 & strictflexarrays3 hardening flags#400408
philiptaron merged 15 commits intoNixOS:stagingfrom
risicle:ris-hardening-strictflexarrays1-3

Conversation

@risicle
Copy link
Contributor

@risicle risicle commented Apr 20, 2025

More background on these flags: https://best.openssf.org/Compiler-Hardening-Guides/Compiler-Options-Hardening-Guide-for-C-and-C++.html#enable-strict-flexible-arrays

In short, they improve coverage of fortify checks by reducing the number of cases the compiler has to be permissive with.

Initially I was just going to add strictflexarrays3 and be satisfied with leaving it as a pkgsExtraHardening flag until projects had caught up and stopped using old-fashioned flexible array declarations, but as you can see from the number of strictflexarrays3 disablements I've added, there are quite a lot of projects with this problem (and this is only the tip of the iceberg - cpython heavily uses [1]-style declarations in its API, meaning much of the python ecosystem will fail to compile with strictflexarrays3 - see python/cpython#84301). So I've also added strictflexarrays1which is the strictest mode python will compile with, and used that for pkgsExtraHardening. strictflexarrays3 is left for those who want to experiment and/or don't need many python packages.

The behaviour of the two flags exactly mirrors the behaviours of fortify and fortify3 and in fact is largely implemented through a copy-pasta of most of those code fragments. A number of tests.hardeningFlags tests are added to prove this. As ever, tinkering with the hardening flags tests caused me to do a bit of refactoring.

As ever, neither of these new flags are enabled by default for normal packagesets.

Tested build of many packages with strictflexarrays3 default-enabled on aarch64-linux and macos 12 x86_64 (enough to gather the various fixes included in this PR). Successfully bootstapped pkgsMusl, pkgsStatic, pkgsCross.riscv64 on aarch64-linux.

Tested tests.hardeningFlags on the default packageset for aarch64-linux and macos 12 x86_64, pkgsLLVM, pkgsi686Linux, pkgsMusl, pkgsStatic with expected results.

Things done

  • Built on platform(s)
    • x86_64-linux
    • aarch64-linux
    • x86_64-darwin
    • aarch64-darwin
  • For non-Linux: Is sandboxing enabled in nix.conf? (See Nix manual)
    • sandbox = relaxed
    • sandbox = true
  • Tested, as applicable:
  • Tested compilation of all packages that depend on this change using nix-shell -p nixpkgs-review --run "nixpkgs-review rev HEAD". Note: all changes have to be committed, also see nixpkgs-review usage
  • Tested basic functionality of all binary files (usually in ./result/bin/)
  • 25.05 Release Notes (or backporting 24.11 and 25.05 Release notes)
    • (Package updates) Added a release notes entry if the change is major or breaking
    • (Module updates) Added a release notes entry if the change is significant
    • (Module addition) Added a release notes entry if adding a new NixOS module
  • Fits CONTRIBUTING.md.

Add a 👍 reaction to pull requests you find important.

@github-actions github-actions bot added 6.topic: nixos Issues or PRs affecting NixOS modules, or package usability issues specific to NixOS 8.has: changelog This PR adds or changes release notes 6.topic: stdenv Standard environment 6.topic: llvm/clang Issues related to llvmPackages, clangStdenv and related 8.has: documentation This PR adds or changes documentation labels Apr 20, 2025
@github-actions github-actions bot added 10.rebuild-darwin: 5001+ This PR causes many rebuilds on Darwin and must target the staging branches. 10.rebuild-darwin: 501+ This PR causes many rebuilds on Darwin and should normally target the staging branches. 10.rebuild-linux: 5001+ This PR causes many rebuilds on Linux and must target the staging branches. 10.rebuild-linux: 501+ This PR causes many rebuilds on Linux and should normally target the staging branches. labels Apr 20, 2025
@risicle risicle force-pushed the ris-hardening-strictflexarrays1-3 branch from 84c8446 to c12424d Compare April 20, 2025 23:37
@risicle risicle marked this pull request as ready for review April 21, 2025 10:22
@RossComputerGuy RossComputerGuy requested a review from a team April 30, 2025 04:13
@risicle risicle force-pushed the ris-hardening-strictflexarrays1-3 branch 2 times, most recently from 52b82c3 to 1100a62 Compare May 17, 2025 18:00
@github-actions github-actions bot removed 6.topic: nixos Issues or PRs affecting NixOS modules, or package usability issues specific to NixOS 8.has: changelog This PR adds or changes release notes labels May 17, 2025
@risicle
Copy link
Contributor Author

risicle commented May 18, 2025

(moved release notes addition from the nixos release notes to the nixpkgs release notes)

@risicle risicle force-pushed the ris-hardening-strictflexarrays1-3 branch from 1100a62 to ec618e8 Compare May 19, 2025 22:59
@risicle
Copy link
Contributor Author

risicle commented May 19, 2025

Rebased to adapt to #400351

Copy link
Contributor

@philiptaron philiptaron left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm trying to test this with the expression:

nix-build --expr 'with import ./. { }; let inherit (tests) hardeningFlags hardeningFlags-clang hardeningFlags-gcc; f = v: let r = builtins.tryEval v.outPath or null; in if r.success then v else null; vs = lib.flatten (map builtins.attrValues [ hardeningFlags hardeningFlags-clang hardeningFlags-gcc ]); evald = lib.filter (v: v != null && lib.isDerivation v) (map f vs); in evald' --keep-going

This calls and runs all the tests in tests.hardeningFlags, tests.hardeningFlags-clang, and tests.hardeningFlags-gcc.

I get many failures.
error: build of '/nix/store/02d9xk9phzxsd7bsw6ckmvrw076n4a6p-test-relROExplicitEnabled.drv', '/nix/store/0fypyjdf3b0yygxhaiqjv538fanyxr2q-test-fortify3EnabledEnvEnablesFortify1.drv', '/nix/store/12smdx2xmfh4h85whbkwfg67lz121sbp-test-fortify1ExplicitDisabledCmdlineEnabled.drv', '/nix/store/187vl8qg9nahsw43f4d0k8i0az24ia3n-test-fortify3ExplicitDisabledDoesntDisableFortify.drv', '/nix/store/2178km0b6wi32z5qx353y7k4axhj47dx-test-sfa3explicitDisabledDoesntDisableSfa1.drv', '/nix/store/2dsdy611sg64ww3bl0yy9l0g4fznnwlz-test-fortifyExplicitEnabled.drv', '/nix/store/3yjf21cr4jh07fiqgqdgrfh9a8cpa4kx-test-stackProtectorReenabledEnv.drv', '/nix/store/44kz1hdr8l6j1f8hi1nqy5mmjml23997-test-sfa3explicitEnabledProtectsDefLen1.drv', '/nix/store/471j6pdkjp1x0sx8d8syx5vjnn0dymfz-test-fortify3StdenvUnsuppDoesntUnsuppFortify1.drv', '/nix/store/6dvqjbc6n0bpnvl39c25vi1199r9f079-test-sfa3explicitEnabledProtectsDefLen1.drv', '/nix/store/6f52i0hbq7nc8xhrch52lxpf2fpf58na-test-stackProtectorReenabledEnv.drv', '/nix/store/8qig3dfnd5xvzdb53p96fidry15zm46q-test-stackProtectorExplicitEnabled.drv', '/nix/store/91l26mbn9wigxhay04mfwqp5nwi9casl-test-pieExplicitEnabled.drv', '/nix/store/9brgyhzvrrdi7zknm5dqv6bnwhvpsz5j-test-fortify1ExplicitEnabledCmdlineDisabled.drv', '/nix/store/9kjkfnc19pk96nxm0nk0w15xybybf0l7-test-fortify1ExplicitEnabledCmdlineDisabled.drv', '/nix/store/9krm5fxhcbk9jp7n5gm7k5hjg3ay37vr-test-sfa3EnabledEnvEnablesSfa1.drv', '/nix/store/9nm2khnrc84vavz0j3lanqvk7fh33bcd-test-fortifyExplicitEnabled.drv', '/nix/store/ab0bgp03km1b165bcww12as3ialjwf5p-test-fortify3ExplicitDisabledDoesntDisableFortify.drv', '/nix/store/b8ijn0y57h810z8xvsppmmg3ih0s3yls-test-fortify3EnabledEnvEnablesFortify1.drv', '/nix/store/ca39j7mx5gs6b0q2p06z36k8pp36lby6-test-fortify3ExplicitEnabled.drv', '/nix/store/czxxsz7bcq7f31s4mpx849773qk5z1sr-test-bindNowExplicitEnabled.drv', '/nix/store/d6fy5a79ikkibnvp1mdl5da79ncqd3bi-test-stackProtectorReenabledFromAllEnv.drv', '/nix/store/gbh9ycrnzjyi6q5kg8g9jf0a1qr17c6q-test-bindNowExplicitEnabled.drv', '/nix/store/gc5hbpad75pfzgr29rkl9pp2h5cdfnij-test-pieExplicitEnabledStructuredAttrs.drv', '/nix/store/gm0rm5fhyx24zpa1ig2dwsl8mfjv16dd-test-pieExplicitEnabledStructuredAttrs.drv', '/nix/store/hyngdz68zsz1i592ii47ym9sgcp7hfp1-test-sfa3EnabledEnvEnablesSfa1.drv', '/nix/store/j5742w0nfbdkl3wq05i36ry5qkkp82a0-test-stackProtectorReenabledFromAllEnv.drv', '/nix/store/jlwxshk6igm84j2ffmgzq9av902l375q-test-stackProtectorExplicitEnabled.drv', '/nix/store/pl8m71rb3qjn53hwdn791whfcg6k7mk3-test-relROExplicitEnabled.drv', '/nix/store/q3bd6xwdfgad005kyvgk3mnqxx1f69zw-test-fortify3StdenvUnsuppDoesntUnsuppFortify1.drv', '/nix/store/r21vwdc0izfmgm14a0wshfbzb03mgv5q-test-sfa3StdenvUnsuppDoesntUnsuppSfa1.drv', '/nix/store/rf4iwpzq3d7mzajipnigzdymiqb220vl-test-sfa3explicitDisabledDoesntDisableSfa1.drv', '/nix/store/vls4jfgz45cdwcc45afk7jqa5vxnyain-test-fortify1ExplicitDisabledCmdlineEnabled.drv', '/nix/store/w1sl16bifkjn3iyjq65k0w18xcrssq4l-test-sfa3StdenvUnsuppDoesntUnsuppSfa1.drv', '/nix/store/x7yjfn2fjbcav5qqr4vcagldn56s6whr-test-pieExplicitEnabled.drv', '/nix/store/y97gb3p50bac0m368df17mypavz066j2-test-sfa1explicitEnabled.drv', '/nix/store/zqqd2xzh5nbyzrj1fpq54rw2cc0iy4mr-test-sfa1explicitEnabled.drv' failed

Any other way I should test this? This is on x86_64-linux on NixOS.

any (x: x == "fortify") hardeningDisable
concretizeFlagImplications =
flag: impliesFlags: list:
if any (x: x == flag) list then unique (list ++ impliesFlags) else list;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

unique is sometimes costly since it's O(n^2) with the length of the list as I understand it -- could we solve the multiple entries in bash? Do we already do that?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've been hoping for the sort-based uniq from #119286 to be included for a while now for exactly this reason, but it feels like I'm the only one interested in it.

It's done in nix instead of bash in attempt to avoid rebuilds for equivalent flag-sets (though it doesn't yet do this fully - if I had the above, faster uniq implementation, I would add more calls to it to make it watertight).

You do raise a point though - I could reduce these all to a single unique call (which we already do for fortify/fortify3).

@risicle
Copy link
Contributor Author

risicle commented May 23, 2025

re the test failures - you should find that all the failing tests are marked broken or won't evaluate for all platforms.

Trying to recall the exact expression I used for this, think it's something along the lines of:

nix-build -E 'let pkgs = (import ./. {}); in pkgs.lib.filterAttrs (k: v: (builtins.tryEval v).success && v ? drvPath && (builtins.tryEval v.drvPath).success) pkgs.tests.hardeningFlags'

@risicle
Copy link
Contributor Author

risicle commented May 24, 2025

Oh hold on, no I know what the failures are - a new version of debian-devscripts has landed that has a new flag I need to add, --nobranchprotection..

@risicle risicle force-pushed the ris-hardening-strictflexarrays1-3 branch from ec618e8 to a7d90a9 Compare May 24, 2025 00:39
@risicle risicle force-pushed the ris-hardening-strictflexarrays1-3 branch from a7d90a9 to b7771e1 Compare May 24, 2025 10:10
)
);

pieExplicitDisabled = brokenIf (stdenv.hostPlatform.isMusl && stdenv.cc.isClang) (
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

allExplicitDisabledPie and this one, pieExplicitDisabled, are the only tests in this file that fails for me on x86_64-linux now.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Interesting - for clang or gcc? They all pass for me now on x86_64 nixos.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For clang.

tests.hardeningFlags-clang.allExplicitDisabledPie

/nix/store/dpx82dk9ncs8igknbynirq9np03y9s52-test-bin/bin/test-bin:
 Position Independent Executable: yes
 Stack protected: no, not found! (ignored)
 Fortify Source functions: no, only unprotected functions found! (ignored)
 Read-only relocations: yes
 Immediate binding: no, not found! (ignored)
 Stack clash protection: unknown, no -fstack-clash-protection instructions found
 Control flow integrity: no, not found! (ignored)
 Branch Protection: no, not found! (ignored)
ERROR: Expected hardening-check to fail, but it passed!

tests.hardeningFlags-clang.pieExplicitDisabled

/nix/store/qfpr0mg2h676c5qa969my6mss2w40dcx-test-bin/bin/test-bin:
 Position Independent Executable: yes
 Stack protected: yes
 Fortify Source functions: yes
 Read-only relocations: yes
 Immediate binding: yes
 Stack clash protection: unknown, no -fstack-clash-protection instructions found
 Control flow integrity: no, not found! (ignored)
 Branch Protection: no, not found! (ignored)
ERROR: Expected hardening-check to fail, but it passed!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, I'll have to look into this...

@github-project-automation github-project-automation bot moved this to In Progress in Stdenv May 24, 2025
@wegank wegank added the 12.approvals: 1 This PR was reviewed and approved by one person. label May 24, 2025
@philiptaron philiptaron merged commit b768689 into NixOS:staging May 26, 2025
18 checks passed
@github-project-automation github-project-automation bot moved this from In Progress to Done in Stdenv May 26, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

6.topic: llvm/clang Issues related to llvmPackages, clangStdenv and related 6.topic: stdenv Standard environment 8.has: documentation This PR adds or changes documentation 10.rebuild-darwin: 501+ This PR causes many rebuilds on Darwin and should normally target the staging branches. 10.rebuild-darwin: 5001+ This PR causes many rebuilds on Darwin and must target the staging branches. 10.rebuild-linux: 501+ This PR causes many rebuilds on Linux and should normally target the staging branches. 10.rebuild-linux: 5001+ This PR causes many rebuilds on Linux and must target the staging branches. 12.approvals: 1 This PR was reviewed and approved by one person.

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

3 participants