Pass AVB data for other non-fatal errors
AVB data is also may be provided for rollback index
and public key related errors.
Test: confirmed data provided
Bug: 337846185
Bug: 374684404
Change-Id: I0181feb8004e72eb761707cb7c0a06ce9f86a97b
Signed-off-by: Dmitrii Merkurev <dimorinny@google.com>
diff --git a/rust/src/error.rs b/rust/src/error.rs
index a5642c6..1222f5f 100644
--- a/rust/src/error.rs
+++ b/rust/src/error.rs
@@ -35,6 +35,9 @@
use core::{fmt, str::Utf8Error};
/// `AvbSlotVerifyResult` error wrapper.
+///
+/// Some of the errors can contain the resulting `SlotVerifyData` if the `AllowVerificationError`
+/// flag was passed into `slot_verify()`.
#[derive(Debug, PartialEq, Eq)]
pub enum SlotVerifyError<'a> {
/// `AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_ARGUMENT`
@@ -46,15 +49,12 @@
/// `AVB_SLOT_VERIFY_RESULT_ERROR_OOM`
Oom,
/// `AVB_SLOT_VERIFY_RESULT_ERROR_PUBLIC_KEY_REJECTED`
- PublicKeyRejected,
+ PublicKeyRejected(Option<SlotVerifyData<'a>>),
/// `AVB_SLOT_VERIFY_RESULT_ERROR_ROLLBACK_INDEX`
- RollbackIndex,
+ RollbackIndex(Option<SlotVerifyData<'a>>),
/// `AVB_SLOT_VERIFY_RESULT_ERROR_UNSUPPORTED_VERSION`
UnsupportedVersion,
/// `AVB_SLOT_VERIFY_RESULT_ERROR_VERIFICATION`
- ///
- /// This verification error can contain the resulting `SlotVerifyData` if the
- /// `AllowVerificationError` flag was passed into `slot_verify()`.
Verification(Option<SlotVerifyData<'a>>),
/// Unexpected internal error. This does not have a corresponding libavb error code.
Internal,
@@ -80,13 +80,24 @@
Self::InvalidMetadata => SlotVerifyError::InvalidMetadata,
Self::Io => SlotVerifyError::Io,
Self::Oom => SlotVerifyError::Oom,
- Self::PublicKeyRejected => SlotVerifyError::PublicKeyRejected,
- Self::RollbackIndex => SlotVerifyError::RollbackIndex,
+ Self::PublicKeyRejected(_) => SlotVerifyError::PublicKeyRejected(None),
+ Self::RollbackIndex(_) => SlotVerifyError::RollbackIndex(None),
Self::UnsupportedVersion => SlotVerifyError::UnsupportedVersion,
Self::Verification(_) => SlotVerifyError::Verification(None),
Self::Internal => SlotVerifyError::Internal,
}
}
+
+ /// Returns a `SlotVerifyData` which can be provided with non-fatal errors in case
+ /// `AllowVerificationError` flag was passed into `slot_verify()`.
+ pub fn verification_data(&self) -> Option<&SlotVerifyData<'a>> {
+ match self {
+ SlotVerifyError::PublicKeyRejected(data)
+ | SlotVerifyError::RollbackIndex(data)
+ | SlotVerifyError::Verification(data) => data.as_ref(),
+ _ => None,
+ }
+ }
}
impl<'a> fmt::Display for SlotVerifyError<'a> {
@@ -96,8 +107,8 @@
Self::InvalidMetadata => write!(f, "Invalid metadata"),
Self::Io => write!(f, "I/O error"),
Self::Oom => write!(f, "Unable to allocate memory"),
- Self::PublicKeyRejected => write!(f, "Public key rejected or data not signed"),
- Self::RollbackIndex => write!(f, "Rollback index violation"),
+ Self::PublicKeyRejected(_) => write!(f, "Public key rejected or data not signed"),
+ Self::RollbackIndex(_) => write!(f, "Rollback index violation"),
Self::UnsupportedVersion => write!(f, "Unsupported vbmeta version"),
Self::Verification(_) => write!(f, "Verification failure"),
Self::Internal => write!(f, "Internal error"),
@@ -109,8 +120,8 @@
/// `AVB_SLOT_VERIFY_RESULT_OK` to the Rust equivalent `Ok(())` and errors to the corresponding
/// `Err(SlotVerifyError)`.
///
-/// A `Verification` error returned here will always have a `None` `SlotVerifyData`; the data should
-/// be added in later if it exists.
+/// An error returned here will always have a `None` `SlotVerifyData`; the data should be added
+/// in later if it exists.
///
/// This function is also important to serve as a compile-time check that we're handling all the
/// libavb enums; if a new one is added to (or removed from) the C code, this will fail to compile
@@ -129,10 +140,10 @@
AvbSlotVerifyResult::AVB_SLOT_VERIFY_RESULT_ERROR_IO => Err(SlotVerifyError::Io),
AvbSlotVerifyResult::AVB_SLOT_VERIFY_RESULT_ERROR_OOM => Err(SlotVerifyError::Oom),
AvbSlotVerifyResult::AVB_SLOT_VERIFY_RESULT_ERROR_PUBLIC_KEY_REJECTED => {
- Err(SlotVerifyError::PublicKeyRejected)
+ Err(SlotVerifyError::PublicKeyRejected(None))
}
AvbSlotVerifyResult::AVB_SLOT_VERIFY_RESULT_ERROR_ROLLBACK_INDEX => {
- Err(SlotVerifyError::RollbackIndex)
+ Err(SlotVerifyError::RollbackIndex(None))
}
AvbSlotVerifyResult::AVB_SLOT_VERIFY_RESULT_ERROR_UNSUPPORTED_VERSION => {
Err(SlotVerifyError::UnsupportedVersion)
diff --git a/rust/src/verify.rs b/rust/src/verify.rs
index bea2275..989c8f1 100644
--- a/rust/src/verify.rs
+++ b/rust/src/verify.rs
@@ -465,7 +465,11 @@
match result {
// libavb will always provide verification data on success.
Ok(()) => Ok(data.unwrap()),
- // Data may also be provided on verification failure, fold it into the error.
+ // Data may also be provided on non-fatal failures, fold it into the error.
+ Err(SlotVerifyError::PublicKeyRejected(None)) => {
+ Err(SlotVerifyError::PublicKeyRejected(data))
+ }
+ Err(SlotVerifyError::RollbackIndex(None)) => Err(SlotVerifyError::RollbackIndex(data)),
Err(SlotVerifyError::Verification(None)) => Err(SlotVerifyError::Verification(data)),
// No other error provides verification data.
Err(e) => Err(e),
diff --git a/rust/tests/cert_tests.rs b/rust/tests/cert_tests.rs
index 171fffb..2dd77e6 100644
--- a/rust/tests/cert_tests.rs
+++ b/rust/tests/cert_tests.rs
@@ -138,7 +138,7 @@
let result = verify_one_image_one_vbmeta(&mut ops);
- assert_eq!(result.unwrap_err(), SlotVerifyError::PublicKeyRejected);
+ assert_eq!(result.unwrap_err(), SlotVerifyError::PublicKeyRejected(None));
}
#[test]
@@ -153,7 +153,7 @@
let result = verify_one_image_one_vbmeta(&mut ops);
- assert_eq!(result.unwrap_err(), SlotVerifyError::PublicKeyRejected);
+ assert_eq!(result.unwrap_err(), SlotVerifyError::PublicKeyRejected(None));
}
#[test]
@@ -164,7 +164,7 @@
let result = verify_one_image_one_vbmeta(&mut ops);
- assert_eq!(result.unwrap_err(), SlotVerifyError::PublicKeyRejected);
+ assert_eq!(result.unwrap_err(), SlotVerifyError::PublicKeyRejected(None));
}
#[test]
@@ -175,7 +175,7 @@
let result = verify_one_image_one_vbmeta(&mut ops);
- assert_eq!(result.unwrap_err(), SlotVerifyError::PublicKeyRejected);
+ assert_eq!(result.unwrap_err(), SlotVerifyError::PublicKeyRejected(None));
}
#[test]
diff --git a/rust/tests/verify_tests.rs b/rust/tests/verify_tests.rs
index a5e67c5..45c15c3 100644
--- a/rust/tests/verify_tests.rs
+++ b/rust/tests/verify_tests.rs
@@ -464,7 +464,7 @@
let result = verify_one_image_one_vbmeta(&mut ops);
let error = result.unwrap_err();
- assert!(matches!(error, SlotVerifyError::RollbackIndex));
+ assert!(matches!(error, SlotVerifyError::RollbackIndex(None)));
}
#[test]
@@ -489,7 +489,7 @@
let result = verify_one_image_one_vbmeta(&mut ops);
let error = result.unwrap_err();
- assert!(matches!(error, SlotVerifyError::PublicKeyRejected));
+ assert!(matches!(error, SlotVerifyError::PublicKeyRejected(None)));
}
#[test]
@@ -629,9 +629,8 @@
);
let error = result.unwrap_err();
- let data = match error {
- SlotVerifyError::Verification(Some(data)) => data,
- _ => panic!("Expected verification data to exist"),
+ let SlotVerifyError::Verification(Some(data)) = error else {
+ panic!("Expected Verification with verification data");
};
assert_eq!(
format!("{data}"),
@@ -640,6 +639,56 @@
}
#[test]
+fn invalid_public_key_verification_data_provided() {
+ let mut ops = build_test_ops_one_image_one_vbmeta();
+ ops.default_vbmeta_key = Some(FakeVbmetaKey::Avb {
+ public_key: b"not_the_key".into(),
+ public_key_metadata: None,
+ });
+
+ 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 SlotVerifyError::PublicKeyRejected(Some(data)) = error else {
+ panic!("Expected PublicKeyRejected with verification data");
+ };
+ assert_eq!(
+ format!("{data}"),
+ r#"slot: "", vbmeta: ["vbmeta": Ok(())], images: ["test_part": Ok(())]"#
+ );
+}
+
+#[test]
+fn invalid_rollback_index_verification_data_provided() {
+ let mut ops = build_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, Ok(1));
+
+ 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 SlotVerifyError::RollbackIndex(Some(data)) = error else {
+ panic!("Expected RollbackIndex with verification data");
+ };
+ assert_eq!(
+ format!("{data}"),
+ r#"slot: "", vbmeta: ["vbmeta": Ok(())], images: ["test_part": Ok(())]"#
+ );
+}
+
+#[test]
fn one_image_gives_single_descriptor() {
let mut ops = build_test_ops_one_image_one_vbmeta();