| // Copyright 2023, The Android Open Source Project |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| |
| //! libavb_rs verification tests. |
| |
| use crate::test_ops::TestOps; |
| use avb::{ |
| slot_verify, HashtreeErrorMode, IoError, SlotVerifyData, SlotVerifyError, SlotVerifyFlags, |
| SlotVerifyResult, |
| }; |
| use std::{ffi::CString, fs}; |
| #[cfg(feature = "uuid")] |
| use uuid::uuid; |
| |
| // These constants must match the values used to create the images in Android.bp. |
| const TEST_IMAGE_PATH: &str = "test_image.img"; |
| const TEST_IMAGE_SIZE: usize = 16 * 1024; |
| const TEST_VBMETA_PATH: &str = "test_vbmeta.img"; |
| const TEST_VBMETA_2_PARTITIONS_PATH: &str = "test_vbmeta_2_parts.img"; |
| const TEST_VBMETA_PERSISTENT_DIGEST_PATH: &str = "test_vbmeta_persistent_digest.img"; |
| const TEST_IMAGE_WITH_VBMETA_FOOTER_PATH: &str = "avbrs_test_image_with_vbmeta_footer.img"; |
| const TEST_IMAGE_WITH_VBMETA_FOOTER_FOR_BOOT_PATH: &str = |
| "avbrs_test_image_with_vbmeta_footer_for_boot.img"; |
| const TEST_PUBLIC_KEY_PATH: &str = "data/testkey_rsa4096_pub.bin"; |
| const TEST_PARTITION_NAME: &str = "test_part"; |
| const TEST_PARTITION_SLOT_C_NAME: &str = "test_part_c"; |
| const TEST_PARTITION_2_NAME: &str = "test_part_2"; |
| const TEST_PARTITION_PERSISTENT_DIGEST_NAME: &str = "test_part_persistent_digest"; |
| const TEST_VBMETA_ROLLBACK_LOCATION: usize = 0; // Default value, we don't explicitly set this. |
| |
| /// Initializes a `TestOps` object such that verification will succeed on `TEST_PARTITION_NAME`. |
| fn test_ops_one_image_one_vbmeta() -> TestOps { |
| let mut ops = TestOps::default(); |
| ops.add_partition(TEST_PARTITION_NAME, fs::read(TEST_IMAGE_PATH).unwrap()); |
| ops.add_partition("vbmeta", fs::read(TEST_VBMETA_PATH).unwrap()); |
| ops.add_vbmeta_key(fs::read(TEST_PUBLIC_KEY_PATH).unwrap(), None, true); |
| ops.rollbacks.insert(TEST_VBMETA_ROLLBACK_LOCATION, 0); |
| ops.unlock_state = Ok(false); |
| ops |
| } |
| |
| /// Calls `slot_verify()` using standard args for `test_ops_one_image_one_vbmeta()` setup. |
| fn verify_one_image_one_vbmeta(ops: &mut TestOps) -> SlotVerifyResult<SlotVerifyData> { |
| slot_verify( |
| ops, |
| &[&CString::new(TEST_PARTITION_NAME).unwrap()], |
| None, |
| SlotVerifyFlags::AVB_SLOT_VERIFY_FLAGS_NONE, |
| HashtreeErrorMode::AVB_HASHTREE_ERROR_MODE_EIO, |
| ) |
| } |
| |
| /// Initializes a `TestOps` object such that verification will succeed on `TEST_PARTITION_NAME` and |
| /// `TEST_PARTITION_2_NAME`. |
| fn test_ops_two_images_one_vbmeta() -> TestOps { |
| let mut ops = test_ops_one_image_one_vbmeta(); |
| // Add in the contents of the second partition and overwrite the vbmeta partition to |
| // include both partition descriptors. |
| ops.add_partition(TEST_PARTITION_2_NAME, fs::read(TEST_IMAGE_PATH).unwrap()); |
| ops.add_partition("vbmeta", fs::read(TEST_VBMETA_2_PARTITIONS_PATH).unwrap()); |
| ops |
| } |
| |
| /// Calls `slot_verify()` using standard args for `test_ops_two_images_one_vbmeta()` setup. |
| fn verify_two_images_one_vbmeta(ops: &mut TestOps) -> SlotVerifyResult<SlotVerifyData> { |
| slot_verify( |
| ops, |
| &[ |
| &CString::new(TEST_PARTITION_NAME).unwrap(), |
| &CString::new(TEST_PARTITION_2_NAME).unwrap(), |
| ], |
| None, |
| SlotVerifyFlags::AVB_SLOT_VERIFY_FLAGS_NONE, |
| HashtreeErrorMode::AVB_HASHTREE_ERROR_MODE_EIO, |
| ) |
| } |
| |
| /// Initializes a `TestOps` object such that verification will succeed on the `boot` partition with |
| /// a combined image + vbmeta. |
| fn test_ops_boot_partition() -> TestOps { |
| let mut ops = test_ops_one_image_one_vbmeta(); |
| ops.partitions.clear(); |
| ops.add_partition( |
| "boot", |
| fs::read(TEST_IMAGE_WITH_VBMETA_FOOTER_FOR_BOOT_PATH).unwrap(), |
| ); |
| ops |
| } |
| |
| /// Calls `slot_verify()` using standard args for `test_ops_boot_partition()` setup. |
| fn verify_boot_partition(ops: &mut TestOps) -> SlotVerifyResult<SlotVerifyData> { |
| slot_verify( |
| ops, |
| &[&CString::new("boot").unwrap()], |
| None, |
| // libavb has some special-case handling to automatically detect a combined image + vbmeta |
| // in the `boot` partition; don't pass the `AVB_SLOT_VERIFY_FLAGS_NO_VBMETA_PARTITION` flag |
| // so we can test this behavior. |
| SlotVerifyFlags::AVB_SLOT_VERIFY_FLAGS_NONE, |
| HashtreeErrorMode::AVB_HASHTREE_ERROR_MODE_EIO, |
| ) |
| } |
| |
| /// Initializes a `TestOps` object such that verification will succeed on |
| /// `TEST_PARTITION_PERSISTENT_DIGEST_NAME`. |
| fn test_ops_persistent_digest(image: Vec<u8>) -> TestOps { |
| let mut ops = test_ops_one_image_one_vbmeta(); |
| ops.partitions.clear(); |
| // Use the vbmeta image with the persistent digest descriptor. |
| ops.add_partition( |
| "vbmeta", |
| fs::read(TEST_VBMETA_PERSISTENT_DIGEST_PATH).unwrap(), |
| ); |
| // Register the image contents to be stored via persistent digest. |
| ops.add_partition(TEST_PARTITION_PERSISTENT_DIGEST_NAME, image); |
| ops |
| } |
| |
| /// Calls `slot_verify()` using standard args for `test_ops_persistent_digest()` setup. |
| fn verify_persistent_digest(ops: &mut TestOps) -> SlotVerifyResult<SlotVerifyData> { |
| slot_verify( |
| ops, |
| &[&CString::new(TEST_PARTITION_PERSISTENT_DIGEST_NAME).unwrap()], |
| None, |
| SlotVerifyFlags::AVB_SLOT_VERIFY_FLAGS_NONE, |
| HashtreeErrorMode::AVB_HASHTREE_ERROR_MODE_EIO, |
| ) |
| } |
| |
| /// Modifies the partition contents by flipping a bit. |
| fn modify_partition_contents(ops: &mut TestOps, partition: &str) { |
| ops.partitions.get_mut(partition).unwrap().contents[0] ^= 0x01; |
| } |
| |
| /// Returns the persistent value name for `TEST_PARTITION_PERSISTENT_DIGEST_NAME`. |
| fn persistent_digest_value_name() -> String { |
| // This exact format is a libavb implementation detail but is unlikely to change. If it does |
| // just update this format to match. |
| format!("avb.persistent_digest.{TEST_PARTITION_PERSISTENT_DIGEST_NAME}") |
| } |
| |
| #[test] |
| fn one_image_one_vbmeta_passes_verification_with_correct_data() { |
| let mut ops = test_ops_one_image_one_vbmeta(); |
| |
| let result = verify_one_image_one_vbmeta(&mut ops); |
| |
| // Make sure the resulting `SlotVerifyData` looks correct. |
| let data = result.unwrap(); |
| assert_eq!(data.ab_suffix().to_bytes(), b""); |
| // We don't care about the exact commandline, just search for a substring we know will |
| // exist to make sure the commandline is being provided to the caller correctly. |
| assert!(data |
| .cmdline() |
| .to_str() |
| .unwrap() |
| .contains("androidboot.vbmeta.device_state=locked")); |
| assert_eq!(data.rollback_indexes(), &[0; 32]); |
| assert_eq!( |
| data.resolved_hashtree_error_mode(), |
| HashtreeErrorMode::AVB_HASHTREE_ERROR_MODE_EIO |
| ); |
| |
| // Check the `VbmetaData` struct looks correct. |
| assert_eq!(data.vbmeta_data().len(), 1); |
| let vbmeta_data = &data.vbmeta_data()[0]; |
| assert_eq!(vbmeta_data.partition_name().to_str().unwrap(), "vbmeta"); |
| assert_eq!(vbmeta_data.data(), fs::read(TEST_VBMETA_PATH).unwrap()); |
| assert_eq!(vbmeta_data.verify_result(), Ok(())); |
| |
| // Check the `PartitionData` struct looks correct. |
| assert_eq!(data.partition_data().len(), 1); |
| let partition_data = &data.partition_data()[0]; |
| assert_eq!( |
| partition_data.partition_name().to_str().unwrap(), |
| TEST_PARTITION_NAME |
| ); |
| assert_eq!(partition_data.data(), fs::read(TEST_IMAGE_PATH).unwrap()); |
| assert!(!partition_data.preloaded()); |
| assert!(partition_data.verify_result().is_ok()); |
| } |
| |
| #[test] |
| fn preloaded_image_passes_verification() { |
| let mut ops = test_ops_one_image_one_vbmeta(); |
| // Mark the image partition to be preloaded. |
| ops.partitions |
| .get_mut(TEST_PARTITION_NAME) |
| .unwrap() |
| .preloaded = true; |
| |
| let result = verify_one_image_one_vbmeta(&mut ops); |
| |
| let data = result.unwrap(); |
| let partition_data = &data.partition_data()[0]; |
| assert!(partition_data.preloaded()); |
| } |
| |
| #[test] |
| fn slotted_partition_passes_verification() { |
| let mut ops = test_ops_one_image_one_vbmeta(); |
| // Move the partitions to a "_c" slot. |
| ops.partitions.clear(); |
| ops.add_partition( |
| TEST_PARTITION_SLOT_C_NAME, |
| fs::read(TEST_IMAGE_PATH).unwrap(), |
| ); |
| ops.add_partition("vbmeta_c", fs::read(TEST_VBMETA_PATH).unwrap()); |
| |
| let result = slot_verify( |
| &mut ops, |
| &[&CString::new(TEST_PARTITION_NAME).unwrap()], |
| Some(&CString::new("_c").unwrap()), |
| SlotVerifyFlags::AVB_SLOT_VERIFY_FLAGS_NONE, |
| HashtreeErrorMode::AVB_HASHTREE_ERROR_MODE_EIO, |
| ); |
| |
| let data = result.unwrap(); |
| assert_eq!(data.ab_suffix().to_bytes(), b"_c"); |
| } |
| |
| #[test] |
| fn two_images_one_vbmeta_passes_verification() { |
| let mut ops = test_ops_two_images_one_vbmeta(); |
| |
| let result = verify_two_images_one_vbmeta(&mut ops); |
| |
| // We should still only have 1 `VbmetaData` since we only used 1 vbmeta image, but it |
| // signed 2 partitions so we should have 2 `PartitionData` objects. |
| let data = result.unwrap(); |
| assert_eq!(data.vbmeta_data().len(), 1); |
| assert_eq!(data.partition_data().len(), 2); |
| assert_eq!( |
| data.partition_data()[0].partition_name().to_str().unwrap(), |
| TEST_PARTITION_NAME |
| ); |
| assert_eq!( |
| data.partition_data()[1].partition_name().to_str().unwrap(), |
| TEST_PARTITION_2_NAME |
| ); |
| } |
| |
| #[test] |
| fn combined_image_vbmeta_partition_passes_verification() { |
| let mut ops = test_ops_one_image_one_vbmeta(); |
| ops.partitions.clear(); |
| // Register the single combined image + vbmeta in `TEST_PARTITION_NAME`. |
| ops.add_partition( |
| TEST_PARTITION_NAME, |
| fs::read(TEST_IMAGE_WITH_VBMETA_FOOTER_PATH).unwrap(), |
| ); |
| // For a combined image we need to register the public key specifically for this partition. |
| ops.add_vbmeta_key_for_partition( |
| fs::read(TEST_PUBLIC_KEY_PATH).unwrap(), |
| None, |
| true, |
| TEST_PARTITION_NAME, |
| TEST_VBMETA_ROLLBACK_LOCATION as u32, |
| ); |
| |
| let result = slot_verify( |
| &mut ops, |
| &[&CString::new(TEST_PARTITION_NAME).unwrap()], |
| None, |
| // Tell libavb that the vbmeta image is embedded, not in its own partition. |
| SlotVerifyFlags::AVB_SLOT_VERIFY_FLAGS_NO_VBMETA_PARTITION, |
| HashtreeErrorMode::AVB_HASHTREE_ERROR_MODE_EIO, |
| ); |
| |
| let data = result.unwrap(); |
| |
| // Vbmeta should indicate that it came from `TEST_PARTITION_NAME`. |
| assert_eq!(data.vbmeta_data().len(), 1); |
| let vbmeta_data = &data.vbmeta_data()[0]; |
| assert_eq!( |
| vbmeta_data.partition_name().to_str().unwrap(), |
| TEST_PARTITION_NAME |
| ); |
| |
| // Partition should indicate that it came from `TEST_PARTITION_NAME`, but only contain the |
| // image contents. |
| assert_eq!(data.partition_data().len(), 1); |
| let partition_data = &data.partition_data()[0]; |
| assert_eq!( |
| partition_data.partition_name().to_str().unwrap(), |
| TEST_PARTITION_NAME |
| ); |
| assert_eq!(partition_data.data(), fs::read(TEST_IMAGE_PATH).unwrap()); |
| } |
| |
| // Validate the custom behavior if the combined image + vbmeta live in the `boot` partition. |
| #[test] |
| fn vbmeta_with_boot_partition_passes_verification() { |
| let mut ops = test_ops_boot_partition(); |
| |
| let result = verify_boot_partition(&mut ops); |
| |
| let data = result.unwrap(); |
| |
| // Vbmeta should indicate that it came from `boot`. |
| assert_eq!(data.vbmeta_data().len(), 1); |
| let vbmeta_data = &data.vbmeta_data()[0]; |
| assert_eq!(vbmeta_data.partition_name().to_str().unwrap(), "boot"); |
| |
| // Partition should indicate that it came from `boot`, but only contain the image contents. |
| assert_eq!(data.partition_data().len(), 1); |
| let partition_data = &data.partition_data()[0]; |
| assert_eq!(partition_data.partition_name().to_str().unwrap(), "boot"); |
| assert_eq!(partition_data.data(), fs::read(TEST_IMAGE_PATH).unwrap()); |
| } |
| |
| #[test] |
| fn persistent_digest_verification_updates_persistent_value() { |
| // With persistent digests, the image hash isn't stored in the descriptor, but is instead |
| // calculated on-demand and stored into a named persistent value. So our test image can contain |
| // anything, but does have to match the size indicated by the descriptor. |
| let image_contents = vec![0xAAu8; TEST_IMAGE_SIZE]; |
| let mut ops = test_ops_persistent_digest(image_contents.clone()); |
| |
| { |
| let result = verify_persistent_digest(&mut ops); |
| let data = result.unwrap(); |
| assert_eq!(data.partition_data()[0].data(), image_contents); |
| } // Drop `result` here so it releases `ops` and we can use it again. |
| |
| assert!(ops |
| .persistent_values |
| .contains_key(&persistent_digest_value_name())); |
| } |
| |
| #[cfg(feature = "uuid")] |
| #[test] |
| fn successful_verification_substitutes_partition_guid() { |
| let mut ops = test_ops_one_image_one_vbmeta(); |
| ops.partitions.get_mut("vbmeta").unwrap().uuid = uuid!("01234567-89ab-cdef-0123-456789abcdef"); |
| |
| let result = verify_one_image_one_vbmeta(&mut ops); |
| |
| let data = result.unwrap(); |
| assert!(data |
| .cmdline() |
| .to_str() |
| .unwrap() |
| .contains("androidboot.vbmeta.device=PARTUUID=01234567-89ab-cdef-0123-456789abcdef")); |
| } |
| |
| #[cfg(feature = "uuid")] |
| #[test] |
| fn successful_verification_substitutes_boot_partition_guid() { |
| let mut ops = test_ops_boot_partition(); |
| ops.partitions.get_mut("boot").unwrap().uuid = uuid!("01234567-89ab-cdef-0123-456789abcdef"); |
| |
| let result = verify_boot_partition(&mut ops); |
| |
| let data = result.unwrap(); |
| // In this case libavb substitutes the `boot` partition GUID in for `vbmeta`. |
| assert!(data |
| .cmdline() |
| .to_str() |
| .unwrap() |
| .contains("androidboot.vbmeta.device=PARTUUID=01234567-89ab-cdef-0123-456789abcdef")); |
| } |
| |
| #[test] |
| fn corrupted_image_fails_verification() { |
| let mut ops = test_ops_one_image_one_vbmeta(); |
| modify_partition_contents(&mut ops, TEST_PARTITION_NAME); |
| |
| let result = verify_one_image_one_vbmeta(&mut ops); |
| |
| let error = result.unwrap_err(); |
| assert!(matches!(error, SlotVerifyError::Verification(None))); |
| } |
| |
| #[test] |
| fn read_partition_callback_error_fails_verification() { |
| let mut ops = test_ops_one_image_one_vbmeta(); |
| ops.partitions.remove(TEST_PARTITION_NAME); |
| |
| let result = verify_one_image_one_vbmeta(&mut ops); |
| |
| let error = result.unwrap_err(); |
| assert!(matches!(error, SlotVerifyError::Io)); |
| } |
| |
| #[test] |
| fn undersized_partition_fails_verification() { |
| let mut ops = test_ops_one_image_one_vbmeta(); |
| ops.partitions |
| .get_mut(TEST_PARTITION_NAME) |
| .unwrap() |
| .contents |
| .pop(); |
| |
| let result = verify_one_image_one_vbmeta(&mut ops); |
| |
| let error = result.unwrap_err(); |
| assert!(matches!(error, SlotVerifyError::Io)); |
| } |
| |
| #[test] |
| fn corrupted_vbmeta_fails_verification() { |
| let mut ops = test_ops_one_image_one_vbmeta(); |
| modify_partition_contents(&mut ops, "vbmeta"); |
| |
| let result = verify_one_image_one_vbmeta(&mut ops); |
| |
| let error = result.unwrap_err(); |
| assert!(matches!(error, SlotVerifyError::InvalidMetadata)); |
| } |
| |
| #[test] |
| fn rollback_violation_fails_verification() { |
| let mut ops = test_ops_one_image_one_vbmeta(); |
| // Device with rollback = 1 should refuse to boot image with rollback = 0. |
| ops.rollbacks.insert(TEST_VBMETA_ROLLBACK_LOCATION, 1); |
| |
| let result = verify_one_image_one_vbmeta(&mut ops); |
| |
| let error = result.unwrap_err(); |
| assert!(matches!(error, SlotVerifyError::RollbackIndex)); |
| } |
| |
| #[test] |
| fn rollback_callback_error_fails_verification() { |
| let mut ops = test_ops_one_image_one_vbmeta(); |
| ops.rollbacks.clear(); |
| |
| let result = verify_one_image_one_vbmeta(&mut ops); |
| |
| let error = result.unwrap_err(); |
| assert!(matches!(error, SlotVerifyError::Io)); |
| } |
| |
| #[test] |
| fn untrusted_vbmeta_keys_fails_verification() { |
| let mut ops = test_ops_one_image_one_vbmeta(); |
| ops.add_vbmeta_key(fs::read(TEST_PUBLIC_KEY_PATH).unwrap(), None, false); |
| |
| let result = verify_one_image_one_vbmeta(&mut ops); |
| |
| let error = result.unwrap_err(); |
| assert!(matches!(error, SlotVerifyError::PublicKeyRejected)); |
| } |
| |
| #[test] |
| fn vbmeta_keys_callback_error_fails_verification() { |
| let mut ops = test_ops_one_image_one_vbmeta(); |
| ops.vbmeta_keys.clear(); |
| |
| let result = verify_one_image_one_vbmeta(&mut ops); |
| |
| let error = result.unwrap_err(); |
| assert!(matches!(error, SlotVerifyError::Io)); |
| } |
| |
| #[test] |
| fn unlock_state_callback_error_fails_verification() { |
| let mut ops = test_ops_one_image_one_vbmeta(); |
| ops.unlock_state = Err(IoError::Io); |
| |
| let result = verify_one_image_one_vbmeta(&mut ops); |
| |
| let error = result.unwrap_err(); |
| assert!(matches!(error, SlotVerifyError::Io)); |
| } |
| |
| #[test] |
| fn persistent_digest_mismatch_fails_verification() { |
| let image_contents = vec![0xAAu8; TEST_IMAGE_SIZE]; |
| let mut ops = test_ops_persistent_digest(image_contents.clone()); |
| // Put in an incorrect persistent digest; `slot_verify()` should detect the mismatch and fail. |
| ops.add_persistent_value(&persistent_digest_value_name(), Ok(b"incorrect_digest")); |
| // Make a copy so we can verify the persistent values don't change on failure. |
| let original_persistent_values = ops.persistent_values.clone(); |
| |
| assert!(verify_persistent_digest(&mut ops).is_err()); |
| |
| // Persistent value should be unchanged. |
| assert_eq!(ops.persistent_values, original_persistent_values); |
| } |
| |
| #[test] |
| fn persistent_digest_callback_error_fails_verification() { |
| let image_contents = vec![0xAAu8; TEST_IMAGE_SIZE]; |
| let mut ops = test_ops_persistent_digest(image_contents.clone()); |
| ops.add_persistent_value(&persistent_digest_value_name(), Err(IoError::NoSuchValue)); |
| |
| let result = verify_persistent_digest(&mut ops); |
| |
| let error = result.unwrap_err(); |
| assert!(matches!(error, SlotVerifyError::Io)); |
| } |
| |
| #[test] |
| fn corrupted_image_with_allow_verification_error_flag_fails_verification_with_data() { |
| let mut ops = test_ops_one_image_one_vbmeta(); |
| modify_partition_contents(&mut ops, TEST_PARTITION_NAME); |
| |
| let result = slot_verify( |
| &mut ops, |
| &[&CString::new(TEST_PARTITION_NAME).unwrap()], |
| None, |
| // Pass the flag to allow verification errors. |
| SlotVerifyFlags::AVB_SLOT_VERIFY_FLAGS_ALLOW_VERIFICATION_ERROR, |
| HashtreeErrorMode::AVB_HASHTREE_ERROR_MODE_EIO, |
| ); |
| |
| // Verification should fail, but with the `AVB_SLOT_VERIFY_FLAGS_ALLOW_VERIFICATION_ERROR` flag |
| // it should give us back the verification data. |
| let error = result.unwrap_err(); |
| let data = match error { |
| SlotVerifyError::Verification(Some(data)) => data, |
| _ => panic!("Expected verification data to exist"), |
| }; |
| |
| // vbmeta verification should have succeeded since that image was still correct. |
| assert_eq!(data.vbmeta_data().len(), 1); |
| assert_eq!(data.vbmeta_data()[0].verify_result(), Ok(())); |
| // Partition verification should have failed since we modified the image. |
| assert_eq!(data.partition_data().len(), 1); |
| assert!(matches!( |
| data.partition_data()[0].verify_result(), |
| Err(SlotVerifyError::Verification(None)) |
| )); |
| } |
| |
| #[test] |
| fn one_image_one_vbmeta_verification_data_display() { |
| let mut ops = test_ops_one_image_one_vbmeta(); |
| |
| let result = verify_one_image_one_vbmeta(&mut ops); |
| |
| let data = result.unwrap(); |
| assert_eq!( |
| format!("{data}"), |
| r#"slot: "", vbmeta: ["vbmeta": Ok(())], images: ["test_part": Ok(())]"# |
| ); |
| } |
| |
| #[test] |
| fn preloaded_image_verification_data_display() { |
| let mut ops = test_ops_one_image_one_vbmeta(); |
| ops.partitions |
| .get_mut(TEST_PARTITION_NAME) |
| .unwrap() |
| .preloaded = true; |
| |
| let result = verify_one_image_one_vbmeta(&mut ops); |
| |
| let data = result.unwrap(); |
| assert_eq!( |
| format!("{data}"), |
| r#"slot: "", vbmeta: ["vbmeta": Ok(())], images: ["test_part"(p): Ok(())]"# |
| ); |
| } |
| |
| #[test] |
| fn two_images_one_vbmeta_verification_data_display() { |
| let mut ops = test_ops_two_images_one_vbmeta(); |
| |
| let result = verify_two_images_one_vbmeta(&mut ops); |
| |
| let data = result.unwrap(); |
| assert_eq!( |
| format!("{data}"), |
| r#"slot: "", vbmeta: ["vbmeta": Ok(())], images: ["test_part": Ok(()), "test_part_2": Ok(())]"# |
| ); |
| } |
| |
| #[test] |
| fn corrupted_image_verification_data_display() { |
| let mut ops = test_ops_one_image_one_vbmeta(); |
| modify_partition_contents(&mut ops, TEST_PARTITION_NAME); |
| |
| let result = slot_verify( |
| &mut ops, |
| &[&CString::new(TEST_PARTITION_NAME).unwrap()], |
| None, |
| SlotVerifyFlags::AVB_SLOT_VERIFY_FLAGS_ALLOW_VERIFICATION_ERROR, |
| HashtreeErrorMode::AVB_HASHTREE_ERROR_MODE_EIO, |
| ); |
| |
| let error = result.unwrap_err(); |
| let data = match error { |
| SlotVerifyError::Verification(Some(data)) => data, |
| _ => panic!("Expected verification data to exist"), |
| }; |
| assert_eq!( |
| format!("{data}"), |
| r#"slot: "", vbmeta: ["vbmeta": Ok(())], images: ["test_part": Err(Verification(None))]"# |
| ); |
| } |