Skip to content

Commit 6cfe74e

Browse files
committed
kernel/vtpm: support persistent state and key storage
SVSM's vTPM could not receive external persistent state on init, nor did it store the KBS key for future state encryption/decryption. Update vtpm_init and TCG TPM backend to accept an optional state buffer and store the KBS secret key in the TcgTpm struct. This stored key will be used for future state decryption on startup. Even though state is passed as a buffer to the vtpm_init() function, it does not come in effect yet, because the tpm reference implementation does not copy platParameter into s_NV buffer in _plat__NVEnable() function. Signed-off-by: Arun Menon <armenon@redhat.com>
1 parent 86cdf74 commit 6cfe74e

3 files changed

Lines changed: 37 additions & 3 deletions

File tree

kernel/src/svsm.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -556,7 +556,7 @@ fn svsm_init(launch_info: &KernelLaunchInfo) {
556556
}
557557

558558
#[cfg(all(feature = "vtpm", not(test)))]
559-
vtpm_init().expect("vTPM failed to initialize");
559+
vtpm_init(None, None).expect("vTPM failed to initialize");
560560

561561
#[cfg(all(feature = "uefivars", not(test)))]
562562
uefi_mm_protocol_init().expect("uefi mm protocol failed to initialize");

kernel/src/vtpm/mod.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,11 +99,13 @@ static VTPM: SpinLock<Vtpm> = SpinLock::new(Vtpm::new());
9999

100100
/// Initialize the TPM by calling the init() implementation of the
101101
/// [`VtpmInterface`]
102-
pub fn vtpm_init() -> Result<(), SvsmReqError> {
102+
pub fn vtpm_init(state: Option<Vec<u8>>, key: Option<&[u8]>) -> Result<(), SvsmReqError> {
103103
let mut vtpm = VTPM.lock();
104104
if vtpm.is_powered_on() {
105105
return Ok(());
106106
}
107+
vtpm.set_key(key);
108+
vtpm.set_state(state);
107109
vtpm.init()?;
108110
Ok(())
109111
}

kernel/src/vtpm/tcgtpm/mod.rs

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,13 +38,17 @@ use crate::{
3838
pub struct TcgTpm {
3939
is_powered_on: bool,
4040
ekpub: Option<Vec<u8>>,
41+
key: Option<Vec<u8>>, // This is the kbs secret used to encrypt the state.
42+
state: Option<Vec<u8>>, // Persistent state buffer.
4143
}
4244

4345
impl TcgTpm {
4446
pub const fn new() -> TcgTpm {
4547
TcgTpm {
4648
is_powered_on: false,
4749
ekpub: None,
50+
key: None,
51+
state: None,
4852
}
4953
}
5054

@@ -75,6 +79,20 @@ impl TcgTpm {
7579
}
7680
}
7781
}
82+
83+
pub fn set_key(&mut self, key: Option<&[u8]>) {
84+
self.key = key.map(|k| k.to_vec());
85+
86+
if self.key.is_some() {
87+
log::info!("vTPM: Attestation key has been set and stored.");
88+
} else {
89+
log::info!("vTPM: Attestation key is not available");
90+
}
91+
}
92+
93+
pub fn set_state(&mut self, state: Option<Vec<u8>>) {
94+
self.state = state;
95+
}
7896
}
7997

8098
const TPM_CMDS_SUPPORTED: &[TpmPlatformCommand] = &[TpmPlatformCommand::SendCommand];
@@ -196,14 +214,28 @@ impl VtpmInterface for TcgTpm {
196214
// 5. Power it on indicating it requires startup. By default, OVMF will start
197215
// and selftest it.
198216

217+
let (ptr, size) = match &mut self.state {
218+
Some(buf) => (buf.as_mut_ptr() as *mut c_void, buf.len() as u32),
219+
None => (VirtAddr::null().as_mut_ptr::<c_void>(), 0),
220+
};
221+
199222
// SAFETY: FFI call. Parameters and return values are checked.
200-
let mut rc = unsafe { _plat__NVEnable(VirtAddr::null().as_mut_ptr::<c_void>(), 0) };
223+
let mut rc = unsafe { _plat__NVEnable(ptr, size as usize) };
201224
if rc != 0 {
202225
log::error!("_plat__NVEnable failed rc={rc}");
203226
return Err(SvsmReqError::incomplete());
204227
}
205228

206229
rc = self.manufacture(1)?;
230+
if rc == 1 {
231+
self.signal_poweron(false)?;
232+
self.signal_nvon()?;
233+
log::info!(
234+
"VTPM: TPM 2.0 Reference Implementation successfully restored from persistent state"
235+
);
236+
return Ok(());
237+
}
238+
207239
if rc != 0 {
208240
// SAFETY: FFI call. Parameter checked, no return value.
209241
unsafe { _plat__NVDisable(core::ptr::without_provenance_mut::<c_void>(1), 0) };

0 commit comments

Comments
 (0)