Skip to content

Commit

Permalink
Merge pull request rust-osdev#1246 from nicholasbishop/bishop-tcg-new…
Browse files Browse the repository at this point in the history
…-boxed

Add PcrEvent::new_in_box/PcrEventInputs::new_in_box
  • Loading branch information
phip1611 committed Jul 16, 2024
2 parents 7a0a8ee + 8bc7605 commit 1fa9408
Show file tree
Hide file tree
Showing 4 changed files with 125 additions and 28 deletions.
5 changes: 2 additions & 3 deletions uefi-test-runner/src/proto/tcg.rs
Original file line number Diff line number Diff line change
@@ -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;

Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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 =
Expand Down
5 changes: 5 additions & 0 deletions uefi/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -14,6 +16,9 @@
The old `MemoryMap` was renamed to `MemoryMapOwned`.
- `pub fn memory_map(&self, mt: MemoryType) -> Result<MemoryMap>` now returns
a `MemoryMapOwned`.
- **Breaking:** `PcrEvent::new_in_buffer` and `PcrEventInputs::new_in_buffer`
now take an initialized buffer (`[u8`] instead of `[MaybeUninit<u8>]`), and if
the buffer is too small the required size is returned in the error data.


# uefi - 0.29.0 (2024-07-02)
Expand Down
66 changes: 54 additions & 12 deletions uefi/src/proto/tcg/v1.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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];

Expand Down Expand Up @@ -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<u8>],
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<usize>> {
let event_data_size = u32::try_from(event_data.len())
.map_err(|_| Error::new(Status::INVALID_PARAMETER, None))?;

let required_size = mem::size_of::<PcrIndex>()
+ mem::size_of::<EventType>()
Expand All @@ -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);
Expand All @@ -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<Box<Self>> {
#[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 {
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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]
Expand Down
77 changes: 64 additions & 13 deletions uefi/src/proto/tcg/v2.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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`.
Expand Down Expand Up @@ -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,
Expand All @@ -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<u8>],
buffer: &'buf mut [u8],
pcr_index: PcrIndex,
event_type: EventType,
event_data: &[u8],
) -> Result<&'buf Self> {
) -> Result<&'buf mut Self, Option<usize>> {
let required_size =
mem::size_of::<u32>() + mem::size_of::<EventHeader>() + 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();

Expand All @@ -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<Box<Self>> {
#[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")
Expand All @@ -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 {
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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]
Expand Down

0 comments on commit 1fa9408

Please sign in to comment.