[avb][test] Add verification tests to check tampered vbmeta
Bug: 256148034
Test: atest libpvmfw_avb.test
Change-Id: If575a1fee8c5919ba4e5bb0ef29238b28a7f3e67
diff --git a/pvmfw/avb/tests/api_test.rs b/pvmfw/avb/tests/api_test.rs
index a4e890e..945c838 100644
--- a/pvmfw/avb/tests/api_test.rs
+++ b/pvmfw/avb/tests/api_test.rs
@@ -15,9 +15,15 @@
*/
use anyhow::Result;
-use avb_bindgen::AvbFooter;
+use avb_bindgen::{
+ avb_footer_validate_and_byteswap, avb_vbmeta_image_header_to_host_byte_order, AvbFooter,
+ AvbVBMetaImageHeader,
+};
use pvmfw_avb::{verify_payload, AvbSlotVerifyError};
-use std::{fs, mem::size_of};
+use std::{
+ fs,
+ mem::{size_of, transmute, MaybeUninit},
+};
const MICRODROID_KERNEL_IMG_PATH: &str = "microdroid_kernel";
const INITRD_NORMAL_IMG_PATH: &str = "microdroid_initrd_normal.img";
@@ -128,6 +134,80 @@
)
}
+#[test]
+fn tampered_vbmeta_fails_verification() -> Result<()> {
+ let mut kernel = load_latest_signed_kernel()?;
+ let footer = extract_avb_footer(&kernel)?;
+ let vbmeta_index: usize = (footer.vbmeta_offset + 1).try_into()?;
+
+ kernel[vbmeta_index] = !kernel[vbmeta_index]; // Flip the bits
+
+ assert_payload_verification_fails(
+ &kernel,
+ &load_latest_initrd_normal()?,
+ &load_trusted_public_key()?,
+ AvbSlotVerifyError::InvalidMetadata,
+ )
+}
+
+#[test]
+fn vbmeta_with_public_key_overwritten_fails_verification() -> Result<()> {
+ let mut kernel = load_latest_signed_kernel()?;
+ let footer = extract_avb_footer(&kernel)?;
+ let vbmeta_header = extract_vbmeta_header(&kernel, &footer)?;
+ let public_key_offset = footer.vbmeta_offset as usize
+ + size_of::<AvbVBMetaImageHeader>()
+ + vbmeta_header.authentication_data_block_size as usize
+ + vbmeta_header.public_key_offset as usize;
+ let public_key_size: usize = vbmeta_header.public_key_size.try_into()?;
+ let empty_public_key = vec![0u8; public_key_size];
+
+ kernel[public_key_offset..(public_key_offset + public_key_size)]
+ .copy_from_slice(&empty_public_key);
+
+ assert_payload_verification_fails(
+ &kernel,
+ &load_latest_initrd_normal()?,
+ &empty_public_key,
+ AvbSlotVerifyError::Verification,
+ )?;
+ assert_payload_verification_fails(
+ &kernel,
+ &load_latest_initrd_normal()?,
+ &load_trusted_public_key()?,
+ AvbSlotVerifyError::Verification,
+ )
+}
+
+// TODO(b/256148034): Test that vbmeta with its verification flag overwritten fails verification.
+
+fn extract_avb_footer(kernel: &[u8]) -> Result<AvbFooter> {
+ let footer_start = kernel.len() - size_of::<AvbFooter>();
+ // SAFETY: The slice is the same size as the struct which only contains simple data types.
+ let mut footer = unsafe {
+ transmute::<[u8; size_of::<AvbFooter>()], AvbFooter>(kernel[footer_start..].try_into()?)
+ };
+ // SAFETY: The function updates the struct in-place.
+ unsafe {
+ avb_footer_validate_and_byteswap(&footer, &mut footer);
+ }
+ Ok(footer)
+}
+
+fn extract_vbmeta_header(kernel: &[u8], footer: &AvbFooter) -> Result<AvbVBMetaImageHeader> {
+ let vbmeta_offset: usize = footer.vbmeta_offset.try_into()?;
+ let vbmeta_size: usize = footer.vbmeta_size.try_into()?;
+ let vbmeta_src = &kernel[vbmeta_offset..(vbmeta_offset + vbmeta_size)];
+ // SAFETY: The latest kernel has a valid VBMeta header at the position specified in footer.
+ let vbmeta_header = unsafe {
+ let mut header = MaybeUninit::uninit();
+ let src = vbmeta_src.as_ptr() as *const _ as *const AvbVBMetaImageHeader;
+ avb_vbmeta_image_header_to_host_byte_order(src, header.as_mut_ptr());
+ header.assume_init()
+ };
+ Ok(vbmeta_header)
+}
+
fn assert_payload_verification_fails(
kernel: &[u8],
initrd: &[u8],