• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2024, The Android Open Source Project
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 //! Gbl AVB operations.
16 
17 use crate::{
18     gbl_avb::state::{BootStateColor, KeyValidationStatus},
19     gbl_print, gbl_println, GblOps,
20 };
21 use abr::SlotIndex;
22 use arrayvec::ArrayString;
23 use avb::{
24     cert_validate_vbmeta_public_key, CertOps, CertPermanentAttributes, IoError, IoResult,
25     Ops as AvbOps, PublicKeyForPartitionInfo, SlotVerifyData, SHA256_DIGEST_SIZE,
26     SHA512_DIGEST_SIZE,
27 };
28 use core::fmt::Write;
29 use core::{
30     cmp::{max, min},
31     ffi::CStr,
32 };
33 use liberror::Error;
34 use safemath::SafeNum;
35 use uuid::Uuid;
36 
37 /// The digest key in commandline provided by libavb.
38 pub const AVB_DIGEST_KEY: &str = "androidboot.vbmeta.digest";
39 
40 // AVB cert tracks versions for the PIK and PSK; PRK cannot be changed so has no version info.
41 const AVB_CERT_NUM_KEY_VERSIONS: usize = 2;
42 
43 /// Implements avb ops callbacks for [GblOps].
44 pub struct GblAvbOps<'a, T> {
45     /// The underlying [GblOps].
46     pub gbl_ops: &'a mut T,
47     slot: Option<SlotIndex>,
48     /// Slotless partitions pre-loaded by the implementation. Provided to avoid redundant IO.
49     preloaded_partitions: &'a [(&'a str, &'a [u8])],
50     /// Used for storing key versions to be set (location, version).
51     ///
52     /// These will initially be `None`, but if using the cert extensions they will be updated during
53     /// verification. These values will not be automatically persisted to disk because whether to do
54     /// so depends on other factors such as slot success state; it's up to the user to persist them
55     /// post-verification if needed.
56     // If `array_map` is imported in the future, consider switching to it.
57     pub key_versions: [Option<(usize, u64)>; AVB_CERT_NUM_KEY_VERSIONS],
58     /// True to use the AVB cert extensions.
59     use_cert: bool,
60     /// Avb public key validation status reported by validate_vbmeta_public_key.
61     /// https://source.android.com/docs/security/features/verifiedboot/boot-flow#locked-devices-with-custom-root-of-trust
62     key_validation_status: Option<KeyValidationStatus>,
63 }
64 
65 impl<'a, 'p, 'q, T: GblOps<'p, 'q>> GblAvbOps<'a, T> {
66     /// Creates a new [GblAvbOps].
new( gbl_ops: &'a mut T, slot: Option<SlotIndex>, preloaded_partitions: &'a [(&'a str, &'a [u8])], use_cert: bool, ) -> Self67     pub fn new(
68         gbl_ops: &'a mut T,
69         slot: Option<SlotIndex>,
70         preloaded_partitions: &'a [(&'a str, &'a [u8])],
71         use_cert: bool,
72     ) -> Self {
73         Self {
74             gbl_ops,
75             slot,
76             preloaded_partitions,
77             key_versions: [None; AVB_CERT_NUM_KEY_VERSIONS],
78             use_cert,
79             key_validation_status: None,
80         }
81     }
82 
83     /// Returns the size of a partition.
84     ///
85     /// This will only consider the [GblOps] partitions. To include preloaded partitions as well,
86     /// use [AvbOps::get_size_of_partition].
partition_size(&mut self, partition: &str) -> IoResult<u64>87     fn partition_size(&mut self, partition: &str) -> IoResult<u64> {
88         self.gbl_ops.partition_size(partition).or(Err(IoError::Io))?.ok_or(IoError::NoSuchPartition)
89     }
90 
91     /// Allowes implementation side to handle verification result.
handle_verification_result( &mut self, slot_verify: Option<&SlotVerifyData>, color: BootStateColor, digest: Option<&str>, ) -> IoResult<()>92     pub fn handle_verification_result(
93         &mut self,
94         slot_verify: Option<&SlotVerifyData>,
95         color: BootStateColor,
96         digest: Option<&str>,
97     ) -> IoResult<()> {
98         // The Android build system automatically generates only the main vbmeta, but also allows
99         // to have separate chained partitions like vbmeta_system (for system, product, system_ext,
100         // etc.) or vbmeta_vendor (for vendor).
101         // https://android.googlesource.com/platform/external/avb/+/master/README.md#build-system-integration
102         //
103         // It may also integrate chained vbmeta into system level metadata partitions such as boot
104         // or init_boot, so they can be updated separately.
105         // https://android.googlesource.com/platform/external/avb/+/master/README.md#gki-2_0-integration
106         //
107         // Custom chained partitions are also supported by the Android build system, but we expect
108         // OEMs to follow about the same pattern.
109         // https://android-review.googlesource.com/q/Id671e2c3aee9ada90256381cce432927df03169b
110         let (
111             boot_os_version,
112             boot_security_patch,
113             system_os_version,
114             system_security_patch,
115             vendor_os_version,
116             vendor_security_patch,
117         ) = match slot_verify {
118             Some(slot_verify) => {
119                 let mut vbmeta = None;
120                 let mut vbmeta_boot = None;
121                 let mut vbmeta_system = None;
122                 let mut vbmeta_vendor = None;
123 
124                 for data in slot_verify.vbmeta_data() {
125                     match data.partition_name().to_str().unwrap_or_default() {
126                         "vbmeta" => vbmeta = Some(data),
127                         "boot" => vbmeta_boot = Some(data),
128                         "vbmeta_system" => vbmeta_system = Some(data),
129                         "vbmeta_vendor" => vbmeta_vendor = Some(data),
130                         _ => {}
131                     }
132                 }
133 
134                 let data = vbmeta.ok_or(IoError::NoSuchPartition)?;
135                 let boot_data = vbmeta_boot.unwrap_or(data);
136                 let system_data = vbmeta_system.unwrap_or(data);
137                 let vendor_data = vbmeta_vendor.unwrap_or(data);
138 
139                 (
140                     boot_data.get_property_value("com.android.build.boot.os_version"),
141                     boot_data.get_property_value("com.android.build.boot.security_patch"),
142                     system_data.get_property_value("com.android.build.system.os_version"),
143                     system_data.get_property_value("com.android.build.system.security_patch"),
144                     vendor_data.get_property_value("com.android.build.vendor.os_version"),
145                     vendor_data.get_property_value("com.android.build.vendor.security_patch"),
146                 )
147             }
148             None => (None, None, None, None, None, None),
149         };
150 
151         // Convert digest rust string to null-terminated string by copying it into separate buffer.
152         let mut digest_buffer = ArrayString::<{ 2 * SHA512_DIGEST_SIZE + 1 }>::new();
153         let digest_cstr = match digest {
154             Some(digest) => {
155                 write!(digest_buffer, "{}\0", digest).or(Err(IoError::InvalidValueSize))?;
156                 Some(
157                     CStr::from_bytes_until_nul(digest_buffer.as_bytes())
158                         .or(Err(IoError::InvalidValueSize))?,
159                 )
160             }
161             None => None,
162         };
163 
164         self.gbl_ops.avb_handle_verification_result(
165             color,
166             digest_cstr,
167             boot_os_version,
168             boot_security_patch,
169             system_os_version,
170             system_security_patch,
171             vendor_os_version,
172             vendor_security_patch,
173         )
174     }
175 
176     /// Get vbmeta public key validation status reported by validate_vbmeta_public_key.
key_validation_status(&self) -> IoResult<KeyValidationStatus>177     pub fn key_validation_status(&self) -> IoResult<KeyValidationStatus> {
178         self.key_validation_status.ok_or(IoError::NotImplemented)
179     }
180 }
181 
182 /// A helper function for converting `CStr` to `str`
cstr_to_str<E>(s: &CStr, err: E) -> Result<&str, E>183 fn cstr_to_str<E>(s: &CStr, err: E) -> Result<&str, E> {
184     Ok(s.to_str().or(Err(err))?)
185 }
186 
187 /// A helper function to split partition into base name and slot index
split_slotted(partition: &str) -> Result<(&str, SlotIndex), Error>188 fn split_slotted(partition: &str) -> Result<(&str, SlotIndex), Error> {
189     // Attempt to split on the last underscore
190     let (partition_name, suffix) = partition.rsplit_once('_').ok_or(Error::InvalidInput)?;
191 
192     // Ensure suffix has exactly one character
193     if suffix.len() != 1 {
194         return Err(Error::InvalidInput);
195     }
196 
197     // Convert that single character into a SlotIndex
198     let slot_char = suffix.chars().next().unwrap();
199     let slot = slot_char.try_into().map_err(|_| Error::InvalidInput)?;
200 
201     Ok((partition_name, slot))
202 }
203 
204 /// # Lifetimes
205 /// * `'a`: preloaded data lifetime
206 /// * `'b`: [GblOps] partition lifetime
207 impl<'a, 'b, 'c, T: GblOps<'b, 'c>> AvbOps<'a> for GblAvbOps<'a, T> {
read_from_partition( &mut self, partition: &CStr, offset: i64, buffer: &mut [u8], ) -> IoResult<usize>208     fn read_from_partition(
209         &mut self,
210         partition: &CStr,
211         offset: i64,
212         buffer: &mut [u8],
213     ) -> IoResult<usize> {
214         let part_str = cstr_to_str(partition, IoError::NoSuchPartition)?;
215         let partition_size = SafeNum::from(self.partition_size(part_str)?);
216         let read_off = match offset < 0 {
217             true => partition_size - offset.abs(),
218             _ => SafeNum::from(offset),
219         };
220         let read_sz = partition_size - read_off;
221         let read_off = read_off.try_into().or(Err(IoError::RangeOutsidePartition))?;
222         let read_sz =
223             min(buffer.len(), read_sz.try_into().or(Err(IoError::RangeOutsidePartition))?);
224         self.gbl_ops.read_from_partition_sync(part_str, read_off, &mut buffer[..read_sz]).map_err(
225             |e| match e {
226                 Error::NotFound => IoError::NoSuchPartition,
227                 Error::ArithmeticOverflow(_) => IoError::RangeOutsidePartition,
228                 _ => IoError::Io,
229             },
230         )?;
231         Ok(read_sz)
232     }
233 
get_preloaded_partition(&mut self, partition: &CStr) -> IoResult<&'a [u8]>234     fn get_preloaded_partition(&mut self, partition: &CStr) -> IoResult<&'a [u8]> {
235         let part_str = cstr_to_str(partition, IoError::NotImplemented)?;
236 
237         let partition_name = match self.slot {
238             // Extract partition slot and ensure it's matched.
239             Some(slot) => {
240                 let (partition_name, partition_slot) =
241                     split_slotted(part_str).map_err(|_| IoError::NotImplemented)?;
242 
243                 if partition_slot != slot {
244                     return Err(IoError::NotImplemented);
245                 }
246 
247                 partition_name
248             }
249             _ => part_str,
250         };
251 
252         self.preloaded_partitions
253             .iter()
254             .find(|(name, _)| *name == partition_name)
255             .map(|(_, data)| *data)
256             .ok_or_else(|| IoError::NotImplemented)
257     }
258 
validate_vbmeta_public_key( &mut self, public_key: &[u8], public_key_metadata: Option<&[u8]>, ) -> IoResult<bool>259     fn validate_vbmeta_public_key(
260         &mut self,
261         public_key: &[u8],
262         public_key_metadata: Option<&[u8]>,
263     ) -> IoResult<bool> {
264         let status = if self.use_cert {
265             match cert_validate_vbmeta_public_key(self, public_key, public_key_metadata)? {
266                 true => KeyValidationStatus::Valid,
267                 false => KeyValidationStatus::Invalid,
268             }
269         } else {
270             self.gbl_ops.avb_validate_vbmeta_public_key(public_key, public_key_metadata).or_else(
271                 |err| {
272                     // TODO(b/337846185): Remove fallback once AVB protocol implementation is
273                     // forced.
274                     fallback_not_implemented(
275                         self.gbl_ops,
276                         err,
277                         "validate_vbmeta_public_key",
278                         KeyValidationStatus::ValidCustomKey,
279                     )
280                 },
281             )?
282         };
283 
284         self.key_validation_status = Some(status);
285 
286         Ok(matches!(status, KeyValidationStatus::Valid | KeyValidationStatus::ValidCustomKey))
287     }
288 
read_rollback_index(&mut self, rollback_index_location: usize) -> IoResult<u64>289     fn read_rollback_index(&mut self, rollback_index_location: usize) -> IoResult<u64> {
290         self.gbl_ops.avb_read_rollback_index(rollback_index_location).or_else(|err| {
291             // TODO(b/337846185): Remove fallback once AVB protocol implementation is
292             // forced.
293             fallback_not_implemented(self.gbl_ops, err, "read_rollback_index", 0)
294         })
295     }
296 
write_rollback_index(&mut self, rollback_index_location: usize, index: u64) -> IoResult<()>297     fn write_rollback_index(&mut self, rollback_index_location: usize, index: u64) -> IoResult<()> {
298         self.gbl_ops.avb_write_rollback_index(rollback_index_location, index).or_else(|err| {
299             // TODO(b/337846185): Remove fallback once AVB protocol implementation is
300             // forced.
301             fallback_not_implemented(self.gbl_ops, err, "write_rollback_index", ())
302         })
303     }
304 
read_is_device_unlocked(&mut self) -> IoResult<bool>305     fn read_is_device_unlocked(&mut self) -> IoResult<bool> {
306         self.gbl_ops.avb_read_is_device_unlocked().or_else(|err| {
307             // TODO(b/337846185): Remove fallback once AVB protocol implementation is
308             // forced.
309             fallback_not_implemented(self.gbl_ops, err, "read_is_device_unlocked", true)
310         })
311     }
312 
get_unique_guid_for_partition(&mut self, partition: &CStr) -> IoResult<Uuid>313     fn get_unique_guid_for_partition(&mut self, partition: &CStr) -> IoResult<Uuid> {
314         // The ops is only used to check that a partition exists. GUID is not used.
315         self.partition_size(cstr_to_str(partition, IoError::NoSuchPartition)?)?;
316         Ok(Uuid::nil())
317     }
318 
get_size_of_partition(&mut self, partition: &CStr) -> IoResult<u64>319     fn get_size_of_partition(&mut self, partition: &CStr) -> IoResult<u64> {
320         match self.get_preloaded_partition(partition) {
321             Ok(img) => Ok(img.len().try_into().unwrap()),
322             _ => {
323                 let part_str = cstr_to_str(partition, IoError::NoSuchPartition)?;
324                 self.partition_size(part_str)
325             }
326         }
327     }
328 
read_persistent_value(&mut self, name: &CStr, value: &mut [u8]) -> IoResult<usize>329     fn read_persistent_value(&mut self, name: &CStr, value: &mut [u8]) -> IoResult<usize> {
330         self.gbl_ops.avb_read_persistent_value(name, value).or_else(|err| {
331             // TODO(b/337846185): Remove fallback once AVB protocol implementation is
332             // forced.
333             fallback_not_implemented(self.gbl_ops, err, "read_persistent_value", 0)
334         })
335     }
336 
write_persistent_value(&mut self, name: &CStr, value: &[u8]) -> IoResult<()>337     fn write_persistent_value(&mut self, name: &CStr, value: &[u8]) -> IoResult<()> {
338         self.gbl_ops.avb_write_persistent_value(name, value).or_else(|err| {
339             // TODO(b/337846185): Remove fallback once AVB protocol implementation is
340             // forced.
341             fallback_not_implemented(self.gbl_ops, err, "write_persistent_value", ())
342         })
343     }
344 
erase_persistent_value(&mut self, name: &CStr) -> IoResult<()>345     fn erase_persistent_value(&mut self, name: &CStr) -> IoResult<()> {
346         self.gbl_ops.avb_erase_persistent_value(name).or_else(|err| {
347             // TODO(b/337846185): Remove fallback once AVB protocol implementation is
348             // forced.
349             fallback_not_implemented(self.gbl_ops, err, "erase_persistent_value", ())
350         })
351     }
352 
validate_public_key_for_partition( &mut self, _partition: &CStr, _public_key: &[u8], _public_key_metadata: Option<&[u8]>, ) -> IoResult<PublicKeyForPartitionInfo>353     fn validate_public_key_for_partition(
354         &mut self,
355         _partition: &CStr,
356         _public_key: &[u8],
357         _public_key_metadata: Option<&[u8]>,
358     ) -> IoResult<PublicKeyForPartitionInfo> {
359         // Not needed yet; eventually we will plumb this through [GblOps].
360         unreachable!();
361     }
362 
cert_ops(&mut self) -> Option<&mut dyn CertOps>363     fn cert_ops(&mut self) -> Option<&mut dyn CertOps> {
364         match self.use_cert {
365             true => Some(self),
366             false => None,
367         }
368     }
369 }
370 
371 /// [GblAvbOps] always implements [CertOps], but it's only used if `use_cert` is set.
372 impl<'a, 'b, T: GblOps<'a, 'b>> CertOps for GblAvbOps<'_, T> {
read_permanent_attributes( &mut self, attributes: &mut CertPermanentAttributes, ) -> IoResult<()>373     fn read_permanent_attributes(
374         &mut self,
375         attributes: &mut CertPermanentAttributes,
376     ) -> IoResult<()> {
377         self.gbl_ops.avb_cert_read_permanent_attributes(attributes)
378     }
379 
read_permanent_attributes_hash(&mut self) -> IoResult<[u8; SHA256_DIGEST_SIZE]>380     fn read_permanent_attributes_hash(&mut self) -> IoResult<[u8; SHA256_DIGEST_SIZE]> {
381         self.gbl_ops.avb_cert_read_permanent_attributes_hash()
382     }
383 
set_key_version(&mut self, rollback_index_location: usize, key_version: u64)384     fn set_key_version(&mut self, rollback_index_location: usize, key_version: u64) {
385         // Checks if there is already an allocated slot for this location.
386         let existing = self
387             .key_versions
388             .iter_mut()
389             .find_map(|v| v.as_mut().filter(|(loc, _)| *loc == rollback_index_location));
390         match existing {
391             Some((_, val)) => *val = max(*val, key_version),
392             _ => {
393                 // Finds an empty slot and stores the rollback index.
394                 *self
395                     .key_versions
396                     .iter_mut()
397                     .find(|v| v.is_none())
398                     .expect("Ran out of key version slots") =
399                     Some((rollback_index_location, key_version))
400             }
401         }
402     }
403 
get_random(&mut self, _: &mut [u8]) -> IoResult<()>404     fn get_random(&mut self, _: &mut [u8]) -> IoResult<()> {
405         // Not needed yet; eventually we will plumb this through [GblOps].
406         unimplemented!()
407     }
408 }
409 
fallback_not_implemented<'a, 'b, T>( ops: &mut impl GblOps<'a, 'b>, error: IoError, method_name: &str, value: T, ) -> IoResult<T>410 fn fallback_not_implemented<'a, 'b, T>(
411     ops: &mut impl GblOps<'a, 'b>,
412     error: IoError,
413     method_name: &str,
414     value: T,
415 ) -> IoResult<T> {
416     match error {
417         IoError::NotImplemented => {
418             gbl_println!(
419                 ops,
420                 "WARNING: UEFI GblEfiAvbProtocol.{} implementation is missing. This will not be \
421                 permitted in the future.",
422                 method_name,
423             );
424             Ok(value)
425         }
426         err => Err(err),
427     }
428 }
429 
430 #[cfg(test)]
431 mod test {
432     use super::*;
433     use crate::ops::test::{FakeGblOps, FakeGblOpsStorage};
434 
435     // Returns test data consisting of `size` incrementing bytes (0-255 repeating).
test_data(size: usize) -> Vec<u8>436     fn test_data(size: usize) -> Vec<u8> {
437         let mut data = vec![0u8; size];
438         for index in 0..data.len() {
439             data[index] = index as u8;
440         }
441         data
442     }
443 
444     #[test]
read_from_partition_positive_off()445     fn read_from_partition_positive_off() {
446         let mut storage = FakeGblOpsStorage::default();
447         storage.add_raw_device(c"test_part", test_data(512));
448 
449         let mut gbl_ops = FakeGblOps::new(&storage);
450         let mut avb_ops = GblAvbOps::new(&mut gbl_ops, None, &[], false);
451 
452         // Positive offset.
453         let mut out = [0u8; 4];
454         assert_eq!(avb_ops.read_from_partition(c"test_part", 1, &mut out[..]), Ok(4));
455         assert_eq!(out, [1, 2, 3, 4]);
456     }
457 
458     #[test]
read_from_partition_negative_off()459     fn read_from_partition_negative_off() {
460         let mut storage = FakeGblOpsStorage::default();
461         storage.add_raw_device(c"test_part", test_data(512));
462 
463         let mut gbl_ops = FakeGblOps::new(&storage);
464         let mut avb_ops = GblAvbOps::new(&mut gbl_ops, None, &[], false);
465 
466         // Negative offset should wrap from the end
467         let mut out = [0u8; 6];
468         assert_eq!(avb_ops.read_from_partition(c"test_part", -6, &mut out[..]), Ok(6));
469         assert_eq!(out, [0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF]);
470     }
471 
472     #[test]
read_from_partition_partial_read()473     fn read_from_partition_partial_read() {
474         let mut storage = FakeGblOpsStorage::default();
475         storage.add_raw_device(c"test_part", test_data(512));
476 
477         let mut gbl_ops = FakeGblOps::new(&storage);
478         let mut avb_ops = GblAvbOps::new(&mut gbl_ops, None, &[], false);
479 
480         // Reading past the end of the partition should truncate.
481         let mut out = [0u8; 6];
482         assert_eq!(avb_ops.read_from_partition(c"test_part", -3, &mut out[..]), Ok(3));
483         assert_eq!(out, [0xFD, 0xFE, 0xFF, 0, 0, 0]);
484     }
485 
486     #[test]
read_from_partition_out_of_bounds()487     fn read_from_partition_out_of_bounds() {
488         let mut storage = FakeGblOpsStorage::default();
489         storage.add_raw_device(c"test_part", test_data(512));
490 
491         let mut gbl_ops = FakeGblOps::new(&storage);
492         let mut avb_ops = GblAvbOps::new(&mut gbl_ops, None, &[], false);
493 
494         // Reads starting out of bounds should fail.
495         let mut out = [0u8; 4];
496         assert_eq!(
497             avb_ops.read_from_partition(c"test_part", 513, &mut out[..]),
498             Err(IoError::RangeOutsidePartition)
499         );
500         assert_eq!(
501             avb_ops.read_from_partition(c"test_part", -513, &mut out[..]),
502             Err(IoError::RangeOutsidePartition)
503         );
504     }
505 
506     #[test]
read_from_partition_unknown_part()507     fn read_from_partition_unknown_part() {
508         let mut gbl_ops = FakeGblOps::new(&[]);
509         let mut avb_ops = GblAvbOps::new(&mut gbl_ops, None, &[], false);
510 
511         let mut out = [0u8; 4];
512         assert_eq!(
513             avb_ops.read_from_partition(c"unknown_part", 0, &mut out[..]),
514             Err(IoError::NoSuchPartition)
515         );
516     }
517 
518     /// Helper function to test reading pre-loaded partitions.
test_read_preloaded_partition( preloaded_partition: &str, slot: Option<SlotIndex>, partition_to_read: &CStr, expect_success: bool, )519     fn test_read_preloaded_partition(
520         preloaded_partition: &str,
521         slot: Option<SlotIndex>,
522         partition_to_read: &CStr,
523         expect_success: bool,
524     ) {
525         let mut gbl_ops = FakeGblOps::new(&[]);
526 
527         let data = &test_data(512);
528         let slice = &data[..];
529         let preloaded = [(preloaded_partition, slice)];
530         let mut avb_ops = GblAvbOps::new(&mut gbl_ops, slot, &preloaded, false);
531 
532         match expect_success {
533             true => {
534                 assert_eq!(
535                     avb_ops.get_size_of_partition(partition_to_read),
536                     Ok(data.len().try_into().unwrap())
537                 );
538                 assert_eq!(avb_ops.get_preloaded_partition(partition_to_read), Ok(slice));
539             }
540             false => {
541                 assert_eq!(
542                     avb_ops.get_preloaded_partition(partition_to_read),
543                     Err(IoError::NotImplemented),
544                 );
545             }
546         }
547     }
548 
549     #[test]
read_from_preloaded_a_partition()550     fn read_from_preloaded_a_partition() {
551         test_read_preloaded_partition(
552             "test_partition",
553             Some(SlotIndex::A),
554             c"test_partition_a",
555             true,
556         );
557     }
558 
559     #[test]
read_from_preloaded_b_partition()560     fn read_from_preloaded_b_partition() {
561         test_read_preloaded_partition(
562             "test_partition",
563             Some(SlotIndex::B),
564             c"test_partition_b",
565             true,
566         );
567     }
568 
569     #[test]
read_from_preloaded_r_partition()570     fn read_from_preloaded_r_partition() {
571         test_read_preloaded_partition(
572             "test_partition",
573             Some(SlotIndex::R),
574             c"test_partition_r",
575             true,
576         );
577     }
578 
579     #[test]
read_from_preloaded_slotless_partition()580     fn read_from_preloaded_slotless_partition() {
581         test_read_preloaded_partition("test_partition", None, c"test_partition", true);
582     }
583 
584     #[test]
read_from_preloaded_partition_wrong_slot()585     fn read_from_preloaded_partition_wrong_slot() {
586         // Ops are slotless but _a is used, so cannot read.
587         test_read_preloaded_partition("test_partition", None, c"test_partition_a", false);
588 
589         // Ops are using A slot but slotless is getting read, so cannot read.
590         test_read_preloaded_partition(
591             "test_partition",
592             Some(SlotIndex::A),
593             c"test_partition",
594             false,
595         );
596 
597         // Ops are using A slot but _b is getting read, so cannot read.
598         test_read_preloaded_partition(
599             "test_partition",
600             Some(SlotIndex::A),
601             c"test_partition_b",
602             false,
603         );
604     }
605 
606     #[test]
set_key_version_default()607     fn set_key_version_default() {
608         let mut gbl_ops = FakeGblOps::new(&[]);
609         let avb_ops = GblAvbOps::new(&mut gbl_ops, None, &[], false);
610 
611         assert_eq!(avb_ops.key_versions, [None, None]);
612     }
613 
614     #[test]
set_key_version_once()615     fn set_key_version_once() {
616         let mut gbl_ops = FakeGblOps::new(&[]);
617         let mut avb_ops = GblAvbOps::new(&mut gbl_ops, None, &[], false);
618 
619         avb_ops.set_key_version(5, 10);
620         assert_eq!(avb_ops.key_versions, [Some((5, 10)), None]);
621     }
622 
623     #[test]
set_key_version_twice()624     fn set_key_version_twice() {
625         let mut gbl_ops = FakeGblOps::new(&[]);
626         let mut avb_ops = GblAvbOps::new(&mut gbl_ops, None, &[], false);
627 
628         avb_ops.set_key_version(5, 10);
629         avb_ops.set_key_version(20, 40);
630         assert_eq!(avb_ops.key_versions, [Some((5, 10)), Some((20, 40))]);
631     }
632 
633     #[test]
set_key_version_overwrite()634     fn set_key_version_overwrite() {
635         let mut gbl_ops = FakeGblOps::new(&[]);
636         let mut avb_ops = GblAvbOps::new(&mut gbl_ops, None, &[], false);
637 
638         avb_ops.set_key_version(5, 10);
639         avb_ops.set_key_version(20, 40);
640         avb_ops.set_key_version(5, 100);
641         assert_eq!(avb_ops.key_versions, [Some((5, 100)), Some((20, 40))]);
642     }
643 
644     // AVB's key version callback cannot return an error, so if it fails we panic.
645     //
646     // It's possible we could stash the failure somewhere and check it later, but we'd have to be
647     // very careful, as failing to check the status would be a security vulnerability. For now it's
648     // safer to panic, and we only ever expect the PSK and PIK to have key versions.
649     #[test]
650     #[should_panic(expected = "Ran out of key version slots")]
set_key_version_overflow()651     fn set_key_version_overflow() {
652         let mut gbl_ops = FakeGblOps::new(&[]);
653         let mut avb_ops = GblAvbOps::new(&mut gbl_ops, None, &[], false);
654 
655         avb_ops.set_key_version(5, 10);
656         avb_ops.set_key_version(20, 40);
657         avb_ops.set_key_version(40, 100);
658     }
659 
660     #[test]
validate_vbmeta_public_key_valid()661     fn validate_vbmeta_public_key_valid() {
662         let mut gbl_ops = FakeGblOps::new(&[]);
663         gbl_ops.avb_key_validation_status = Some(Ok(KeyValidationStatus::Valid));
664 
665         let mut avb_ops = GblAvbOps::new(&mut gbl_ops, None, &[], false);
666         assert_eq!(avb_ops.validate_vbmeta_public_key(&[], None), Ok(true));
667         assert_eq!(avb_ops.key_validation_status(), Ok(KeyValidationStatus::Valid));
668     }
669 
670     #[test]
validate_vbmeta_public_key_valid_custom_key()671     fn validate_vbmeta_public_key_valid_custom_key() {
672         let mut gbl_ops = FakeGblOps::new(&[]);
673         gbl_ops.avb_key_validation_status = Some(Ok(KeyValidationStatus::ValidCustomKey));
674 
675         let mut avb_ops = GblAvbOps::new(&mut gbl_ops, None, &[], false);
676         assert_eq!(avb_ops.validate_vbmeta_public_key(&[], None), Ok(true));
677         assert_eq!(avb_ops.key_validation_status(), Ok(KeyValidationStatus::ValidCustomKey));
678     }
679 
680     #[test]
validate_vbmeta_public_key_invalid()681     fn validate_vbmeta_public_key_invalid() {
682         let mut gbl_ops = FakeGblOps::new(&[]);
683         gbl_ops.avb_key_validation_status = Some(Ok(KeyValidationStatus::Invalid));
684 
685         let mut avb_ops = GblAvbOps::new(&mut gbl_ops, None, &[], false);
686         assert_eq!(avb_ops.validate_vbmeta_public_key(&[], None), Ok(false));
687         assert_eq!(avb_ops.key_validation_status(), Ok(KeyValidationStatus::Invalid));
688     }
689 
690     #[test]
validate_vbmeta_public_key_failed()691     fn validate_vbmeta_public_key_failed() {
692         let mut gbl_ops = FakeGblOps::new(&[]);
693         gbl_ops.avb_key_validation_status = Some(Err(IoError::Io));
694 
695         let mut avb_ops = GblAvbOps::new(&mut gbl_ops, None, &[], false);
696         assert_eq!(avb_ops.validate_vbmeta_public_key(&[], None), Err(IoError::Io));
697         assert!(avb_ops.key_validation_status().is_err());
698     }
699 
700     // TODO(b/337846185): Remove test once AVB protocol implementation is forced.
701     #[test]
validate_vbmeta_public_key_not_implemented()702     fn validate_vbmeta_public_key_not_implemented() {
703         let mut gbl_ops = FakeGblOps::new(&[]);
704         gbl_ops.avb_key_validation_status = Some(Err(IoError::NotImplemented));
705 
706         let mut avb_ops = GblAvbOps::new(&mut gbl_ops, None, &[], false);
707 
708         assert_eq!(avb_ops.validate_vbmeta_public_key(&[], None), Ok(true));
709         assert_eq!(avb_ops.key_validation_status(), Ok(KeyValidationStatus::ValidCustomKey));
710     }
711 
712     #[test]
read_rollback_index_read_value()713     fn read_rollback_index_read_value() {
714         const EXPECTED_INDEX: usize = 1;
715         const EXPECTED_VALUE: u64 = 100;
716 
717         let mut gbl_ops = FakeGblOps::new(&[]);
718         gbl_ops.avb_ops.rollbacks.insert(EXPECTED_INDEX, Ok(EXPECTED_VALUE));
719 
720         let mut avb_ops = GblAvbOps::new(&mut gbl_ops, None, &[], false);
721         assert_eq!(avb_ops.read_rollback_index(EXPECTED_INDEX), Ok(EXPECTED_VALUE));
722     }
723 
724     #[test]
read_rollback_index_error_handled()725     fn read_rollback_index_error_handled() {
726         let mut gbl_ops = FakeGblOps::new(&[]);
727 
728         let mut avb_ops = GblAvbOps::new(&mut gbl_ops, None, &[], false);
729         assert_eq!(avb_ops.read_rollback_index(0), Err(IoError::Io));
730     }
731 
732     // TODO(b/337846185): Remove test once AVB protocol implementation is forced.
733     #[test]
read_rollback_index_not_implemented()734     fn read_rollback_index_not_implemented() {
735         let mut gbl_ops = FakeGblOps::new(&[]);
736         gbl_ops.avb_ops.rollbacks.insert(0, Err(IoError::NotImplemented));
737 
738         let mut avb_ops = GblAvbOps::new(&mut gbl_ops, None, &[], false);
739         assert_eq!(avb_ops.read_rollback_index(0), Ok(0));
740     }
741 
742     #[test]
write_rollback_index_write_value()743     fn write_rollback_index_write_value() {
744         const EXPECTED_INDEX: usize = 1;
745         const EXPECTED_VALUE: u64 = 100;
746 
747         let mut gbl_ops = FakeGblOps::new(&[]);
748 
749         let mut avb_ops = GblAvbOps::new(&mut gbl_ops, None, &[], false);
750         assert_eq!(avb_ops.write_rollback_index(EXPECTED_INDEX, EXPECTED_VALUE), Ok(()));
751         assert_eq!(
752             gbl_ops.avb_ops.rollbacks.get(&EXPECTED_INDEX),
753             Some(Ok(EXPECTED_VALUE)).as_ref()
754         );
755     }
756 
757     #[test]
write_rollback_index_error_handled()758     fn write_rollback_index_error_handled() {
759         let mut gbl_ops = FakeGblOps::new(&[]);
760         gbl_ops.avb_ops.rollbacks.insert(0, Err(IoError::Io));
761 
762         let mut avb_ops = GblAvbOps::new(&mut gbl_ops, None, &[], false);
763         assert_eq!(avb_ops.write_rollback_index(0, 0), Err(IoError::Io));
764     }
765 
766     // TODO(b/337846185): Remove test once AVB protocol implementation is forced.
767     #[test]
write_rollback_index_not_implemented()768     fn write_rollback_index_not_implemented() {
769         let mut gbl_ops = FakeGblOps::new(&[]);
770         gbl_ops.avb_ops.rollbacks.insert(0, Err(IoError::NotImplemented));
771 
772         let mut avb_ops = GblAvbOps::new(&mut gbl_ops, None, &[], false);
773         assert_eq!(avb_ops.write_rollback_index(0, 0), Ok(()));
774     }
775 
776     #[test]
read_is_device_unlocked_value_obtained()777     fn read_is_device_unlocked_value_obtained() {
778         let mut gbl_ops = FakeGblOps::new(&[]);
779         gbl_ops.avb_ops.unlock_state = Ok(true);
780 
781         let mut avb_ops = GblAvbOps::new(&mut gbl_ops, None, &[], false);
782 
783         assert_eq!(avb_ops.read_is_device_unlocked(), Ok(true));
784     }
785 
786     #[test]
read_is_device_unlocked_error_handled()787     fn read_is_device_unlocked_error_handled() {
788         let mut gbl_ops = FakeGblOps::new(&[]);
789         gbl_ops.avb_ops.unlock_state = Err(IoError::Io);
790 
791         let mut avb_ops = GblAvbOps::new(&mut gbl_ops, None, &[], false);
792         assert_eq!(avb_ops.read_is_device_unlocked(), Err(IoError::Io));
793     }
794 
795     // TODO(b/337846185): Remove test once AVB protocol implementation is forced.
796     #[test]
read_is_device_unlocked_not_implemented()797     fn read_is_device_unlocked_not_implemented() {
798         let mut gbl_ops = FakeGblOps::new(&[]);
799         gbl_ops.avb_ops.unlock_state = Err(IoError::NotImplemented);
800 
801         let mut avb_ops = GblAvbOps::new(&mut gbl_ops, None, &[], false);
802         assert_eq!(avb_ops.read_is_device_unlocked(), Ok(true));
803     }
804 
805     #[test]
read_persistent_value_success()806     fn read_persistent_value_success() {
807         const EXPECTED_NAME: &CStr = c"test";
808         const EXPECTED_VALUE: &[u8] = b"test";
809 
810         let mut gbl_ops = FakeGblOps::new(&[]);
811         gbl_ops.avb_ops.add_persistent_value(EXPECTED_NAME.to_str().unwrap(), Ok(EXPECTED_VALUE));
812 
813         let mut avb_ops = GblAvbOps::new(&mut gbl_ops, None, &[], false);
814         let mut buffer = [0u8; EXPECTED_VALUE.len()];
815         assert_eq!(
816             avb_ops.read_persistent_value(EXPECTED_NAME, &mut buffer),
817             Ok(EXPECTED_VALUE.len())
818         );
819         assert_eq!(buffer, EXPECTED_VALUE);
820     }
821 
822     #[test]
read_persistent_value_error()823     fn read_persistent_value_error() {
824         const EXPECTED_NAME: &CStr = c"test";
825 
826         let mut gbl_ops = FakeGblOps::new(&[]);
827         gbl_ops.avb_ops.add_persistent_value(EXPECTED_NAME.to_str().unwrap(), Err(IoError::Io));
828 
829         let mut avb_ops = GblAvbOps::new(&mut gbl_ops, None, &[], false);
830         let mut buffer = [0u8; 4];
831         assert_eq!(avb_ops.read_persistent_value(EXPECTED_NAME, &mut buffer), Err(IoError::Io));
832     }
833 
834     // TODO(b/337846185): Remove test once AVB protocol implementation is forced.
835     #[test]
read_persistent_value_not_implemented()836     fn read_persistent_value_not_implemented() {
837         const EXPECTED_NAME: &CStr = c"test";
838 
839         let mut gbl_ops = FakeGblOps::new(&[]);
840         gbl_ops
841             .avb_ops
842             .add_persistent_value(EXPECTED_NAME.to_str().unwrap(), Err(IoError::NotImplemented));
843 
844         let mut avb_ops = GblAvbOps::new(&mut gbl_ops, None, &[], false);
845         let mut buffer = [0u8; 0];
846         assert_eq!(avb_ops.read_persistent_value(EXPECTED_NAME, &mut buffer), Ok(0));
847     }
848 
849     #[test]
write_persistent_value_success()850     fn write_persistent_value_success() {
851         const EXPECTED_NAME: &CStr = c"test";
852         const EXPECTED_VALUE: &[u8] = b"test";
853 
854         let mut gbl_ops = FakeGblOps::new(&[]);
855 
856         let mut avb_ops = GblAvbOps::new(&mut gbl_ops, None, &[], false);
857         assert_eq!(avb_ops.write_persistent_value(EXPECTED_NAME, EXPECTED_VALUE), Ok(()));
858 
859         assert_eq!(
860             gbl_ops.avb_ops.persistent_values.get(EXPECTED_NAME.to_str().unwrap()),
861             Some(Ok(EXPECTED_VALUE.to_vec())).as_ref()
862         );
863     }
864 
865     #[test]
write_persistent_value_error()866     fn write_persistent_value_error() {
867         const EXPECTED_NAME: &CStr = c"test";
868         const EXPECTED_VALUE: &[u8] = b"test";
869 
870         let mut gbl_ops = FakeGblOps::new(&[]);
871         gbl_ops.avb_ops.add_persistent_value(EXPECTED_NAME.to_str().unwrap(), Err(IoError::Io));
872 
873         let mut avb_ops = GblAvbOps::new(&mut gbl_ops, None, &[], false);
874         assert_eq!(avb_ops.write_persistent_value(EXPECTED_NAME, EXPECTED_VALUE), Err(IoError::Io));
875     }
876 
877     // TODO(b/337846185): Remove test once AVB protocol implementation is forced.
878     #[test]
write_persistent_value_not_implemented()879     fn write_persistent_value_not_implemented() {
880         const EXPECTED_NAME: &CStr = c"test";
881         const EXPECTED_VALUE: &[u8] = b"test";
882 
883         let mut gbl_ops = FakeGblOps::new(&[]);
884         gbl_ops
885             .avb_ops
886             .add_persistent_value(EXPECTED_NAME.to_str().unwrap(), Err(IoError::NotImplemented));
887 
888         let mut avb_ops = GblAvbOps::new(&mut gbl_ops, None, &[], false);
889         assert_eq!(avb_ops.write_persistent_value(EXPECTED_NAME, EXPECTED_VALUE), Ok(()));
890     }
891 
892     #[test]
erase_persistent_value_success()893     fn erase_persistent_value_success() {
894         const EXPECTED_NAME: &CStr = c"test";
895 
896         let mut gbl_ops = FakeGblOps::new(&[]);
897         gbl_ops.avb_ops.add_persistent_value(EXPECTED_NAME.to_str().unwrap(), Ok(b"test"));
898 
899         let mut avb_ops = GblAvbOps::new(&mut gbl_ops, None, &[], false);
900         assert_eq!(avb_ops.erase_persistent_value(EXPECTED_NAME), Ok(()));
901 
902         assert!(!gbl_ops.avb_ops.persistent_values.contains_key(EXPECTED_NAME.to_str().unwrap()));
903     }
904 
905     #[test]
erase_persistent_value_error()906     fn erase_persistent_value_error() {
907         const EXPECTED_NAME: &CStr = c"test";
908 
909         let mut gbl_ops = FakeGblOps::new(&[]);
910         gbl_ops.avb_ops.add_persistent_value(EXPECTED_NAME.to_str().unwrap(), Err(IoError::Io));
911 
912         let mut avb_ops = GblAvbOps::new(&mut gbl_ops, None, &[], false);
913         assert_eq!(avb_ops.erase_persistent_value(EXPECTED_NAME), Err(IoError::Io));
914     }
915 
916     // TODO(b/337846185): Remove test once AVB protocol implementation is forced.
917     #[test]
erase_persistent_value_not_implemented()918     fn erase_persistent_value_not_implemented() {
919         const EXPECTED_NAME: &CStr = c"test";
920 
921         let mut gbl_ops = FakeGblOps::new(&[]);
922         gbl_ops
923             .avb_ops
924             .add_persistent_value(EXPECTED_NAME.to_str().unwrap(), Err(IoError::NotImplemented));
925 
926         let mut avb_ops = GblAvbOps::new(&mut gbl_ops, None, &[], false);
927         assert_eq!(avb_ops.erase_persistent_value(EXPECTED_NAME), Ok(()));
928     }
929 }
930