Support amending vendor hashtree digest when virtmgr constructs DTBO based on host DT
Bug: 325555638
Test: atest MicrodroidTests#configuringVendorDiskImageRequiresCustomPermission
Test: atest MicrodroidTests#bootsWithVendorPartition
Test: atest MicrodroidTests#bootsWithCustomVendorPartitionForNonPvm
Test: atest MicrodroidTests#bootFailsWithCustomVendorPartitionForPvm
Test: atest MicrodroidTests#creationFailsWithUnsignedVendorPartition
Test: atest virtualizationmanager_device_test
Change-Id: I3a008c4bbb34d7673d843c18c0b479212b925065
diff --git a/virtualizationmanager/src/aidl.rs b/virtualizationmanager/src/aidl.rs
index 88700ec..c32960b 100644
--- a/virtualizationmanager/src/aidl.rs
+++ b/virtualizationmanager/src/aidl.rs
@@ -87,6 +87,7 @@
use std::os::unix::raw::pid_t;
use std::path::{Path, PathBuf};
use std::sync::{Arc, Mutex, Weak};
+use vbmeta::VbMetaImage;
use vmconfig::VmConfig;
use vsock::VsockStream;
use zip::ZipArchive;
@@ -381,6 +382,23 @@
None
};
+ let vendor_hashtree_digest = extract_vendor_hashtree_digest(config)
+ .context("Failed to extract vendor hashtree digest")
+ .or_service_specific_exception(-1)?;
+
+ let trusted_props = if let Some(ref vendor_hashtree_digest) = vendor_hashtree_digest {
+ info!(
+ "Passing vendor hashtree digest to pvmfw. This will be rejected if it doesn't \
+ match the trusted digest in the pvmfw config, causing the VM to fail to start."
+ );
+ vec![(
+ cstr!("vendor_hashtree_descriptor_root_digest"),
+ vendor_hashtree_digest.as_slice(),
+ )]
+ } else {
+ vec![]
+ };
+
let untrusted_props = if cfg!(llpvm_changes) {
// TODO(b/291213394): Replace this with a per-VM instance Id.
let instance_id = b"sixtyfourbyteslonghardcoded_indeed_sixtyfourbyteslonghardcoded_h";
@@ -389,17 +407,23 @@
vec![]
};
- let device_tree_overlay = if host_ref_dt.is_some() || !untrusted_props.is_empty() {
- let dt_output = temporary_directory.join(VM_DT_OVERLAY_PATH);
- let mut data = [0_u8; VM_DT_OVERLAY_MAX_SIZE];
- let fdt = create_device_tree_overlay(&mut data, host_ref_dt, &untrusted_props)
+ let device_tree_overlay =
+ if host_ref_dt.is_some() || !untrusted_props.is_empty() || !trusted_props.is_empty() {
+ let dt_output = temporary_directory.join(VM_DT_OVERLAY_PATH);
+ let mut data = [0_u8; VM_DT_OVERLAY_MAX_SIZE];
+ let fdt = create_device_tree_overlay(
+ &mut data,
+ host_ref_dt,
+ &untrusted_props,
+ &trusted_props,
+ )
.map_err(|e| anyhow!("Failed to create DT overlay, {e:?}"))
.or_service_specific_exception(-1)?;
- fs::write(&dt_output, fdt.as_slice()).or_service_specific_exception(-1)?;
- Some(File::open(dt_output).or_service_specific_exception(-1)?)
- } else {
- None
- };
+ fs::write(&dt_output, fdt.as_slice()).or_service_specific_exception(-1)?;
+ Some(File::open(dt_output).or_service_specific_exception(-1)?)
+ } else {
+ None
+ };
let debug_level = match config {
VirtualMachineConfig::AppConfig(config) => config.debugLevel,
@@ -601,6 +625,32 @@
}
}
+fn extract_vendor_hashtree_digest(config: &VirtualMachineConfig) -> Result<Option<Vec<u8>>> {
+ let VirtualMachineConfig::AppConfig(config) = config else {
+ return Ok(None);
+ };
+ let Some(custom_config) = &config.customConfig else {
+ return Ok(None);
+ };
+ let Some(file) = custom_config.vendorImage.as_ref() else {
+ return Ok(None);
+ };
+
+ let file = clone_file(file)?;
+ let size =
+ file.metadata().context("Failed to get metadata from microdroid vendor image")?.len();
+ let vbmeta = VbMetaImage::verify_reader_region(&file, 0, size)
+ .context("Failed to get vbmeta from microdroid-vendor.img")?;
+
+ for descriptor in vbmeta.descriptors()?.iter() {
+ if let vbmeta::Descriptor::Hashtree(_) = descriptor {
+ let root_digest = hex::encode(descriptor.to_hashtree()?.root_digest());
+ return Ok(Some(root_digest.as_bytes().to_vec()));
+ }
+ }
+ Err(anyhow!("No hashtree digest is extracted from microdroid vendor image"))
+}
+
fn write_zero_filler(zero_filler_path: &Path) -> Result<()> {
let file = OpenOptions::new()
.create_new(true)