diff --git a/rust/lanzatool/src/install.rs b/rust/lanzatool/src/install.rs index 1e9d1f8..99bc1e5 100644 --- a/rust/lanzatool/src/install.rs +++ b/rust/lanzatool/src/install.rs @@ -104,45 +104,31 @@ impl Installer { let wrapped_initrd = pe::wrap_initrd(&secure_temp_dir, &self.initrd_stub, &initrd_location) .context("Failed to assemble stub")?; - println!("Copy files to EFI system partition..."); + println!("Sign and copy files to EFI system partition..."); + + let signer = Signer::new(&self.public_key, &self.private_key); let systemd_boot = bootspec_doc .extension .systemd .join("lib/systemd/boot/efi/systemd-bootx64.efi"); - let files_to_copy = [ - (bootspec_doc.kernel, &esp_paths.kernel), - (wrapped_initrd, &esp_paths.initrd), - (lanzaboote_image, &esp_paths.lanzaboote_image), - (systemd_boot.clone(), &esp_paths.efi_fallback), - (systemd_boot, &esp_paths.systemd_boot), + let files_to_copy_and_sign = [ + (&systemd_boot, &esp_paths.efi_fallback), + (&systemd_boot, &esp_paths.systemd_boot), + (&lanzaboote_image, &esp_paths.lanzaboote_image), + (&bootspec_doc.kernel, &esp_paths.kernel), + (&wrapped_initrd, &esp_paths.initrd), ]; - for (source, target) in files_to_copy { - copy(&source, &target)?; - } + for (from, to) in files_to_copy_and_sign { + println!("Signing {}...", to.display()); - // TODO: we should implement sign_and_copy which would be secure - // by construction for TOCTOU. - - println!("Signing files..."); - - let signer = Signer::new(&self.public_key, &self.private_key); - - let files_to_sign = [ - &esp_paths.efi_fallback, - &esp_paths.systemd_boot, - &esp_paths.lanzaboote_image, - &esp_paths.kernel, - &esp_paths.initrd, - ]; - - for file in files_to_sign { - println!("Signing {}...", file.display()); - signer - .sign_file(&file) - .with_context(|| format!("Failed to sign file {}", &file.display()))?; + ensure_parent_dir(to); + signer.sign_and_copy(&from, &to).with_context(|| { + format!("Failed to copy and sign file from {:?} to {:?}", from, to) + })?; + // Call sync to improve the likelihood that file is actually written to disk sync(); } @@ -185,10 +171,7 @@ fn assemble_kernel_cmdline(init: PathBuf, kernel_params: Vec) -> Vec Result<()> { - match to.parent() { - Some(parent) => fs::create_dir_all(parent).unwrap_or(()), - _ => (), - }; + ensure_parent_dir(to); fs::copy(from, to) .with_context(|| format!("Failed to copy from {} to {}", from.display(), to.display()))?; @@ -202,3 +185,10 @@ fn copy(from: &Path, to: &Path) -> Result<()> { Ok(()) } + +// Ensures the parent directory of an arbitrary path exists +fn ensure_parent_dir(path: &Path) { + if let Some(parent) = path.parent() { + fs::create_dir_all(parent).ok(); + } +} diff --git a/rust/lanzatool/src/signer.rs b/rust/lanzatool/src/signer.rs index 933eb3d..d3e6420 100644 --- a/rust/lanzatool/src/signer.rs +++ b/rust/lanzatool/src/signer.rs @@ -18,20 +18,21 @@ impl Signer { } } - pub fn sign_file(&self, filepath: &Path) -> Result<()> { + pub fn sign_and_copy(&self, from: &Path, to: &Path) -> Result<()> { let args = vec![ String::from("--key"), utils::path_to_string(&self.private_key), String::from("--cert"), utils::path_to_string(&self.public_key), - utils::path_to_string(filepath), + utils::path_to_string(from), String::from("--output"), - utils::path_to_string(filepath), + utils::path_to_string(to), ]; - let status = Command::new("sbsign").args(&args).status()?; + let output = Command::new("sbsign").args(&args).output()?; - if !status.success() { + if !output.status.success() { + print!("{:?}", output.stderr); return Err(anyhow::anyhow!( "Failed to sign file using sbsign with args `{:?}`", &args