-
-
Notifications
You must be signed in to change notification settings - Fork 13.9k
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
[linux-hardened] RANDSTRUCT can't be enabled, issues with out of tree modules #53592
Comments
So as it turns out this is "by design": see the last few paragraphs in https://lwn.net/Articles/722293/ If we want to ship RANDSTRUCT in nixpkgs, we'll need to have a fixed seed for all nixpkgs users, which reduces the usefulness of RANDSTRUCT (it doesn't make it useless, since it still increases diversity and thus makes exploits harder to develop). NixOS could however allow users to define their own seed -- at the cost of not being able to use binary caches for kernel / module packages. It's not perfect -- if build machine == deployment machine the seed will be trivially readable in the Nix store, but the kernel itself is readable in the Nix store and I'm pretty sure from there one can recover the seed anyway. This still forces attackers to specifically target NixOS-hardened setups, which I imagine is a population below the caring threshold :-) Plan:
Not completely sure how to implement this just yet, just throwing it out here for potential feedback. |
Any mitigation strategy that relies on compile-time randomization is weakened/rendered useless by distributing the kernel binaries, even if the seed is not leaked directly, because you can see all the compile-time offsets & so on regardless of how they were determined (randomly or not). This is not specific to randstruct but affects e.g., KASLR which we also enable in the distro kernel. It seems to me that allowing the seed to vary between builds is somewhat stronger than using a fixed seed for all builds. A local seed is strongest, obviously, subject to the tradeoffs you've listed. |
Agreed. I'm planning to use something like |
I'd be happy to take anything that allows us to enable the feature and have out-of-tree modules work. That said, some half-baked ideas below.
I take it that the reason to index on the kernel version is to ensure that the value changes intermittently even with a fixed input seed? If so it seems like kernel version strings are too predictable to offer much improvement. Maybe the nixpkgs default could be derived from the nixpkgs revision (or maybe use that as the index). Hashing the input to get a predictably sized value seems like a good idea in any case. I suspect that for distro kernels it won't matter too much what we do for the seed. My inclination was to try to carry over the build-time random seed to the out-of-tree module build somehow. If carrying the seed forward works, then there'd be no reason to let the user override the seed as such because it'll be different every time a build runs (and would be shared by all the packages built as part of the Given that kernel packages are rebuilt more often than new kernel versions are released, the range should be a fair bit greater with build-time random values (assuming they don't know exactly which channel/rev you're running on), but I've no idea whether that translates to significant increase in dollar cost to carry out an exploit. It seems most prudent to just assume that compile-time randomization in distro kernels is trivially defeatible & focus on making the local build scenario as good as possible. For reproducibility, making the seed explicit/exogenous would be good, so that's something to consider & favours your approach over build-time randomization. EDIT: I should note that I have no particular expertise in crypto, so take all of the above with your preferred condiments, or disregard entirely. |
The seed is already being carried over:
The problem is that since it's being randomly generated during kernel build time, two kernels with the same derivation hash can end up with two different seeds. Not only is this fundamentaly broken, but that means that all out-of-tree module builds are then "contaminated" by the same non-reproducibility problem: two modules with the same derivation hash ended up being built with two different RANDSTRUCT seeds, causing them to be incompatible with other kernel builds. I think the only way this can be solved is by having a fixed seed part of the kernel derivation. I'm a complete Nix noob so I'd love to be proven wrong though! |
What I had in mind is that if the seed is captured when the kernel is initially built, all you should need to do is rig the out-of-tree kernel module build to use that captured seed. It should then not matter that the seed is recreated whenever a build of the kernel is triggered, as you presumably build all of |
I had really expected this to Just Work, so there may be a wrinkle in there that I've failed to consider. In any case, I think an externally provided seed is the way to go, even if it should be possible to fix the build process to work the way I've outlined. |
It also fails obviously if it is not the case that all of |
The seed could be (deterministically) derived from the store path of the kernel source (or some other kernel related derivation). This fulfills reproducibility and some amount of diversity. |
With #53802 merged, RANDSTRUCT is now re-enabled with a seed that's derived from kernel source + config file Nix store path. Let's see if it sticks this time :-) I'll repurpose this issue for the next step of the plan described earlier: making the seed user-configurable, and adding the required NixOS plumbing to allow users to set their own for their deployments. |
I've merged @delroth's patch. Thank you. |
We've had to disable the RANDSTRUCT kernel GCC plugin due to issues with out-of-tree modules. It seems like the RANDSTRUCT seed that gets picked is different for kernel builds vs. module builds, causing module loading to fail:
Filing this to track a fix so we can later on re-enable RANDSTRUCT.
The text was updated successfully, but these errors were encountered: