lanzaboote: verify hash of kernel and initrd

This commit is contained in:
Julian Stecklina 2022-11-28 01:37:16 +01:00
parent 7a15bba50b
commit 1739ffde26
3 changed files with 88 additions and 8 deletions

View File

@ -2,6 +2,18 @@
# It is not intended for manual editing.
version = 3
[[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 = "bit_field"
version = "0.10.1"
@ -14,12 +26,37 @@ 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",
]
[[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"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "constant_time_eq"
version = "0.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f3ad85c1f65dc7b37604eb0e89748faf0b9653065f2a8ef69f96a687ec1e9279"
[[package]]
name = "ed25519-compact"
version = "2.0.2"
@ -41,6 +78,7 @@ dependencies = [
name = "lanzaboote"
version = "0.1.0"
dependencies = [
"blake3",
"ed25519-compact",
"goblin",
"log",

View File

@ -11,6 +11,9 @@ log = "0.4.17"
ed25519-compact = { version = "2.0.2", default-features = false, features = [] }
goblin = { version = "0.6.0", default-features = false, features = [ "pe64", "alloc" ]}
# We don't want the assembly implementations for now.
blake3 = { version = "1.3.3", default-features = false, features = [ "pure" ]}
[profile.release]
opt-level = "s"
lto = true

View File

@ -9,7 +9,8 @@ mod linux_loader;
mod pe_section;
mod uefi_helpers;
use pe_section::pe_section_as_string;
use blake3::Hash;
use pe_section::{pe_section, pe_section_as_string};
use uefi::{
prelude::*,
proto::{
@ -52,9 +53,33 @@ struct EmbeddedConfiguration {
/// lanzaboote binary.
kernel_filename: CString16,
/// The cryptographic hash of the kernel.
kernel_hash: Hash,
/// The filename of the initrd to be passed to the kernel. See
/// `kernel_filename` for how to interpret these filenames.
initrd_filename: CString16,
/// The cryptographic hash of the initrd. This hash is computed
/// over the whole PE binary, not only the embedded initrd.
initrd_hash: Hash,
}
/// Extract a filename from a PE section. The filename is stored as UTF-8.
fn extract_filename(file_data: &[u8], section: &str) -> Result<CString16> {
let filename = pe_section_as_string(file_data, section).ok_or(Status::INVALID_PARAMETER)?;
Ok(CString16::try_from(filename.as_str()).map_err(|_| Status::INVALID_PARAMETER)?)
}
/// Extract a Blake3 hash from a PE section.
fn extract_hash(file_data: &[u8], section: &str) -> Result<Hash> {
let array: [u8; 32] = pe_section(file_data, section)
.ok_or(Status::INVALID_PARAMETER)?
.try_into()
.map_err(|_| Status::INVALID_PARAMETER)?;
Ok(array.into())
}
impl EmbeddedConfiguration {
@ -62,14 +87,12 @@ impl EmbeddedConfiguration {
file.set_position(0)?;
let file_data = read_all(file)?;
let kernel_filename =
pe_section_as_string(&file_data, ".kernelp").ok_or(Status::INVALID_PARAMETER)?;
let initrd_filename =
pe_section_as_string(&file_data, ".initrdp").ok_or(Status::INVALID_PARAMETER)?;
Ok(Self {
kernel_filename: CString16::try_from(kernel_filename.as_str()).unwrap(),
initrd_filename: CString16::try_from(initrd_filename.as_str()).unwrap(),
kernel_filename: extract_filename(&file_data, ".kernelp")?,
kernel_hash: extract_hash(&file_data, ".kernelh")?,
initrd_filename: extract_filename(&file_data, ".initrdp")?,
initrd_hash: extract_hash(&file_data, ".initrdh")?,
})
}
}
@ -121,6 +144,22 @@ fn main(handle: Handle, mut system_table: SystemTable<Boot>) -> Status {
initrd_data = read_all(&mut initrd_file).expect("Failed to read kernel file into memory");
}
if blake3::hash(&kernel_data) != config.kernel_hash {
system_table
.stdout()
.output_string(cstr16!("Hash mismatch for kernel. Refusing to load!\r\n"))
.unwrap();
return Status::SECURITY_VIOLATION;
}
if blake3::hash(&initrd_data) != config.initrd_hash {
system_table
.stdout()
.output_string(cstr16!("Hash mismatch for initrd. Refusing to load!\r\n"))
.unwrap();
return Status::SECURITY_VIOLATION;
}
let kernel_cmdline =
booted_image_cmdline(system_table.boot_services()).expect("Failed to fetch command line");