Add BCC checking
Check whether any stage in the received BCC is marked as debug. If
not, refuse to apply any debug policy we receive. (The bootloader
shouldn't pass one in this case, this is just to make sure we catch
any mistake here.)
In passing fix the lifetime of the config descriptor buffer
(b/280617929).
Bug: 275424867
Test: atest MicrodroidTests
Change-Id: I507fedee9e21e8cbda60044a4e0324e0d6530b00
diff --git a/pvmfw/src/main.rs b/pvmfw/src/main.rs
index 96b707e..abe6a25 100644
--- a/pvmfw/src/main.rs
+++ b/pvmfw/src/main.rs
@@ -19,6 +19,7 @@
extern crate alloc;
+mod bcc;
mod bootargs;
mod config;
mod crypto;
@@ -36,10 +37,7 @@
mod rand;
mod virtio;
-use alloc::boxed::Box;
-use alloc::string::ToString;
-use core::ops::Range;
-
+use crate::bcc::Bcc;
use crate::dice::PartialInputs;
use crate::entry::RebootReason;
use crate::fdt::modify_for_next_stage;
@@ -48,38 +46,24 @@
use crate::instance::get_or_generate_instance_salt;
use crate::memory::MemoryTracker;
use crate::virtio::pci;
-use ciborium::{de::from_reader, value::Value};
-use diced_open_dice::bcc_handover_main_flow;
-use diced_open_dice::bcc_handover_parse;
-use diced_open_dice::DiceArtifacts;
+use alloc::boxed::Box;
+use core::ops::Range;
+use diced_open_dice::{bcc_handover_main_flow, bcc_handover_parse, DiceArtifacts};
use fdtpci::{PciError, PciInfo};
use libfdt::Fdt;
-use log::{debug, error, info, trace};
+use log::{debug, error, info, trace, warn};
use pvmfw_avb::verify_payload;
use pvmfw_avb::DebugLevel;
use pvmfw_embedded_key::PUBLIC_KEY;
const NEXT_BCC_SIZE: usize = GUEST_PAGE_SIZE;
-type CiboriumError = ciborium::de::Error<ciborium_io::EndOfFile>;
-
-/// Decodes the provided binary CBOR-encoded value and returns a
-/// ciborium::Value struct wrapped in Result.
-fn value_from_bytes(mut bytes: &[u8]) -> Result<Value, CiboriumError> {
- let value = from_reader(&mut bytes)?;
- // Ciborium tries to read one Value, but doesn't care if there is trailing data. We do.
- if !bytes.is_empty() {
- return Err(CiboriumError::Semantic(Some(0), "unexpected trailing data".to_string()));
- }
- Ok(value)
-}
-
fn main(
fdt: &mut Fdt,
signed_kernel: &[u8],
ramdisk: Option<&[u8]>,
current_bcc_handover: &[u8],
- debug_policy: Option<&mut [u8]>,
+ mut debug_policy: Option<&mut [u8]>,
memory: &mut MemoryTracker,
) -> Result<Range<usize>, RebootReason> {
info!("pVM firmware");
@@ -91,22 +75,25 @@
} else {
debug!("Ramdisk: None");
}
+
let bcc_handover = bcc_handover_parse(current_bcc_handover).map_err(|e| {
error!("Invalid BCC Handover: {e:?}");
RebootReason::InvalidBcc
})?;
trace!("BCC: {bcc_handover:x?}");
- // Minimal BCC verification - check the BCC exists & is valid CBOR.
- // TODO(alanstokes): Do something more useful.
- if let Some(bytes) = bcc_handover.bcc() {
- let _ = value_from_bytes(bytes).map_err(|e| {
- error!("Invalid BCC: {e:?}");
- RebootReason::InvalidBcc
- })?;
- } else {
- error!("Missing BCC");
- return Err(RebootReason::InvalidBcc);
+ let cdi_seal = bcc_handover.cdi_seal();
+
+ let bcc = Bcc::new(bcc_handover.bcc()).map_err(|e| {
+ error!("{e}");
+ RebootReason::InvalidBcc
+ })?;
+
+ // The bootloader should never pass us a debug policy when the boot is secure (the bootloader
+ // is locked). If it gets it wrong, disregard it & log it, to avoid it causing problems.
+ if debug_policy.is_some() && !bcc.is_debug_mode() {
+ warn!("Ignoring debug policy, BCC does not indicate Debug mode");
+ debug_policy = None;
}
// Set up PCI bus for VirtIO devices.
@@ -130,7 +117,6 @@
error!("Failed to compute partial DICE inputs: {e:?}");
RebootReason::InternalError
})?;
- let cdi_seal = DiceArtifacts::cdi_seal(&bcc_handover);
let (new_instance, salt) = get_or_generate_instance_salt(&mut pci_root, &dice_inputs, cdi_seal)
.map_err(|e| {
error!("Failed to get instance.img salt: {e}");
@@ -138,10 +124,13 @@
})?;
trace!("Got salt from instance.img: {salt:x?}");
- let dice_inputs = dice_inputs.into_input_values(&salt).map_err(|e| {
- error!("Failed to generate DICE inputs: {e:?}");
- RebootReason::InternalError
- })?;
+ let mut config_descriptor_buffer = [0; 128];
+ let dice_inputs =
+ dice_inputs.into_input_values(&salt, &mut config_descriptor_buffer).map_err(|e| {
+ error!("Failed to generate DICE inputs: {e:?}");
+ RebootReason::InternalError
+ })?;
+
let _ = bcc_handover_main_flow(current_bcc_handover, &dice_inputs, next_bcc).map_err(|e| {
error!("Failed to derive next-stage DICE secrets: {e:?}");
RebootReason::SecretDerivationError