Skip to content

Commit 26683c9

Browse files
committed
runtime: Harden DPE index cache
Follow-up to #3729. - Update reset initializes the cache only if the marker is missing, supporting 2.1.1 -> 2.1.2 once, without rescanning on later 2.1.2+ updates. - Switched cached-index users from raw u32 tci_type to CaliptraManagedDpeContext enum. - Moved measurement unchanged check into update_caliptra_managed_measurement() so CCIV/MCFW no-op updates do not extend cumulative state.
1 parent 6199f73 commit 26683c9

6 files changed

Lines changed: 137 additions & 80 deletions

File tree

drivers/src/lib.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,10 @@ pub use pcr_reset::PcrResetCounter;
112112
pub use persistent::fmc_alias_csr::FmcAliasCsrs;
113113
pub use persistent::IDEVID_CSR_ENVELOP_MARKER;
114114
#[cfg(feature = "runtime")]
115-
pub use persistent::{AuthManifestImageMetadataList, ExportedCdiEntry, ExportedCdiHandles};
115+
pub use persistent::{
116+
AuthManifestImageMetadataList, CaliptraManagedDpeContextIndices, ExportedCdiEntry,
117+
ExportedCdiHandles,
118+
};
116119
pub use persistent::{
117120
Ecc384IdevIdCsr, FuseLogArray, InitDevIdCsrEnvelope, Mldsa87IdevIdCsr, PcrLogArray,
118121
PersistentData, PersistentDataAccessor, StashMeasurementArray, ECC384_MAX_FMC_ALIAS_CSR_SIZE,

drivers/src/persistent.rs

Lines changed: 39 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -98,12 +98,49 @@ pub type AuthManifestImageMetadataList =
9898
[AuthManifestImageMetadata; AUTH_MANIFEST_IMAGE_METADATA_MAX_COUNT];
9999

100100
#[cfg(feature = "runtime")]
101-
#[derive(Clone, Copy, FromBytes, Immutable, IntoBytes, KnownLayout, Zeroize, Default)]
101+
#[derive(Clone, Copy, FromBytes, Immutable, IntoBytes, KnownLayout, Zeroize)]
102102
#[repr(C)]
103103
pub struct CaliptraManagedDpeContextIndices {
104+
pub initialized: u8,
104105
pub cciv: u8,
105106
pub mcu_rt: u8,
106-
pub reserved: [u8; 2],
107+
pub reserved: [u8; 1],
108+
}
109+
110+
#[cfg(feature = "runtime")]
111+
impl CaliptraManagedDpeContextIndices {
112+
pub const INVALID_INDEX: u8 = 0xff;
113+
const INITIALIZED_MARKER: u8 = 0xa5;
114+
115+
pub fn invalidate(&mut self) {
116+
*self = Self::default();
117+
}
118+
119+
pub fn is_initialized(&self) -> bool {
120+
self.initialized == Self::INITIALIZED_MARKER
121+
}
122+
123+
pub fn set_cciv(&mut self, idx: u8) {
124+
self.initialized = Self::INITIALIZED_MARKER;
125+
self.cciv = idx;
126+
}
127+
128+
pub fn set_mcu_rt(&mut self, idx: u8) {
129+
self.initialized = Self::INITIALIZED_MARKER;
130+
self.mcu_rt = idx;
131+
}
132+
}
133+
134+
#[cfg(feature = "runtime")]
135+
impl Default for CaliptraManagedDpeContextIndices {
136+
fn default() -> Self {
137+
Self {
138+
initialized: Self::INVALID_INDEX,
139+
cciv: Self::INVALID_INDEX,
140+
mcu_rt: Self::INVALID_INDEX,
141+
reserved: [Self::INVALID_INDEX; 1],
142+
}
143+
}
107144
}
108145

109146
#[derive(Clone, Immutable, IntoBytes, KnownLayout, TryFromBytes, Zeroize)]

runtime/src/activate_firmware.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ Abstract:
1515
use core::mem::offset_of;
1616

1717
use crate::authorize_and_stash::{self, AuthorizeAndStashCmd};
18-
use crate::drivers::{McuFwStatus, McuResetReason};
18+
use crate::drivers::{CaliptraManagedDpeContext, McuFwStatus, McuResetReason};
1919
use crate::Drivers;
2020
use crate::{manifest::find_metadata_entry, mutrefbytes};
2121
use caliptra_api::mailbox::{AuthorizeAndStashReq, ImageHashSource};
@@ -223,7 +223,7 @@ impl ActivateFirmwareCmd {
223223
}
224224
drivers
225225
.update_caliptra_managed_measurement(
226-
Drivers::MCU_RT_TCI_TYPE,
226+
CaliptraManagedDpeContext::McuRt,
227227
&measurement,
228228
Some(pl0_pauser_locality),
229229
)

runtime/src/drivers.rs

Lines changed: 85 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -57,9 +57,9 @@ use caliptra_drivers::{
5757
hand_off::DataStore,
5858
pcr_log::{PCR_ID_STASH_MEASUREMENT, RT_FW_CURRENT_PCR, RT_FW_JOURNEY_PCR},
5959
sha2_512_384::Sha2DigestOpTrait,
60-
Aes, Array4x12, CaliptraError, CaliptraResult, Ecc384, Hmac, KeyId, KeyVault, Lms, Mldsa87,
61-
Mldsa87PubKey, PcrBank, PersistentDataAccessor, Pic, ResetReason, Sha1, Sha256, Sha256Alg,
62-
Sha2_512_384, Sha2_512_384Acc, SocIfc, Trng,
60+
Aes, Array4x12, CaliptraError, CaliptraManagedDpeContextIndices, CaliptraResult, Ecc384, Hmac,
61+
KeyId, KeyVault, Lms, Mldsa87, Mldsa87PubKey, PcrBank, PersistentDataAccessor, Pic,
62+
ResetReason, Sha1, Sha256, Sha256Alg, Sha2_512_384, Sha2_512_384Acc, SocIfc, Trng,
6363
};
6464
use caliptra_drivers::{Dma, DmaMmio};
6565
use caliptra_image_types::ImageManifest;
@@ -98,6 +98,21 @@ impl From<McuResetReason> for u32 {
9898
}
9999
}
100100

101+
#[derive(Clone, Copy)]
102+
pub(crate) enum CaliptraManagedDpeContext {
103+
Cciv,
104+
McuRt,
105+
}
106+
107+
impl CaliptraManagedDpeContext {
108+
fn tci_type(self) -> u32 {
109+
match self {
110+
Self::Cciv => Drivers::CCIV_TCI_TYPE,
111+
Self::McuRt => Drivers::MCU_RT_TCI_TYPE,
112+
}
113+
}
114+
}
115+
101116
#[derive(Debug, Copy, Clone)]
102117
pub enum McuFwStatus {
103118
NotLoaded,
@@ -229,21 +244,22 @@ impl Drivers {
229244
match reset_reason {
230245
ResetReason::ColdReset => {
231246
cfi_assert_eq(self.soc_ifc.reset_reason(), ResetReason::ColdReset);
247+
self.persistent_data
248+
.get_mut()
249+
.caliptra_managed_dpe_context_indices
250+
.invalidate();
232251
Self::initialize_dpe(self)?;
233252
if self.soc_ifc.subsystem_mode() {
234253
RecoveryFlow::recovery_flow(self)?;
235254
}
236-
self.cache_caliptra_managed_dpe_context_indices()?;
237255
}
238256
ResetReason::UpdateReset => {
239257
cfi_assert_eq(self.soc_ifc.reset_reason(), ResetReason::UpdateReset);
240258
Self::validate_dpe_structure(self)?;
241259
Self::validate_context_tags(self)?;
260+
self.init_dpe_index_cache()?;
242261
Self::update_dpe_rt_tci(self)?;
243262
Self::update_dpe_cciv(self)?;
244-
// Repopulate appended context-index cache for hitless updates
245-
// from older runtimes that did not have these persistent fields.
246-
self.cache_caliptra_managed_dpe_context_indices()?;
247263
}
248264
ResetReason::WarmReset => {
249265
cfi_assert_eq(self.soc_ifc.reset_reason(), ResetReason::WarmReset);
@@ -321,22 +337,39 @@ impl Drivers {
321337
}
322338

323339
#[inline(always)]
324-
fn get_caliptra_managed_dpe_context_index(&self, tci_type: u32) -> CaliptraResult<usize> {
340+
fn get_caliptra_managed_dpe_context_index(
341+
&self,
342+
context: CaliptraManagedDpeContext,
343+
) -> Option<usize> {
325344
let indices = self
326345
.persistent_data
327346
.get()
328347
.caliptra_managed_dpe_context_indices;
329-
let idx = match tci_type {
330-
Self::CCIV_TCI_TYPE => indices.cciv,
331-
Self::MCU_RT_TCI_TYPE => indices.mcu_rt,
332-
_ => return Err(CaliptraError::RUNTIME_DPE_CONTEXT_NOT_FOUND),
348+
349+
if !indices.is_initialized() {
350+
return None;
351+
}
352+
353+
let idx = match context {
354+
CaliptraManagedDpeContext::Cciv => indices.cciv,
355+
CaliptraManagedDpeContext::McuRt => indices.mcu_rt,
333356
};
334357

335-
Ok(idx as usize)
358+
if idx == CaliptraManagedDpeContextIndices::INVALID_INDEX {
359+
None
360+
} else {
361+
Some(idx as usize)
362+
}
336363
}
337364

338-
fn cache_caliptra_managed_dpe_context_indices(&mut self) -> CaliptraResult<()> {
339-
if self.persistent_data.get().attestation_disabled.get() {
365+
fn init_dpe_index_cache(&mut self) -> CaliptraResult<()> {
366+
if self.persistent_data.get().attestation_disabled.get()
367+
|| self
368+
.persistent_data
369+
.get()
370+
.caliptra_managed_dpe_context_indices
371+
.is_initialized()
372+
{
340373
return Ok(());
341374
}
342375

@@ -364,11 +397,14 @@ impl Drivers {
364397
.persistent_data
365398
.get_mut()
366399
.caliptra_managed_dpe_context_indices;
367-
indices.cciv =
368-
u8::try_from(cciv_idx).map_err(|_| CaliptraError::RUNTIME_DPE_CONTEXT_NOT_FOUND)?;
400+
indices.set_cciv(
401+
u8::try_from(cciv_idx).map_err(|_| CaliptraError::RUNTIME_DPE_CONTEXT_NOT_FOUND)?,
402+
);
369403
if let Some(mcu_rt_idx) = mcu_rt_idx {
370-
indices.mcu_rt = u8::try_from(mcu_rt_idx)
371-
.map_err(|_| CaliptraError::RUNTIME_DPE_CONTEXT_NOT_FOUND)?;
404+
indices.set_mcu_rt(
405+
u8::try_from(mcu_rt_idx)
406+
.map_err(|_| CaliptraError::RUNTIME_DPE_CONTEXT_NOT_FOUND)?,
407+
);
372408
}
373409

374410
Ok(())
@@ -378,32 +414,34 @@ impl Drivers {
378414
#[inline(never)]
379415
pub(crate) fn update_caliptra_managed_measurement(
380416
&mut self,
381-
tci_type: u32,
417+
caliptra_managed_context: CaliptraManagedDpeContext,
382418
measurement: &[u8; 48],
383419
locality: Option<u32>,
384420
) -> CaliptraResult<()> {
385-
let persistent_data = self.persistent_data.get();
386-
let idx = self.get_caliptra_managed_dpe_context_index(tci_type)?;
387-
let ctx = persistent_data
388-
.state
389-
.contexts
390-
.get(idx)
391-
.ok_or(CaliptraError::RUNTIME_DPE_CONTEXT_NOT_FOUND)?;
392-
if ctx.state == ContextState::Inactive
393-
|| ctx.context_type != ContextType::Normal
394-
|| ctx.tci.tci_type != tci_type
395-
|| locality.is_some_and(|locality| ctx.locality != locality)
396-
{
397-
return Err(CaliptraError::RUNTIME_DPE_CONTEXT_NOT_FOUND);
398-
}
399-
let prev_journey = persistent_data
400-
.state
401-
.contexts
402-
.get(idx)
403-
.ok_or(CaliptraError::RUNTIME_DPE_CONTEXT_NOT_FOUND)?
404-
.tci
405-
.tci_cumulative
406-
.0;
421+
let tci_type = caliptra_managed_context.tci_type();
422+
let (idx, prev_journey) = {
423+
let persistent_data = self.persistent_data.get();
424+
let Some(idx) = self.get_caliptra_managed_dpe_context_index(caliptra_managed_context)
425+
else {
426+
return Ok(());
427+
};
428+
let ctx = persistent_data
429+
.state
430+
.contexts
431+
.get(idx)
432+
.ok_or(CaliptraError::RUNTIME_DPE_CONTEXT_NOT_FOUND)?;
433+
if ctx.state == ContextState::Inactive
434+
|| ctx.context_type != ContextType::Normal
435+
|| ctx.tci.tci_type != tci_type
436+
|| locality.is_some_and(|locality| ctx.locality != locality)
437+
{
438+
return Err(CaliptraError::RUNTIME_DPE_CONTEXT_NOT_FOUND);
439+
}
440+
if ctx.tci.tci_current.0 == *measurement {
441+
return Ok(());
442+
}
443+
(idx, ctx.tci.tci_cumulative.0)
444+
};
407445

408446
let mut digest_op = self.sha2_512_384.sha384_digest_init()?;
409447
digest_op.update(&prev_journey)?;
@@ -509,31 +547,8 @@ impl Drivers {
509547
}
510548
let initialization_values_hash: [u8; 48] =
511549
<[u8; 48]>::from(Self::compute_initialization_values_hash(drivers)?);
512-
// Only update if changed
513-
let dpe = &drivers.persistent_data.get().state;
514-
let root_idx = Self::get_dpe_root_context_idx(dpe)? as u8;
515-
let cciv_idx =
516-
Self::get_dpe_context_idx_by_tci_type(dpe, Self::CCIV_TCI_TYPE, None, Some(root_idx))?;
517-
let cciv_ctx = drivers
518-
.persistent_data
519-
.get()
520-
.state
521-
.contexts
522-
.get(cciv_idx)
523-
.ok_or(CaliptraError::RUNTIME_DPE_CONTEXT_NOT_FOUND)?;
524-
if cciv_ctx.state == ContextState::Inactive
525-
|| cciv_ctx.context_type != ContextType::Normal
526-
|| cciv_ctx.tci.tci_type != Self::CCIV_TCI_TYPE
527-
{
528-
return Err(CaliptraError::RUNTIME_DPE_CONTEXT_NOT_FOUND);
529-
}
530-
let prev_current: [u8; 48] = cciv_ctx.tci.tci_current.0;
531-
if prev_current == initialization_values_hash {
532-
return Ok(());
533-
}
534-
535550
drivers.update_caliptra_managed_measurement(
536-
Self::CCIV_TCI_TYPE,
551+
CaliptraManagedDpeContext::Cciv,
537552
&initialization_values_hash,
538553
None,
539554
)
@@ -759,12 +774,15 @@ impl Drivers {
759774
}
760775
Err(CaliptraError::RUNTIME_ADD_CCIV_MEASUREMENT_TO_DPE_FAILED)?
761776
}
762-
pdata.caliptra_managed_dpe_context_indices.cciv = u8::try_from(
777+
let cciv_idx = u8::try_from(
763778
env.state
764779
.get_active_context_pos(&ContextHandle::default(), pl0_pauser_locality)
765780
.map_err(|_| CaliptraError::RUNTIME_DPE_CONTEXT_NOT_FOUND)?,
766781
)
767782
.map_err(|_| CaliptraError::RUNTIME_DPE_CONTEXT_NOT_FOUND)?;
783+
pdata
784+
.caliptra_managed_dpe_context_indices
785+
.set_cciv(cciv_idx);
768786

769787
// Call DeriveContext to create TCIs for each measurement added in ROM
770788
let num_measurements = pdata.fht.meas_log_index as usize;

runtime/src/stash_measurement.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -105,12 +105,13 @@ impl StashMeasurementCmd {
105105
.state
106106
.get_active_context_pos(&ContextHandle::default(), locality)
107107
.map_err(|_| CaliptraError::RUNTIME_DPE_CONTEXT_NOT_FOUND)?;
108+
let mcu_rt_dpe_context_idx = u8::try_from(mcu_rt_dpe_context_idx)
109+
.map_err(|_| CaliptraError::RUNTIME_DPE_CONTEXT_NOT_FOUND)?;
108110
drivers
109111
.persistent_data
110112
.get_mut()
111113
.caliptra_managed_dpe_context_indices
112-
.mcu_rt = u8::try_from(mcu_rt_dpe_context_idx)
113-
.map_err(|_| CaliptraError::RUNTIME_DPE_CONTEXT_NOT_FOUND)?;
114+
.set_mcu_rt(mcu_rt_dpe_context_idx);
114115
}
115116

116117
// Extend the measurement into PCR31

runtime/tests/runtime_integration_tests/test_activate_firmware.rs

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -334,12 +334,10 @@ fn test_activate_mcu_fw_success() {
334334
{
335335
let updated_mcu_tci = get_mcu_tci(&mut model);
336336
assert_eq!(updated_mcu_tci.tci_current, mcu_digest);
337-
338-
let mut hasher = Sha384::new();
339-
hasher.update(initial_mcu_tci.tci_cumulative);
340-
hasher.update(mcu_digest);
341-
let expected_updated_cumulative: [u8; 48] = hasher.finalize().into();
342-
assert_eq!(updated_mcu_tci.tci_cumulative, expected_updated_cumulative);
337+
assert_eq!(
338+
updated_mcu_tci.tci_cumulative,
339+
initial_mcu_tci.tci_cumulative
340+
);
343341
}
344342
}
345343

0 commit comments

Comments
 (0)