Invoke get_report() using private memory
This commit is contained in:
parent
0636e1048e
commit
83176020f2
|
|
@ -1,12 +1,18 @@
|
|||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
use core::{mem::size_of, time::Duration};
|
||||
use core::{
|
||||
mem::{offset_of, size_of},
|
||||
time::Duration,
|
||||
};
|
||||
|
||||
use align_ext::AlignExt;
|
||||
use aster_util::{field_ptr, safe_ptr::SafePtr};
|
||||
use device_id::DeviceId;
|
||||
use ostd::{
|
||||
mm::{DmaCoherent, FrameAllocOptions, HasPaddr, HasSize, VmIo, PAGE_SIZE},
|
||||
const_assert,
|
||||
mm::{
|
||||
io_util::HasVmReaderWriter, DmaCoherent, FrameAllocOptions, HasPaddr, HasSize, USegment,
|
||||
VmIo, PAGE_SIZE,
|
||||
},
|
||||
sync::WaitQueue,
|
||||
};
|
||||
use tdx_guest::{
|
||||
|
|
@ -26,16 +32,6 @@ use crate::{
|
|||
process::signal::{PollHandle, Pollable},
|
||||
};
|
||||
|
||||
const TDX_REPORTDATA_LEN: usize = 64;
|
||||
const TDX_REPORT_LEN: usize = 1024;
|
||||
|
||||
#[derive(Debug, Clone, Copy, Pod)]
|
||||
#[repr(C)]
|
||||
pub struct TdxReportRequest {
|
||||
report_data: [u8; TDX_REPORTDATA_LEN],
|
||||
tdx_report: [u8; TDX_REPORT_LEN],
|
||||
}
|
||||
|
||||
pub struct TdxGuest;
|
||||
|
||||
impl Device for TdxGuest {
|
||||
|
|
@ -126,9 +122,12 @@ pub fn tdx_get_quote(inblob: &[u8]) -> Result<Box<[u8]>> {
|
|||
|
||||
field_ptr!(&report_ptr, TdxQuoteHdr, version).write(&1u64)?;
|
||||
field_ptr!(&report_ptr, TdxQuoteHdr, status).write(&0u64)?;
|
||||
field_ptr!(&report_ptr, TdxQuoteHdr, in_len).write(&(TDX_REPORT_LEN as u32))?;
|
||||
field_ptr!(&report_ptr, TdxQuoteHdr, in_len).write(&(size_of::<TdReport>() as u32))?;
|
||||
field_ptr!(&report_ptr, TdxQuoteHdr, out_len).write(&0u32)?;
|
||||
buf.write_bytes(size_of::<TdxQuoteHdr>(), &report)?;
|
||||
buf.write(
|
||||
size_of::<TdxQuoteHdr>(),
|
||||
report.reader().to_fallible().limit(size_of::<TdReport>()),
|
||||
)?;
|
||||
|
||||
// FIXME: The `get_quote` 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.
|
||||
|
|
@ -168,50 +167,118 @@ struct TdxQuoteHdr {
|
|||
out_len: u32,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, Pod)]
|
||||
#[repr(C)]
|
||||
struct TdxReportRequest {
|
||||
report_data: ReportData,
|
||||
tdx_report: TdReport,
|
||||
}
|
||||
|
||||
impl TdxReportRequest {
|
||||
fn report_inblob(&self) -> &[u8] {
|
||||
self.report_data.as_bytes()
|
||||
}
|
||||
}
|
||||
|
||||
/// TDX Report structure (`TDREPORT_STRUCT`) as defined in the Intel TDX Module Specification.
|
||||
#[derive(Debug, Clone, Copy, Pod)]
|
||||
#[repr(C)]
|
||||
struct TdReport {
|
||||
report_mac: ReportMac,
|
||||
_reserved: [u8; 256],
|
||||
td_info: TdInfo,
|
||||
}
|
||||
const_assert!(size_of::<TdReport>() == 1024);
|
||||
|
||||
#[derive(Debug, Clone, Copy, Pod)]
|
||||
#[repr(C)]
|
||||
struct ReportMac {
|
||||
_reserved1: [u8; 128],
|
||||
report_data: ReportData,
|
||||
_reserved2: [u8; 64],
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, Pod)]
|
||||
#[repr(C)]
|
||||
struct TdInfo {
|
||||
attributes: [u8; 8],
|
||||
xfam: [u8; 8],
|
||||
mrtd: [u8; 48],
|
||||
mrconfigid: [u8; 48],
|
||||
mrowner: [u8; 48],
|
||||
mrownerconfig: [u8; 48],
|
||||
rtmr1: [u8; 48],
|
||||
rtmr2: [u8; 48],
|
||||
rtmr3: [u8; 48],
|
||||
rtmr4: [u8; 48],
|
||||
servtd_hash: [u8; 48],
|
||||
extension: [u8; 64],
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, Pod)]
|
||||
#[repr(C)]
|
||||
struct ReportData {
|
||||
data: [u8; 64],
|
||||
}
|
||||
|
||||
impl TdReport {
|
||||
const fn report_data_offset() -> usize {
|
||||
offset_of!(TdReport, report_mac) + offset_of!(ReportMac, report_data)
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_get_report(arg: usize) -> Result<i32> {
|
||||
let current_task = ostd::task::Task::current().unwrap();
|
||||
let user_space = CurrentUserSpace::new(current_task.as_thread_local().unwrap());
|
||||
let user_request: TdxReportRequest = user_space.read_val(arg)?;
|
||||
|
||||
let report = tdx_get_report(&user_request.report_data)?;
|
||||
let report = tdx_get_report(&user_request.report_inblob())?;
|
||||
|
||||
let tdx_report_vaddr = arg + TDX_REPORTDATA_LEN;
|
||||
user_space.write_bytes(tdx_report_vaddr, &mut VmReader::from(report.as_ref()))?;
|
||||
let tdx_report_vaddr = arg + offset_of!(TdxReportRequest, tdx_report);
|
||||
user_space.write_bytes(
|
||||
tdx_report_vaddr,
|
||||
report.reader().limit(size_of::<TdReport>()),
|
||||
)?;
|
||||
Ok(0)
|
||||
}
|
||||
|
||||
fn tdx_get_report(inblob: &[u8]) -> Result<Box<[u8]>> {
|
||||
if inblob.len() != TDX_REPORTDATA_LEN {
|
||||
/// 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<USegment> {
|
||||
if inblob.len() != size_of::<ReportData>() {
|
||||
return_errno_with_message!(Errno::EINVAL, "Invalid inblob length");
|
||||
}
|
||||
|
||||
let segment = FrameAllocOptions::new().alloc_segment(2)?;
|
||||
let dma_coherent = DmaCoherent::map(segment.into(), false).unwrap();
|
||||
dma_coherent.write_bytes(0, &inblob).unwrap();
|
||||
let report: USegment = {
|
||||
const REPORT_SIZE_IN_PAGES: usize = size_of::<TdReport>().div_ceil(PAGE_SIZE);
|
||||
FrameAllocOptions::new()
|
||||
.alloc_segment(REPORT_SIZE_IN_PAGES)?
|
||||
.into()
|
||||
};
|
||||
|
||||
// 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(
|
||||
((dma_coherent.paddr() + 1024) as u64) | SHARED_MASK,
|
||||
(dma_coherent.paddr() as u64) | SHARED_MASK,
|
||||
)?;
|
||||
|
||||
// Note: We cannot convert `DmaCoherent` to `USegment` here. When shared memory is converted back
|
||||
// to private memory in TDX, `TDG.MEM.PAGE.ACCEPT` will zero out all content.
|
||||
// TDX Module Specification - `TDG.MEM.PAGE.ACCEPT` Leaf:
|
||||
// "Accept a pending private page and initialize it to all-0 using the TD ephemeral private key."
|
||||
let mut generated_report = Box::new([0u8; TDX_REPORT_LEN]);
|
||||
dma_coherent
|
||||
.read_bytes(1024, generated_report.as_mut())
|
||||
.unwrap();
|
||||
|
||||
Ok(generated_report)
|
||||
get_report(report.paddr() as u64, report_data_paddr as u64)?;
|
||||
Ok(report)
|
||||
}
|
||||
|
||||
fn alloc_dma_buf(buf_len: usize) -> Result<DmaCoherent> {
|
||||
let aligned_buf_len = buf_len.align_up(PAGE_SIZE);
|
||||
let segment = FrameAllocOptions::new().alloc_segment(aligned_buf_len / PAGE_SIZE)?;
|
||||
|
||||
let segment = FrameAllocOptions::new().alloc_segment(buf_len.div_ceil(PAGE_SIZE))?;
|
||||
let dma_buf = DmaCoherent::map(segment.into(), false).unwrap();
|
||||
Ok(dma_buf)
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue