Git Product home page Git Product logo

lanzaboote's Introduction

Lanzaboote: Secure Boot for NixOS

Chat on Matrix GitHub branch checks state made-with-rust GitHub

This repository contains tooling for UEFI Secure Boot on NixOS. The goal is to make Secure Boot available from nixpkgs for any platform that supports UEFI.

⚡ Quickstart ⚡

If you want to try this out, head over here for instructions. In case of any issues, have a look at the troubleshooting document.

🪛 Get Involved 🪛

There is still a bunch of work to do before this work can be upstreamed into nixpkgs. Please coordinate in the Matrix room or check the issues, if you want to take something up.

Overview

Secure Boot

The goal of UEFI Secure Boot is to allow only trusted operating systems to boot on a system. This can be used to defend against certain classes of attacks that compromise the boot flow of a system. For example, an attacker will have difficulty replacing the Linux kernel that boots a system when Secure Boot is active.

UEFI Secure Boot works by digitally signing all drivers, bootloaders, the Linux kernel and its initrd. This establishes a chain of trust where one trusted component only hands off control to the next part of the boot flow when the integrity of the chain is cryptographically validated.

Caveats

There are some additional steps that are required to make UEFI Secure Boot effective:

  • There must be a BIOS password or a similar restriction that prevents unauthorized changes to the Secure Boot policy.
  • The booted system must have some form of integrity protection.
  • The firmware must be kept up-to-date.

These steps will not be covered here.

lzbt-*, the Lanzaboote tool

At the moment, boot loaders, kernels and initrds on NixOS are signed on the current system. These then need to be prepared as Unified Kernel Images (UKI) and placed on the EFI System Partition (ESP).

lzbt is a Linux command line application that takes care of this flow. It takes a NixOS bootspec document, signs the relevant files, creates a UKI using the stub (see below) and installs the UKI along with other required files to the ESP. lzbt is also aware of multiple NixOS generations and will sign all configurations that should be bootable.

We have multiple backends for lzbt:

In the future, lzbt may support more backends.

Shared code lives in rust/tool/shared.

Stub

When the Linux kernel and initrd are packed into a UKI, they need an UEFI application stub. This role is typically filled by systemd-stub.

The downside of systemd-stub is that it requires the kernel and initrd to be packed into the UKI, which makes it pretty large. As we need one UKI per NixOS configuration, systems with many configurations quickly run out of the limited disk space in the ESP.

The Lanzaboote stub is a UEFI stub that solves the same problem as systemd-stub, but allows kernel and initrd to be stored separately on the ESP. The chain of trust is maintained by validating the signature on the Linux kernel and embedding a cryptographic hash of the initrd into the signed UKI.

The stub is available in a "thin" and a "fat" variant. The "thin" variant is the one described above and is tailor made for NixOS. The "fat" variant aims to work exactly like the systemd-stub---in fact, it's supposed to eventually replace it. The "thin" variant is the default, you can build it from the stub directory with cargo build. The "fat" variant needs to be enabled at build time with cargo build --no-default-features --features fat.

The stub lives in rust/uefi/stub.

Fwupd

When both Lanzaboote and services.fwupd are enabled, for fwupd.service a preStart will be added that ensures a signed fwupd binary is placed in /run that fwupd will use.

State of Upstreaming to Nixpkgs

SecureBoot is available by adding this project to your configuration.

It relies on bootspec which is enabled by default since NixOS 23.05.

We are currently working on making Lanzaboote work out of the box in upstream Nixpkgs.

Funding

Logo of NLnet Foundation     Logo of NGI Assure

This project was funded through the NGI Assure Fund, a fund established by NLnet with financial support from the European Commission's Next Generation Internet programme, under the aegis of DG Communications Networks, Content and Technology under grant agreement No 957073. Applications are still open, you can apply today.

If your organization wants to support the project with extra funding in order to add support for more architectures, PKCS#11 workflows or integration, please contact one of the maintainers.

lanzaboote's People

Contributors

adtya avatar alois31 avatar blitz avatar dasj avatar dweee avatar ercao avatar erdnaxe avatar janik-haag avatar jappie3 avatar jh-devv avatar julienmalka avatar justinas avatar kanashimia avatar laurent2916 avatar lilyinstarlight avatar ma27 avatar mic92 avatar myaats avatar nikstur avatar phip1611 avatar raitobezarius avatar rbran avatar renovate[bot] avatar supersandro2000 avatar tilpner avatar tuxiqae avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

lanzaboote's Issues

"Built on" date always set to 1970-01-01

In both title and version for the boot entry, the "Built on" date is always set to 1970-01-01.

The below output is taken from bootctl status.

Default Boot Loader Entry:
         type: Boot Loader Specification Type #2 (.efi)
        title: NixOS Stoat 23.05.20230315.ac718d0 (Linux 6.2.6-zen1) (Generation 79, Built on 1970-01-01)
           id: nixos-generation-79.efi
       source: /boot/EFI/Linux/nixos-generation-79.efi
     sort-key: lanza
      version: Generation 79, Built on 1970-01-01
        linux: EFI/Linux/nixos-generation-79.efi
      options: init=/nix/store/apv56ilylfas2ilpcrjhg0116nk0w08x-nixos-system-Skipper-23.05.20230315.ac718d0/init

could the fs::metadata(path)?.mtime() in read_build_time return 0 for any reason?
I've checked the mtime on the generations files and they all have the correct mtime.

$ stat /nix/var/nix/profiles/system-79-link 
  File: /nix/var/nix/profiles/system-79-link -> /nix/store/apv56ilylfas2ilpcrjhg0116nk0w08x-nixos-system-Skipper-23.05.20230315.ac718d0
  Size: 87              Blocks: 8          IO Block: 4096   symbolic link
Device: 0,36    Inode: 5434462     Links: 1
Access: (0777/lrwxrwxrwx)  Uid: (    0/    root)   Gid: (    0/    root)
Access: 2023-03-19 13:22:53.467218885 +0530
Modify: 2023-03-19 13:22:53.400212392 +0530
Change: 2023-03-19 13:22:53.400212392 +0530
 Birth: 2023-03-19 13:22:53.400212392 +0530

Contributing guideline

We should create a contributing guideline. This should include our commit conventions (following nixpkgs) and a logging policy (as mentioned in #121). Ideally, we would have a CONTRIBUTING.md file that is linked from the README.

Desync between stub hashes and actual hashes due to non-reproducibility

Supposedly, given a (kernel, initrd), we generate a stub with the kernelh and initrdh corresponding.

The issue is that if we regenerate those files, if they are not reproducible, we have no guarantee the hash will be the same unfortunately.

We should try actively to detect those situations and update the stub hashes.

lanzaboote_tool fails to build on current unstable

error: builder for '/nix/store/nhhd04plbhyv6akld7banyhnh34rj3z0-lanzaboote_tool-0.1.0.drv' failed with exit code 101;
       last 10 log lines:
       > thread 'overwrite_unsigned_images' panicked at 'assertion failed: verify_signature(&image1)?', tests/install.rs:63:5
       > note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
       >
       >
       > failures:
       >     overwrite_unsigned_images
       >
       > test result: FAILED. 2 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.31s
       >
       > error: test failed, to rerun pass `--test install`

Remove hardcoding of the bootloader options

You should be able to configure systemd-boot options and maybe optionally ID=lanza tag.

I have arch installed with UKI and it always selected by default with this module, because of the alphabetical ordering.
To boot into the lastest nixos generation by default, you need to either modify ID to something lower than arch,
or you need to modify loader.conf, for example like this:

timeout 0
console-mode keep
default nixos-*

You can use globbing in the configuration, multiple entries are automatically ordered as described in the The Boot Loader Specification

Finish line tracker

  • Proper name of the stub per generation, so it gets sorted WELL
  • Proper name for the initrd & kernel
  • Bootspec for /boot/EFI/nixos place
  • Correct permissions for all files on ESP (a064f07)
  • Documentation on key rotation
  • Documentation on enrolling keys (simple scenarios)
  • Testing that initrd and kernel are signed (try to boot with an unsigned initrd or kernel and check that it fails): b46e05d
  • Changing asciiart to correctly display "lanzaboote" (54112e99e907c5b2a9aafa7b048994959a488af9)
  • Display nice error messages when a file is not signed
  • Management of "getting out of SB mode" and "re-entering SB mode" wrt to old generations and older loader files: #37
  • TPM event logging things & measurements in our stub
  • Sync the FAT32 writes
  • Specialisation is still working?
    • Recursive signing of the specialisations files with lanzatool through bootspec

Lanzatool doesn't sign kernel

I've just switched to boot.lanzaboote.enable = true; and noticed that the Linux kernel and systemd-boot did not get signed:

$ sudo nixos-rebuild -L boot --flake . --builders ""
building the system configuration...
trace: warning: RFC-0125 is not merged yet, this is a feature preview of bootspec.
        The schema is not definitive and features are not guaranteed to be stable until RFC-0125 is merged.
        See:
        - https://github.com/NixOS/nixpkgs/pull/172237 to track merge status in nixpkgs.
        - https://github.com/NixOS/rfcs/pull/125 to track RFC status.

Installing generation 353
Appending secrets to initrd...
/boot/EFI/BOOT/BOOTX64.EFI already exists, skipping...
/boot/EFI/systemd/systemd-bootx64.efi already exists, skipping...
/boot/EFI/nixos/0n01vj3mq06pc31i2yhxndvhv4kwl2vp-linux-6.1.3-bzImage.efi already exists, skipping...
/boot/EFI/nixos/lzxjx9ykfzhv5c2r4v36v2w7b69yrpc1-initrd-linux-6.1.3-initrd.efi already exists, skipping...
Signing and installing /boot/EFI/Linux/nixos-generation-353.efi...
Successfully installed lanzaboote to '/boot'
Installing generation 352
Appending secrets to initrd...
/boot/EFI/BOOT/BOOTX64.EFI already exists, skipping...
/boot/EFI/systemd/systemd-bootx64.efi already exists, skipping...
/boot/EFI/nixos/0n01vj3mq06pc31i2yhxndvhv4kwl2vp-linux-6.1.3-bzImage.efi already exists, skipping...
/boot/EFI/nixos/lzxjx9ykfzhv5c2r4v36v2w7b69yrpc1-initrd-linux-6.1.3-initrd.efi already exists, skipping...
Signing and installing /boot/EFI/Linux/nixos-generation-352.efi...
Successfully installed lanzaboote to '/boot'
'/boot/EFI/nixos/.extra-files' not in use anymore. Removing...
'/boot/EFI/Linux/nixos-generation-351.efi' not in use anymore. Removing...

$ sudo sbctl verify
Verifying file database and EFI images in /boot...
✗ /boot/EFI/BOOT/BOOTX64.EFI is not signed
✓ /boot/EFI/Linux/nixos-generation-352.efi is signed
✓ /boot/EFI/Linux/nixos-generation-353.efi is signed
✗ /boot/EFI/nixos/0n01vj3mq06pc31i2yhxndvhv4kwl2vp-linux-6.1.3-bzImage.efi is not signed
✗ /boot/EFI/systemd/systemd-bootx64.efi is not signed

lanzaboote_stub build fails with the latest nixos-unstable

nixpkgs commit: github:nixos/nixpkgs/a028e2873d7fcf44e66b784b4ba061824315537f.

Log message:

$ nix log /nix/store/ab31y6zi83zl1gjv8gwx942v187dcj9d-lanzaboote_stub-deps-0.1.0.drv
cargoArtifacts not set, will not reuse any cargo artifacts
@nix { "action": "setPhase", "phase": "unpackPhase" }
unpacking sources
unpacking source archive /nix/store/l8fgi4i99574nlmrgh56wcz89ydi44ip-source
source root is source
@nix { "action": "setPhase", "phase": "patchPhase" }
patching sources
Executing configureCargoCommonVars
@nix { "action": "setPhase", "phase": "configurePhase" }
configuring
will append /build/source/.cargo-home/config.toml with contents of /nix/store/a3022jf6iqc34rrn2grc8s1s5fr81qni-vendor-cargo-deps/config.toml
default configurePhase, nothing to do
@nix { "action": "setPhase", "phase": "buildPhase" }
building
++ command cargo --version
cargo 1.67.0-nightly (eb5d35917 2022-11-17)
++ command cargo check --profile release
   Compiling proc-macro2 v1.0.51
   Compiling quote v1.0.23
   Compiling unicode-ident v1.0.6
   Compiling syn v1.0.107
   Compiling version_check v0.9.4
   Compiling typenum v1.16.0
    Checking cfg-if v1.0.0
   Compiling log v0.4.17
    Checking bit_field v0.10.1
    Checking bitflags v1.3.2
   Compiling lanzaboote_stub v0.1.0 (/build/source)
    Checking plain v0.2.3
    Checking cpufeatures v0.2.5
    Checking ucs2 v0.3.2
   Compiling generic-array v0.14.6
    Checking crypto-common v0.1.6
    Checking block-buffer v0.10.3
    Checking digest v0.10.6
    Checking sha2 v0.10.6
   Compiling ptr_meta_derive v0.2.0
   Compiling scroll_derive v0.11.0
   Compiling uefi-macros v0.10.0
    Checking ptr_meta v0.2.0
    Checking uefi v0.19.1
    Checking scroll v0.11.0
    Checking goblin v0.6.1
    Checking uefi-services v0.16.0
    Finished release [optimized] target(s) in 7.95s
++ command cargo build --profile release
   Compiling cfg-if v1.0.0
   Compiling bit_field v0.10.1
   Compiling bitflags v1.3.2
   Compiling plain v0.2.3
   Compiling cpufeatures v0.2.5
   Compiling typenum v1.16.0
   Compiling ptr_meta v0.2.0
   Compiling scroll v0.11.0
   Compiling log v0.4.17
   Compiling ucs2 v0.3.2
   Compiling uefi v0.19.1
   Compiling goblin v0.6.1
   Compiling generic-array v0.14.6
   Compiling block-buffer v0.10.3
   Compiling crypto-common v0.1.6
   Compiling digest v0.10.6
   Compiling sha2 v0.10.6
   Compiling uefi-services v0.16.0
   Compiling lanzaboote_stub v0.1.0 (/build/source)
error: linking with `rust-lld` failed: exit status: 1
  |
  = note: "rust-lld" "-flavor" "link" "/NOLOGO" "/entry:efi_main" "/subsystem:efi_application" "/build/rustcGYQvD4/symbols.o" "/build/source/target/x86_64-unknown-uefi/release/deps/crane_dummy-f5ff7f1b0a877747.crane_dummy.5b3dabb0-cgu.0.rcgu.o" "/LIBPATH:/build/source/target/x86_64-unknown-uefi/release/deps" "/LIBPATH:/build/source/target/release/deps" "/LIBPATH:/nix/store/brn1yshckgwiaid1yx2kvslrkcgik7f5-rust-default-1.67.0-nightly-2022-11-21/lib/rustlib/x86_64-unknown-uefi/lib" "/nix/store/w2dcvszp75bxqcy8i1prfsc41xng221y-rust-std-1.67.0-nightly-2022-11-21-x86_64-unknown-uefi/lib/rustlib/x86_64-unknown-uefi/lib/libcompiler_builtins-bb944ea2862a44ff.rlib" "/NXCOMPAT" "/LIBPATH:/nix/store/brn1yshckgwiaid1yx2kvslrkcgik7f5-rust-default-1.67.0-nightly-2022-11-21/lib/rustlib/x86_64-unknown-uefi/lib" "/OUT:/build/source/target/x86_64-unknown-uefi/release/deps/crane_dummy-f5ff7f1b0a877747.efi" "/OPT:REF,ICF" "/DEBUG" "/NODEFAULTLIB"
  = note: rust-lld: error: <root>: undefined symbol: efi_main
          

error: could not compile `lanzaboote_stub` due to previous error

Atomic writes to ESP

All writes to the ESP should be atomic. This means specifically that files should first be written to the esp with a .tmp suffix and then moved to the actual file name (which is an atomic operation on POSIX).

Generation name in boot screen contains twice NixOS and kernel version

An systemd boot entry looks like: NixOS (Generation 85 NixOS 23.05, Linux Kernel 6.1.9, Built on 2023-02-08)
a lanzaboote one is a bit longer and contains redundant information: NixOS Stoat 23.05 (Linux 6.1.9) (Generation 85 NixOS 23.05), Linux Kernel 6.1.9, Built on 1970-01-01)

I don't mind the release name (Stoat), that is a nice feature we should maybe add to systemd-boot in nixos, too but the first Linux version can go. Maybe the first release number but not sure on that one.

Move the kernels somewhere else

Since we don't sign them anymore but still place them where sbctl expects them, they get marked as unsigned:

Verifying file database and EFI images in /boot...
✓ /boot/EFI/BOOT/BOOTX64.EFI is signed
✓ /boot/EFI/Linux/nixos-generation-553.efi is signed
✓ /boot/EFI/Linux/nixos-generation-554.efi is signed
✓ /boot/EFI/Linux/nixos-generation-555.efi is signed
✓ /boot/EFI/Linux/nixos-generation-556.efi is signed
✓ /boot/EFI/Linux/nixos-generation-557.efi is signed
✓ /boot/EFI/Linux/nixos-generation-558.efi is signed
✓ /boot/EFI/Linux/nixos-generation-559.efi is signed
✓ /boot/EFI/Linux/nixos-generation-560.efi is signed
✓ /boot/EFI/Linux/nixos-generation-561.efi is signed
✓ /boot/EFI/Linux/nixos-generation-562.efi is signed
✓ /boot/EFI/Linux/nixos-generation-563.efi is signed
✓ /boot/EFI/nixos/fwupdx64.efi is signed
✗ /boot/EFI/nixos/mh3za9ksj2lhpybfvv03ysxb5bwq7gv4-linux-5.15.93-bzImage.efi is not signed
✓ /boot/EFI/systemd/systemd-bootx64.efi is signed

We should probably put them where they don't get found by sbctl so users aren't alarmed by the red cross in their shells. (cc @blitz we talked about this)

Dependency Dashboard

This issue lists Renovate updates and detected dependencies. Read the Dependency Dashboard docs to learn more.

Open

These updates have all been created already. Click a checkbox below to force a retry/rebase of any.

Detected dependencies

cargo
rust/tool/shared/Cargo.toml
  • anyhow 1
  • serde_json 1
  • tempfile 3.10.1
  • bootspec 1
  • walkdir 2
  • time 0.3
  • sha2 0.10
  • fastrand 2.0.2
  • log 0.4
rust/tool/systemd/Cargo.toml
  • anyhow 1.0.82
  • base32ct 0.2.0
  • stderrlog 0.6.0
  • log 0.4.21
  • clap 4.5.4
  • indoc 2.0.5
  • serde_json 1.0.115
  • sha2 0.10.8
  • tempfile 3.10.1
  • nix 0.28.0
  • assert_cmd 2.0.14
  • expect-test 1.5.0
  • filetime 0.2.23
  • rand 0.8.5
  • walkdir 2.5.0
rust/uefi/linux-bootloader/Cargo.toml
  • uefi 0.27.0
  • bitflags 2.5.0
  • log 0.4.21
rust/uefi/pio/Cargo.toml
  • embedded-io 0.6.1
  • snafu 0.8.2
  • cpio 0.3.0
rust/uefi/stub/Cargo.toml
  • uefi 0.27.0
  • uefi-services 0.24.0
  • log 0.4.21
  • sha2 0.10.8
nix
flake.nix
  • nixpkgs nixos-unstable-small

  • Check this box to trigger a request for Renovate to run again on this repository

Support flicker-free boot

Pretty much boils down to just not touching the graphics at all.
When nobody draws over the BGRT (or draws things at all), plymouth should be able to pick the logo up up in initrd ;)

Ignore Hash Mismatches with Secure Boot Disabled

When lanzaboote doesn't find kernels/initrds that match its hashes, it will decline to boot them regardless of the Secure Boot setup. In combination with #56 and manually signing of initrds/kernels this can easily result in an unbootable system.

Lanzaboot should ignore hashes when Secure Boot is not enabled to give users a good recovery path that doesn't involve booting into a recovery system.

Improve subproject/crate naming

Lanzaboote is the name of the entire project, but also of the boot stub. I think we should find a better distinction.

I propose to rename the stub:

Rename the source code directory: rust/lanzaboote -> rust/stub
Rename crate in Cargo.toml: lanzaboote -> lanzaboote_stub

To make it even more streamlined we could also rename lanzatool

Rename the source code directory: rust/lanzatool -> rust/tool
Rename crate in Cargo.toml: lanzatool -> lanzaboote_tool
Use lzbt as the command name.

Can I automatically run systemd-cryptenroll after bootloader is updated?

I want to auto-unlock LUKS encrypted system drive only when the computer boots NixOS installed to an SSD. For that I need to run systemd-cryptenroll /dev/nvme0n1p1 --tpm2-device=auto --tpm2-pcrs=0+2+4+7 There appears to be no way to run custom commands when lanzaboote bootloader is installed:

installHook = pkgs.writeShellScript "bootinstall" ''
${optionalString cfg.enrollKeys ''
mkdir -p /tmp/pki
cp -r ${cfg.pkiBundle}/* /tmp/pki
${sbctlWithPki}/bin/sbctl enroll-keys --yes-this-might-brick-my-machine
''}
${cfg.package}/bin/lanzatool install \
--public-key ${cfg.publicKeyFile} \
--private-key ${cfg.privateKeyFile} \
--configuration-limit ${toString configurationLimit} \
${config.boot.loader.efi.efiSysMountPoint} \
/nix/var/nix/profiles/system-*-link
'';

Can we add custom command option to the module that runs only when bootloader is updated?

Plan for Shim integration

Some systems (e.g. as far as I can tell my new HP Spectre 360) do not allow for enrolling new keys, and so need to use something like https://github.com/rhboot/shim which a) has MS-signed binaries available (e.g. from Fedora/Ubuntu) and b) allows for user-controlled keys separate from the core firmware limitations.

From what I've gathered, this will require:

  1. Installing the signed stub as grubx64.efi next to the shim efi (yes, it must literally must have that name and filesystem location)
  2. Adding the signing keys to the shim database
  3. Teaching the stub to use the shim protocol for validating the image (See systemd/systemd#24574 for a somewhat related issue for systemd-boot).

See https://www.rodsbooks.com/efi-bootloaders/secureboot.html#shim for the best source of info I've found about shim.

Error during build: libgcc_s.so.1 -> not found!

I'm getting this error while trying to build lanzaboote. Any idea what is causing this?

❯ sudo nixos-rebuild switch --flake ~/dots
building the system configuration...
trace: warning: RFC-0125 is not merged yet, this is a feature preview of bootspec.
        The schema is not definitive and features are not guaranteed to be stable until RFC-0125 is merged.
        See:
        - https://github.com/NixOS/nixpkgs/pull/172237 to track merge status in nixpkgs.
        - https://github.com/NixOS/rfcs/pull/125 to track RFC status.

error: builder for '/nix/store/nm9zpk22770b94w8f5bmz60yp3azjql5-cargo-1.68.2-x86_64-unknown-linux-gnu.drv' failed with exit code 1;
       last 10 log lines:
       > searching for dependencies of /nix/store/4cphbbnm7rwm490vp2jvyzh7q3wgyi8q-cargo-1.68.2-x86_64-unknown-linux-gnu/libexec/cargo-credential-1password
       >     libgcc_s.so.1 -> not found!
       > auto-patchelf: 2 dependencies could not be satisfied
       > error: auto-patchelf could not satisfy dependency libgcc_s.so.1 wanted by /nix/store/4cphbbnm7rwm490vp2jvyzh7q3wgyi8q-cargo-1.68.2-x86_64-unknown-linux-gnu/bin/cargo
       > error: auto-patchelf could not satisfy dependency libgcc_s.so.1 wanted by /nix/store/4cphbbnm7rwm490vp2jvyzh7q3wgyi8q-cargo-1.68.2-x86_64-unknown-linux-gnu/libexec/cargo-credential-1password
       > auto-patchelf failed to find all the required dependencies.
       > Add the missing dependencies to --libs or use `--ignore-missing="foo.so.1 bar.so etc.so"`.
       > /nix/store/aa283g93zqf3111m66kawl6d5z3wlawd-stdenv-linux/setup: line 79: pop_var_context: head of shell_variables not a function context
       > /nix/store/aa283g93zqf3111m66kawl6d5z3wlawd-stdenv-linux/setup: line 1457: pop_var_context: head of shell_variables not a function context
       > /nix/store/aa283g93zqf3111m66kawl6d5z3wlawd-stdenv-linux/setup: line 1594: pop_var_context: head of shell_variables not a function context
       For full logs, run 'nix log /nix/store/nm9zpk22770b94w8f5bmz60yp3azjql5-cargo-1.68.2-x86_64-unknown-linux-gnu.drv'.
error: 1 dependencies of derivation '/nix/store/5fdy18sj8pb7yslwnwb8gz4y47nmm0f6-rust-default-1.68.2.drv' failed to build
error: 1 dependencies of derivation '/nix/store/yaka5xn8p6r3y1bgwnl9xk0x8g3czg5b-lanzaboote_stub-0.1.0.drv' failed to build
error: 1 dependencies of derivation '/nix/store/jfrqi3zb8s41sp5lrsvyh2lpms3dqw8n-lzbt.drv' failed to build
error: 1 dependencies of derivation '/nix/store/yz9ki1qgjiysb0lpxvg36fw0cxszbvhi-bootinstall.drv' failed to build
error (ignored): error: cannot unlink '/tmp/nix-build-linux-config-6.1.24.drv-1/linux-6.1.24/drivers/gpu/drm': Directory not empty
error: 1 dependencies of derivation '/nix/store/zv06nqdyad6rzkj6ngds1a78chqj8kcf-nixos-system-zoidberg-23.05.20230414.abe7316.drv' failed to build

Sign kernel modules and enable kernel lockdown

Once secureboot is enabled, it is possible to lock down the kernel, although module signing is disabled by default ( https://github.com/NixOS/nixpkgs/blob/nixos-22.11/pkgs/os-specific/linux/kernel/common-config.nix#L514-L517 ). Furthermore, it is possible to feed a custom key for signing the kernel and its modules ( https://www.kernel.org/doc/html/v4.15/admin-guide/module-signing.html ), which we could use the secureboot keys for. It would also allow for the signature of other kernel modules (e.g. virtualbox's kernel modules).

Isn't it insecure to store the key for signing bootloaders and kernels in unencrypted drive?

Docs doesn't mention anything about storing keys in an encrypted drive.

I believe that secure boot should always be used with full disk encryption, without that an attacker could read signing keys stored in the device, or store malicious programs to the system partition.

To protect the key and the certificate from such attack, users should either

  1. Password-protect system drive with LUKS
  2. Password-protect system drive with LUKS and run systemd-cryptenroll with --tpm2-pcrs=0+2+4+7 if you want to auto-unlock the drive (though you need to re-enter password everytime bootloader is updated, as I described in #61 (comment))

It might not be relevant if the drive is not removable and booting from other devices is not allowed, but most of the time that's not the case.

"No bootable" protection

In situations where lanzaboote find no generation to generate bootables for, we need to assert that we have still at least ONE bootable, otherwise, this is a fatal failure and can render systems unbootable.

This situation arised in our tests for specialisations because of "no readable bootspecs".

Manipulate efivars when installing via `lzbt`

We should manipulate the efivars when we install Lanzaboote to point the standard boot entry to the systemd-boot path. This should be implemented via a command line flag that is disabled by default. Otherwise Without being able to disable manipulating efivars, testing becomes annoying (i.e. our rust unit tests) and it also makes building disk images much harder.

Multiple profiles support

Finalizing Bootspec, we discovered that nixos-rebuild switch has support for different profiles (--profile-name flag), this is some form of switching-time "specialisation".
Currently, we collect all generations links through: /nix/var/nix/profiles/system-*-link, but that's wrong with respect to multiple profiles.

When you create a profile, you have a /nix/var/nix/profiles/system-profiles/<profile-name>-*.

Bootspec is also about handling "multiple profiles", apparently, systemd-boot and GRUB supports them, we do not.

Potential TOCTOU while reading stub data from filesystem rather than memory

To the best of my understanding, it was analyzed in #96 that lanzastub is reading the hashes/filenames from the filesystem, exposing lanzastub to a nasty time of check, time of use vulnerability where an attacker with a primitive that can modify the filesystem and suspend execution of lanzastub can race for changing hashes / filenames to load attacker-controlled files which will bypass SecureBoot model because lanzastub being already executed means that firmware has validated its signature and is allowed to do anything now.

The fix is quite easy: rather than reading from the filesystem, we should read our own binary memory and extract the relevant sections from there.

cc @blitz

Reported-By: @GovanifY

kexec is broken with lanzaboote

I am trying to reboot via kexec my computer using systemdctl kexec. This used to work just fine with normal nixos, but I am trying out lanzaboote (very cool btw :)) and it is not working at all anymore.

I now get this error.

Running /nix/store/pjp3v7ni274d1hh7cn4m5yhslgggzbrl-kexec-tools-2.0.25/bin/kexec --load "/boot/EFI/Linux/nixos-generation-294.efi" --append "init=/nix/store/h4mjlcgl479ll843nv43slmaqzr62wd8-nixos-system-poopbox-23.05.20230406.0e19daa/init loglevel=4"(null)
Cannot determine the file type of /boot/EFI/Linux/nixos-generation-294.efi
(kexec) failed with exit status 255.

Is there something I can do to fix this, or is kexec just something that is broken right now?

Bootloader configuration deleted

As we can see in https://bin.hubrecht.ovh/?b376f2a3f8e744c3#8hdQHWaR7zvZCtYikanp1CdTL16z5jgD6UBV6b4SECW4 , when we run nixos-rebuild switch with lanzaboote activated, it deletes almost all directories in /boot/EFI/, but the directory /boot/EFI/loader` is used to store the configuration of the bootloader, so it is erased at each rebuild. This is very annoying as when we use systemd-boot there is no longer a timeout and we cannot choose which generation we want to boot on.

bzImage.efi is not signed

I just installed lanzaboote, deleted everything in /boot, and then rebuilt and reinstalled the bootloader.

Unfortunately, sbctl verify prints ✗ /boot/EFI/nixos/3h0yzc1r0h8hf4a43lz5plfvvfmj9q3q-linux-6.1.6-bzImage.efi is not signed. I don't think this is #39, since I tried deleting everything in /boot twice and nix-collect-garbage -d, and the issue persists.

fwupd support

Probably a niche feature, but it'd be nice to have fwupd work out of the box.
It looks like all we have to do is make it sign its efi file source by doing:

and add the file to the EXTRA_SIGN list in /etc/sbupdate.conf.

Not 100% sure though, I haven't looked at this any further and I just did my updates before switching to lanzaboote ;)

XBOOTLDR support

As far as I can tell, there's no option to tell Lanzaboot to install the bootloader entries to /boot, with the bootloader itself residing on /efi.

This is necessary for systems that are dual-boot and have to deal with Windows anemic 512MB ESP.

This is something I implemented for systemd-boot in : NixOS/nixpkgs#226692

Don't use crane for production

crane builds each cargo dependency in multiple derivations. This adds over a 100 extra dependencies instead of one vendor directory. This usually slows things down quite a bite. For a release using nixpkgs tools is faster.

Ugly backtraces for non-bootspec generations

Lanzatool outputs some intimidating backtraces when it encounters non-bootspec generations. This should be handled more gracefully by having an actionable log messages. Something like "Failed to sign generation X, because it is not bootspec compliant."

Installing generation 351
Appending secrets to initrd...
/boot/EFI/BOOT/BOOTX64.EFI already exists, skipping...
/boot/EFI/systemd/systemd-bootx64.efi already exists, skipping...
/boot/EFI/nixos/0n01vj3mq06pc31i2yhxndvhv4kwl2vp-linux-6.1.3-bzImage.efi already exists, skipping...
/boot/EFI/nixos/lzxjx9ykfzhv5c2r4v36v2w7b69yrpc1-initrd-linux-6.1.3-initrd.efi already exists, skipping...
Signing and installing /boot/EFI/Linux/nixos-generation-351.efi...
Successfully installed lanzaboote to '/boot'
Malformed generation: Failed to build generation from link: GenerationLink { version: 350, path: "/nix/var/nix/profiles/system-350-link" }

Caused by:
    0: Failed to read bootspec file
    1: No such file or directory (os error 2)

Stack backtrace:
   0: anyhow::context::<impl anyhow::Context<T,E> for core::result::Result<T,E>>::context
   1: lanzatool::generation::Generation::from_link
   2: lanzatool::install::Installer::install
   3: lanzatool::cli::Cli::call
   4: lanzatool::main
   5: std::sys_common::backtrace::__rust_begin_short_backtrace
   6: std::rt::lang_start::{{closure}}
   7: std::rt::lang_start_internal
   8: main
   9: __libc_start_call_main
  10: __libc_start_main_alias_1
  11: _start
Malformed generation: Failed to build generation from link: GenerationLink { version: 349, path: "/nix/var/nix/profiles/system-349-link" }

Caused by:
    0: Failed to read bootspec file
    1: No such file or directory (os error 2)

Stack backtrace:
   0: anyhow::context::<impl anyhow::Context<T,E> for core::result::Result<T,E>>::context
   1: lanzatool::generation::Generation::from_link
   2: lanzatool::install::Installer::install
   3: lanzatool::cli::Cli::call
   4: lanzatool::main
   5: std::sys_common::backtrace::__rust_begin_short_backtrace
   6: std::rt::lang_start::{{closure}}
   7: std::rt::lang_start_internal
   8: main
   9: __libc_start_call_main
  10: __libc_start_main_alias_1
  11: _start
'/boot/EFI/nixos/qalw2n6bvbsbvrhz9q9ax82fzxg5xhj0-linux-6.1.2-bzImage.efi' not in use anymore. Removing...
'/boot/EFI/nixos/81r7ygqb3hrzvhqgp0wzm1zmvhj1pzvf-initrd-linux-6.1.2-initrd.efi' not in use anymore. Removing...
'/boot/EFI/nixos/.extra-files' not in use anymore. Removing...

systemd-stub feature parity

We would like to have similar design and features as systemd-stub, ideally, lanzastub should be a drop-in replacement tailored for NixOS:

Random seed

  • Support

SMBIOS

  • Load command line via SMBIOS

Addons support

  • Load command line addons

Sections in the stub

  • DTB support
  • Bootsplash support
  • Expected TPM2 PCR signatures
  • TPM2 PCR public key support

Companion files

  • Local credentials files specific to that generation
  • System extensions images
  • Global credentials

EFI variables passed to the OS

  • LoaderDevicePartUUID
  • LoaderFirmwareInfo
  • LoaderFirmwareType
  • LoaderImageIdentifier
  • StubInfo
  • StubFeatures
  • StubPcrKernelImage
  • StubPcrKernelParameters
  • StubPcrInitRDSysExts

Support systemd-boot random seed

Thanks for your work on this amazing project.

I've just successfully setup lanzaboote and enabled random seed using bootctl. After a reboot i noticed that random seed exists but isn't passed to the OS.

Random Seed:
 Passed to OS: no
 System Token: set
       Exists: yes

Write loader.conf when installing

lzbtneeds to write a loader.conf to the ESP so systemd-boot (e.g. the timeout) can be configured by the user via the usual (and expected) mechanisms.

Do a sub-0.1 release

We should definitely do a sub-0.1 release now and then, and keep some kind of release process until 1.0 (#9).

Informative logging for malformed generations

Currently, we lost the ability to tell the users about anomalous situations (malformed generations) in info-level logging (the default).

It would be helpful to devise strategies to tell the users in an helpful way about potential problems and offers potential solutions.

Signed kernel can load unprotected initrd

As far as I understand, lanzaboote aims to protect the known kernel+initrd combinations using a signature on the stub UKI containing their hashes.

However, it also signs the kernel (presumably so that LoadImage works). Thus, it is possible to instruct systemd-boot to boot a Linux kernel directly, pointing it to an unprotected initrd.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.