Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions src/certs/sev/ca/cert/v1.rs
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,9 @@ impl PartialEq for Certificate {
}
}

// SAFETY: All fields of Data, recursively, are integers or arrays of integers.
unsafe impl crate::util::AnyBitPattern for Data {}

impl Decoder<()> for Certificate {
fn decode(reader: &mut impl Read, _: ()) -> Result<Self> {
let p = Preamble {
Expand Down
5 changes: 5 additions & 0 deletions src/certs/sev/sev/cert/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,11 @@ impl<U: Copy + Into<crate::certs::sev::Usage>> PartialEq<U> for Certificate {
}
}

// SAFETY: Certificate is a union of a u32 and a v1 certificate. All fields
// of the v1 certificate, recursively, are integers, arrays, or unions of
// these.
unsafe impl crate::util::AnyBitPattern for Certificate {}

impl Decoder<()> for Certificate {
fn decode(reader: &mut impl Read, params: ()) -> Result<Self> {
Ok(match u32::from_le(reader.load()?) {
Expand Down
8 changes: 8 additions & 0 deletions src/certs/sev/sev/cert/v1/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,14 @@ impl Certificate {
}
}

// SAFETY: All fields of Data, recursively, are integers, arrays, or unions of
// these.
unsafe impl crate::util::AnyBitPattern for body::Data {}

// SAFETY: All fields of Signature, recursively, are integers, arrays, or
// unions of these.
unsafe impl crate::util::AnyBitPattern for sig::Signature {}

impl Decoder<()> for Certificate {
fn decode(reader: &mut impl Read, _: ()) -> Result<Self> {
Ok(Self {
Expand Down
11 changes: 4 additions & 7 deletions src/firmware/host/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ use std::{

#[cfg(feature = "sev")]
#[cfg(target_os = "linux")]
use std::mem::MaybeUninit;
use crate::util::AnyBitPattern;

#[cfg(feature = "snp")]
#[cfg(target_os = "linux")]
Expand Down Expand Up @@ -131,8 +131,7 @@ impl Firmware {
/// Request a signature for the PEK.
#[cfg(feature = "sev")]
pub fn pek_csr(&mut self) -> Result<Certificate, UserApiError> {
#[allow(clippy::uninit_assumed_init)]
let mut pek: Certificate = unsafe { MaybeUninit::uninit().assume_init() };
let mut pek = Certificate::zeroed();
let mut csr = PekCsr::new(&mut pek);
let mut cmd_buf = Command::from_mut(&mut csr);
PEK_CSR
Expand All @@ -155,10 +154,8 @@ impl Firmware {
/// Export the SEV certificate chain.
#[cfg(feature = "sev")]
pub fn pdh_cert_export(&mut self) -> Result<Chain, UserApiError> {
#[allow(clippy::uninit_assumed_init)]
let mut chain: [Certificate; 3] = unsafe { MaybeUninit::uninit().assume_init() };
#[allow(clippy::uninit_assumed_init)]
let mut pdh: Certificate = unsafe { MaybeUninit::uninit().assume_init() };
let mut chain = <[Certificate; 3]>::zeroed();
let mut pdh = Certificate::zeroed();
let mut pdh_cert_export = PdhCertExport::new(&mut pdh, &mut chain);
let mut cmd_buf = Command::from_mut(&mut pdh_cert_export);

Expand Down
3 changes: 3 additions & 0 deletions src/firmware/host/types/sev.rs
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,9 @@ impl std::fmt::Display for Build {
}
}

// SAFETY: Build and Version contain only u8 fields.
unsafe impl crate::util::AnyBitPattern for Build {}

impl Decoder<()> for Build {
fn decode(reader: &mut impl Read, _: ()) -> std::io::Result<Self> {
reader.load()
Expand Down
10 changes: 10 additions & 0 deletions src/launch/sev.rs
Original file line number Diff line number Diff line change
Expand Up @@ -383,6 +383,10 @@ pub struct Start {
pub session: Session,
}

// SAFETY: All fields of Start, recursively, are integers, arrays, or unions
// of these. The bit flag types wrap integers.
unsafe impl crate::util::AnyBitPattern for Start {}

impl Decoder<()> for Start {
fn decode(reader: &mut impl Read, _: ()) -> std::io::Result<Self> {
reader.load()
Expand Down Expand Up @@ -460,6 +464,9 @@ pub struct Secret {
pub ciphertext: Vec<u8>,
}

// SAFETY: Header contains bit flags over a u32 and byte arrays.
unsafe impl crate::util::AnyBitPattern for Header {}

impl Decoder<()> for Secret {
fn decode(reader: &mut impl Read, _: ()) -> std::io::Result<Self> {
let header = reader.load()?;
Expand Down Expand Up @@ -488,6 +495,9 @@ pub struct Measurement {
pub mnonce: [u8; 16],
}

// SAFETY: Measurement contains only byte arrays.
unsafe impl crate::util::AnyBitPattern for Measurement {}

impl Decoder<()> for Measurement {
fn decode(reader: &mut impl Read, _: ()) -> std::io::Result<Self> {
reader.load()
Expand Down
60 changes: 54 additions & 6 deletions src/util/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,37 @@ use std::{
slice::{from_raw_parts, from_raw_parts_mut},
};

/// A type for which every initialized bit pattern of `size_of::<Self>()` bytes
/// is a valid value.
///
/// # Safety
///
/// Implement this only for types whose fields, recursively, are all integers,
/// arrays, or unions of such types. Types that contain `bool`, `char`, enums,
/// references, pointers, or `NonZero*` values must not implement it.
pub unsafe trait AnyBitPattern: Copy {
/// Returns a value with every byte set to zero.
fn zeroed() -> Self {
// SAFETY: Self accepts every bit pattern, including all zeroes.
unsafe { MaybeUninit::zeroed().assume_init() }
}
}

// SAFETY: Every bit pattern is a valid u32.
unsafe impl AnyBitPattern for u32 {}

// SAFETY: An array is valid when each element is valid.
unsafe impl<T: AnyBitPattern, const N: usize> AnyBitPattern for [T; N] {}

pub trait TypeLoad: Read {
fn load<T: Sized + Copy>(&mut self) -> Result<T> {
#[allow(clippy::uninit_assumed_init)]
let mut t = unsafe { MaybeUninit::uninit().assume_init() };
let p = &mut t as *mut T as *mut u8;
let s = unsafe { from_raw_parts_mut(p, size_of::<T>()) };
fn load<T: AnyBitPattern>(&mut self) -> Result<T> {
let mut t = MaybeUninit::<T>::zeroed();
// SAFETY: t owns size_of::<T>() bytes. zeroed() initialized all of
// them, which makes them valid u8 values.
let s = unsafe { from_raw_parts_mut(t.as_mut_ptr() as *mut u8, size_of::<T>()) };
self.read_exact(s)?;
Ok(t)
// SAFETY: read_exact filled every byte, and T accepts any bit pattern.
Ok(unsafe { t.assume_init() })
}
}

Expand All @@ -35,3 +58,28 @@ pub trait TypeSave: Write {

impl<T: Read> TypeLoad for T {}
impl<T: Write> TypeSave for T {}

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn test_load_reads_value() {
let mut reader: &[u8] = &[1, 2, 3, 4, 5, 6, 7, 8];
let value: [u32; 2] = reader.load().unwrap();
assert_eq!(
value,
[
u32::from_ne_bytes([1, 2, 3, 4]),
u32::from_ne_bytes([5, 6, 7, 8])
]
);
}

#[test]
fn test_load_short_input() {
let mut reader: &[u8] = &[1, 2, 3];
let err = reader.load::<u32>().unwrap_err();
assert_eq!(err.kind(), std::io::ErrorKind::UnexpectedEof);
}
}
3 changes: 3 additions & 0 deletions src/vmsa/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -393,6 +393,9 @@ impl Default for Vmsa {
}
}

// SAFETY: Vmsa and VmcbSegment contain only integers and integer arrays.
unsafe impl crate::util::AnyBitPattern for Vmsa {}

impl Decoder<()> for Vmsa {
fn decode(reader: &mut impl Read, _: ()) -> Result<Self, std::io::Error> {
reader.load()
Expand Down
Loading