lanzatool: embed kernel and initrd hashes
This commit is contained in:
parent
ba119d398f
commit
3f78939d0a
|
@ -8,6 +8,18 @@ version = "1.0.66"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "216261ddc8289130e551ddcd5ce8a064710c0d064a4d2895c67151c92b5443f6"
|
||||
|
||||
[[package]]
|
||||
name = "arrayref"
|
||||
version = "0.3.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a4c527152e37cf757a3f78aae5a06fbeefdb07ccc535c980a3208ee3060dd544"
|
||||
|
||||
[[package]]
|
||||
name = "arrayvec"
|
||||
version = "0.7.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8da52d66c7071e2e3fa2a1e5c6d088fec47b593032b254f5e980de8ea54454d6"
|
||||
|
||||
[[package]]
|
||||
name = "atty"
|
||||
version = "0.2.14"
|
||||
|
@ -31,6 +43,35 @@ version = "1.3.2"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
|
||||
|
||||
[[package]]
|
||||
name = "blake3"
|
||||
version = "1.3.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "42ae2468a89544a466886840aa467a25b766499f4f04bf7d9fcd10ecee9fccef"
|
||||
dependencies = [
|
||||
"arrayref",
|
||||
"arrayvec",
|
||||
"cc",
|
||||
"cfg-if",
|
||||
"constant_time_eq",
|
||||
"digest",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "block-buffer"
|
||||
version = "0.10.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "69cce20737498f97b993470a6e536b8523f0af7892a4f928cceb1ac5e52ebe7e"
|
||||
dependencies = [
|
||||
"generic-array",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cc"
|
||||
version = "1.0.77"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e9f73505338f7d905b19d18738976aae232eb46b8efc15554ffc56deb5d9ebe4"
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
version = "1.0.0"
|
||||
|
@ -74,6 +115,33 @@ dependencies = [
|
|||
"os_str_bytes",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "constant_time_eq"
|
||||
version = "0.2.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f3ad85c1f65dc7b37604eb0e89748faf0b9653065f2a8ef69f96a687ec1e9279"
|
||||
|
||||
[[package]]
|
||||
name = "crypto-common"
|
||||
version = "0.1.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3"
|
||||
dependencies = [
|
||||
"generic-array",
|
||||
"typenum",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "digest"
|
||||
version = "0.10.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8168378f4e5023e7218c89c891c0fd8ecdb5e5e4f18cb78f38cf245dd021e76f"
|
||||
dependencies = [
|
||||
"block-buffer",
|
||||
"crypto-common",
|
||||
"subtle",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fastrand"
|
||||
version = "1.8.0"
|
||||
|
@ -83,6 +151,16 @@ dependencies = [
|
|||
"instant",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "generic-array"
|
||||
version = "0.14.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bff49e947297f3312447abdca79f45f4738097cc82b06e72054d2223f601f1b9"
|
||||
dependencies = [
|
||||
"typenum",
|
||||
"version_check",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "goblin"
|
||||
version = "0.6.0"
|
||||
|
@ -129,6 +207,7 @@ name = "lanzatool"
|
|||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"blake3",
|
||||
"clap",
|
||||
"goblin",
|
||||
"nix",
|
||||
|
@ -305,6 +384,12 @@ version = "0.10.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
|
||||
|
||||
[[package]]
|
||||
name = "subtle"
|
||||
version = "2.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601"
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "1.0.103"
|
||||
|
@ -339,6 +424,12 @@ dependencies = [
|
|||
"winapi-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "typenum"
|
||||
version = "1.15.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dcf81ac59edc17cc8697ff311e8f5ef2d99fcbd9817b34cec66f90b6c3dfd987"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
version = "1.0.5"
|
||||
|
|
|
@ -13,3 +13,4 @@ nix = { version = "0.25.0", default-features = false, features = [ "fs" ] }
|
|||
serde = { version = "1.0.147", features = ["derive"] }
|
||||
serde_json = "1.0.89"
|
||||
tempfile = "3.3.0"
|
||||
blake3 = "1.3.3"
|
||||
|
|
|
@ -87,17 +87,6 @@ impl Installer {
|
|||
// TODO(Raito): prove to niksnur this is actually acceptable.
|
||||
let secure_temp_dir = tempdir()?;
|
||||
|
||||
let lanzaboote_image = pe::lanzaboote_image(
|
||||
&secure_temp_dir,
|
||||
&self.lanzaboote_stub,
|
||||
&bootspec.extension.os_release,
|
||||
&kernel_cmdline,
|
||||
&esp_paths.kernel,
|
||||
&esp_paths.initrd,
|
||||
&esp_paths.esp,
|
||||
)
|
||||
.context("Failed to assemble stub")?;
|
||||
|
||||
println!("Wrapping initrd into a PE binary...");
|
||||
|
||||
let initrd_location = secure_temp_dir.path().join("initrd");
|
||||
|
@ -114,24 +103,37 @@ impl Installer {
|
|||
.toplevel
|
||||
.join("systemd/lib/systemd/boot/efi/systemd-bootx64.efi");
|
||||
|
||||
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.kernel, &esp_paths.kernel),
|
||||
(&wrapped_initrd, &esp_paths.initrd),
|
||||
];
|
||||
]
|
||||
.into_iter()
|
||||
.try_for_each(|(from, to)| install_signed(&self.key_pair, from, to))?;
|
||||
|
||||
for (from, to) in files_to_copy_and_sign {
|
||||
println!("Signing {}...", to.display());
|
||||
let lanzaboote_image = pe::lanzaboote_image(
|
||||
&secure_temp_dir,
|
||||
&self.lanzaboote_stub,
|
||||
&bootspec.extension.os_release,
|
||||
&kernel_cmdline,
|
||||
&esp_paths.kernel,
|
||||
&esp_paths.initrd,
|
||||
&esp_paths.esp,
|
||||
)
|
||||
.context("Failed to assemble stub")?;
|
||||
|
||||
ensure_parent_dir(to);
|
||||
self.key_pair.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
|
||||
install_signed(
|
||||
&self.key_pair,
|
||||
&lanzaboote_image,
|
||||
&esp_paths.lanzaboote_image,
|
||||
)
|
||||
.context("Failed to install lanzaboote")?;
|
||||
|
||||
// Sync files to persistent storage. This may improve the
|
||||
// chance of a consistent boot directory in case the system
|
||||
// crashes.
|
||||
sync();
|
||||
}
|
||||
|
||||
println!(
|
||||
"Successfully installed lanzaboote to '{}'",
|
||||
|
@ -142,6 +144,18 @@ impl Installer {
|
|||
}
|
||||
}
|
||||
|
||||
/// Install a PE file. The PE gets signed in the process.
|
||||
fn install_signed(key_pair: &KeyPair, from: &Path, to: &Path) -> Result<()> {
|
||||
println!("Signing {}...", to.display());
|
||||
|
||||
ensure_parent_dir(to);
|
||||
key_pair
|
||||
.sign_and_copy(from, to)
|
||||
.with_context(|| format!("Failed to copy and sign file from {:?} to {:?}", from, to))?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn append_initrd_secrets(
|
||||
append_initrd_secrets_path: &Path,
|
||||
initrd_path: &PathBuf,
|
||||
|
|
|
@ -12,6 +12,11 @@ use crate::utils;
|
|||
|
||||
use tempfile::TempDir;
|
||||
|
||||
/// Attach all information that lanzaboote needs into the PE binary.
|
||||
///
|
||||
/// When this function is called the referenced files already need to
|
||||
/// be present in the ESP. This is required, because we need to read
|
||||
/// them to compute hashes.
|
||||
pub fn lanzaboote_image(
|
||||
target_dir: &TempDir,
|
||||
lanzaboote_stub: &Path,
|
||||
|
@ -21,36 +26,56 @@ pub fn lanzaboote_image(
|
|||
initrd_path: &Path,
|
||||
esp: &Path,
|
||||
) -> Result<PathBuf> {
|
||||
// objcopy copies files into the PE binary. That's why we have to write the contents
|
||||
// of some bootspec properties to disk
|
||||
let (kernel_cmdline_file, _) =
|
||||
write_to_tmp(target_dir, "kernel-cmdline", kernel_cmdline.join(" "))?;
|
||||
let (kernel_path_file, _) = write_to_tmp(
|
||||
// objcopy can only copy files into the PE binary. That's why we
|
||||
// have to write the contents of some bootspec properties to disk.
|
||||
let kernel_cmdline_file = write_to_tmp(target_dir, "kernel-cmdline", kernel_cmdline.join(" "))?;
|
||||
|
||||
let kernel_path_file = write_to_tmp(
|
||||
target_dir,
|
||||
"kernel-esp-path",
|
||||
esp_relative_path_string(esp, kernel_path),
|
||||
)?;
|
||||
let (initrd_path_file, _) = write_to_tmp(
|
||||
let kernel_hash_file = write_to_tmp(
|
||||
target_dir,
|
||||
"kernel-hash",
|
||||
file_hash(kernel_path)?.as_bytes(),
|
||||
)?;
|
||||
|
||||
let initrd_path_file = write_to_tmp(
|
||||
target_dir,
|
||||
"initrd-esp-path",
|
||||
esp_relative_path_string(esp, initrd_path),
|
||||
)?;
|
||||
let initrd_hash_file = write_to_tmp(
|
||||
target_dir,
|
||||
"initrd-hash",
|
||||
file_hash(initrd_path)?.as_bytes(),
|
||||
)?;
|
||||
|
||||
let os_release_offs = stub_offset(lanzaboote_stub)?;
|
||||
let kernel_cmdline_offs = os_release_offs + file_size(os_release)?;
|
||||
let initrd_path_offs = kernel_cmdline_offs + file_size(&kernel_cmdline_file)?;
|
||||
let kernel_path_offs = initrd_path_offs + file_size(&initrd_path_file)?;
|
||||
let initrd_hash_offs = kernel_path_offs + file_size(&kernel_path_file)?;
|
||||
let kernel_hash_offs = initrd_hash_offs + file_size(&initrd_hash_file)?;
|
||||
|
||||
let sections = vec![
|
||||
s(".osrel", os_release, os_release_offs),
|
||||
s(".cmdline", kernel_cmdline_file, kernel_cmdline_offs),
|
||||
s(".initrdp", initrd_path_file, initrd_path_offs),
|
||||
s(".kernelp", kernel_path_file, kernel_path_offs),
|
||||
s(".initrdh", initrd_hash_file, initrd_hash_offs),
|
||||
s(".kernelh", kernel_hash_file, kernel_hash_offs),
|
||||
];
|
||||
|
||||
wrap_in_pe(target_dir, "lanzaboote-stub.efi", lanzaboote_stub, sections)
|
||||
}
|
||||
|
||||
/// Compute the blake3 hash of a file.
|
||||
fn file_hash(file: &Path) -> Result<blake3::Hash> {
|
||||
Ok(blake3::hash(&fs::read(file)?))
|
||||
}
|
||||
|
||||
/// Wrap an initrd into a PE binary.
|
||||
///
|
||||
/// This is required for lanzaboote to verify the signature of the
|
||||
|
@ -125,21 +150,26 @@ fn s(name: &'static str, file_path: impl AsRef<Path>, offset: u64) -> Section {
|
|||
}
|
||||
}
|
||||
|
||||
/// Write a `u8` slice to a temporary file.
|
||||
fn write_to_tmp(
|
||||
secure_temp: &TempDir,
|
||||
filename: &str,
|
||||
contents: impl AsRef<[u8]>,
|
||||
) -> Result<(PathBuf, fs::File)> {
|
||||
) -> Result<PathBuf> {
|
||||
let path = secure_temp.path().join(filename);
|
||||
|
||||
let mut tmpfile = fs::OpenOptions::new()
|
||||
.create(true)
|
||||
.write(true)
|
||||
.mode(0o600)
|
||||
.open(secure_temp.path().join(filename))
|
||||
.open(&path)
|
||||
.context("Failed to create tempfile")?;
|
||||
|
||||
tmpfile
|
||||
.write_all(contents.as_ref())
|
||||
.context("Failed to write to tempfile")?;
|
||||
Ok((secure_temp.path().join(filename), tmpfile))
|
||||
|
||||
Ok(path)
|
||||
}
|
||||
|
||||
fn esp_relative_path_string(esp: &Path, path: &Path) -> String {
|
||||
|
|
Loading…
Reference in New Issue