Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

hardening flags: add FORTIFY_SOURCE=3 support #212498

Merged
merged 6 commits into from
Feb 16, 2023
Merged

Conversation

risicle
Copy link
Contributor

@risicle risicle commented Jan 24, 2023

Description of changes

https://developers.redhat.com/articles/2022/09/17/gccs-new-fortification-level

GCC 12 makes available the new -D_FORTIFY_SOURCE=3 mode, which significantly improves coverage over the existing protections. Other distributions have reportedly already enabled the flag universally with few problems. It would be nice to be ready to enable this flag once we've switched to GCC 12 as our default compiler.

The problem in doing this however is that the existing hardening flag mechanisms are based around flags being purely boolean and independent - we've never had to handle flags with multiple modes before.

After a lot of thought, what I've done here is to introduce a new flag, fortify3. fortify continues to mean FORTIFY_SOURCE=2 mode - its behaviour remains unchanged for backwards compatibility. There are a couple of special handling rules to deconflict the meaning of the two:

  • When specifying fortify3 in a positive sense (i.e. hardeningEnable, defaultHardeningFlags, NIX_HARDENING_ENABLE), fortify3 supersedes plain fortify.
  • When specifying fortify in a negative sense (i.e. hardeningDisable, hardeningUnsupportedFlags, hardening_unsupported_flags), fortify implies that fortify3 should also be disabled.

Interestingly, the "negative" rule has to be implemented twice, once at the nix-level for hardeningDisable and once at the bash-level for hardening_unsupported_flags.

In this PR, fortify3 is then added to hardeningUnsupportedFlags for all compilers but GCC 12 (importantly also the bootstrap compilers). According to the above article, clang also supposedly supports FORTIFY_SOURCE=3, but reliable information on clang's fortify-support at any level is very hard to come by so I'm not going down that rabbit hole.

I've done a lot of building on nixos x86_64 with this:

  • as-is, everything disabled (came across no failures)
  • fortify3 enabled by default (came across no failures)
  • fortify3 enabled by default & default compiler GCC 12 (a couple of failures, fixes included)

I was very surprised at how ready both GCC 12 and fortify3 support appear to be, at least for nixos x86_64.

I also built a substantial amount on x86_64 darwin, including packages using gccStdenv, not finding any breakages.

This PR itself shouldn't change how any packages are built as it neither adds fortify3 to the defaultHardeningFlags or has a default compiler that supports fortify3, but once we're ready we'll have to add a straightforward commit such as risicle@665b354 to do so (:point_left: consider testing with this cherry-picked on top)

Edit: have also built some pkgsMusl, pkgsStatic and pkgsCross.aarch64-multiplatform packages on x86_64 linux under various configurations of compiler/fortify3-enablement/disablement.

Things done
  • Built on platform(s)
    • x86_64-linux
    • aarch64-linux
    • x86_64-darwin
    • aarch64-darwin
  • For non-Linux: Is sandbox = true set in nix.conf? (See Nix manual)
  • 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/)
  • 23.05 Release Notes (or backporting 22.11 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
    • (Release notes changes) Ran nixos/doc/manual/md-to-db.sh to update generated release notes
  • Fits CONTRIBUTING.md.

@risicle
Copy link
Contributor Author

risicle commented Feb 12, 2023

I will probably merge this next week unless there are any objections - want this to get a lot of testing before we approach release-time.

@vcunat
Copy link
Member

vcunat commented Feb 12, 2023

Based on what I've read I wasn't sure if the level 3 is a suitable default (for us), but that certainly doesn't matter for this PR.

@risicle risicle merged commit 0eedcfc into NixOS:staging Feb 16, 2023
@trofi
Copy link
Contributor

trofi commented Feb 17, 2023

I did not bisect precisely but I have a strong suspiction it's fortify. libomxil-bellagio fails to build in staging (due to a legitimate stack overflow) as a:

$ nix build --no-link -f. -L libomxil-bellagio
...
libomxil-bellagio> omx_base_component.c: In function 'omx_base_component_GetComponentVersion':
libomxil-bellagio> omx_base_component.c:830:3: error: 'memcpy' reading 72 bytes from a region of size 24 [8;;https://gcc.gnu.org/onlinedocs/gcc/Warning-Options.html#index-Wstringop-overread-Werror=stringop-overread8;;]
libomxil-bellagio>   830 |   memcpy(*pComponentUUID, uuid, 3*sizeof(uuid));
libomxil-bellagio>       |   ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

@risicle
Copy link
Contributor Author

risicle commented Feb 17, 2023

Hmm. The only unusual things this package does is set NIX_CFLAGS_COMPILE with -Wno-error=stringop-overflow=8 among other flags. This isn't exactly stringop-overread though. Is this linux x86_64 gcc?

@trofi
Copy link
Contributor

trofi commented Feb 17, 2023

Yeah, vanilla unpatched x86_64-linux. I can bisect, will take quite a bit (afraid I lost my main machine for a while).

@risicle
Copy link
Contributor Author

risicle commented Feb 17, 2023

You could try using the NIX_DEBUG env var to see if the same flags are getting through to the compiler before and after.

@trofi
Copy link
Contributor

trofi commented Feb 20, 2023

Finally bisected it down to 0eedcfc Merge pull request #212498 from risicle/ris-fortify3. Which is (AFAIU) a merge commit. git show -m shows that this merge commit switches from gcc-11 to gcc-12.

That explains at least the warning change. I'll work on a natural fix.

@trofi trofi mentioned this pull request Feb 20, 2023
12 tasks
@trofi
Copy link
Contributor

trofi commented Feb 20, 2023

Proposed the change as #217379

@risicle
Copy link
Contributor Author

risicle commented Feb 20, 2023

I still don't understand how this PR is related, because it doesn't actually enable fortify3 by default, even on gcc 12.

@trofi
Copy link
Contributor

trofi commented Feb 20, 2023

Good point. Could it be that we lost fortify unconditionally? NIX_DEBUG=1 says it's off for that file:

--- a/pkgs/development/libraries/libomxil-bellagio/default.nix
+++ b/pkgs/development/libraries/libomxil-bellagio/default.nix
@@ -27,6 +27,8 @@ stdenv.mkDerivation rec {
     if stdenv.cc.isGNU then "-Wno-error=array-bounds -Wno-error=stringop-overflow=8"
     else "-Wno-error=absolute-value -Wno-error=enum-conversion -Wno-error=logical-not-parentheses -Wno-error=non-literal-null-conversion";

+  NIX_DEBUG="1";
+
   meta = with lib; {
     homepage = "https://omxil.sourceforge.net/";
     description = "An opensource implementation of the Khronos OpenMAX Integration Layer API to access multimedia components";
libomxil-bellagio> HARDENING: disabled flags: pie fortify
libomxil-bellagio> HARDENING: Is active (not completely disabled with "all" flag)
libomxil-bellagio> HARDENING: enabling pic
libomxil-bellagio> HARDENING: enabling format
libomxil-bellagio> HARDENING: enabling stackprotector
libomxil-bellagio> HARDENING: enabling strictoverflow
libomxil-bellagio> extra flags before to /nix/store/0spl4agq94fairydh94xjmsm47zfk684-gcc-12.2.0/bin/gcc:
libomxil-bellagio>   -fPIC
libomxil-bellagio>   -Wformat
libomxil-bellagio>   -Wformat-security
libomxil-bellagio>   -Werror=format-security
libomxil-bellagio>   -fstack-protector-strong
libomxil-bellagio>   --param
libomxil-bellagio>   ssp-buffer-size=4
libomxil-bellagio>   -fno-strict-overflow
libomxil-bellagio> original flags to /nix/store/0spl4agq94fairydh94xjmsm47zfk684-gcc-12.2.0/bin/gcc:
libomxil-bellagio>   -DHAVE_CONFIG_H
libomxil-bellagio>   -I.
libomxil-bellagio>   -I../..
libomxil-bellagio>   -I../../include
libomxil-bellagio>   -I../../src
libomxil-bellagio>   -Wall
libomxil-bellagio>   -Werror
libomxil-bellagio>   -DCONFIG_DEBUG_LEVEL=0
libomxil-bellagio>   -c
libomxil-bellagio>   omx_base_component.c
libomxil-bellagio> extra flags after to /nix/store/0spl4agq94fairydh94xjmsm47zfk684-gcc-12.2.0/bin/gcc:
libomxil-bellagio>   -B/nix/store/fcx9kxk5lnzw6wj9wsrfwbfmyapvp1x3-glibc-2.35-224/lib/
libomxil-bellagio>   -idirafter
libomxil-bellagio>   /nix/store/7g4gmx9injcjkcm87jjbkqb3mvjzdfq1-glibc-2.35-224-dev/include
libomxil-bellagio>   -idirafter
libomxil-bellagio>   /nix/store/0spl4agq94fairydh94xjmsm47zfk684-gcc-12.2.0/lib/gcc/x86_64-unknown-linux-gnu/12.2.0/include-fixed
libomxil-bellagio>   -B/nix/store/pwz9248d67bbf1rwlcl22kb7bq2n5znb-gcc-12.2.0-lib/lib
libomxil-bellagio>   -B/nix/store/kppvssg3zckrry3xy3d7v07k8nz086bn-gcc-wrapper-12.2.0/bin/
libomxil-bellagio>   -Wno-error=array-bounds
libomxil-bellagio>   -Wno-error=stringop-overflow=8
libomxil-bellagio>   -frandom-seed=1303k8pk7r

if [[ -z "${hardeningEnableMap[fortify3]-}" ]]; then
unset -v "hardeningEnableMap['fortify']"
fi

if (( "${NIX_DEBUG:-0}" >= 1 )); then
declare -a allHardeningFlags=(fortify stackprotector pie pic strictoverflow format)
Copy link
Contributor

Choose a reason for hiding this comment

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

I wonder if we should add fortify3 flag here to avoid ignorance.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes probably I think the first time I scanned this I assumed it was another default setting, not just debugging output.

@risicle
Copy link
Contributor Author

risicle commented Feb 21, 2023

At this point I should probably reveal #217390 that I've been working on.

@risicle
Copy link
Contributor Author

risicle commented Feb 21, 2023

...however, I haven't had the resources & time lately to do the rebuild required to test this PR with those tests.

Comment on lines +22 to +24
if [[ -z "${hardeningEnableMap[fortify3]-}" ]]; then
unset -v "hardeningEnableMap['fortify']"
fi
Copy link
Contributor

Choose a reason for hiding this comment

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

If I read it correctly it unsets fortify if fortify3 is not present (i.e. always).

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Snap. See #217394

done

# make fortify and fortify3 mutually exclusive
if [[ -z "${hardeningEnableMap[fortify3]-}" ]]; then
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 think I've got the sense of this flipped. This should be -n shouldn't it?

@trofi
Copy link
Contributor

trofi commented Feb 21, 2023

Surprisingly samba also was broken by dropped fortify flag with very amusing linker failures. #217394 fixes samba as well.

trofi added a commit that referenced this pull request Feb 22, 2023
`-DFORTIFY_SOURCE=3` managed to expose stack overread problem as:
    #212498 (comment)

The change pull fix proposed upstream to avoid stack overread.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants