[service-vm] Identitfy service VM in pvmfw with avb property
The kernel footer only accepted hash descriptor prior to this change.
With this change, at most one property descriptor is allow to
indicate that this VM is a service VM.
Test: atest libpvmfw_avb.integration_test
Bug: 279557218
Change-Id: Ied476eba2e88be63ab78eae7ed05512a97406ec2
diff --git a/pvmfw/avb/src/verify.rs b/pvmfw/avb/src/verify.rs
index ded0766..c5ed8cc 100644
--- a/pvmfw/avb/src/verify.rs
+++ b/pvmfw/avb/src/verify.rs
@@ -18,6 +18,8 @@
use crate::error::AvbSlotVerifyError;
use crate::ops::{Ops, Payload};
use crate::partition::PartitionName;
+use alloc::vec;
+use alloc::vec::Vec;
use avb_bindgen::{AvbPartitionData, AvbVBMetaData};
use core::ffi::c_char;
@@ -32,6 +34,8 @@
pub initrd_digest: Option<Digest>,
/// Trusted public key.
pub public_key: &'a [u8],
+ /// VM capabilities.
+ pub capabilities: Vec<Capability>,
}
/// This enum corresponds to the `DebugLevel` in `VirtualMachineConfig`.
@@ -43,6 +47,35 @@
Full,
}
+/// VM Capability.
+#[derive(Debug, PartialEq, Eq)]
+pub enum Capability {
+ /// Remote attestation.
+ RemoteAttest,
+}
+
+impl Capability {
+ const KEY: &[u8] = b"com.android.virt.cap";
+ const REMOTE_ATTEST: &[u8] = b"remote_attest";
+ const SEPARATOR: u8 = b'|';
+
+ fn get_capabilities(property_value: &[u8]) -> Result<Vec<Self>, AvbSlotVerifyError> {
+ let mut res = Vec::new();
+
+ for v in property_value.split(|b| *b == Self::SEPARATOR) {
+ let cap = match v {
+ Self::REMOTE_ATTEST => Self::RemoteAttest,
+ _ => return Err(AvbSlotVerifyError::UnknownVbmetaProperty),
+ };
+ if res.contains(&cap) {
+ return Err(AvbSlotVerifyError::InvalidMetadata);
+ }
+ res.push(cap);
+ }
+ Ok(res)
+ }
+}
+
fn verify_only_one_vbmeta_exists(
vbmeta_images: &[AvbVBMetaData],
) -> Result<(), AvbSlotVerifyError> {
@@ -95,6 +128,20 @@
}
}
+/// Verifies that the vbmeta contains at most one property descriptor and it indicates the
+/// vm type is service VM.
+fn verify_property_and_get_capabilities(
+ descriptors: &Descriptors,
+) -> Result<Vec<Capability>, AvbSlotVerifyError> {
+ if !descriptors.has_property_descriptor() {
+ return Ok(vec![]);
+ }
+ descriptors
+ .find_property_value(Capability::KEY)
+ .ok_or(AvbSlotVerifyError::UnknownVbmetaProperty)
+ .and_then(Capability::get_capabilities)
+}
+
/// Verifies the payload (signed kernel + initrd) against the trusted public key.
pub fn verify_payload<'a>(
kernel: &[u8],
@@ -113,6 +160,7 @@
// which is returned by `avb_slot_verify()` when the verification succeeds. It is
// guaranteed by libavb to be non-null and to point to a valid VBMeta structure.
let descriptors = unsafe { Descriptors::from_vbmeta(vbmeta_image)? };
+ let capabilities = verify_property_and_get_capabilities(&descriptors)?;
let kernel_descriptor = descriptors.find_hash_descriptor(PartitionName::Kernel)?;
if initrd.is_none() {
@@ -122,6 +170,7 @@
kernel_digest: *kernel_descriptor.digest,
initrd_digest: None,
public_key: trusted_public_key,
+ capabilities,
});
}
@@ -146,5 +195,6 @@
kernel_digest: *kernel_descriptor.digest,
initrd_digest: Some(*initrd_descriptor.digest),
public_key: trusted_public_key,
+ capabilities,
})
}