[avb] Verify that extended initrd fails the payload verification
Bug: 256148034
Test: m pvmfw_img && atest libpvmfw_avb.integration_test
Change-Id: I8f7bd5f1a95c2ac0ddd92b7aa167902620c3b10a
diff --git a/pvmfw/avb/src/ops.rs b/pvmfw/avb/src/ops.rs
index 03c05af..e7f0ac7 100644
--- a/pvmfw/avb/src/ops.rs
+++ b/pvmfw/avb/src/ops.rs
@@ -21,7 +21,7 @@
use crate::utils::{self, as_ref, is_not_null, to_nonnull, write};
use avb_bindgen::{
avb_slot_verify, avb_slot_verify_data_free, AvbHashtreeErrorMode, AvbIOResult, AvbOps,
- AvbSlotVerifyData, AvbSlotVerifyFlags, AvbVBMetaData,
+ AvbPartitionData, AvbSlotVerifyData, AvbSlotVerifyFlags, AvbVBMetaData,
};
use core::{
ffi::{c_char, c_void, CStr},
@@ -325,4 +325,15 @@
unsafe { slice::from_raw_parts(data.vbmeta_images, data.num_vbmeta_images) };
Ok(vbmeta_images)
}
+
+ pub(crate) fn loaded_partitions(&self) -> Result<&[AvbPartitionData], AvbSlotVerifyError> {
+ let data = self.as_ref();
+ is_not_null(data.loaded_partitions).map_err(|_| AvbSlotVerifyError::Io)?;
+ // SAFETY: It is safe as the raw pointer `data.loaded_partitions` is a nonnull pointer and
+ // is guaranteed by libavb to point to a valid `AvbPartitionData` array as part of the
+ // `AvbSlotVerifyData` struct.
+ let loaded_partitions =
+ unsafe { slice::from_raw_parts(data.loaded_partitions, data.num_loaded_partitions) };
+ Ok(loaded_partitions)
+ }
}
diff --git a/pvmfw/avb/src/verify.rs b/pvmfw/avb/src/verify.rs
index bcc320a..a062061 100644
--- a/pvmfw/avb/src/verify.rs
+++ b/pvmfw/avb/src/verify.rs
@@ -20,7 +20,7 @@
use crate::utils::{is_not_null, to_usize, usize_checked_add, write};
use avb_bindgen::{
avb_descriptor_foreach, avb_hash_descriptor_validate_and_byteswap, AvbDescriptor,
- AvbHashDescriptor, AvbVBMetaData,
+ AvbHashDescriptor, AvbPartitionData, AvbVBMetaData,
};
use core::{
ffi::{c_char, c_void},
@@ -154,6 +154,29 @@
}
}
+fn verify_loaded_partition_has_expected_length(
+ loaded_partitions: &[AvbPartitionData],
+ partition_name: PartitionName,
+ expected_len: usize,
+) -> Result<(), AvbSlotVerifyError> {
+ if loaded_partitions.len() != 1 {
+ // Only one partition should be loaded in each verify result.
+ return Err(AvbSlotVerifyError::Io);
+ }
+ let loaded_partition = loaded_partitions[0];
+ if !PartitionName::try_from(loaded_partition.partition_name as *const c_char)
+ .map_or(false, |p| p == partition_name)
+ {
+ // Only the requested partition should be loaded.
+ return Err(AvbSlotVerifyError::Io);
+ }
+ if loaded_partition.data_size == expected_len {
+ Ok(())
+ } else {
+ Err(AvbSlotVerifyError::Verification)
+ }
+}
+
/// Verifies the payload (signed kernel + initrd) against the trusted public key.
pub fn verify_payload(
kernel: &[u8],
@@ -163,6 +186,7 @@
let mut payload = Payload::new(kernel, initrd, trusted_public_key);
let mut ops = Ops::from(&mut payload);
let kernel_verify_result = ops.verify_partition(PartitionName::Kernel.as_cstr())?;
+
let vbmeta_images = kernel_verify_result.vbmeta_images()?;
verify_only_one_vbmeta_exists(vbmeta_images)?;
let vbmeta_image = vbmeta_images[0];
@@ -175,12 +199,20 @@
// TODO(b/256148034): Check the vbmeta doesn't have hash descriptors other than
// boot, initrd_normal, initrd_debug.
- let debug_level = if ops.verify_partition(PartitionName::InitrdNormal.as_cstr()).is_ok() {
- DebugLevel::None
- } else if ops.verify_partition(PartitionName::InitrdDebug.as_cstr()).is_ok() {
- DebugLevel::Full
- } else {
- return Err(AvbSlotVerifyError::Verification);
- };
+ let initrd = initrd.unwrap();
+ let (debug_level, initrd_verify_result, initrd_partition_name) =
+ if let Ok(result) = ops.verify_partition(PartitionName::InitrdNormal.as_cstr()) {
+ (DebugLevel::None, result, PartitionName::InitrdNormal)
+ } else if let Ok(result) = ops.verify_partition(PartitionName::InitrdDebug.as_cstr()) {
+ (DebugLevel::Full, result, PartitionName::InitrdDebug)
+ } else {
+ return Err(AvbSlotVerifyError::Verification);
+ };
+ let loaded_partitions = initrd_verify_result.loaded_partitions()?;
+ verify_loaded_partition_has_expected_length(
+ loaded_partitions,
+ initrd_partition_name,
+ initrd.len(),
+ )?;
Ok(debug_level)
}
diff --git a/pvmfw/avb/tests/api_test.rs b/pvmfw/avb/tests/api_test.rs
index 41ead59..0572789 100644
--- a/pvmfw/avb/tests/api_test.rs
+++ b/pvmfw/avb/tests/api_test.rs
@@ -202,6 +202,19 @@
}
#[test]
+fn extended_initrd_fails_verification() -> Result<()> {
+ let mut initrd = load_latest_initrd_normal()?;
+ initrd.extend(b"androidboot.vbmeta.digest=1111");
+
+ assert_payload_verification_with_initrd_eq(
+ &load_latest_signed_kernel()?,
+ &initrd,
+ &load_trusted_public_key()?,
+ Err(AvbSlotVerifyError::Verification),
+ )
+}
+
+#[test]
fn tampered_vbmeta_fails_verification() -> Result<()> {
let mut kernel = load_latest_signed_kernel()?;
let footer = extract_avb_footer(&kernel)?;