1 // Copyright 2023, 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 //! # Generic Boot Loader (gbl) Library
16 //!
17 //! TODO: b/312610098 - add documentation.
18 //!
19 //! The intended users of this library are firmware, bootloader, and bring-up teams at OEMs and SOC
20 //! Vendors
21 //!
22 //! # Features
23 //! * `alloc` - enables AVB ops related logic that relies on allocation and depends on allocation.
24 
25 // This code is intended for use in bootloaders that typically will not support
26 // the Rust standard library
27 #![cfg_attr(not(any(test, android_dylib)), no_std)]
28 // TODO: b/312610985 - return warning for unused partitions
29 #![allow(unused_variables, dead_code)]
30 // TODO: b/312608163 - Adding ZBI library usage to check dependencies
31 extern crate avb;
32 extern crate core;
33 extern crate cstr;
34 extern crate gbl_storage;
35 extern crate spin;
36 extern crate zbi;
37 
38 use avb::{HashtreeErrorMode, SlotVerifyData, SlotVerifyError, SlotVerifyFlags, SlotVerifyResult};
39 use core::ffi::CStr;
40 use core::fmt::Debug;
41 use cstr::cstr;
42 use gbl_storage::AsMultiBlockDevices;
43 use spin::Mutex;
44 
45 pub mod boot_mode;
46 pub mod boot_reason;
47 pub mod error;
48 pub mod fastboot;
49 pub mod ops;
50 mod overlap;
51 
52 /// The 'slots' module, containing types and traits for
53 /// querying and modifying slotted boot behavior.
54 pub mod slots;
55 
56 use slots::{BootTarget, BootToken, Cursor, Manager, OneShot, SuffixBytes, UnbootableReason};
57 
58 pub use avb::Descriptor;
59 pub use boot_mode::BootMode;
60 pub use boot_reason::KnownBootReason;
61 pub use error::{Error, IntegrationError, Result};
62 pub use ops::{
63     AndroidBootImages, BootImages, DefaultGblOps, FuchsiaBootImages, GblOps, GblOpsError,
64 };
65 
66 use ops::GblUtils;
67 use overlap::is_overlap;
68 
69 // TODO: b/312607649 - Replace placeholders with actual structures: https://r.android.com/2721974, etc
70 /// TODO: b/312607649 - placeholder type
71 pub struct Partition {}
72 /// TODO: b/312607649 - placeholder type
73 pub struct InfoStruct {}
74 
75 /// Data structure holding verified slot data.
76 #[derive(Debug)]
77 pub struct VerifiedData<'a>(SlotVerifyData<'a>);
78 
79 /// Structure representing partition and optional address it is required to be loaded.
80 /// If no address is provided GBL will use default one.
81 pub struct PartitionRamMap<'b, 'c> {
82     /// Partition details
83     pub partition: &'b Partition,
84 
85     /// Optional memory region to load partitions.
86     /// If it's not provided default values will be used.
87     pub address: Option<&'c mut [u8]>,
88 
89     loaded: bool,
90     verified: bool,
91 }
92 
93 /// Boot Image in memory
94 pub struct BootImage<'a>(&'a mut [u8]);
95 
96 /// Vendor Boot Image in memory
97 pub struct VendorBootImage<'a>(&'a mut [u8]);
98 
99 /// Init Boot Image in memory
100 pub struct InitBootImage<'a>(&'a mut [u8]);
101 
102 /// Kernel Image in memory
103 pub struct KernelImage<'a>(&'a mut [u8]);
104 
105 /// Ramdisk in memory
106 pub struct Ramdisk<'a>(&'a mut [u8]);
107 /// Bootconfig in memory
108 pub struct Bootconfig<'a>(&'a mut [u8]);
109 /// DTB in memory
110 pub struct Dtb<'a>(&'a mut [u8]);
111 
112 /// Create Boot Image from corresponding partition for `partitions_ram_map` and `avb_descriptors`
113 /// lists
get_boot_image<'a: 'b, 'b: 'c, 'c, 'd>( verified_data: &mut VerifiedData<'d>, partitions_ram_map: &'a mut [PartitionRamMap<'b, 'c>], ) -> (Option<BootImage<'c>>, &'a mut [PartitionRamMap<'b, 'c>])114 pub fn get_boot_image<'a: 'b, 'b: 'c, 'c, 'd>(
115     verified_data: &mut VerifiedData<'d>,
116     partitions_ram_map: &'a mut [PartitionRamMap<'b, 'c>],
117 ) -> (Option<BootImage<'c>>, &'a mut [PartitionRamMap<'b, 'c>]) {
118     match partitions_ram_map.len() {
119         0 => (None, partitions_ram_map),
120         _ => {
121             let (partition_map, tail) = partitions_ram_map.split_first_mut().unwrap();
122             (partition_map.address.take().map(BootImage), tail)
123         }
124     }
125 }
126 
127 /// Create Vendor Boot Image from corresponding partition for `partitions_ram_map` and
128 /// `avb_descriptors` lists
get_vendor_boot_image<'a: 'b, 'b: 'c, 'c, 'd>( verified_data: &mut VerifiedData<'d>, partitions_ram_map: &'a mut [PartitionRamMap<'b, 'c>], ) -> (Option<VendorBootImage<'c>>, &'a mut [PartitionRamMap<'b, 'c>])129 pub fn get_vendor_boot_image<'a: 'b, 'b: 'c, 'c, 'd>(
130     verified_data: &mut VerifiedData<'d>,
131     partitions_ram_map: &'a mut [PartitionRamMap<'b, 'c>],
132 ) -> (Option<VendorBootImage<'c>>, &'a mut [PartitionRamMap<'b, 'c>]) {
133     match partitions_ram_map.len() {
134         0 => (None, partitions_ram_map),
135         _ => {
136             let (partition_map, tail) = partitions_ram_map.split_first_mut().unwrap();
137             (partition_map.address.take().map(VendorBootImage), tail)
138         }
139     }
140 }
141 
142 /// Create Init Boot Image from corresponding partition for `partitions` and `avb_descriptors` lists
get_init_boot_image<'a: 'b, 'b: 'c, 'c, 'd>( verified_data: &mut VerifiedData<'d>, partitions_ram_map: &'a mut [PartitionRamMap<'b, 'c>], ) -> (Option<InitBootImage<'c>>, &'a mut [PartitionRamMap<'b, 'c>])143 pub fn get_init_boot_image<'a: 'b, 'b: 'c, 'c, 'd>(
144     verified_data: &mut VerifiedData<'d>,
145     partitions_ram_map: &'a mut [PartitionRamMap<'b, 'c>],
146 ) -> (Option<InitBootImage<'c>>, &'a mut [PartitionRamMap<'b, 'c>]) {
147     match partitions_ram_map.len() {
148         0 => (None, partitions_ram_map),
149         _ => {
150             let (partition_map, tail) = partitions_ram_map.split_first_mut().unwrap();
151             (partition_map.address.take().map(InitBootImage), tail)
152         }
153     }
154 }
155 
156 /// Create separate image types from [avb::Descriptor]
get_images<'a: 'b, 'b: 'c, 'c, 'd>( verified_data: &mut VerifiedData<'d>, partitions_ram_map: &'a mut [PartitionRamMap<'b, 'c>], ) -> ( Option<BootImage<'c>>, Option<InitBootImage<'c>>, Option<VendorBootImage<'c>>, &'a mut [PartitionRamMap<'b, 'c>], )157 pub fn get_images<'a: 'b, 'b: 'c, 'c, 'd>(
158     verified_data: &mut VerifiedData<'d>,
159     partitions_ram_map: &'a mut [PartitionRamMap<'b, 'c>],
160 ) -> (
161     Option<BootImage<'c>>,
162     Option<InitBootImage<'c>>,
163     Option<VendorBootImage<'c>>,
164     &'a mut [PartitionRamMap<'b, 'c>],
165 ) {
166     let (boot_image, partitions_ram_map) = get_boot_image(verified_data, partitions_ram_map);
167     let (init_boot_image, partitions_ram_map) =
168         get_init_boot_image(verified_data, partitions_ram_map);
169     let (vendor_boot_image, partitions_ram_map) =
170         get_vendor_boot_image(verified_data, partitions_ram_map);
171     (boot_image, init_boot_image, vendor_boot_image, partitions_ram_map)
172 }
173 
174 static BOOT_TOKEN: Mutex<Option<BootToken>> = Mutex::new(Some(BootToken(())));
175 
176 type AvbVerifySlot = for<'b> fn(
177     ops: &mut dyn avb::Ops<'b>,
178     requested_partitions: &[&CStr],
179     ab_suffix: Option<&CStr>,
180     flags: SlotVerifyFlags,
181     hashtree_error_mode: HashtreeErrorMode,
182 ) -> SlotVerifyResult<'b, SlotVerifyData<'b>>;
183 
184 /// GBL object that provides implementation of helpers for boot process.
185 ///
186 /// To create this object use [GblBuilder].
187 pub struct Gbl<'a, G>
188 where
189     G: GblOps,
190 {
191     ops: &'a mut G,
192     verify_slot: AvbVerifySlot,
193 }
194 
195 impl<'a, G> Gbl<'a, G>
196 where
197     G: GblOps,
198 {
199     /// Verify + Load Image Into memory
200     ///
201     /// Load from disk, validate with AVB
202     ///
203     /// # Arguments
204     ///   * `avb_ops` - implementation for `avb::Ops` that would be borrowed in result to prevent
205     ///   changes to partitions until it is out of scope.
206     ///   * `partitions_ram_map` - Partitions to verify with optional address to load image to.
207     ///   * `slot_verify_flags` - AVB slot verification flags
208     ///   * `boot_target` - [Optional] Boot Target
209     ///
210     /// # Returns
211     ///
212     /// * `Ok(&[avb_descriptor])` - Array of AVB Descriptors - AVB return codes, partition name,
213     /// image load address, image size, AVB Footer contents (version details, etc.)
214     /// * `Err(Error)` - on failure
load_and_verify_image<'b>( &mut self, avb_ops: &mut impl avb::Ops<'b>, partitions_ram_map: &mut [PartitionRamMap], slot_verify_flags: SlotVerifyFlags, boot_target: Option<BootTarget>, ) -> Result<VerifiedData<'b>>215     pub fn load_and_verify_image<'b>(
216         &mut self,
217         avb_ops: &mut impl avb::Ops<'b>,
218         partitions_ram_map: &mut [PartitionRamMap],
219         slot_verify_flags: SlotVerifyFlags,
220         boot_target: Option<BootTarget>,
221     ) -> Result<VerifiedData<'b>> {
222         let bytes: SuffixBytes =
223             if let Some(tgt) = boot_target { tgt.suffix().into() } else { Default::default() };
224 
225         let requested_partitions = [cstr!("")];
226         let avb_suffix = CStr::from_bytes_until_nul(&bytes)?;
227 
228         let verified_data = VerifiedData(
229             (self.verify_slot)(
230                 avb_ops,
231                 &requested_partitions,
232                 Some(avb_suffix),
233                 slot_verify_flags,
234                 HashtreeErrorMode::AVB_HASHTREE_ERROR_MODE_EIO,
235             )
236             .map_err(|v| v.without_verify_data())?,
237         );
238 
239         Ok(verified_data)
240     }
241 
242     /// Load Slot Manager Interface
243     ///
244     /// The default implementation loads from the `durable_boot` partition
245     /// and writes changes back on the destruction of the cursor.
246     ///
247     /// # Returns
248     ///
249     /// * `Ok(Cursor)` - Cursor object that manages a Manager
250     /// * `Err(Error)` - on failure
load_slot_interface<'b, B: gbl_storage::AsBlockDevice, M: Manager>( &mut self, block_device: &'b mut B, ) -> Result<Cursor<'b, B, M>>251     pub fn load_slot_interface<'b, B: gbl_storage::AsBlockDevice, M: Manager>(
252         &mut self,
253         block_device: &'b mut B,
254     ) -> Result<Cursor<'b, B, M>> {
255         let boot_token = BOOT_TOKEN.lock().take().ok_or(Error::OperationProhibited)?;
256         self.ops
257             .load_slot_interface::<B, M>(block_device, boot_token)
258             .map_err(|_| Error::OperationProhibited.into())
259     }
260 
261     /// Info Load
262     ///
263     /// Unpack boot image in RAM
264     ///
265     /// # Arguments
266     ///   * `boot_image_buffer` - Buffer that contains (Optionally Verified) Boot Image
267     ///   * `boot_mode` - Boot Mode
268     ///   * `boot_target` - [Optional] Boot Target
269     ///
270     /// # Returns
271     ///
272     /// * `Ok(InfoStruct)` - Info Struct (Concatenated kernel commandline - includes slot,
273     /// bootconfig selection, normal_mode, Concatenated bootconfig) on success
274     /// * `Err(Error)` - on failure
unpack_boot_image( &self, boot_image_buffer: &BootImage, boot_target: Option<BootTarget>, ) -> Result<InfoStruct>275     pub fn unpack_boot_image(
276         &self,
277         boot_image_buffer: &BootImage,
278         boot_target: Option<BootTarget>,
279     ) -> Result<InfoStruct> {
280         unimplemented!();
281     }
282 
283     /// Kernel Load
284     ///
285     /// Prepare kernel in RAM for booting
286     ///
287     /// # Arguments
288     ///   * `info` - Info Struct from Info Load
289     ///   * `image_buffer` - Buffer that contains (Verified) Boot Image
290     ///   * `load_buffer` - Kernel Load buffer
291     ///
292     /// # Returns
293     ///
294     /// * `Ok(())` - on success
295     /// * `Err(Error)` - on failure
kernel_load<'b>( &self, info: &InfoStruct, image_buffer: BootImage, load_buffer: &'b mut [u8], ) -> Result<KernelImage<'b>>296     pub fn kernel_load<'b>(
297         &self,
298         info: &InfoStruct,
299         image_buffer: BootImage,
300         load_buffer: &'b mut [u8],
301     ) -> Result<KernelImage<'b>> {
302         unimplemented!();
303     }
304 
305     /// Ramdisk + Bootconfig Load
306     ///
307     /// Kernel Load
308     /// (Could break this into a RD and Bootconfig specific function each, TBD)
309     /// Prepare ramdisk/bootconfig in RAM for booting
310     ///
311     /// # Arguments
312     ///   * `info` - Info Struct from Info Load
313     ///   * `vendor_boot_image` - Buffer that contains (Verified) Vendor Boot Image
314     ///   * `init_boot_image` - Buffer that contains (Verified) Init Boot Image
315     ///   * `ramdisk_load_buffer` - Ramdisk Load buffer (not compressed). It will be filled with
316     ///     a concatenation of `vendor_boot_image`, `init_boot_image` and bootconfig at the end.
317     ///
318     /// # Returns
319     ///
320     /// * `Ok(&str)` - on success returns Kernel command line
321     /// * `Err(Error)` - on failure
ramdisk_bootconfig_load( &self, info: &InfoStruct, vendor_boot_image: &VendorBootImage, init_boot_image: &InitBootImage, ramdisk: &mut Ramdisk, ) -> Result<&'static str>322     pub fn ramdisk_bootconfig_load(
323         &self,
324         info: &InfoStruct,
325         vendor_boot_image: &VendorBootImage,
326         init_boot_image: &InitBootImage,
327         ramdisk: &mut Ramdisk,
328     ) -> Result<&'static str> {
329         unimplemented!();
330     }
331 
332     /// DTB Update And Load
333     ///
334     /// Prepare DTB in RAM for booting
335     ///
336     /// # Arguments
337     ///   * `info` - Info Struct from Info Load
338     ///   * `vendor_boot_image_buffer` - Buffer that contains (Verified) Vendor Boot Image
339     ///
340     /// # Returns
341     ///
342     /// * `Ok()` - on success
343     /// * `Err(Error)` - on failure
dtb_update_and_load( &self, info: &InfoStruct, vendor_boot_image_buffer: VendorBootImage, ) -> Result<Dtb>344     pub fn dtb_update_and_load(
345         &self,
346         info: &InfoStruct,
347         vendor_boot_image_buffer: VendorBootImage,
348     ) -> Result<Dtb> {
349         unimplemented!();
350     }
351 
352     /// Kernel Jump
353     ///
354     ///
355     /// # Arguments
356     ///   * `kernel_load_buffer` - Kernel Load buffer
357     ///   * `ramdisk_bootconfi_load_buffer` - Concatenated Ramdisk, (Bootconfig if present) Load
358     ///   buffer
359     ///   * `dtb_load_buffer` - DTB Load buffer
360     ///   * `boot_token` - Consumable boot token
361     ///
362     /// # Returns
363     ///
364     /// * doesn't return on success
365     /// * `Err(Error)` - on failure
366     // Nevertype could be used here when it is stable https://github.com/serde-rs/serde/issues/812
kernel_jump( &self, kernel_load_buffer: KernelImage, ramdisk_load_buffer: Ramdisk, dtb_load_buffer: Dtb, boot_token: BootToken, ) -> Result<()>367     pub fn kernel_jump(
368         &self,
369         kernel_load_buffer: KernelImage,
370         ramdisk_load_buffer: Ramdisk,
371         dtb_load_buffer: Dtb,
372         boot_token: BootToken,
373     ) -> Result<()> {
374         unimplemented!();
375     }
376 
377     /// Load, verify, and boot
378     ///
379     /// Wrapper around the above functions for devices that don't need custom behavior between each
380     /// step
381     ///
382     /// Warning: If the call to load_verify_boot fails, the device MUST
383     ///          be restarted in order to make forward boot progress.
384     ///          Callers MAY log the error, enter an interactive mode,
385     ///          or take other actions before rebooting.
386     ///
387     ///
388     /// # Arguments
389     ///   * `avb_ops` - implementation for `avb::Ops` that would be borrowed in result to prevent
390     ///   changes to partitions until it is out of scope.
391     ///   * `partitions_ram_map` - Partitions to verify and optional address for them to be loaded.
392     ///   * `slot_verify_flags` - AVB slot verification flags
393     ///   * `slot_cursor` - Cursor object that manages interactions with boot slot management
394     ///   * `kernel_load_buffer` - Buffer for loading the kernel.
395     ///   * `ramdisk_load_buffer` - Buffer for loading the ramdisk.
396     ///   * `fdt` - Buffer containing a flattened device tree blob.
397     ///
398     /// # Returns
399     ///
400     /// * doesn't return on success
401     /// * `Err(Error)` - on failure
402     // Nevertype could be used here when it is stable https://github.com/serde-rs/serde/issues/812
403     #[allow(clippy::too_many_arguments)]
load_verify_boot<'b: 'c, 'c, 'd: 'b, B: gbl_storage::AsBlockDevice>( &mut self, avb_ops: &mut impl avb::Ops<'b>, partitions_ram_map: &'d mut [PartitionRamMap<'b, 'c>], slot_verify_flags: SlotVerifyFlags, slot_cursor: Cursor<B, impl Manager>, kernel_load_buffer: &mut [u8], ramdisk_load_buffer: &mut [u8], fdt: &mut [u8], ) -> Result<()>404     pub fn load_verify_boot<'b: 'c, 'c, 'd: 'b, B: gbl_storage::AsBlockDevice>(
405         &mut self,
406         avb_ops: &mut impl avb::Ops<'b>,
407         partitions_ram_map: &'d mut [PartitionRamMap<'b, 'c>],
408         slot_verify_flags: SlotVerifyFlags,
409         slot_cursor: Cursor<B, impl Manager>,
410         kernel_load_buffer: &mut [u8],
411         ramdisk_load_buffer: &mut [u8],
412         fdt: &mut [u8],
413     ) -> Result<()> {
414         let dtb = Dtb(&mut fdt[..]);
415         let mut ramdisk = Ramdisk(ramdisk_load_buffer);
416 
417         // Call the inner method which consumes the cursor
418         // in order to properly manager cursor lifetime
419         // and cleanup.
420         let (kernel_image, token) = self.lvb_inner(
421             avb_ops,
422             &mut ramdisk,
423             kernel_load_buffer,
424             partitions_ram_map,
425             slot_verify_flags,
426             slot_cursor,
427         )?;
428 
429         self.kernel_jump(kernel_image, ramdisk, dtb, token)
430     }
431 
is_unrecoverable_error(error: &IntegrationError) -> bool432     fn is_unrecoverable_error(error: &IntegrationError) -> bool {
433         // Note: these ifs are nested instead of chained because multiple
434         //       expressions in an if-let is an unstable features
435         if let IntegrationError::AvbSlotVerifyError(ref avb_error) = error {
436             // These are the AVB errors that are not recoverable on a subsequent attempt.
437             // If necessary in the future, this helper function can be moved to the GblOps trait
438             // and customized for platform specific behavior.
439             if matches!(
440                 avb_error,
441                 SlotVerifyError::Verification(_)
442                     | SlotVerifyError::PublicKeyRejected
443                     | SlotVerifyError::RollbackIndex
444             ) {
445                 return true;
446             }
447         }
448         false
449     }
450 
lvb_inner<'b: 'c, 'c, 'd: 'b, 'e, B: gbl_storage::AsBlockDevice>( &mut self, avb_ops: &mut impl avb::Ops<'b>, ramdisk: &mut Ramdisk, kernel_load_buffer: &'e mut [u8], partitions_ram_map: &'d mut [PartitionRamMap<'b, 'c>], slot_verify_flags: SlotVerifyFlags, mut slot_cursor: Cursor<B, impl Manager>, ) -> Result<(KernelImage<'e>, BootToken)>451     fn lvb_inner<'b: 'c, 'c, 'd: 'b, 'e, B: gbl_storage::AsBlockDevice>(
452         &mut self,
453         avb_ops: &mut impl avb::Ops<'b>,
454         ramdisk: &mut Ramdisk,
455         kernel_load_buffer: &'e mut [u8],
456         partitions_ram_map: &'d mut [PartitionRamMap<'b, 'c>],
457         slot_verify_flags: SlotVerifyFlags,
458         mut slot_cursor: Cursor<B, impl Manager>,
459     ) -> Result<(KernelImage<'e>, BootToken)> {
460         let mut oneshot_status = slot_cursor.ctx.get_oneshot_status();
461         slot_cursor.ctx.clear_oneshot_status();
462 
463         if oneshot_status == Some(OneShot::Bootloader) {
464             match self.ops.do_fastboot(&mut slot_cursor) {
465                 Ok(_) => oneshot_status = slot_cursor.ctx.get_oneshot_status(),
466                 Err(IntegrationError::GblNativeError(Error::NotImplemented)) => (),
467                 Err(e) => return Err(e),
468             }
469         }
470 
471         let boot_target = match oneshot_status {
472             None | Some(OneShot::Bootloader) => slot_cursor.ctx.get_boot_target(),
473             Some(OneShot::Continue(recovery)) => BootTarget::Recovery(recovery),
474         };
475 
476         let mut verify_data = self
477             .load_and_verify_image(
478                 avb_ops,
479                 partitions_ram_map,
480                 slot_verify_flags,
481                 Some(boot_target),
482             )
483             .map_err(|e: IntegrationError| {
484                 if let BootTarget::NormalBoot(slot) = boot_target {
485                     if Self::is_unrecoverable_error(&e) {
486                         let _ = slot_cursor.ctx.set_slot_unbootable(
487                             slot.suffix,
488                             UnbootableReason::VerificationFailure,
489                         );
490                     } else {
491                         // Note: the call to mark_boot_attempt will fail if any of the following occur:
492                         // * the target was already Unbootable before the call to load_and_verify_image
493                         // * policy, I/O, or other errors in mark_boot_attempt
494                         //
495                         // We don't really care about those circumstances.
496                         // The call here is a best effort attempt to decrement tries remaining.
497                         let _ = slot_cursor.ctx.mark_boot_attempt();
498                     }
499                 }
500                 e
501             })?;
502 
503         let (boot_image, init_boot_image, vendor_boot_image, _) =
504             get_images(&mut verify_data, partitions_ram_map);
505         let boot_image = boot_image.ok_or(Error::MissingImage)?;
506         let vendor_boot_image = vendor_boot_image.ok_or(Error::MissingImage)?;
507         let init_boot_image = init_boot_image.ok_or(Error::MissingImage)?;
508 
509         if is_overlap(&[
510             boot_image.0,
511             vendor_boot_image.0,
512             init_boot_image.0,
513             &ramdisk.0,
514             kernel_load_buffer,
515         ]) {
516             return Err(IntegrationError::GblNativeError(Error::BufferOverlap));
517         }
518 
519         let info_struct = self.unpack_boot_image(&boot_image, Some(boot_target))?;
520 
521         let kernel_image = self.kernel_load(&info_struct, boot_image, kernel_load_buffer)?;
522 
523         let cmd_line = self.ramdisk_bootconfig_load(
524             &info_struct,
525             &vendor_boot_image,
526             &init_boot_image,
527             ramdisk,
528         )?;
529 
530         self.dtb_update_and_load(&info_struct, vendor_boot_image)?;
531 
532         let token = slot_cursor.ctx.mark_boot_attempt().map_err(|_| Error::OperationProhibited)?;
533 
534         Ok((kernel_image, token))
535     }
536 
537     /// Loads and boots a Zircon kernel according to ABR + AVB.
zircon_load_and_boot(&mut self, load_buffer: &mut [u8]) -> Result<()>538     pub fn zircon_load_and_boot(&mut self, load_buffer: &mut [u8]) -> Result<()> {
539         let (mut block_devices, load_buffer) = GblUtils::new(self.ops, load_buffer)?;
540         block_devices.sync_gpt_all(&mut |_, _, _| {});
541         // TODO(b/334962583): Implement zircon ABR + AVB.
542         // The following are place holder for test of invocation in the integration test only.
543         let ptn_size = block_devices
544             .find_partition("zircon_a")?
545             .size()
546             .map_err(|e: gbl_storage::StorageError| IntegrationError::StorageError(e))?
547             .try_into()
548             .or(Err(Error::ArithmeticOverflow))?;
549         let (kernel, remains) = load_buffer.split_at_mut(ptn_size);
550         block_devices.read_gpt_partition("zircon_a", 0, kernel)?;
551         self.ops.boot(BootImages::Fuchsia(FuchsiaBootImages {
552             zbi_kernel: kernel,
553             zbi_items: &mut [],
554         }))?;
555         Err(Error::BootFailed.into())
556     }
557 }
558 
559 /// Builder for GBL object
560 #[derive(Debug)]
561 pub struct GblBuilder<'a, G>
562 where
563     G: GblOps,
564 {
565     ops: &'a mut G,
566     verify_slot: AvbVerifySlot,
567 }
568 
569 impl<'a, G> GblBuilder<'a, G>
570 where
571     G: GblOps,
572 {
573     /// Start Gbl object creation, with default GblOps implementation
new(ops: &'a mut G) -> Self574     pub fn new(ops: &'a mut G) -> Self {
575         GblBuilder { ops, verify_slot: avb::slot_verify }
576     }
577 
578     // Override [avb::slot_verify] for testing only
579     #[cfg(test)]
verify_slot(mut self, verify_slot: AvbVerifySlot) -> Self580     fn verify_slot(mut self, verify_slot: AvbVerifySlot) -> Self {
581         self.verify_slot = verify_slot;
582         self
583     }
584 
585     /// Finish Gbl object construction and return it as the result
build(self) -> Gbl<'a, G>586     pub fn build(self) -> Gbl<'a, G> {
587         Gbl { ops: self.ops, verify_slot: self.verify_slot }
588     }
589 }
590 
591 #[cfg(test)]
592 mod tests {
593     extern crate avb_sysdeps;
594     extern crate avb_test;
595     use super::*;
596     use avb::IoError;
597     use avb::IoResult as AvbIoResult;
598     use avb::PublicKeyForPartitionInfo;
599     use avb_test::{FakeVbmetaKey, TestOps};
600     use std::{fs, path::Path};
601 
602     struct AvbOpsUnimplemented {}
603     impl avb::Ops<'_> for AvbOpsUnimplemented {
validate_vbmeta_public_key(&mut self, _: &[u8], _: Option<&[u8]>) -> AvbIoResult<bool>604         fn validate_vbmeta_public_key(&mut self, _: &[u8], _: Option<&[u8]>) -> AvbIoResult<bool> {
605             Err(IoError::NotImplemented)
606         }
read_from_partition(&mut self, _: &CStr, _: i64, _: &mut [u8]) -> AvbIoResult<usize>607         fn read_from_partition(&mut self, _: &CStr, _: i64, _: &mut [u8]) -> AvbIoResult<usize> {
608             Err(IoError::NotImplemented)
609         }
read_rollback_index(&mut self, _: usize) -> AvbIoResult<u64>610         fn read_rollback_index(&mut self, _: usize) -> AvbIoResult<u64> {
611             Err(IoError::NotImplemented)
612         }
write_rollback_index(&mut self, _: usize, _: u64) -> AvbIoResult<()>613         fn write_rollback_index(&mut self, _: usize, _: u64) -> AvbIoResult<()> {
614             Err(IoError::NotImplemented)
615         }
read_is_device_unlocked(&mut self) -> AvbIoResult<bool>616         fn read_is_device_unlocked(&mut self) -> AvbIoResult<bool> {
617             Err(IoError::NotImplemented)
618         }
619         #[cfg(feature = "uuid")]
get_unique_guid_for_partition(&mut self, partition: &CStr) -> AvbIoResult<uuid::Uuid>620         fn get_unique_guid_for_partition(&mut self, partition: &CStr) -> AvbIoResult<uuid::Uuid> {
621             Err(IoError::NotImplemented)
622         }
get_size_of_partition(&mut self, partition: &CStr) -> AvbIoResult<u64>623         fn get_size_of_partition(&mut self, partition: &CStr) -> AvbIoResult<u64> {
624             Err(IoError::NotImplemented)
625         }
read_persistent_value(&mut self, name: &CStr, value: &mut [u8]) -> AvbIoResult<usize>626         fn read_persistent_value(&mut self, name: &CStr, value: &mut [u8]) -> AvbIoResult<usize> {
627             Err(IoError::NotImplemented)
628         }
write_persistent_value(&mut self, name: &CStr, value: &[u8]) -> AvbIoResult<()>629         fn write_persistent_value(&mut self, name: &CStr, value: &[u8]) -> AvbIoResult<()> {
630             Err(IoError::NotImplemented)
631         }
erase_persistent_value(&mut self, name: &CStr) -> AvbIoResult<()>632         fn erase_persistent_value(&mut self, name: &CStr) -> AvbIoResult<()> {
633             Err(IoError::NotImplemented)
634         }
validate_public_key_for_partition( &mut self, partition: &CStr, public_key: &[u8], public_key_metadata: Option<&[u8]>, ) -> AvbIoResult<PublicKeyForPartitionInfo>635         fn validate_public_key_for_partition(
636             &mut self,
637             partition: &CStr,
638             public_key: &[u8],
639             public_key_metadata: Option<&[u8]>,
640         ) -> AvbIoResult<PublicKeyForPartitionInfo> {
641             Err(IoError::NotImplemented)
642         }
643     }
644 
645     #[test]
test_load_and_verify_image_avb_io_error()646     fn test_load_and_verify_image_avb_io_error() {
647         let mut gbl_ops = DefaultGblOps {};
648         let mut gbl = GblBuilder::new(&mut gbl_ops).build();
649         let mut avb_ops = AvbOpsUnimplemented {};
650         let mut partitions_ram_map: [PartitionRamMap; 0] = [];
651         let res = gbl.load_and_verify_image(
652             &mut avb_ops,
653             &mut partitions_ram_map,
654             SlotVerifyFlags::AVB_SLOT_VERIFY_FLAGS_NONE,
655             None,
656         );
657         assert_eq!(res.unwrap_err(), IntegrationError::AvbSlotVerifyError(SlotVerifyError::Io));
658     }
659 
660     const TEST_ZIRCON_PARTITION_NAME: &str = "zircon_a";
661     const TEST_ZIRCON_IMAGE_PATH: &str = "zircon_a.bin";
662     const TEST_ZIRCON_VBMETA_PATH: &str = "zircon_a.vbmeta";
663     const TEST_PUBLIC_KEY_PATH: &str = "testkey_rsa4096_pub.bin";
664     const TEST_VBMETA_ROLLBACK_LOCATION: usize = 0; // Default value, we don't explicitly set this.
665 
666     /// Returns the contents of a test data file.
667     ///
668     /// Panicks if the requested file cannot be read.
669     ///
670     /// # Arguments
671     /// * `path`: file path relative to libgbl's `testdata/` directory.
testdata(path: &str) -> Vec<u8>672     fn testdata(path: &str) -> Vec<u8> {
673         let full_path = Path::new("external/gbl/libgbl/testdata").join(path);
674         fs::read(full_path).unwrap()
675     }
676 
677     #[test]
test_load_and_verify_image_stub()678     fn test_load_and_verify_image_stub() {
679         let mut gbl_ops = DefaultGblOps {};
680         let mut gbl = GblBuilder::new(&mut gbl_ops).build();
681         let mut avb_ops = TestOps::default();
682 
683         avb_ops.add_partition(TEST_ZIRCON_PARTITION_NAME, testdata(TEST_ZIRCON_IMAGE_PATH));
684         avb_ops.add_partition("vbmeta", testdata(TEST_ZIRCON_VBMETA_PATH));
685         avb_ops.default_vbmeta_key = Some(FakeVbmetaKey::Avb {
686             public_key: testdata(TEST_PUBLIC_KEY_PATH),
687             public_key_metadata: None,
688         });
689         avb_ops.rollbacks.insert(TEST_VBMETA_ROLLBACK_LOCATION, 0);
690         avb_ops.unlock_state = Ok(false);
691 
692         let mut partitions_ram_map: [PartitionRamMap; 0] = [];
693         let res = gbl.load_and_verify_image(
694             &mut avb_ops,
695             &mut partitions_ram_map,
696             SlotVerifyFlags::AVB_SLOT_VERIFY_FLAGS_NONE,
697             None,
698         );
699         assert!(res.is_ok());
700     }
701 
702     #[test]
test_load_and_verify_image_avb_error()703     fn test_load_and_verify_image_avb_error() {
704         const TEST_ERROR: SlotVerifyError<'static> = SlotVerifyError::Verification(None);
705         let expected_error = SlotVerifyError::Verification(None);
706         let mut gbl_ops = DefaultGblOps {};
707         let mut gbl =
708             GblBuilder::new(&mut gbl_ops).verify_slot(|_, _, _, _, _| Err(TEST_ERROR)).build();
709         let mut avb_ops = AvbOpsUnimplemented {};
710         let mut partitions_ram_map: [PartitionRamMap; 0] = [];
711         let res = gbl.load_and_verify_image(
712             &mut avb_ops,
713             &mut partitions_ram_map,
714             SlotVerifyFlags::AVB_SLOT_VERIFY_FLAGS_NONE,
715             None,
716         );
717         assert_eq!(res.unwrap_err(), IntegrationError::AvbSlotVerifyError(TEST_ERROR));
718     }
719 }
720