diff options
author | David Pursell <dpursell@google.com> | 2023-10-13 17:02:55 +0000 |
---|---|---|
committer | Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com> | 2023-10-13 17:02:55 +0000 |
commit | 0363aeac13d2fc7b9f5b480c5c6a462ba2c22df6 (patch) | |
tree | 8fe728f5ea7d877313e313f00e56027a7d74182f | |
parent | 77b10a974090c65b542a032478873a7fcfbaa220 (diff) | |
parent | fff9cb3534a0bcf8915686bf55a5f62ebf2ecc11 (diff) | |
download | avb-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.rs | 113 |
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); + } } |