From 95f596f4dcb53f87e9e5f31d9efc3ffee388bcc5 Mon Sep 17 00:00:00 2001 From: Ryan Lahfa Date: Sat, 26 Nov 2022 03:14:21 +0100 Subject: [PATCH] =?UTF-8?q?lanzatool:=20add=20support=20for=20generations?= =?UTF-8?q?=20and=20correct=20naming=20of=20kernels=20a=E2=80=A6=20(#12)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * lanzatool: add support for generations and correct naming of kerels and initrds * test: use convert_to_esp(extract_bspec_attr(⋅)) for unsigned tests * lanzatool: ryan is a B class engineer Co-authored-by: nikstur@outlook.com --- flake.nix | 5 ++- nix/lanzaboote.nix | 2 +- rust/lanzatool/src/cli.rs | 10 ++++-- rust/lanzatool/src/esp.rs | 39 +++++++++++++++++++---- rust/lanzatool/src/install.rs | 58 +++++++++++++++++++++++++++++++++-- 5 files changed, 100 insertions(+), 14 deletions(-) diff --git a/flake.nix b/flake.nix index 95b1967..3edf51f 100644 --- a/flake.nix +++ b/flake.nix @@ -139,7 +139,6 @@ machine.start() bootspec = json.loads(machine.succeed("cat /run/current-system/bootspec/boot.v1.json")) - print(machine.succeed("ls /boot/EFI/nixos")) src_path = ${path.src} dst_path = ${path.dst} machine.succeed(f"cp -rf {src_path} {dst_path}") @@ -187,14 +186,14 @@ name = "unsigned-initrd-do-not-boot-under-secureboot"; path = { src = "extract_bspec_attr('initrd')"; - dst = "\"/boot/EFI/nixos/initrd\""; + dst = "convert_to_esp(extract_bspec_attr('initrd'))"; }; }; is-kernel-secured = mkUnsignedTest { name = "unsigned-kernel-do-not-boot-under-secureboot"; path = { src = "extract_bspec_attr('kernel')"; - dst = "\"/boot/EFI/nixos/kernel\""; + dst = "convert_to_esp(extract_bspec_attr('kernel'))"; }; }; diff --git a/nix/lanzaboote.nix b/nix/lanzaboote.nix index 0bf9b75..791ffa9 100644 --- a/nix/lanzaboote.nix +++ b/nix/lanzaboote.nix @@ -45,7 +45,7 @@ in cp -r ${cfg.pkiBundle}/* /tmp/pki ${sbctlWithPki}/bin/sbctl enroll-keys --yes-this-might-brick-my-machine ''} - ${cfg.package}/bin/lanzatool install --pki-bundle ${cfg.pkiBundle} --public-key ${cfg.publicKeyFile} --private-key ${cfg.privateKeyFile} "$@" + ${cfg.package}/bin/lanzatool install --pki-bundle ${cfg.pkiBundle} --public-key ${cfg.publicKeyFile} --private-key ${cfg.privateKeyFile} "$@" /nix/var/nix/profiles/system-*-link ''}/bin/bootinstall"; # ${cfg.package}/bin/lanzatool install ${optionalString cfg.enrollKeys "--auto-enroll"} --pki-bundle ${cfg.pkiBundle} }; diff --git a/rust/lanzatool/src/cli.rs b/rust/lanzatool/src/cli.rs index 9c56cff..8164fa8 100644 --- a/rust/lanzatool/src/cli.rs +++ b/rust/lanzatool/src/cli.rs @@ -32,6 +32,8 @@ pub enum Commands { auto_enroll: bool, bootspec: PathBuf, + + generations: Vec, }, } @@ -50,12 +52,14 @@ impl Commands { pki_bundle, auto_enroll, bootspec, + generations, } => install( &public_key, &private_key, - pki_bundle, + &pki_bundle, auto_enroll, &bootspec, + generations, ), } } @@ -64,9 +68,10 @@ impl Commands { fn install( public_key: &Path, private_key: &Path, - pki_bundle: Option, + pki_bundle: &Option, auto_enroll: bool, bootspec: &Path, + generations: Vec, ) -> Result<()> { let lanzaboote_stub = std::env::var("LANZABOOTE_STUB").context("Failed to read LANZABOOTE_STUB env variable")?; @@ -79,6 +84,7 @@ fn install( pki_bundle, auto_enroll, bootspec, + generations, Path::new(&lanzaboote_stub), Path::new(&initrd_stub), ) diff --git a/rust/lanzatool/src/esp.rs b/rust/lanzatool/src/esp.rs index 853cc6c..8bd76d4 100644 --- a/rust/lanzatool/src/esp.rs +++ b/rust/lanzatool/src/esp.rs @@ -1,5 +1,8 @@ +use anyhow::{Context, Result}; use std::path::{Path, PathBuf}; +use crate::bootspec::Bootspec; + pub struct EspPaths { pub esp: PathBuf, pub nixos: PathBuf, @@ -14,24 +17,48 @@ pub struct EspPaths { } impl EspPaths { - pub fn new(esp: &str) -> Self { + pub fn new(esp: &str, generation: u64, bootspec: &Bootspec) -> Result { let esp = Path::new(esp); let esp_nixos = esp.join("EFI/nixos"); let esp_linux = esp.join("EFI/Linux"); let esp_systemd = esp.join("EFI/systemd"); let esp_efi_fallback_dir = esp.join("EFI/BOOT"); - Self { + Ok(Self { esp: esp.to_owned(), nixos: esp_nixos.clone(), - kernel: esp_nixos.join("kernel"), - initrd: esp_nixos.join("initrd"), + kernel: esp_nixos.join(nixos_path(&bootspec.kernel, "bzImage")?), + initrd: esp_nixos.join(nixos_path(&bootspec.initrd, "initrd")?), linux: esp_linux.clone(), - lanzaboote_image: esp_linux.join("lanzaboote-image.efi"), + lanzaboote_image: esp_linux.join(generation_path(generation)), efi_fallback_dir: esp_efi_fallback_dir.clone(), efi_fallback: esp_efi_fallback_dir.join("BOOTX64.EFI"), systemd: esp_systemd.clone(), systemd_boot: esp_systemd.join("systemd-bootx64.efi"), - } + }) } } + +fn nixos_path(path: impl AsRef, name: &str) -> Result { + let resolved = path.as_ref().read_link().unwrap_or(path.as_ref().into()); + + let parent = resolved.parent().ok_or(anyhow::anyhow!(format!( + "Path: {} does not have a parent", + resolved.display() + )))?; + + let without_store = parent.strip_prefix("/nix/store").with_context(|| { + format!( + "Failed to strip /nix/store from path {}", + path.as_ref().display() + ) + })?; + + let nixos_filename = format!("{}-{}.efi", without_store.display(), name); + + Ok(PathBuf::from(nixos_filename)) +} + +fn generation_path(generation: u64) -> PathBuf { + PathBuf::from(format!("nixos-generation-{}.efi", generation)) +} diff --git a/rust/lanzatool/src/install.rs b/rust/lanzatool/src/install.rs index cfbbe4b..bb8d341 100644 --- a/rust/lanzatool/src/install.rs +++ b/rust/lanzatool/src/install.rs @@ -17,7 +17,61 @@ use std::process::Command; pub fn install( public_key: &Path, private_key: &Path, - _pki_bundle: Option, + pki_bundle: &Option, + auto_enroll: bool, + bootspec: &Path, + generations: Vec, + lanzaboote_stub: &Path, + initrd_stub: &Path, +) -> Result<()> { + for generation in generations { + let generation_version = extract_generation_version(&generation).with_context(|| { + format!( + "Failed to extract generation version from generation: {}", + generation.display() + ) + })?; + + println!("Installing generation {generation_version}"); + + install_generation( + generation_version, + public_key, + private_key, + pki_bundle, + auto_enroll, + bootspec, + lanzaboote_stub, + initrd_stub, + )?; + } + + Ok(()) +} + +fn extract_generation_version(path: impl AsRef) -> Result { + let file_name = path.as_ref().file_name().ok_or(anyhow::anyhow!( + "Failed to extract file name from generation" + ))?; + let file_name_str = file_name + .to_str() + .with_context(|| "Failed to convert file name of generation to string")?; + + let generation_version = file_name_str + .split("-") + .nth(1) + .ok_or(anyhow::anyhow!("Failed to extract version from generation"))?; + + Ok(generation_version + .parse() + .with_context(|| format!("Failed to parse generation version: {}", generation_version))?) +} + +fn install_generation( + generation: u64, + public_key: &Path, + private_key: &Path, + _pki_bundle: &Option, _auto_enroll: bool, bootspec: &Path, lanzaboote_stub: &Path, @@ -29,7 +83,7 @@ pub fn install( serde_json::from_slice(&fs::read(bootspec).context("Failed to read bootspec file")?) .context("Failed to parse bootspec json")?; - let esp_paths = EspPaths::new(&bootspec_doc.extension.esp); + let esp_paths = EspPaths::new(&bootspec_doc.extension.esp, generation, &bootspec_doc)?; println!("Assembling lanzaboote image...");