aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Pursell <dpursell@google.com>2023-10-13 17:02:55 +0000
committerAutomerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>2023-10-13 17:02:55 +0000
commit0363aeac13d2fc7b9f5b480c5c6a462ba2c22df6 (patch)
tree8fe728f5ea7d877313e313f00e56027a7d74182f
parent77b10a974090c65b542a032478873a7fcfbaa220 (diff)
parentfff9cb3534a0bcf8915686bf55a5f62ebf2ecc11 (diff)
downloadavb-0363aeac13d2fc7b9f5b480c5c6a462ba2c22df6.tar.gz
libavb_rs: add unlocked state callback op am: b309fba8ca am: fff9cb3534
Original change: https://android-review.googlesource.com/c/platform/external/avb/+/2787011 Change-Id: Iaac636cd551c5488be6da165f370f32fb5e44069 Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
-rw-r--r--rust/src/verify.rs113
1 files changed, 111 insertions, 2 deletions
diff --git a/rust/src/verify.rs b/rust/src/verify.rs
index 94fa511..4d7b90a 100644
--- a/rust/src/verify.rs
+++ b/rust/src/verify.rs
@@ -110,6 +110,12 @@ pub trait Ops {
/// # Returns
/// Unit on success or `IoError` on error.
fn write_rollback_index(&mut self, rollback_index_location: usize, index: u64) -> Result<()>;
+
+ /// Returns the device unlock state.
+ ///
+ /// # Returns
+ /// True if the device is unlocked, false if locked, `IoError` on error.
+ fn read_is_device_unlocked(&mut self) -> Result<bool>;
}
/// Helper to pass user-provided `Ops` through libavb via the `user_data` pointer.
@@ -182,8 +188,8 @@ impl<'a> ScopedAvbOps<'a> {
validate_vbmeta_public_key: Some(validate_vbmeta_public_key),
read_rollback_index: Some(read_rollback_index),
write_rollback_index: Some(write_rollback_index),
+ read_is_device_unlocked: Some(read_is_device_unlocked),
// TODO: add callback wrappers for the remaining API.
- read_is_device_unlocked: None,
get_unique_guid_for_partition: None,
get_size_of_partition: None,
read_persistent_value: None,
@@ -544,6 +550,43 @@ unsafe fn try_write_rollback_index(
ops.write_rollback_index(rollback_index_location, rollback_index)
}
+/// Wraps a callback to convert the given `Result<>` to raw `AvbIOResult` for libavb.
+///
+/// See corresponding `try_*` function docs.
+unsafe extern "C" fn read_is_device_unlocked(
+ ops: *mut AvbOps,
+ out_is_unlocked: *mut bool,
+) -> AvbIOResult {
+ result_to_io_enum(try_read_is_device_unlocked(ops, out_is_unlocked))
+}
+
+/// Bounces the C callback into the user-provided Rust implementation.
+///
+/// # Safety
+/// * `ops` must have been created via `ScopedAvbOps`.
+/// * `out_is_unlocked` must adhere to the requirements of `ptr::write()`.
+unsafe fn try_read_is_device_unlocked(ops: *mut AvbOps, out_is_unlocked: *mut bool) -> Result<()> {
+ check_nonnull(out_is_unlocked)?;
+
+ // Initialize the output variables first in case something fails.
+ // SAFETY:
+ // * we've checked that the pointer is non-NULL.
+ // * libavb gives us a properly-allocated `out_is_unlocked`.
+ unsafe { ptr::write(out_is_unlocked, false) };
+
+ // SAFETY:
+ // * we only use `ops` objects created via `ScopedAvbOps` as required.
+ // * `ops` is only extracted once and is dropped at the end of the callback.
+ let ops = unsafe { as_ops(ops) }?;
+ let unlocked = ops.read_is_device_unlocked()?;
+
+ // SAFETY:
+ // * we've checked that the pointer is non-NULL.
+ // * libavb gives us a properly-allocated `out_is_unlocked`.
+ unsafe { ptr::write(out_is_unlocked, unlocked) };
+ Ok(())
+}
+
#[cfg(test)]
mod tests {
use super::*;
@@ -555,7 +598,6 @@ mod tests {
///
/// In addition to being used to exercise individual callback wrappers, this will be used for
/// full verification tests so behavior needs to be correct.
- #[derive(Default)]
struct TestOps {
/// Partitions to "read" on request.
partitions: HashMap<&'static str, Vec<u8>>,
@@ -567,6 +609,20 @@ mod tests {
vbmeta_keys: HashMap<(&'static [u8], Option<&'static [u8]>), bool>,
/// Rollback indices. Accessing unknown locations will return `IoError::Io`.
rollbacks: HashMap<usize, u64>,
+ /// Unlock state. Set an error to simulate IoError during access.
+ unlock_state: Result<bool>,
+ }
+
+ impl Default for TestOps {
+ fn default() -> Self {
+ Self {
+ partitions: HashMap::new(),
+ preloaded: HashMap::new(),
+ vbmeta_keys: HashMap::new(),
+ rollbacks: HashMap::new(),
+ unlock_state: Err(IoError::Io),
+ }
+ }
}
impl Ops for TestOps {
@@ -634,6 +690,10 @@ mod tests {
*(self.rollbacks.get_mut(&location).ok_or(IoError::Io)?) = index;
Ok(())
}
+
+ fn read_is_device_unlocked(&mut self) -> Result<bool> {
+ self.unlock_state.clone()
+ }
}
/// Calls the `read_from_partition()` C callback the same way libavb would.
@@ -765,6 +825,16 @@ mod tests {
unsafe { avb_ops.write_rollback_index.unwrap()(avb_ops, rollback_index_location, index) }
}
+ /// Calls the `read_is_device_unlocked()` C callback the same way libavb would.
+ fn call_read_is_device_unlocked(ops: &mut impl Ops, out_is_unlocked: &mut bool) -> AvbIOResult {
+ let mut user_data = UserData(ops);
+ let mut scoped_ops = ScopedAvbOps::new(&mut user_data);
+ let avb_ops = scoped_ops.as_mut();
+
+ // SAFETY: we've properly created and initialized all the raw pointers being passed in.
+ unsafe { avb_ops.read_is_device_unlocked.unwrap()(avb_ops, out_is_unlocked) }
+ }
+
#[test]
fn test_read_from_partition() {
let mut ops = TestOps::default();
@@ -974,4 +1044,43 @@ mod tests {
);
assert_eq!(*ops.rollbacks.get(&10).unwrap(), 30);
}
+
+ #[test]
+ fn test_read_is_device_unlocked_yes() {
+ let mut ops = TestOps::default();
+ ops.unlock_state = Ok(true);
+
+ let mut unlocked = false;
+ assert_eq!(
+ call_read_is_device_unlocked(&mut ops, &mut unlocked),
+ AvbIOResult::AVB_IO_RESULT_OK
+ );
+ assert_eq!(unlocked, true);
+ }
+
+ #[test]
+ fn test_read_is_device_unlocked_no() {
+ let mut ops = TestOps::default();
+ ops.unlock_state = Ok(false);
+
+ let mut unlocked = true;
+ assert_eq!(
+ call_read_is_device_unlocked(&mut ops, &mut unlocked),
+ AvbIOResult::AVB_IO_RESULT_OK
+ );
+ assert_eq!(unlocked, false);
+ }
+
+ #[test]
+ fn test_read_is_device_unlocked_error() {
+ let mut ops = TestOps::default();
+ ops.unlock_state = Err(IoError::Io);
+
+ let mut unlocked = true;
+ assert_eq!(
+ call_read_is_device_unlocked(&mut ops, &mut unlocked),
+ AvbIOResult::AVB_IO_RESULT_ERROR_IO
+ );
+ assert_eq!(unlocked, false);
+ }
}