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

kernel: enable module signing #87426

Closed
wants to merge 8 commits into from
Closed

Conversation

eadwu
Copy link
Member

@eadwu eadwu commented May 9, 2020

This suffers from the same pitfalls as #86835, if the kernel needs to be rebuilt twice, the generated certificate will be wrong and thus the module is unable to be loaded due to the invalid certificate.

Though with the flawed approach to force the kernel to be the same, I included an example to show it works (zfs).

Motivation for this change

If lockdown is enabled, or module signatures are forced, unsigned modules are unable to be loaded.

Things done
  • Tested using sandboxing (nix.useSandbox on NixOS, or option sandbox in nix.conf on non-NixOS linux)
  • Built on platform(s)
    • NixOS
    • macOS
    • other Linux distributions
  • Tested via one or more NixOS test(s) if existing and applicable for the change (look inside nixos/tests)
  • Tested compilation of all pkgs that depend on this change using nix-shell -p nixpkgs-review --run "nixpkgs-review wip"
  • Tested execution of all binary files (usually in ./result/bin/)
  • Determined the impact on package closure size (by running nix path-info -S before and after)
  • Ensured that relevant documentation is up to date
  • Fits CONTRIBUTING.md.

autoModuleSignHook = kernel: makeSetupHook
{ substitutions =
{ kernel = kernel.dev + "/lib/modules/${kernel.modDirVersion}/build";
hash = if (kernel.configfile.structuredConfig ? MODULE_SIG_HASH)
Copy link
Member Author

Choose a reason for hiding this comment

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

Another shortcoming, due to differing hash algos, we need to specify a default or read it in from the output config.

cp $buildRoot/$f $dev/lib/modules/${modDirVersion}/build/certs
fi
done

Copy link
Member

Choose a reason for hiding this comment

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

With the private signing key in the store, wouldn't this allow anyone on the system to sign arbitrary modules?

Copy link
Member Author

Choose a reason for hiding this comment

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

I thought it wouldn't be as much of a problem as the certs are generated on every kernel build since we don't supply one by default.

I also assumed that derivations in /nix/store wouldn't be writable by other things (if that's compromised I don't think anything I could do would be much better).

Copy link
Member

Choose a reason for hiding this comment

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

I'm not sure I understand? As long as the key is in the store, you can just take it and sign an arbitrary module with it, without ever needing to touch anything else in the nix store, right?

Copy link
Member Author

@eadwu eadwu May 15, 2020

Choose a reason for hiding this comment

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

For my specific use case for this PR, it's to modprobe out of tree modules doing the boot phase. The only modules in the initrd are the result of a nix derivation so I'd expect that nothing would be compromised there.

I'm not sure if you can modprobe modules that aren't in the nix store, but if you can, then yeah, that would be a problem.

If it's just the act of signing arbitrary modules, then if the above isn't possible, then it shouldn't really matter, since if you can't use it, it doesn't make a difference?

Copy link
Member

Choose a reason for hiding this comment

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

I think you can load a module from anywhere if it's binary-compatible with your kernel.

Let's imagine the scenario: I somehow gained access to the insmod command (it loads a kernel module from a file and is a low-level interface to module loading facilities) and able to pass it any path (incorrect SUID configuration on a vulnerable program?). I could craft a kernel module for the same kernel you use (and I could make a reasonable guess by comparing the hashes, if you use a standard Nixpkgs kernel) and then inject it into the kernel.

If the private keys for signing kernel modules are in the /nix/store, I could try to exfiltrate them using the hashes to find the kernel directory (or just by using /run/booted-system?) and sign the module with them. Bam, I have kernel-level access.

Copy link
Member

Choose a reason for hiding this comment

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

One use-case I could imagine would be the builder nix store being kept secret (e.g. separate, access-restriced machine).

Without access to that, the security would hold on the target machine.

@eadwu
Copy link
Member Author

eadwu commented May 15, 2020

Depends on #87856 for certain scenarios.

@vikanezrimaya
Copy link
Member

vikanezrimaya commented Nov 11, 2020

Can one sign modules after-the-fact with a key and make the kernel recognize it without rebuilding? While I understand signing modules after building would hurt binary reproducibility of derivations including kernel modules (will it? I've heard signatures can be stripped easily if needed or even accidentally) it would allow the private keys to be outside of /nix/store.

@Atemu
Copy link
Member

Atemu commented Jan 11, 2021

I also think signing modules and baking the key into the kernel after the fact would be the better approach.

It'd probably be best to do that outside a Nix drv honestly; a script that signs modules on nixos-rebuild switch could use any form of authentication you could want (e.g. private key inside a hardware token) and the kernel + modules need to be touched at that moment anyways.

@ofborg ofborg bot requested a review from andresilva January 11, 2021 19:42
@eadwu
Copy link
Member Author

eadwu commented Jan 11, 2021

It is probably possible to inject the key afterwards, but I'm not sure how much effort it would require nor am I exactly really keen on doing so right now. This was just simple POC-ish thing that would allow booting (with external modules) to work with lockdown

If I recall correctly, the signature is just appended to the module (I think, I'm not sure, don't really remember), in which case yes, it will be easy to strip the signature afterwards.

Probably the way to go if we go this route is to let the kernel generate a key and sign its modules (with MODULE_SIG and whatnot config options), before stripping the signatures and public key in the fixupPhase, before doing some brittle monkey patching on the kernel (a good idea?) and resigning the modules, though it probably will result in an extra kernel and kernel-modules derivation in the store.

@vikanezrimaya
Copy link
Member

I feel like whatever would be going on with keys and signing better happen out of my Nix store, preferably in the bootloader integration phase in the switching. It will make nixos-rebuild boot a little bit longer but a lot more secure.

I wish we could sign kernels for Secure Boot in a similar way... I've been thinking about doing it with a modified systemd-boot module, but my laptop turned out to have a glitchy UEFI and now I can't boot NixOS automatically, the UEFI entries just refuse to be modified.

@stale
Copy link

stale bot commented Sep 3, 2021

I marked this as stale due to inactivity. → More info

@stale stale bot added the 2.status: stale https://github.com/NixOS/nixpkgs/blob/master/.github/STALE-BOT.md label Sep 3, 2021
@eadwu
Copy link
Member Author

eadwu commented Sep 3, 2021

Closing for now ... I'll see how this ends up going if I have time in between university and 2 research groups ...

@stale stale bot removed the 2.status: stale https://github.com/NixOS/nixpkgs/blob/master/.github/STALE-BOT.md label Sep 3, 2021
@eadwu eadwu closed this Sep 3, 2021
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.

None yet

5 participants