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