Link TSM-MR interface to TDX report
This commit is contained in:
parent
f85afc41c8
commit
4b93006263
|
|
@ -162,7 +162,7 @@ impl FileIo for TdxGuestFile {
|
|||
inblob_ptr.read()?
|
||||
};
|
||||
|
||||
let outblob = tdx_get_report(inblob.as_bytes())?;
|
||||
let outblob = tdx_get_report(Some(inblob.as_bytes()))?;
|
||||
let outblob_ptr = field_ptr!(&data_ptr, TdxReportRequest, tdx_report);
|
||||
outblob_ptr.copy_from(&SafePtr::new(&*outblob, 0))?;
|
||||
|
||||
|
|
@ -176,11 +176,24 @@ impl FileIo for TdxGuestFile {
|
|||
|
||||
static TDX_REPORT: Once<RwMutex<USegment>> = Once::new();
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub enum MeasurementReg {
|
||||
MrConfigId,
|
||||
MrOwner,
|
||||
MrOwnerConfig,
|
||||
MrTd,
|
||||
Rtmr0,
|
||||
Rtmr1,
|
||||
Rtmr2,
|
||||
Rtmr3,
|
||||
}
|
||||
|
||||
/// Gets the TDX quote given the specified data in `inblob`.
|
||||
pub fn tdx_get_quote(inblob: &[u8]) -> Result<Box<[u8]>> {
|
||||
const GET_QUOTE_IN_FLIGHT: u64 = 0xFFFF_FFFF_FFFF_FFFF;
|
||||
const GET_QUOTE_BUF_SIZE: usize = 8 * 1024;
|
||||
|
||||
let report = tdx_get_report(inblob)?;
|
||||
let report = tdx_get_report(Some(inblob))?;
|
||||
let report_ptr: SafePtr<TdReport, _, _> = SafePtr::new(&*report, 0);
|
||||
|
||||
let buf = DmaCoherent::alloc(GET_QUOTE_BUF_SIZE.div_ceil(PAGE_SIZE), false)?;
|
||||
|
|
@ -219,6 +232,52 @@ pub fn tdx_get_quote(inblob: &[u8]) -> Result<Box<[u8]>> {
|
|||
Ok(outblob)
|
||||
}
|
||||
|
||||
/// Gets the TDX report given the specified data in `inblob`.
|
||||
///
|
||||
/// The first `size_of::<TdReport>()` bytes of data in the returned `USegment` is the report.
|
||||
/// The rest in `USegment` should be ignored.
|
||||
/// If `inblob` is `None`, use the existing report data to get the report, i.e. refresh the
|
||||
/// report.
|
||||
pub fn tdx_get_report(inblob: Option<&[u8]>) -> Result<RwMutexUpgradeableGuard<'_, USegment>> {
|
||||
let report = TDX_REPORT.get().unwrap().write();
|
||||
|
||||
if let Some(inblob) = inblob {
|
||||
if inblob.len() != size_of::<ReportData>() {
|
||||
return_errno_with_message!(Errno::EINVAL, "Invalid inblob length");
|
||||
}
|
||||
|
||||
// Use `inblob` as the data associated with the report.
|
||||
report
|
||||
.write_bytes(TdReport::report_data_offset(), inblob)
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
// From TDX Module Specification, the report structure returned by TDX Module
|
||||
// places the report data at offset 128, so using the same offset keeps the
|
||||
// memory layout consistent with the TDX Modules's output format. And we can
|
||||
// directly call `get_report` on the existing report structure without needing
|
||||
// to rewrite the report data.
|
||||
let report_data_ptr = report.paddr() + TdReport::report_data_offset();
|
||||
|
||||
// FIXME: The `get_report` API from the `tdx_guest` crate should have been marked `unsafe`
|
||||
// because it has no way to determine if the input physical address is safe or not.
|
||||
get_report(report.paddr() as u64, report_data_ptr as u64)?;
|
||||
Ok(report.downgrade())
|
||||
}
|
||||
|
||||
const SHA384_DIGEST_SIZE: usize = 48;
|
||||
|
||||
/// Gets the measurement register value from the TDX report.
|
||||
pub fn tdx_get_mr(reg: MeasurementReg) -> Result<[u8; SHA384_DIGEST_SIZE]> {
|
||||
let report = TDX_REPORT.get().unwrap().read();
|
||||
|
||||
let mut blob = [0u8; SHA384_DIGEST_SIZE];
|
||||
report
|
||||
.read_bytes(TdReport::mr_offset(reg), blob.as_mut())
|
||||
.unwrap();
|
||||
Ok(blob)
|
||||
}
|
||||
|
||||
pub(super) fn init() -> Result<()> {
|
||||
TDX_REPORT.call_once(|| {
|
||||
let report = FrameAllocOptions::new()
|
||||
|
|
@ -283,10 +342,10 @@ struct TdInfo {
|
|||
mrconfigid: [u8; 48],
|
||||
mrowner: [u8; 48],
|
||||
mrownerconfig: [u8; 48],
|
||||
rtmr0: [u8; 48],
|
||||
rtmr1: [u8; 48],
|
||||
rtmr2: [u8; 48],
|
||||
rtmr3: [u8; 48],
|
||||
rtmr4: [u8; 48],
|
||||
servtd_hash: [u8; 48],
|
||||
extension: [u8; 64],
|
||||
}
|
||||
|
|
@ -295,6 +354,20 @@ impl TdReport {
|
|||
const fn report_data_offset() -> usize {
|
||||
offset_of!(TdReport, report_mac) + offset_of!(ReportMac, report_data)
|
||||
}
|
||||
|
||||
const fn mr_offset(reg: MeasurementReg) -> usize {
|
||||
offset_of!(TdReport, td_info)
|
||||
+ match reg {
|
||||
MeasurementReg::MrConfigId => offset_of!(TdInfo, mrconfigid),
|
||||
MeasurementReg::MrOwner => offset_of!(TdInfo, mrowner),
|
||||
MeasurementReg::MrOwnerConfig => offset_of!(TdInfo, mrownerconfig),
|
||||
MeasurementReg::MrTd => offset_of!(TdInfo, mrtd),
|
||||
MeasurementReg::Rtmr0 => offset_of!(TdInfo, rtmr0),
|
||||
MeasurementReg::Rtmr1 => offset_of!(TdInfo, rtmr1),
|
||||
MeasurementReg::Rtmr2 => offset_of!(TdInfo, rtmr2),
|
||||
MeasurementReg::Rtmr3 => offset_of!(TdInfo, rtmr3),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mod ioctl_defs {
|
||||
|
|
@ -306,33 +379,3 @@ mod ioctl_defs {
|
|||
pub(super) type GetTdxReport =
|
||||
ioc!(TDX_CMD_GET_REPORT0, b'T', 0x01, InOutData<TdxReportRequest>);
|
||||
}
|
||||
|
||||
/// Gets the TDX report given the specified data in `inblob`.
|
||||
///
|
||||
/// The first `size_of::<TdReport>()` bytes of data in the returned `USegment` is the report.
|
||||
/// The rest in `USegment` should be ignored.
|
||||
fn tdx_get_report(inblob: &[u8]) -> Result<RwMutexUpgradeableGuard<'_, USegment>> {
|
||||
if inblob.len() != size_of::<ReportData>() {
|
||||
return_errno_with_message!(Errno::EINVAL, "Invalid inblob length");
|
||||
}
|
||||
|
||||
let report = TDX_REPORT.get().unwrap().write();
|
||||
|
||||
// Use `inblob` as the data associated with the report.
|
||||
let report_data_paddr = {
|
||||
// From TDX Module Specification, the report structure returned by TDX Module
|
||||
// places the report data at offset 128, so using the same offset keeps the
|
||||
// memory layout consistent with the TDX Modules's output format. And we can
|
||||
// directly call `get_report` on the existing report structure without needing
|
||||
// to rewrite the report data.
|
||||
report
|
||||
.write_bytes(TdReport::report_data_offset(), inblob)
|
||||
.unwrap();
|
||||
report.paddr() + TdReport::report_data_offset()
|
||||
};
|
||||
|
||||
// FIXME: The `get_report` API from the `tdx_guest` crate should have been marked `unsafe`
|
||||
// because it has no way to determine if the input physical address is safe or not.
|
||||
get_report(report.paddr() as u64, report_data_paddr as u64)?;
|
||||
Ok(report.downgrade())
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,7 +7,12 @@ use aster_systree::{
|
|||
inherit_sys_branch_node, inherit_sys_leaf_node,
|
||||
};
|
||||
use inherit_methods_macro::inherit_methods;
|
||||
use ostd::mm::{VmReader, VmWriter};
|
||||
use ostd::{
|
||||
mm::{FallibleVmWrite, VmReader, VmWriter},
|
||||
sync::RwMutex,
|
||||
};
|
||||
|
||||
use crate::device::misc::tdxguest::{MeasurementReg, tdx_get_mr, tdx_get_report};
|
||||
|
||||
pub(super) fn init() {
|
||||
let node = {
|
||||
|
|
@ -66,46 +71,71 @@ inherit_sys_branch_node!(TdxGuestSysNodeRoot, fields, {
|
|||
#[derive(Debug)]
|
||||
struct Measurement {
|
||||
fields: NormalNodeFields<Self>,
|
||||
in_sync: RwMutex<bool>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct MeasurementAttr {
|
||||
name: &'static str,
|
||||
perms: SysPerms,
|
||||
reg: MeasurementReg,
|
||||
refresh_on_read: bool,
|
||||
}
|
||||
|
||||
impl MeasurementAttr {
|
||||
fn refresh_on_read(&self) -> bool {
|
||||
self.refresh_on_read
|
||||
}
|
||||
}
|
||||
|
||||
const MEASUREMENT_ATTRS: &[MeasurementAttr] = &[
|
||||
MeasurementAttr {
|
||||
name: "mrconfigid",
|
||||
perms: SysPerms::DEFAULT_RO_ATTR_PERMS,
|
||||
reg: MeasurementReg::MrConfigId,
|
||||
refresh_on_read: false,
|
||||
},
|
||||
MeasurementAttr {
|
||||
name: "mrowner",
|
||||
perms: SysPerms::DEFAULT_RO_ATTR_PERMS,
|
||||
reg: MeasurementReg::MrOwner,
|
||||
refresh_on_read: false,
|
||||
},
|
||||
MeasurementAttr {
|
||||
name: "mrownerconfig",
|
||||
perms: SysPerms::DEFAULT_RO_ATTR_PERMS,
|
||||
reg: MeasurementReg::MrOwnerConfig,
|
||||
refresh_on_read: false,
|
||||
},
|
||||
MeasurementAttr {
|
||||
name: "mrtd:sha384",
|
||||
perms: SysPerms::DEFAULT_RO_ATTR_PERMS,
|
||||
reg: MeasurementReg::MrTd,
|
||||
refresh_on_read: false,
|
||||
},
|
||||
MeasurementAttr {
|
||||
name: "rtmr0:sha384",
|
||||
perms: SysPerms::DEFAULT_RW_ATTR_PERMS,
|
||||
reg: MeasurementReg::Rtmr0,
|
||||
refresh_on_read: true,
|
||||
},
|
||||
MeasurementAttr {
|
||||
name: "rtmr1:sha384",
|
||||
perms: SysPerms::DEFAULT_RW_ATTR_PERMS,
|
||||
reg: MeasurementReg::Rtmr1,
|
||||
refresh_on_read: true,
|
||||
},
|
||||
MeasurementAttr {
|
||||
name: "rtmr2:sha384",
|
||||
perms: SysPerms::DEFAULT_RW_ATTR_PERMS,
|
||||
reg: MeasurementReg::Rtmr2,
|
||||
refresh_on_read: true,
|
||||
},
|
||||
MeasurementAttr {
|
||||
name: "rtmr3:sha384",
|
||||
perms: SysPerms::DEFAULT_RW_ATTR_PERMS,
|
||||
reg: MeasurementReg::Rtmr3,
|
||||
refresh_on_read: true,
|
||||
},
|
||||
];
|
||||
|
||||
|
|
@ -120,7 +150,10 @@ impl Measurement {
|
|||
Arc::new_cyclic(|weak_self| {
|
||||
let fields = NormalNodeFields::new(name, attrs, weak_self.clone());
|
||||
|
||||
Measurement { fields }
|
||||
Measurement {
|
||||
fields,
|
||||
in_sync: RwMutex::new(false),
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
@ -131,7 +164,28 @@ inherit_sys_leaf_node!(Measurement, fields, {
|
|||
}
|
||||
|
||||
fn read_attr_at(&self, name: &str, offset: usize, writer: &mut VmWriter) -> Result<usize> {
|
||||
Err(Error::AttributeError)
|
||||
let attr = MEASUREMENT_ATTRS
|
||||
.iter()
|
||||
.find(|attr| attr.name == name)
|
||||
.unwrap();
|
||||
|
||||
let mut in_sync = self.in_sync.upread();
|
||||
|
||||
if attr.refresh_on_read() && !*in_sync {
|
||||
let mut in_sync_write = in_sync.upgrade();
|
||||
if !*in_sync_write {
|
||||
tdx_get_report(None).map_err(|_| Error::AttributeError)?;
|
||||
*in_sync_write = true;
|
||||
}
|
||||
in_sync = in_sync_write.downgrade();
|
||||
}
|
||||
|
||||
let mr = tdx_get_mr(attr.reg).map_err(|_| Error::AttributeError)?;
|
||||
|
||||
let mut reader = VmReader::from(&mr[offset..]);
|
||||
writer
|
||||
.write_fallible(&mut reader)
|
||||
.map_err(|_| Error::AttributeError)
|
||||
}
|
||||
|
||||
fn write_attr(&self, name: &str, reader: &mut VmReader) -> Result<usize> {
|
||||
|
|
|
|||
Loading…
Reference in New Issue