Merge changes from topic "ud-dice-hal"
* changes:
Remove botoconfig from MicrodroidData
Implement DICE HAL against the driver
diff --git a/microdroid/dice/android.hardware.security.dice-service.microdroid.rc b/microdroid/dice/android.hardware.security.dice-service.microdroid.rc
index 162081e..7d9d441 100644
--- a/microdroid/dice/android.hardware.security.dice-service.microdroid.rc
+++ b/microdroid/dice/android.hardware.security.dice-service.microdroid.rc
@@ -1,3 +1,3 @@
service vendor.dice-microdroid /vendor/bin/hw/android.hardware.security.dice-service.microdroid
- class early_hal
- user nobody
+ user diced
+ group diced
diff --git a/microdroid/dice/service.rs b/microdroid/dice/service.rs
index 3401654..8cb5cc3 100644
--- a/microdroid/dice/service.rs
+++ b/microdroid/dice/service.rs
@@ -14,17 +14,103 @@
//! Main entry point for the microdroid IDiceDevice HAL implementation.
-use anyhow::Result;
+use anyhow::{bail, Error, Result};
+use byteorder::{NativeEndian, ReadBytesExt};
use diced::{
dice,
hal_node::{DiceArtifacts, DiceDevice, ResidentHal, UpdatableDiceArtifacts},
};
+use libc::{c_void, mmap, munmap, MAP_FAILED, MAP_PRIVATE, PROT_READ};
use serde::{Deserialize, Serialize};
+use std::fs;
+use std::os::unix::io::AsRawFd;
use std::panic;
+use std::path::{Path, PathBuf};
+use std::ptr::null_mut;
+use std::slice;
use std::sync::Arc;
const DICE_HAL_SERVICE_NAME: &str = "android.hardware.security.dice.IDiceDevice/default";
+/// Artifacts that are mapped into the process address space from the driver.
+struct MappedDriverArtifacts<'a> {
+ mmap_addr: *mut c_void,
+ mmap_size: usize,
+ cdi_attest: &'a [u8; dice::CDI_SIZE],
+ cdi_seal: &'a [u8; dice::CDI_SIZE],
+ bcc: &'a [u8],
+}
+
+impl MappedDriverArtifacts<'_> {
+ fn new(driver_path: &Path) -> Result<Self> {
+ let mut file = fs::File::open(driver_path)
+ .map_err(|error| Error::new(error).context("Opening driver"))?;
+ let mmap_size =
+ file.read_u64::<NativeEndian>()
+ .map_err(|error| Error::new(error).context("Reading driver"))? as usize;
+ // It's safe to map the driver as the service will only create a single
+ // mapping per process.
+ let mmap_addr = unsafe {
+ let fd = file.as_raw_fd();
+ mmap(null_mut(), mmap_size, PROT_READ, MAP_PRIVATE, fd, 0)
+ };
+ if mmap_addr == MAP_FAILED {
+ bail!("Failed to mmap {:?}", driver_path);
+ }
+ // The slice is created for the region of memory that was just
+ // successfully mapped into the process address space so it will be
+ // accessible and not referenced from anywhere else.
+ let mmap_buf =
+ unsafe { slice::from_raw_parts((mmap_addr as *const u8).as_ref().unwrap(), mmap_size) };
+ // Very inflexible parsing / validation of the BccHandover data. Assumes deterministically
+ // encoded CBOR.
+ //
+ // BccHandover = {
+ // 1 : bstr .size 32, ; CDI_Attest
+ // 2 : bstr .size 32, ; CDI_Seal
+ // 3 : Bcc, ; Certificate chain
+ // }
+ if mmap_buf[0..4] != [0xa3, 0x01, 0x58, 0x20]
+ || mmap_buf[36..39] != [0x02, 0x58, 0x20]
+ || mmap_buf[71] != 0x03
+ {
+ bail!("BccHandover format mismatch");
+ }
+ Ok(Self {
+ mmap_addr,
+ mmap_size,
+ cdi_attest: mmap_buf[4..36].try_into().unwrap(),
+ cdi_seal: mmap_buf[39..71].try_into().unwrap(),
+ bcc: &mmap_buf[72..],
+ })
+ }
+}
+
+impl Drop for MappedDriverArtifacts<'_> {
+ fn drop(&mut self) {
+ // All references to the mapped region have the same lifetime as self.
+ // Since self is being dropped, so are all the references to the mapped
+ // region meaning its safe to unmap.
+ let ret = unsafe { munmap(self.mmap_addr, self.mmap_size) };
+ if ret != 0 {
+ log::warn!("Failed to munmap ({})", ret);
+ }
+ }
+}
+
+impl DiceArtifacts for MappedDriverArtifacts<'_> {
+ fn cdi_attest(&self) -> &[u8; dice::CDI_SIZE] {
+ self.cdi_attest
+ }
+ fn cdi_seal(&self) -> &[u8; dice::CDI_SIZE] {
+ self.cdi_seal
+ }
+ fn bcc(&self) -> Vec<u8> {
+ // The BCC only contains public information so it's fine to copy.
+ self.bcc.to_vec()
+ }
+}
+
/// Artifacts that are kept in the process address space after the artifacts
/// from the driver have been consumed.
#[derive(Clone, Serialize, Deserialize)]
@@ -49,19 +135,26 @@
#[derive(Clone, Serialize, Deserialize)]
enum DriverArtifactManager {
+ Driver(PathBuf),
Updated(RawArtifacts),
}
impl DriverArtifactManager {
- fn new() -> Self {
- // TODO(214231981): replace with true values passed by bootloader
- let (cdi_attest, cdi_seal, bcc) = diced_sample_inputs::make_sample_bcc_and_cdis()
- .expect("Failed to create sample dice artifacts.");
- Self::Updated(RawArtifacts {
- cdi_attest: cdi_attest[..].try_into().unwrap(),
- cdi_seal: cdi_seal[..].try_into().unwrap(),
- bcc,
- })
+ fn new(driver_path: &Path) -> Self {
+ // TODO(218793274): fail if driver is missing in protected mode
+ if driver_path.exists() {
+ log::info!("Using DICE values from driver");
+ Self::Driver(driver_path.to_path_buf())
+ } else {
+ log::warn!("Using sample DICE values");
+ let (cdi_attest, cdi_seal, bcc) = diced_sample_inputs::make_sample_bcc_and_cdis()
+ .expect("Failed to create sample dice artifacts.");
+ Self::Updated(RawArtifacts {
+ cdi_attest: cdi_attest[..].try_into().unwrap(),
+ cdi_seal: cdi_seal[..].try_into().unwrap(),
+ bcc,
+ })
+ }
}
}
@@ -71,10 +164,17 @@
F: FnOnce(&dyn DiceArtifacts) -> Result<T>,
{
match self {
+ Self::Driver(driver_path) => f(&MappedDriverArtifacts::new(driver_path.as_path())?),
Self::Updated(raw_artifacts) => f(raw_artifacts),
}
}
fn update(self, new_artifacts: &impl DiceArtifacts) -> Result<Self> {
+ if let Self::Driver(driver_path) = self {
+ // Writing to the device wipes the artifcates. The string is ignored
+ // by the driver but included for documentation.
+ fs::write(driver_path, "wipe")
+ .map_err(|error| Error::new(error).context("Wiping driver"))?;
+ }
Ok(Self::Updated(RawArtifacts {
cdi_attest: *new_artifacts.cdi_attest(),
cdi_seal: *new_artifacts.cdi_seal(),
@@ -102,7 +202,7 @@
// Safety: ResidentHal cannot be used in multi threaded processes.
// This service does not start a thread pool. The main thread is the only thread
// joining the thread pool, thereby keeping the process single threaded.
- ResidentHal::new(DriverArtifactManager::new())
+ ResidentHal::new(DriverArtifactManager::new(Path::new("/dev/open-dice0")))
}
.expect("Failed to create ResidentHal implementation."),
);
diff --git a/microdroid/ueventd.rc b/microdroid/ueventd.rc
index 037b8fc..340a1f7 100644
--- a/microdroid/ueventd.rc
+++ b/microdroid/ueventd.rc
@@ -27,3 +27,5 @@
# Virtual console for logcat
/dev/hvc2 0660 logd logd
+
+/dev/open-dice0 0660 diced diced
diff --git a/microdroid_manager/src/instance.rs b/microdroid_manager/src/instance.rs
index 4d65421..267a0e3 100644
--- a/microdroid_manager/src/instance.rs
+++ b/microdroid_manager/src/instance.rs
@@ -322,7 +322,6 @@
pub apk_data: ApkData,
pub extra_apks_data: Vec<ApkData>,
pub apex_data: Vec<ApexData>,
- pub bootconfig: Box<[u8]>,
}
#[derive(Debug, Serialize, Deserialize, PartialEq)]
diff --git a/microdroid_manager/src/main.rs b/microdroid_manager/src/main.rs
index 827f9ff..005baf6 100644
--- a/microdroid_manager/src/main.rs
+++ b/microdroid_manager/src/main.rs
@@ -34,7 +34,6 @@
use log::{error, info};
use microdroid_metadata::{write_metadata, Metadata};
use microdroid_payload_config::{Task, TaskType, VmPayloadConfig};
-use once_cell::sync::OnceCell;
use payload::{get_apex_data_from_payload, load_metadata, to_metadata};
use rand::Fill;
use ring::digest;
@@ -42,7 +41,6 @@
use rustutils::system_properties::PropertyWatcher;
use std::convert::TryInto;
use std::fs::{self, create_dir, File, OpenOptions};
-use std::io::BufRead;
use std::os::unix::io::{FromRawFd, IntoRawFd};
use std::path::Path;
use std::process::{Child, Command, Stdio};
@@ -308,13 +306,6 @@
) -> Result<MicrodroidData> {
let start_time = SystemTime::now();
- if let Some(saved_bootconfig) = saved_data.map(|d| &d.bootconfig) {
- ensure!(
- saved_bootconfig.as_ref() == get_bootconfig()?.as_slice(),
- MicrodroidError::PayloadChanged(String::from("Bootconfig has changed."))
- );
- }
-
// Verify main APK
let root_hash = saved_data.map(|d| &d.apk_data.root_hash);
let root_hash_from_idsig = get_apk_root_hash_from_idsig(MAIN_APK_IDSIG_PATH)?;
@@ -455,7 +446,6 @@
apk_data: ApkData { root_hash: root_hash_from_idsig, pubkey: main_apk_pubkey },
extra_apks_data,
apex_data: apex_data_from_payload,
- bootconfig: get_bootconfig()?.clone().into_boxed_slice(),
})
}
@@ -506,35 +496,6 @@
}
}
-fn get_bootconfig() -> Result<&'static Vec<u8>> {
- static VAL: OnceCell<Vec<u8>> = OnceCell::new();
- VAL.get_or_try_init(|| -> Result<Vec<u8>> {
- let f = File::open("/proc/bootconfig")?;
-
- // Filter-out androidboot.vbmeta.device which contains UUID of the vbmeta partition. That
- // UUID could change everytime when the same VM is started because the composite disk image
- // is ephemeral. A change in UUID is okay as long as other configs (e.g.
- // androidboot.vbmeta.digest) remain same.
- Ok(std::io::BufReader::new(f)
- .lines()
- // note: this try_fold is to early return when we fail to read a line from the file
- .try_fold(Vec::new(), |mut lines, line| {
- line.map(|s| {
- lines.push(s);
- lines
- })
- })?
- .into_iter()
- .filter(|line| {
- let tokens: Vec<&str> = line.splitn(2, '=').collect();
- // note: if `line` doesn't have =, tokens[0] is the entire line.
- tokens[0].trim() != "androidboot.vbmeta.device"
- })
- .flat_map(|line| (line + "\n").into_bytes())
- .collect())
- })
-}
-
fn load_config(path: &Path) -> Result<VmPayloadConfig> {
info!("loading config from {:?}...", path);
let file = ioutil::wait_for_file(path, WAIT_TIMEOUT)?;