pvmfw: Validate input BCC handover
Ensure that the BCC contained in the configuration data is properly formatted as a "BCC Handover" [1] i.e. a CBOR-encoded map BccHandover = { 1 : bstr .size 32, ; CDI_Attest 2 : bstr .size 32, ; CDI_Seal 3 : Bcc, ; Certificate chain } If not, abort the pVM boot. [1]: https://pigweed.googlesource.com/open-dice/+/72ad792c4d9ffffef3412801b5da46568a6b3197/src/android/bcc.c#260 Bug: 256827715 Test: atest MicrodroidHostTests Change-Id: Ibade0ebd1e50d912a59b32c1282022aa46235501
This commit is contained in:
parent
db14ada78b
commit
8edf72eafa
|
@ -0,0 +1,88 @@
|
|||
/*
|
||||
* Copyright 2022 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
//! Wrapper around dice/android/bcc.h.
|
||||
|
||||
use core::mem;
|
||||
use core::ptr;
|
||||
|
||||
use open_dice_bcc_bindgen::BccHandoverParse;
|
||||
|
||||
use crate::check_call;
|
||||
use crate::Cdi;
|
||||
use crate::Error;
|
||||
use crate::Result;
|
||||
|
||||
/// Boot Chain Certificate handover format combining the BCC and CDIs in a single CBOR object.
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct Handover<'a> {
|
||||
/// Attestation CDI.
|
||||
pub cdi_attest: &'a Cdi,
|
||||
/// Sealing CDI.
|
||||
pub cdi_seal: &'a Cdi,
|
||||
/// Boot Chain Certificate (optional).
|
||||
pub bcc: Option<&'a [u8]>,
|
||||
}
|
||||
|
||||
impl<'a> Handover<'a> {
|
||||
/// Validates and extracts the fields of a BCC handover buffer.
|
||||
pub fn new(buffer: &'a [u8]) -> Result<Self> {
|
||||
let mut cdi_attest: *const u8 = ptr::null();
|
||||
let mut cdi_seal: *const u8 = ptr::null();
|
||||
let mut bcc: *const u8 = ptr::null();
|
||||
let mut bcc_size: usize = 0;
|
||||
|
||||
// SAFETY - The buffer is only read and never stored and the returned pointers should all
|
||||
// point within the address range of the buffer or be NULL.
|
||||
check_call(unsafe {
|
||||
BccHandoverParse(
|
||||
buffer.as_ptr(),
|
||||
buffer.len(),
|
||||
&mut cdi_attest as *mut *const u8,
|
||||
&mut cdi_seal as *mut *const u8,
|
||||
&mut bcc as *mut *const u8,
|
||||
&mut bcc_size as *mut usize,
|
||||
)
|
||||
})?;
|
||||
|
||||
let cdi_attest = {
|
||||
let i = index_from_ptr(buffer, cdi_attest).ok_or(Error::PlatformError)?;
|
||||
let s = buffer.get(i..(i + mem::size_of::<Cdi>())).ok_or(Error::PlatformError)?;
|
||||
s.try_into().map_err(|_| Error::PlatformError)?
|
||||
};
|
||||
let cdi_seal = {
|
||||
let i = index_from_ptr(buffer, cdi_seal).ok_or(Error::PlatformError)?;
|
||||
let s = buffer.get(i..(i + mem::size_of::<Cdi>())).ok_or(Error::PlatformError)?;
|
||||
s.try_into().map_err(|_| Error::PlatformError)?
|
||||
};
|
||||
let bcc = if bcc.is_null() {
|
||||
None
|
||||
} else {
|
||||
let i = index_from_ptr(buffer, bcc).ok_or(Error::PlatformError)?;
|
||||
Some(buffer.get(i..(i + bcc_size)).ok_or(Error::PlatformError)?)
|
||||
};
|
||||
|
||||
Ok(Self { cdi_attest, cdi_seal, bcc })
|
||||
}
|
||||
}
|
||||
|
||||
fn index_from_ptr(slice: &[u8], pointer: *const u8) -> Option<usize> {
|
||||
if slice.as_ptr_range().contains(&pointer) {
|
||||
(pointer as usize).checked_sub(slice.as_ptr() as usize)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
|
@ -28,8 +28,13 @@ use open_dice_cbor_bindgen::DiceResult_kDiceResultInvalidInput as DICE_RESULT_IN
|
|||
use open_dice_cbor_bindgen::DiceResult_kDiceResultOk as DICE_RESULT_OK;
|
||||
use open_dice_cbor_bindgen::DiceResult_kDiceResultPlatformError as DICE_RESULT_PLATFORM_ERROR;
|
||||
|
||||
pub mod bcc;
|
||||
|
||||
const CDI_SIZE: usize = open_dice_cbor_bindgen::DICE_CDI_SIZE as usize;
|
||||
const HASH_SIZE: usize = open_dice_cbor_bindgen::DICE_HASH_SIZE as usize;
|
||||
|
||||
/// Array type of CDIs.
|
||||
pub type Cdi = [u8; CDI_SIZE];
|
||||
/// Array type of hashes used by DICE.
|
||||
pub type Hash = [u8; HASH_SIZE];
|
||||
|
||||
|
|
|
@ -15,6 +15,7 @@ rust_ffi_static {
|
|||
"libaarch64_paging",
|
||||
"libavb_nostd",
|
||||
"libbuddy_system_allocator",
|
||||
"libdice_nostd",
|
||||
"liblibfdt",
|
||||
"liblog_rust_nostd",
|
||||
"libpvmfw_embedded_key",
|
||||
|
|
|
@ -24,6 +24,7 @@ use crate::mmu;
|
|||
use core::arch::asm;
|
||||
use core::num::NonZeroUsize;
|
||||
use core::slice;
|
||||
use dice::bcc::Handover;
|
||||
use log::debug;
|
||||
use log::error;
|
||||
use log::info;
|
||||
|
@ -228,8 +229,9 @@ fn main_wrapper(fdt: usize, payload: usize, payload_size: usize) -> Result<(), R
|
|||
RebootReason::InvalidConfig
|
||||
})?;
|
||||
|
||||
let bcc = appended.get_bcc_mut().ok_or_else(|| {
|
||||
error!("Invalid BCC");
|
||||
let bcc_slice = appended.get_bcc_mut();
|
||||
let bcc = Handover::new(bcc_slice).map_err(|e| {
|
||||
error!("Invalid BCC Handover: {e:?}");
|
||||
RebootReason::InvalidBcc
|
||||
})?;
|
||||
|
||||
|
@ -243,7 +245,7 @@ fn main_wrapper(fdt: usize, payload: usize, payload_size: usize) -> Result<(), R
|
|||
let slices = MemorySlices::new(fdt, payload, payload_size, &mut memory)?;
|
||||
|
||||
// This wrapper allows main() to be blissfully ignorant of platform details.
|
||||
crate::main(slices.fdt, slices.kernel, slices.ramdisk, bcc, &mut memory)?;
|
||||
crate::main(slices.fdt, slices.kernel, slices.ramdisk, &bcc, &mut memory)?;
|
||||
|
||||
// TODO: Overwrite BCC before jumping to payload to avoid leaking our sealing key.
|
||||
|
||||
|
@ -366,12 +368,10 @@ impl<'a> AppendedPayload<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
fn get_bcc_mut(&mut self) -> Option<&mut [u8]> {
|
||||
let bcc = match self {
|
||||
fn get_bcc_mut(&mut self) -> &mut [u8] {
|
||||
match self {
|
||||
Self::LegacyBcc(ref mut bcc) => bcc,
|
||||
Self::Config(ref mut cfg) => cfg.get_bcc_mut(),
|
||||
};
|
||||
// TODO(b/256148034): return None if BccHandoverParse(bcc) != kDiceResultOk.
|
||||
Some(bcc)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -39,14 +39,15 @@ use crate::{
|
|||
};
|
||||
use avb::PUBLIC_KEY;
|
||||
use avb_nostd::verify_image;
|
||||
use dice::bcc;
|
||||
use libfdt::Fdt;
|
||||
use log::{debug, error, info};
|
||||
use log::{debug, error, info, trace};
|
||||
|
||||
fn main(
|
||||
fdt: &Fdt,
|
||||
signed_kernel: &[u8],
|
||||
ramdisk: Option<&[u8]>,
|
||||
bcc: &[u8],
|
||||
bcc: &bcc::Handover,
|
||||
memory: &mut MemoryTracker,
|
||||
) -> Result<(), RebootReason> {
|
||||
info!("pVM firmware");
|
||||
|
@ -57,7 +58,7 @@ fn main(
|
|||
} else {
|
||||
debug!("Ramdisk: None");
|
||||
}
|
||||
debug!("BCC: {:?} ({:#x} bytes)", bcc.as_ptr(), bcc.len());
|
||||
trace!("BCC: {bcc:x?}");
|
||||
|
||||
// Set up PCI bus for VirtIO devices.
|
||||
let pci_node = pci_node(fdt)?;
|
||||
|
|
Loading…
Reference in New Issue