Skip to content

Commit

Permalink
feat: pack the TPM2 PCR files as CPIOs if they are present
Browse files Browse the repository at this point in the history
  • Loading branch information
RaitoBezarius committed Apr 30, 2023
1 parent 07f6158 commit f260b6f
Show file tree
Hide file tree
Showing 5 changed files with 85 additions and 34 deletions.
2 changes: 1 addition & 1 deletion rust/stub/src/cpio.rs
Original file line number Diff line number Diff line change
Expand Up @@ -286,7 +286,7 @@ pub fn pack_cpio(

pub fn pack_cpio_literal(
boot_services: &BootServices,
data: &Vec<u8>,
data: &[u8],
target_dir_prefix: &str,
target_filename: &CStr16,
dir_mode: u32,
Expand Down
2 changes: 1 addition & 1 deletion rust/stub/src/initrd.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ pub enum CompanionInitrd {
}

pub fn export_pcr_efi_variables(runtime_services: &RuntimeServices,
initrds: Vec<CompanionInitrd>) -> uefi::Result {
initrds: &Vec<CompanionInitrd>) -> uefi::Result {
// Do we have kernel parameters that were measured
if initrds.iter().any(|e| match e {
CompanionInitrd::Credentials(_) => true,
Expand Down
47 changes: 41 additions & 6 deletions rust/stub/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ use uefi::{
CStr16, CString16, Result,
};
use uefi_helpers::SystemdLoaderFeatures;
use unified_sections::UnifiedSection;

use crate::{
linux_loader::InitrdLoader,
Expand Down Expand Up @@ -257,12 +258,11 @@ fn main(handle: Handle, mut system_table: SystemTable<Boot>) -> Status {
}
}

unsafe {
// Iterate over unified sections and measure them
let _ = measure_image(&system_table, booted_image_file(
// Iterate over unified sections and measure them
let (_, discovered_unified_sections) = unsafe { measure_image(&system_table, booted_image_file(
system_table.boot_services()
).unwrap()).expect("Failed to measure the image");
}
).unwrap()).expect("Failed to measure the image")
};

export_efi_variables(&system_table)
.expect("Failed to export stub EFI variables");
Expand Down Expand Up @@ -307,7 +307,42 @@ fn main(handle: Handle, mut system_table: SystemTable<Boot>) -> Status {
}

// Let's export any StubPcr EFI variable we might need.
let _ = initrd::export_pcr_efi_variables(&system_table.runtime_services(), initrds);
let _ = initrd::export_pcr_efi_variables(&system_table.runtime_services(), &initrds);

// Pack relevant left CPIOs:
// - TPM2 PCR signatures
// - TPM2 PCR public keys
for uf_section in discovered_unified_sections {
match uf_section {
UnifiedSection::PcrSig(pcrsig_data) => {
if let Ok(pcrsig_initrd) = cpio::pack_cpio_literal(system_table.boot_services(),
pcrsig_data,
".extra",
cstr16!("tpm2-pcr-signature.json"),
0o555,
0o444,
// Do not perform any measurement.
uefi::proto::tcg::PcrIndex(u32::MAX),
"") {
initrds.push(CompanionInitrd::PcrSignature(pcrsig_initrd));
}
}
UnifiedSection::PcrPkey(pcrpkey_data) => {
if let Ok(pcrpkey_initrd) = cpio::pack_cpio_literal(system_table.boot_services(),
pcrpkey_data,
".extra",
cstr16!("tpm2-pcr-public-key.pem"),
0o555,
0o444,
// Do not perform any measurement.
uefi::proto::tcg::PcrIndex(u32::MAX),
"") {
initrds.push(CompanionInitrd::PcrPublicKey(pcrpkey_initrd));
}
}
_ => continue,
}
}

if is_kernel_hash_correct && is_initrd_hash_correct {
boot_linux_unchecked(
Expand Down
15 changes: 11 additions & 4 deletions rust/stub/src/measure.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use uefi::{table::{runtime::VariableAttributes, Boot, SystemTable}, cstr16, proto::tcg::PcrIndex};

use alloc::vec::Vec;
use crate::{uefi_helpers::{PeInMemory, SD_LOADER}, pe_section::pe_section_data, unified_sections::UnifiedSection, tpm::tpm_log_event_ascii};

/// This is the TPM PCR where lanzastub extends its payload into, before using them.
Expand All @@ -20,7 +20,7 @@ pub const TPM_PCR_INDEX_VOLUME_KEY: PcrIndex = PcrIndex(15);

pub unsafe fn measure_image(
system_table: &SystemTable<Boot>,
image: PeInMemory) -> uefi::Result<u32> {
image: PeInMemory) -> uefi::Result<(u32, Vec<UnifiedSection>)> {
let runtime_services = system_table.runtime_services();
let boot_services = system_table.boot_services();

Expand All @@ -29,9 +29,12 @@ pub unsafe fn measure_image(
.map_err(|_err| uefi::Status::LOAD_ERROR)?;

let mut measurements = 0;
// We would like to use core::mem::variant_count
// https://github.com/rust-lang/rust/issues/73662
let mut unified_sections = Vec::with_capacity(8);
for section in pe.sections {
let section_name = section.name().map_err(|_err| uefi::Status::UNSUPPORTED)?;
if let Ok(unified_section) = UnifiedSection::try_from(section_name) {
if let Ok(unified_section) = UnifiedSection::from_section_table(&pe_binary, &section) {
// UNSTABLE: && in the previous if is an unstable feature
// https://github.com/rust-lang/rust/issues/53667
if unified_section.should_be_measured() {
Expand All @@ -42,6 +45,10 @@ pub unsafe fn measure_image(
}
}
}
// We would like to use push_within_capacity and err out correctly
// if the capacity is exceeded.
// https://github.com/rust-lang/rust/issues/100486
unified_sections.push(unified_section);
}
}

Expand All @@ -56,5 +63,5 @@ pub unsafe fn measure_image(
)?;
}

Ok(measurements)
Ok((measurements, unified_sections))
}
53 changes: 31 additions & 22 deletions rust/stub/src/unified_sections.rs
Original file line number Diff line number Diff line change
@@ -1,42 +1,51 @@
use goblin::pe::{section_table::SectionTable, PE};

use crate::pe_section::pe_section_data;

/// List of PE sections that have a special meaning with respect to
/// UKI specification.
/// This is the canonical order in which they are measured into TPM
/// PCR 11.
/// !!! DO NOT REORDER !!!
pub enum UnifiedSection {
pub enum UnifiedSection<'a> {
Linux,
OsRel,
CmdLine,
Initrd,
Splash,
DTB,
PcrSig,
PcrPkey
}

impl TryFrom<&str> for UnifiedSection {
type Error = uefi::Error;
fn try_from(value: &str) -> Result<Self, Self::Error> {
Ok(match value {
".linux" => Self::Linux,
".osrel" => Self::OsRel,
".cmdline" => Self::CmdLine,
".initrd" => Self::Initrd,
".splash" => Self::Splash,
".dtb" => Self::DTB,
".pcrsig" => Self::PcrSig,
".pcrpkey" => Self::PcrPkey,
_ => return Err(uefi::Status::INVALID_PARAMETER.into())
})
}
// We only need to store the data for those for now,
// because we need to pack them as CPIOs.
PcrSig(&'a [u8]),
PcrPkey(&'a [u8])
}

impl UnifiedSection {
impl<'a> UnifiedSection<'a> {
/// Whether this section should be measured into TPM.
pub fn should_be_measured(&self) -> bool {
match self {
UnifiedSection::PcrSig => false,
UnifiedSection::PcrSig(_) => false,
_ => true
}
}

pub fn from_section_table(pe: &'a [u8], section: &SectionTable) -> uefi::Result<Self> {
if let Some(data) = pe_section_data(pe, &section) {
Ok(match section.name().unwrap() {
".linux" => Self::Linux,
".osrel" => Self::OsRel,
".cmdline" => Self::CmdLine,
".initrd" => Self::Initrd,
".splash" => Self::Splash,
".dtb" => Self::DTB,
".pcrsig" => Self::PcrSig(data),
".pcrpkey" => Self::PcrPkey(data),
_ => return Err(uefi::Status::INVALID_PARAMETER.into())
})
} else {
// No data in the section is equivalent to missing section.
Err(uefi::Status::INVALID_PARAMETER.into())
}
}

}

0 comments on commit f260b6f

Please sign in to comment.