diff --git a/uefi-test-runner/src/proto/tcg.rs b/uefi-test-runner/src/proto/tcg.rs index 21e0cce55..b74772578 100644 --- a/uefi-test-runner/src/proto/tcg.rs +++ b/uefi-test-runner/src/proto/tcg.rs @@ -1,5 +1,4 @@ use alloc::vec::Vec; -use core::mem::MaybeUninit; use uefi::proto::tcg::{v1, v2, AlgorithmId, EventType, HashAlgorithm, PcrIndex}; use uefi::table::boot::BootServices; @@ -63,7 +62,7 @@ fn test_tcg_v1(bt: &BootServices) { let pcr_index = PcrIndex(8); - let mut event_buf = [MaybeUninit::uninit(); 256]; + let mut event_buf = [0; 256]; let event = v1::PcrEvent::new_in_buffer( &mut event_buf, pcr_index, @@ -279,7 +278,7 @@ pub fn test_tcg_v2(bt: &BootServices) { // Create a PCR event. let pcr_index = PcrIndex(8); - let mut event_buf = [MaybeUninit::uninit(); 256]; + let mut event_buf = [0; 256]; let event_data = [0x12, 0x13, 0x14, 0x15]; let data_to_hash = b"some-data"; let event = diff --git a/uefi/CHANGELOG.md b/uefi/CHANGELOG.md index 5119d3547..c00f2a651 100644 --- a/uefi/CHANGELOG.md +++ b/uefi/CHANGELOG.md @@ -4,6 +4,8 @@ - `uefi::system` is a new module that provides freestanding functions for accessing fields of the global system table. - Add standard derives for `ConfigTableEntry`. +- `PcrEvent`/`PcrEventInputs` impl `Align`, `Eq`, and `PartialEq`. +- Added `PcrEvent::new_in_box` and `PcrEventInputs::new_in_box`. ## Changed - **Breaking:** `uefi::helpers::init` no longer takes an argument. @@ -14,6 +16,9 @@ The old `MemoryMap` was renamed to `MemoryMapOwned`. - `pub fn memory_map(&self, mt: MemoryType) -> Result` now returns a `MemoryMapOwned`. +- **Breaking:** `PcrEvent::new_in_buffer` and `PcrEventInputs::new_in_buffer` + now take an initialized buffer (`[u8`] instead of `[MaybeUninit]`), and if + the buffer is too small the required size is returned in the error data. # uefi - 0.29.0 (2024-07-02) diff --git a/uefi/src/proto/tcg/v1.rs b/uefi/src/proto/tcg/v1.rs index 7f0226806..0fc55a7da 100644 --- a/uefi/src/proto/tcg/v1.rs +++ b/uefi/src/proto/tcg/v1.rs @@ -9,17 +9,21 @@ //! [TPM]: https://en.wikipedia.org/wiki/Trusted_Platform_Module use super::{AlgorithmId, EventType, HashAlgorithm, PcrIndex}; -use crate::data_types::PhysicalAddress; -use crate::polyfill::maybe_uninit_slice_as_mut_ptr; +use crate::data_types::{Align, PhysicalAddress}; use crate::proto::unsafe_protocol; use crate::util::{ptr_write_unaligned_and_add, usize_from_u32}; use crate::{Error, Result, Status, StatusExt}; use core::fmt::{self, Debug, Formatter}; use core::marker::PhantomData; -use core::mem::{self, MaybeUninit}; -use core::ptr; +use core::{mem, ptr}; use ptr_meta::Pointee; +#[cfg(feature = "alloc")] +use {crate::mem::make_boxed, alloc::boxed::Box}; + +#[cfg(all(feature = "unstable", feature = "alloc"))] +use {alloc::alloc::Global, core::alloc::Allocator}; + /// 20-byte SHA-1 digest. pub type Sha1Digest = [u8; 20]; @@ -128,19 +132,19 @@ impl PcrEvent { /// # Errors /// /// Returns [`Status::BUFFER_TOO_SMALL`] if the `buffer` is not large - /// enough. + /// enough. The required size will be returned in the error data. /// /// Returns [`Status::INVALID_PARAMETER`] if the `event_data` size is too /// large. pub fn new_in_buffer<'buf>( - buffer: &'buf mut [MaybeUninit], + buffer: &'buf mut [u8], pcr_index: PcrIndex, event_type: EventType, digest: Sha1Digest, event_data: &[u8], - ) -> Result<&'buf mut Self> { - let event_data_size = - u32::try_from(event_data.len()).map_err(|_| Error::from(Status::INVALID_PARAMETER))?; + ) -> Result<&'buf mut Self, Option> { + let event_data_size = u32::try_from(event_data.len()) + .map_err(|_| Error::new(Status::INVALID_PARAMETER, None))?; let required_size = mem::size_of::() + mem::size_of::() @@ -149,10 +153,10 @@ impl PcrEvent { + event_data.len(); if buffer.len() < required_size { - return Err(Status::BUFFER_TOO_SMALL.into()); + return Err(Error::new(Status::BUFFER_TOO_SMALL, Some(required_size))); } - let mut ptr: *mut u8 = maybe_uninit_slice_as_mut_ptr(buffer); + let mut ptr: *mut u8 = buffer.as_mut_ptr().cast(); unsafe { ptr_write_unaligned_and_add(&mut ptr, pcr_index); @@ -167,6 +171,32 @@ impl PcrEvent { } } + /// Create a new `PcrEvent` in a [`Box`]. + /// + /// # Errors + /// + /// Returns [`Status::INVALID_PARAMETER`] if the `event_data` size is too + /// large. + #[cfg(feature = "alloc")] + pub fn new_in_box( + pcr_index: PcrIndex, + event_type: EventType, + digest: Sha1Digest, + event_data: &[u8], + ) -> Result> { + #[cfg(not(feature = "unstable"))] + { + make_boxed(|buf| Self::new_in_buffer(buf, pcr_index, event_type, digest, event_data)) + } + #[cfg(feature = "unstable")] + { + make_boxed( + |buf| Self::new_in_buffer(buf, pcr_index, event_type, digest, event_data), + Global, + ) + } + } + /// PCR index for the event. #[must_use] pub fn pcr_index(&self) -> PcrIndex { @@ -200,6 +230,12 @@ impl PcrEvent { } } +impl Align for PcrEvent { + fn alignment() -> usize { + 1 + } +} + // Manual `Debug` implementation since it can't be derived for a packed DST. impl Debug for PcrEvent { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { @@ -533,7 +569,7 @@ mod tests { #[test] fn test_new_pcr_event() { - let mut event_buf = [MaybeUninit::uninit(); 256]; + let mut event_buf = [0; 256]; #[rustfmt::skip] let digest = [ 0x00, 0x01, 0x02, 0x03, @@ -571,6 +607,12 @@ mod tests { // Event data 0x14, 0x15, 0x16, 0x17, ]); + + // Check that `new_in_box` gives the same value. + assert_eq!( + event, + &*PcrEvent::new_in_box(PcrIndex(4), EventType::IPL, digest, &data).unwrap() + ); } #[test] diff --git a/uefi/src/proto/tcg/v2.rs b/uefi/src/proto/tcg/v2.rs index 86b3bb39c..df762f311 100644 --- a/uefi/src/proto/tcg/v2.rs +++ b/uefi/src/proto/tcg/v2.rs @@ -11,17 +11,22 @@ //! [TPM]: https://en.wikipedia.org/wiki/Trusted_Platform_Module use super::{v1, AlgorithmId, EventType, HashAlgorithm, PcrIndex}; -use crate::data_types::{PhysicalAddress, UnalignedSlice}; +use crate::data_types::{Align, PhysicalAddress, UnalignedSlice}; use crate::proto::unsafe_protocol; use crate::util::{ptr_write_unaligned_and_add, usize_from_u32}; use crate::{Error, Result, Status, StatusExt}; use bitflags::bitflags; use core::fmt::{self, Debug, Formatter}; use core::marker::PhantomData; -use core::mem::MaybeUninit; use core::{mem, ptr, slice}; use ptr_meta::{Pointee, PtrExt}; +#[cfg(feature = "alloc")] +use {crate::mem::make_boxed, alloc::boxed::Box}; + +#[cfg(all(feature = "unstable", feature = "alloc"))] +use {alloc::alloc::Global, core::alloc::Allocator}; + /// Version information. /// /// Layout compatible with the C type `EFI_TG2_VERSION`. @@ -158,7 +163,7 @@ struct EventHeader { /// `TCG_PCR_EVENT2` for reading events. To help clarify the usage, our /// API renames these types to `PcrEventInputs` and `PcrEvent`, /// respectively. -#[derive(Pointee)] +#[derive(Eq, Pointee)] #[repr(C, packed)] pub struct PcrEventInputs { size: u32, @@ -172,24 +177,24 @@ impl PcrEventInputs { /// # Errors /// /// Returns [`Status::BUFFER_TOO_SMALL`] if the `buffer` is not large - /// enough. + /// enough. The required size will be returned in the error data. /// /// Returns [`Status::INVALID_PARAMETER`] if the `event_data` size is too /// large. pub fn new_in_buffer<'buf>( - buffer: &'buf mut [MaybeUninit], + buffer: &'buf mut [u8], pcr_index: PcrIndex, event_type: EventType, event_data: &[u8], - ) -> Result<&'buf Self> { + ) -> Result<&'buf mut Self, Option> { let required_size = mem::size_of::() + mem::size_of::() + event_data.len(); if buffer.len() < required_size { - return Err(Status::BUFFER_TOO_SMALL.into()); + return Err(Error::new(Status::BUFFER_TOO_SMALL, Some(required_size))); } - let size_field = - u32::try_from(required_size).map_err(|_| Error::from(Status::INVALID_PARAMETER))?; + let size_field = u32::try_from(required_size) + .map_err(|_| Error::new(Status::INVALID_PARAMETER, None))?; let mut ptr: *mut u8 = buffer.as_mut_ptr().cast(); @@ -206,13 +211,44 @@ impl PcrEventInputs { ); ptr::copy(event_data.as_ptr(), ptr, event_data.len()); - let ptr: *const PcrEventInputs = - ptr_meta::from_raw_parts(buffer.as_ptr().cast(), event_data.len()); - Ok(&*ptr) + let ptr: *mut PcrEventInputs = + ptr_meta::from_raw_parts_mut(buffer.as_mut_ptr().cast(), event_data.len()); + Ok(&mut *ptr) + } + } + + /// Create a new `PcrEventInputs` in a [`Box`]. + /// + /// # Errors + /// + /// Returns [`Status::INVALID_PARAMETER`] if the `event_data` size is too + /// large. + #[cfg(feature = "alloc")] + pub fn new_in_box( + pcr_index: PcrIndex, + event_type: EventType, + event_data: &[u8], + ) -> Result> { + #[cfg(not(feature = "unstable"))] + { + make_boxed(|buf| Self::new_in_buffer(buf, pcr_index, event_type, event_data)) + } + #[cfg(feature = "unstable")] + { + make_boxed( + |buf| Self::new_in_buffer(buf, pcr_index, event_type, event_data), + Global, + ) } } } +impl Align for PcrEventInputs { + fn alignment() -> usize { + 1 + } +} + impl Debug for PcrEventInputs { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { f.debug_struct("PcrEventInputs") @@ -223,6 +259,15 @@ impl Debug for PcrEventInputs { } } +// Manual `PartialEq` implementation since it can't be derived for a packed DST. +impl PartialEq for PcrEventInputs { + fn eq(&self, other: &PcrEventInputs) -> bool { + self.size == other.size + && self.event_header == other.event_header + && self.event == other.event + } +} + #[repr(C, packed)] #[derive(Clone, Copy, Debug, PartialEq, Eq)] struct AlgorithmDigestSize { @@ -785,7 +830,7 @@ mod tests { #[test] fn test_new_event() { - let mut buf = [MaybeUninit::uninit(); 22]; + let mut buf = [0; 22]; let event_data = [0x12, 0x13, 0x14, 0x15]; let event = PcrEventInputs::new_in_buffer(&mut buf, PcrIndex(4), EventType::IPL, &event_data) @@ -824,6 +869,12 @@ mod tests { // Event data 0x12, 0x13, 0x14, 0x15, ]); + + // Check that `new_in_box` gives the same value. + assert_eq!( + event, + &*PcrEventInputs::new_in_box(PcrIndex(4), EventType::IPL, &event_data).unwrap() + ); } #[test]