Skip to content
Open
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
28 changes: 24 additions & 4 deletions kernel/src/protocols/attest.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,17 @@ pub struct AttestServicesOp {
}

impl AttestServicesOp {
/// Take a PhysAddr and return Self
pub fn try_from_guest(paddr: PhysAddr) -> Result<Self, SvsmReqError> {
let ops = read_from_guest::<Self>(paddr).map_err(|_| SvsmReqError::invalid_parameter())?;

if !ops.is_reserved_clear() {
return Err(SvsmReqError::invalid_parameter());
}
Comment on lines +63 to +65
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we not also want to check the validity requirements of the nonce and manifest?
We can then say that there's the PreAttestServicesOp type that is structurally all the fields to read, and try_from_guest returns AttestServicesOp which is ensured to have valid fields. That allows all the get_ methods to not need to do any wellformedness checks.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we not also want to check the validity requirements of the nonce and manifest?

Maybe yes, but I just followed what we did in try_from_as_ref() so I guess we should fix both.

We can then say that there's the PreAttestServicesOp type that is structurally all the fields to read, and try_from_guest returns AttestServicesOp which is ensured to have valid fields. That allows all the get_ methods to not need to do any wellformedness checks.

Yep, this is something similar to what I did in #603 where I added a generic validate() method called by the try_from_* API. Maybe I can do the same here (in another commit). WDYT?

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think even moreso here and there. both TpmSendCommandRequest and AttestServicesOp ought to have their fields in TpmSendCommandRequestState/AttestServicesOpState structs that get embedded in TpmSendCommandRequest/AttestServicesOp only if their values pass validation. This ensures that operations are only associated with the struct type that maintains the wellformedness invariant.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we make fields private and provide only try_from* method to build those structures, we should have the same, without embending them, no?
Or maybe I'm missing something.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we make fields private and provide only try_from* method to build those structures, we should have the same, without embending them, no? Or maybe I'm missing something.

@deeglaze WDYT?


Ok(ops)
}

/// Take a slice and return a reference for Self
pub fn try_from_as_ref(buffer: &[u8]) -> Result<&Self, SvsmReqError> {
let ops: &Self =
Expand Down Expand Up @@ -189,6 +200,17 @@ pub struct AttestSingleServiceOp {
}

impl AttestSingleServiceOp {
/// Take a PhysAddr and return Self
pub fn try_from_guest(paddr: PhysAddr) -> Result<Self, SvsmReqError> {
let ops = read_from_guest::<Self>(paddr).map_err(|_| SvsmReqError::invalid_parameter())?;

if !ops.is_reserved_clear() {
return Err(SvsmReqError::invalid_parameter());
}

Ok(ops)
}

/// Take a slice and return a reference for Self
pub fn try_from_as_ref(buffer: &[u8]) -> Result<&Self, SvsmReqError> {
let ops: &Self =
Expand Down Expand Up @@ -343,8 +365,7 @@ fn attest_single_vtpm(
fn attest_multiple_services(params: &mut RequestParams) -> Result<(), SvsmReqError> {
let gpa = PhysAddr::from(params.rcx);

let attest_op =
read_from_guest::<AttestServicesOp>(gpa).map_err(|_| SvsmReqError::invalid_parameter())?;
let attest_op = AttestServicesOp::try_from_guest(gpa)?;

// Attest multiple services is expected to return a GUID table (mixed endian ordering) of the
// enumerated active services' attestation manifest. A service that does not have its own
Expand Down Expand Up @@ -379,8 +400,7 @@ fn attest_single_service_handler(params: &mut RequestParams) -> Result<(), SvsmR
// Get the gpa of Attest Single Service Operation structure
let gpa = PhysAddr::from(params.rcx);

let attest_op = read_from_guest::<AttestSingleServiceOp>(gpa)
.map_err(|_| SvsmReqError::invalid_parameter())?;
let attest_op = AttestSingleServiceOp::try_from_guest(gpa)?;

// Extract the GUID from the Attest Single Service Operation structure.
// The GUID is used to determine the specific service to be attested.
Expand Down