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: fix #18995 #28029
hardening: fix #18995 #28029
Conversation
How is all handled now? (Granted looking on phone.) CC @orivej |
Nevermind did not scroll down enough. I like this: Nix > bash. |
pkgs/stdenv/generic/setup.sh
Outdated
@@ -3,6 +3,9 @@ set -o pipefail | |||
|
|||
: ${outputs:=out} | |||
|
|||
# If unset, assume the default hardening flags. | |||
: ${NIX_HARDENING_ENABLE="fortify stackprotector pic strictoverflow format relro bindnow"} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It seems that =
instead of :=
works, but is it documented?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah. Per the docs:
When not performing substring expansion, using the form described below (e.g., ‘:-’), Bash tests for a parameter that is unset or null. Omitting the colon results in a test only for a parameter that is unset. Put another way, if the colon is included, the operator tests for both parameter’s existence and that its value is not null; if the colon is omitted, the operator tests only for existence.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Interesting, this means we can write e.g. ${NIX_STORE-}
instead of ${NIX_STORE:-}
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Perhaps this should go in the setup-hook for cc-wrapper? setup.sh
isn't exactly a paragon of clean layering, but I wouldn't want to make it worse.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I could do that; do I then need to do something similar for bintools, though?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah if we go with two separate env vars, then it is not a problem.
|
||
hardeningEnable = | ||
let val = attrs.hardeningEnable or [ ]; | ||
in if builtins.isList val then val else [ val ]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is implemented in lib.toList
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice find, thanks! I'll make that change shortly-ish.
Why do you move hardening args before command line args, now that hardening is not enabled outside nix-build environment? AFAIK programs often overspecify |
Please don't merge yet, I want to go through this thoroughly and test if this still applies the hardening correctly (maybe add a checksecPhase using |
Assuming I interpreted the statements in #18995 correctly, some people were complaining about As you point out, though, that does mean that the hardening would silently not apply if e.g. a Makefile sets I think I'll make that change soonish (hopefully several people can approve of and validate that idea). And thanks for reviewing this :) |
I tried pretty hard to keep the behavior of
should behave as before: add If there are any deviations that I'm missing, please do point them out. |
/cc @Ralith |
@@ -107,6 +123,8 @@ rec { | |||
++ optional (elem "host" configurePlatforms) "--host=${stdenv.hostPlatform.config}" | |||
++ optional (elem "target" configurePlatforms) "--target=${stdenv.targetPlatform.config}"; | |||
|
|||
} // lib.optionalAttrs (hardeningDisable != [] || hardeningEnable != []) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
IIRC doing this sort of stuff on the Nix level is somewhat discouraged since it slows down evaluation of Nixpkgs.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Well, more bash causes other problems too. I don't think its so clear cut.
Does this change actually do that? I thought everyone was pretty much in agreement that
Almost every single person who wants to do C/C++ development with Nix will (continue to) be badly bitten if you leave things the way they currently are in master and have been historically, user guide or no. Completely and silently breaking debug info unless you set an esoteric configuration flag that nobody outside of Nix has any context for is an incredibly bad user experience. If packages are broken, fix the packages. I'm not even convinced there's a significant proportion of packages that have -O0 or -O1 hardcoded in their release builds in the first place without a good reason (or at all, for that matter), and when there is a good reason, silently clobbering it represents a frustrating landmine for packagers. To be very clear, this goes for both |
This change lets standalone Could you clarify how you build packages and their dependencies with debug info? Do you add |
I'm not sure who's making non-trivial use of gcc outside of a
When I'm working in |
@Ralith This continues to provide hardening support for both nix-build nix-shell. Outside of either of those two, NIX_HARDENING_ENABLE env var won't be set, and thus system-wide gcc will no longer default to enabling hardening. Regarding optimization and debug builds: I only see three options:
At the present moment, this implements number 1, though as noted earlier I'm interested in moving to either of the latter two options. |
Right, but a system-wide gcc isn't very useful to anyone regardless.
Option 2 is what Nix has without this PR, and is why there is a long string of confused and unhappy developers in #18995, plus however many more who never managed to find the issue. It makes Nix hostile to developers who aren't already aware of the problem, and cost me personally a considerable amount of time, very nearly driving me to abandon Nix before I determined the cause. 3 would be tolerable; it's weird and nonstandard but you can't miss it, so it won't waste peoples' time the way 2 does, assuming the message is clear enough. It'd also make packages with broken builds obvious, which would clarify how common a problem that is. |
I think the point is that plain GCC provided by Nix should behave like any other GCC on any other distro. Injecting hardening flags is something that should be provided by the build environment, as environment variables or explicit command line options to the compiler. |
I don't think using gcc outside of a Nix build environment is a very important case, frankly. I'm happy to see it no longer be affected by the issue, but that doesn't make the issue any less serious for the case I actually use. |
As far as I'm concerned, the only thing this is waiting on is a decision on how to handle user supplied |
I don't know yet how I feel about this, but this popped into my head I figured I'd share it before I forget: I wonder if it might make sense to print the enabled hardening flags when first starting a |
|
||
# Intentionally word-split in case 'hardeningDisable' is defined in Nix. The | ||
# Create table of unsupported flags for this toolchain. | ||
for flag in @hardening_unsupported_flags@; do |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we still need the disabled map if mkDerivation
converts everything to a whitelist? I rather have this filter the whitelist.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm, upon further reading, maybe something like:
if [[ -n "$NIX_DEBUG" ]]; then
declare -A hardeningDisableMap=()
fi
for flag in @hardening_unsupported_flags@; do
[[ -n ${hardeningEnableMap[$flag]} ]] || continue
if [[ -n "$NIX_DEBUG" ]]; then
hardeningEnableMap[$flag]=1
fi
unset hardeningEnableMap[$flag]
done
if [[ -n "$NIX_DEBUG" ]]; then
// print disabled flags as before
fi
Then it is clear that all the logic follows from the whitelist, and the disable map is only used for debugging.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sounds good, will do 👍
for flag in ${hardeningDisable[@]} @hardening_unsupported_flags@ | ||
do | ||
hardeningDisableMap[$flag]=1 | ||
for flag in ${NIX_HARDENING_ENABLE-}; do |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could we do NIX_CC_WRAPPER_@infixSalt@_HARDENING_ENABLE
? For the sake of clean laying I've wanted to use the NIX_CC_WRAPPER
prefix instead, so might as well start with a new environment variable. add-flags.sh
can take care of dealing with the @infixSalt@
part; it should be fairly easy to cargo cult.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What is infixSalt
? I've never seen it before, but all of a sudden Nixpkgs has dozens of references to it...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@edolstra it's so we can have multiple cc-wrappers that don't conflict for cross compilation. I left a bunch of comments in https://github.com/NixOS/nixpkgs/blob/master/pkgs/build-support/cc-wrapper/setup-hook.sh and https://github.com/NixOS/nixpkgs/blob/master/pkgs/build-support/cc-wrapper/add-flags.sh
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Will do.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@Ericson2314 This still needs to be changed to NIX_@infixSalt@_HARDENING_ENABLE
(under the assumption that we'll stick to the old name for now, rather than NIX_CC_WRAPPER_HARDENING_ENABLE
), right?
I must confess that I haven't found the time to learn how your cross compiling changes work, though I hope to soon-ish. Of course "soon" for me probably translates to "in a couple eons" for most people, given my schedule as of late...
As far as #28029 (comment) goes, I'm also in favor of either solution 1 or 3. I'd say that if the breakage in |
@@ -107,6 +119,8 @@ rec { | |||
++ optional (elem "host" configurePlatforms) "--host=${stdenv.hostPlatform.config}" | |||
++ optional (elem "target" configurePlatforms) "--target=${stdenv.targetPlatform.config}"; | |||
|
|||
} // lib.optionalAttrs (hardeningDisable != [] || hardeningEnable != []) { | |||
NIX_HARDENING_ENABLE = enabledHardeningOptions; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@Ericson2314 Regarding your comment regarding NIX_CC_WRAPPER_@infixSalt@_HARDENING_ENABLE
, what's the appropriate thing to do here? Should I mostly leave this alone (the only change, perhaps, being a rename to NIX_CC_WRAPPER_HARDENING_ENABLE
), and then have (per another one of your recommendations) the setupHook for the CC-wrapper use the $NIX_CC_WRAPPER_HARDENING_ENABLE
when $NIX_CC_WRAPPER_@infixSalt@_HARDENING_ENABLE
isn't defined? Curious what the exact logic should be here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
- https://github.com/NixOS/nixpkgs/blob/master/pkgs/build-support/cc-wrapper/add-flags.sh#L7-L13 in there goes
NIX_CC_WRAPPER+HARDENING_ENABLE
. - this line becomes
NIX_CC_WRAPPER_HARDENING_ENABLE ..
Now that there's a bintools wrapper too, we would have to do an analogous thing there with this plan. So OTOH if we want just one variable with both, then maybe we shouldn't add the _CC_WRAPPER
to the name. But, no matter what we still want to do the infix salt.
Okay, after some more investigation this is not as scary as I though. I mixed up i686 and x86_64 evaluations a bit, so
pkgs/development/libraries/a52dec/default.nix
only needs
```
hardeningDisable = stdenv.lib.optional stdenv.isi686 "pic";
# with the above removed
# doCheck fails 1 out of 1 tests with "BAD GLOBAL SYMBOLS"
```
to pass (and that's likely a bug in the tests themselves) and ilmbase seems to be broken on i686 (which is kinda scary since wine depends on it), but it's not hardenings' fault.
It is still the case that many packages broke with `-Wformat-security`, but I got sweating here thinking that format hardening could make a difference in tests. But it does not. Good.
Then, I think, this PR needs no follow-ups in that regard.
|
Please investigate this further as staging has been blocked now for over a month. |
Bad combination of flags, somehow? |
GHC is not the only package that has this issue. I have a whole bunch of fixes for exactly that error message. Will PR in the next couple of days.
|
@@ -57,8 +57,8 @@ fi | |||
|
|||
source @out@/nix-support/add-hardening.sh | |||
|
|||
extraAfter=("${hardeningLDFlags[@]}") | |||
extraBefore=() | |||
extraAfter=() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sounds good.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I really need to go to sleep so feel free to try it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can the hardening flags be injected at the start instead of the end? I'd hate to see us reintroduce the problems that prompted this PR in the first place.
Hardening currently triggers warnings, and warnings cause the build to fail. So we hardcode `-w` in the CPP options.
Can we please revert this on master until the many broken packages are fixed on staging? |
I fixed everything I know of on master #41192 |
It moved our -O2 before their -O3, but -O3 inlines "checkValueVecEqual(&,&)" into "checkValueVecEqual(*,*)".
* master: (30 commits) bitlbee: fix build git: 2.17.0 -> 2.17.1 sc-controller: 0.4.2 -> 0.4.3 zeroc-ice: fix parallel building pythonPackages.bsddb3: fix build after 0fd461d haskellPackages.hlibgit2: fix build after #28029 gdk-pixbuf: patch library rpath references on darwin virtualbox: fix build after #28029 GHCJS darwin fixes (#41120) neovim-remote: 1.8.6 -> 2.0.5 messenger-for-desktop: remove (#41224) typora: gnome2 cleanup (#41167) discord: gnome2 cleanup (#41174) skypeforlinux: gnome2 cleanup (#41176) wire-desktop: gnome2 cleanup (#41155) hyper: gnome2 cleanup (#41170) drone: 0.5 -> 0.8.5 (#41200) racket: use proper uname, allow for unix sockets kytea: fix build after #28029 yoda: fix build after #28029 ...
The breakage is mostly, if not entirely, due to the change in the order in which the flags are inserted. If the breakage is too great to keep things as they are now, I would recommend committing the couple line diff needed to revert just that part of this change set. That would retain 99% of the benefits while fixing any currently broken packages. |
When -O2 from hardening does not redefine -O3 from CMake, the build fails with: src/qpid/broker/SelectorExpression.cpp: In member function ‘qpid::broker::Expression* qpid::broker::Parse::orExpression(qpid::broker::Tokeniser&)’: src/qpid/broker/SelectorExpression.cpp:1041:13: error: ‘*((void*)& s +17)’ may be used uninitialized in this function [-Werror=maybe-uninitialized] if (s[1]=='b' || s[1]=='B') {
After #28029 it is necessary to add "strictoverflow" to the disabled hardening flags. That probably has something to do with the `-O3` option in palps makefile. This commit also adds a test to check for this regression (as it only occured at runtime).
Motivation for this change
This should (hopefully) fix #18995.
This moves
hardeningLDFlags
toextraBefore
, so e.g. user supplied-O
flags should take precedence over the hardening flags. (EDIT: I'm actually not sure how I feel about this; see commentary below)Also, this changes the wrappers such that they now expect a whitelist of hardening flags, instead of (predominately) expecting a blacklist. Instead of taking
$hardeningEnable
and$hardeningDisable
from the environment, they now use$NIX_HARDENING_ENABLE
instead. If the user has sethardeningEnable
and orhardeningDisable
in a call tomkDerivation
, we pass along the appropriateNIX_HARDENING_ENABLE
.stdenv/setup.sh
now sets$NIX_HARDENING_ENABLE
to the default enabled hardening flags if the variable is unset.This latter change is desirable for a couple reasons:
NIX_
;hardening{Enable,Disable}
are the exceptions.gcc
et al are installed system-wide, most users don't realize that they have to explicitely opt out of hardening, which results in plenty of confusion and time lost trying to figure out why/when things are mysteriously broken.This should provide the same behavior as before, aside from fixing the unintuitive bits mentioned above.
Note that I left a bit of
add-hardening.sh
oddly indented; I wanted to keep the diff readable during review. I'll fix the indentation before we merge.If it makes sense, I can move the derivation of
$NIX_HARDENING_ENABLE
from Nix tostdenv/setup.sh
, so that settinghardening{Enable,Disable}
from Nix in a regular oldderivation
will work just as well as frommkDerivation
(right now, that'll only happen for the latter). Please let me know how feel about this, either way.Feel free to ask me any questions, or point out any concerns.
I'm still testing this at the moment.This now works as described. See comments below for any open questions.Things done
Please check what applies. Note that these are not hard requirements but merely serve as information for reviewers.
(nix.useSandbox on NixOS,
or option
build-use-sandbox
innix.conf
on non-NixOS)
nix-shell -p nox --run "nox-review wip"
./result/bin/
)