1*5225e6b1SAndroid Build Coastguard Worker // Copyright 2023, The Android Open Source Project
2*5225e6b1SAndroid Build Coastguard Worker //
3*5225e6b1SAndroid Build Coastguard Worker // Licensed under the Apache License, Version 2.0 (the "License");
4*5225e6b1SAndroid Build Coastguard Worker // you may not use this file except in compliance with the License.
5*5225e6b1SAndroid Build Coastguard Worker // You may obtain a copy of the License at
6*5225e6b1SAndroid Build Coastguard Worker //
7*5225e6b1SAndroid Build Coastguard Worker // http://www.apache.org/licenses/LICENSE-2.0
8*5225e6b1SAndroid Build Coastguard Worker //
9*5225e6b1SAndroid Build Coastguard Worker // Unless required by applicable law or agreed to in writing, software
10*5225e6b1SAndroid Build Coastguard Worker // distributed under the License is distributed on an "AS IS" BASIS,
11*5225e6b1SAndroid Build Coastguard Worker // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12*5225e6b1SAndroid Build Coastguard Worker // See the License for the specific language governing permissions and
13*5225e6b1SAndroid Build Coastguard Worker // limitations under the License.
14*5225e6b1SAndroid Build Coastguard Worker
15*5225e6b1SAndroid Build Coastguard Worker //! # Generic Boot Loader (gbl) Library
16*5225e6b1SAndroid Build Coastguard Worker //!
17*5225e6b1SAndroid Build Coastguard Worker //! TODO: b/312610098 - add documentation.
18*5225e6b1SAndroid Build Coastguard Worker //!
19*5225e6b1SAndroid Build Coastguard Worker //! The intended users of this library are firmware, bootloader, and bring-up teams at OEMs and SOC
20*5225e6b1SAndroid Build Coastguard Worker //! Vendors
21*5225e6b1SAndroid Build Coastguard Worker //!
22*5225e6b1SAndroid Build Coastguard Worker //! This library is `no_std` as it is intended for use in bootloaders that typically will not
23*5225e6b1SAndroid Build Coastguard Worker //! support the Rust standard library. However, it does require `alloc` with a global allocator,
24*5225e6b1SAndroid Build Coastguard Worker //! currently used for:
25*5225e6b1SAndroid Build Coastguard Worker //! * libavb
26*5225e6b1SAndroid Build Coastguard Worker //! * kernel decompression
27*5225e6b1SAndroid Build Coastguard Worker
28*5225e6b1SAndroid Build Coastguard Worker #![cfg_attr(not(any(test, android_dylib)), no_std)]
29*5225e6b1SAndroid Build Coastguard Worker // TODO: b/312610985 - return warning for unused partitions
30*5225e6b1SAndroid Build Coastguard Worker #![allow(async_fn_in_trait)]
31*5225e6b1SAndroid Build Coastguard Worker // Needed for MaybeUninit::fill() experimental API
32*5225e6b1SAndroid Build Coastguard Worker #![feature(maybe_uninit_fill)]
33*5225e6b1SAndroid Build Coastguard Worker extern crate avb;
34*5225e6b1SAndroid Build Coastguard Worker extern crate core;
35*5225e6b1SAndroid Build Coastguard Worker extern crate gbl_storage;
36*5225e6b1SAndroid Build Coastguard Worker extern crate spin;
37*5225e6b1SAndroid Build Coastguard Worker extern crate zbi;
38*5225e6b1SAndroid Build Coastguard Worker
39*5225e6b1SAndroid Build Coastguard Worker use avb::{HashtreeErrorMode, SlotVerifyData, SlotVerifyError, SlotVerifyFlags};
40*5225e6b1SAndroid Build Coastguard Worker use core::ffi::CStr;
41*5225e6b1SAndroid Build Coastguard Worker use core::marker::PhantomData;
42*5225e6b1SAndroid Build Coastguard Worker
43*5225e6b1SAndroid Build Coastguard Worker pub mod android_boot;
44*5225e6b1SAndroid Build Coastguard Worker pub mod boot_mode;
45*5225e6b1SAndroid Build Coastguard Worker pub mod boot_reason;
46*5225e6b1SAndroid Build Coastguard Worker pub mod constants;
47*5225e6b1SAndroid Build Coastguard Worker pub mod decompress;
48*5225e6b1SAndroid Build Coastguard Worker pub mod device_tree;
49*5225e6b1SAndroid Build Coastguard Worker pub mod error;
50*5225e6b1SAndroid Build Coastguard Worker pub mod fastboot;
51*5225e6b1SAndroid Build Coastguard Worker pub mod fuchsia_boot;
52*5225e6b1SAndroid Build Coastguard Worker pub mod gbl_avb;
53*5225e6b1SAndroid Build Coastguard Worker pub mod ops;
54*5225e6b1SAndroid Build Coastguard Worker pub mod partition;
55*5225e6b1SAndroid Build Coastguard Worker
56*5225e6b1SAndroid Build Coastguard Worker /// The 'slots' module, containing types and traits for
57*5225e6b1SAndroid Build Coastguard Worker /// querying and modifying slotted boot behavior.
58*5225e6b1SAndroid Build Coastguard Worker pub mod slots;
59*5225e6b1SAndroid Build Coastguard Worker
60*5225e6b1SAndroid Build Coastguard Worker mod image_buffer;
61*5225e6b1SAndroid Build Coastguard Worker mod overlap;
62*5225e6b1SAndroid Build Coastguard Worker
63*5225e6b1SAndroid Build Coastguard Worker use slots::{BootTarget, BootToken, Cursor, OneShot, SuffixBytes, UnbootableReason};
64*5225e6b1SAndroid Build Coastguard Worker
65*5225e6b1SAndroid Build Coastguard Worker pub use avb::Descriptor;
66*5225e6b1SAndroid Build Coastguard Worker pub use boot_mode::BootMode;
67*5225e6b1SAndroid Build Coastguard Worker pub use boot_reason::KnownBootReason;
68*5225e6b1SAndroid Build Coastguard Worker pub use error::{IntegrationError, Result};
69*5225e6b1SAndroid Build Coastguard Worker use liberror::Error;
70*5225e6b1SAndroid Build Coastguard Worker pub use ops::{GblOps, Os};
71*5225e6b1SAndroid Build Coastguard Worker
72*5225e6b1SAndroid Build Coastguard Worker use overlap::is_overlap;
73*5225e6b1SAndroid Build Coastguard Worker
74*5225e6b1SAndroid Build Coastguard Worker // TODO: b/312607649 - Replace placeholders with actual structures: https://r.android.com/2721974, etc
75*5225e6b1SAndroid Build Coastguard Worker /// TODO: b/312607649 - placeholder type
76*5225e6b1SAndroid Build Coastguard Worker pub struct Partition {}
77*5225e6b1SAndroid Build Coastguard Worker /// TODO: b/312607649 - placeholder type
78*5225e6b1SAndroid Build Coastguard Worker pub struct InfoStruct {}
79*5225e6b1SAndroid Build Coastguard Worker
80*5225e6b1SAndroid Build Coastguard Worker /// Structure representing partition and optional address it is required to be loaded.
81*5225e6b1SAndroid Build Coastguard Worker /// If no address is provided GBL will use default one.
82*5225e6b1SAndroid Build Coastguard Worker pub struct PartitionRamMap<'b, 'c> {
83*5225e6b1SAndroid Build Coastguard Worker /// Partition details
84*5225e6b1SAndroid Build Coastguard Worker pub partition: &'b Partition,
85*5225e6b1SAndroid Build Coastguard Worker
86*5225e6b1SAndroid Build Coastguard Worker /// Optional memory region to load partitions.
87*5225e6b1SAndroid Build Coastguard Worker /// If it's not provided default values will be used.
88*5225e6b1SAndroid Build Coastguard Worker pub address: Option<&'c mut [u8]>,
89*5225e6b1SAndroid Build Coastguard Worker }
90*5225e6b1SAndroid Build Coastguard Worker
91*5225e6b1SAndroid Build Coastguard Worker /// Boot Image in memory
92*5225e6b1SAndroid Build Coastguard Worker #[allow(dead_code)]
93*5225e6b1SAndroid Build Coastguard Worker pub struct BootImage<'a>(&'a mut [u8]);
94*5225e6b1SAndroid Build Coastguard Worker
95*5225e6b1SAndroid Build Coastguard Worker /// Vendor Boot Image in memory
96*5225e6b1SAndroid Build Coastguard Worker pub struct VendorBootImage<'a>(&'a mut [u8]);
97*5225e6b1SAndroid Build Coastguard Worker
98*5225e6b1SAndroid Build Coastguard Worker /// Init Boot Image in memory
99*5225e6b1SAndroid Build Coastguard Worker pub struct InitBootImage<'a>(&'a mut [u8]);
100*5225e6b1SAndroid Build Coastguard Worker
101*5225e6b1SAndroid Build Coastguard Worker /// Kernel Image in memory
102*5225e6b1SAndroid Build Coastguard Worker #[allow(dead_code)]
103*5225e6b1SAndroid Build Coastguard Worker pub struct KernelImage<'a>(&'a mut [u8]);
104*5225e6b1SAndroid Build Coastguard Worker
105*5225e6b1SAndroid Build Coastguard Worker /// Ramdisk in memory
106*5225e6b1SAndroid Build Coastguard Worker pub struct Ramdisk<'a>(&'a mut [u8]);
107*5225e6b1SAndroid Build Coastguard Worker /// Bootconfig in memory
108*5225e6b1SAndroid Build Coastguard Worker #[allow(dead_code)]
109*5225e6b1SAndroid Build Coastguard Worker pub struct Bootconfig<'a>(&'a mut [u8]);
110*5225e6b1SAndroid Build Coastguard Worker /// DTB in memory
111*5225e6b1SAndroid Build Coastguard Worker #[allow(dead_code)]
112*5225e6b1SAndroid Build Coastguard Worker pub struct Dtb<'a>(&'a mut [u8]);
113*5225e6b1SAndroid Build Coastguard Worker
114*5225e6b1SAndroid Build Coastguard Worker /// Create Boot Image from corresponding partition for `partitions_ram_map` and `avb_descriptors`
115*5225e6b1SAndroid Build Coastguard Worker /// lists
get_boot_image<'a: 'b, 'b: 'c, 'c, 'd>( partitions_ram_map: &'a mut [PartitionRamMap<'b, 'c>], ) -> (Option<BootImage<'c>>, &'a mut [PartitionRamMap<'b, 'c>])116*5225e6b1SAndroid Build Coastguard Worker pub fn get_boot_image<'a: 'b, 'b: 'c, 'c, 'd>(
117*5225e6b1SAndroid Build Coastguard Worker partitions_ram_map: &'a mut [PartitionRamMap<'b, 'c>],
118*5225e6b1SAndroid Build Coastguard Worker ) -> (Option<BootImage<'c>>, &'a mut [PartitionRamMap<'b, 'c>]) {
119*5225e6b1SAndroid Build Coastguard Worker match partitions_ram_map.len() {
120*5225e6b1SAndroid Build Coastguard Worker 0 => (None, partitions_ram_map),
121*5225e6b1SAndroid Build Coastguard Worker _ => {
122*5225e6b1SAndroid Build Coastguard Worker let (partition_map, tail) = partitions_ram_map.split_first_mut().unwrap();
123*5225e6b1SAndroid Build Coastguard Worker (partition_map.address.take().map(BootImage), tail)
124*5225e6b1SAndroid Build Coastguard Worker }
125*5225e6b1SAndroid Build Coastguard Worker }
126*5225e6b1SAndroid Build Coastguard Worker }
127*5225e6b1SAndroid Build Coastguard Worker
128*5225e6b1SAndroid Build Coastguard Worker /// Create Vendor Boot Image from corresponding partition for `partitions_ram_map` and
129*5225e6b1SAndroid Build Coastguard Worker /// `avb_descriptors` lists
get_vendor_boot_image<'a: 'b, 'b: 'c, 'c, 'd>( partitions_ram_map: &'a mut [PartitionRamMap<'b, 'c>], ) -> (Option<VendorBootImage<'c>>, &'a mut [PartitionRamMap<'b, 'c>])130*5225e6b1SAndroid Build Coastguard Worker pub fn get_vendor_boot_image<'a: 'b, 'b: 'c, 'c, 'd>(
131*5225e6b1SAndroid Build Coastguard Worker partitions_ram_map: &'a mut [PartitionRamMap<'b, 'c>],
132*5225e6b1SAndroid Build Coastguard Worker ) -> (Option<VendorBootImage<'c>>, &'a mut [PartitionRamMap<'b, 'c>]) {
133*5225e6b1SAndroid Build Coastguard Worker match partitions_ram_map.len() {
134*5225e6b1SAndroid Build Coastguard Worker 0 => (None, partitions_ram_map),
135*5225e6b1SAndroid Build Coastguard Worker _ => {
136*5225e6b1SAndroid Build Coastguard Worker let (partition_map, tail) = partitions_ram_map.split_first_mut().unwrap();
137*5225e6b1SAndroid Build Coastguard Worker (partition_map.address.take().map(VendorBootImage), tail)
138*5225e6b1SAndroid Build Coastguard Worker }
139*5225e6b1SAndroid Build Coastguard Worker }
140*5225e6b1SAndroid Build Coastguard Worker }
141*5225e6b1SAndroid Build Coastguard Worker
142*5225e6b1SAndroid Build Coastguard Worker /// Create Init Boot Image from corresponding partition for `partitions` and `avb_descriptors` lists
get_init_boot_image<'a: 'b, 'b: 'c, 'c, 'd>( partitions_ram_map: &'a mut [PartitionRamMap<'b, 'c>], ) -> (Option<InitBootImage<'c>>, &'a mut [PartitionRamMap<'b, 'c>])143*5225e6b1SAndroid Build Coastguard Worker pub fn get_init_boot_image<'a: 'b, 'b: 'c, 'c, 'd>(
144*5225e6b1SAndroid Build Coastguard Worker partitions_ram_map: &'a mut [PartitionRamMap<'b, 'c>],
145*5225e6b1SAndroid Build Coastguard Worker ) -> (Option<InitBootImage<'c>>, &'a mut [PartitionRamMap<'b, 'c>]) {
146*5225e6b1SAndroid Build Coastguard Worker match partitions_ram_map.len() {
147*5225e6b1SAndroid Build Coastguard Worker 0 => (None, partitions_ram_map),
148*5225e6b1SAndroid Build Coastguard Worker _ => {
149*5225e6b1SAndroid Build Coastguard Worker let (partition_map, tail) = partitions_ram_map.split_first_mut().unwrap();
150*5225e6b1SAndroid Build Coastguard Worker (partition_map.address.take().map(InitBootImage), tail)
151*5225e6b1SAndroid Build Coastguard Worker }
152*5225e6b1SAndroid Build Coastguard Worker }
153*5225e6b1SAndroid Build Coastguard Worker }
154*5225e6b1SAndroid Build Coastguard Worker
155*5225e6b1SAndroid Build Coastguard Worker /// Create separate image types from [avb::Descriptor]
get_images<'a: 'b, 'b: 'c, 'c, 'd>( partitions_ram_map: &'a mut [PartitionRamMap<'b, 'c>], ) -> ( Option<BootImage<'c>>, Option<InitBootImage<'c>>, Option<VendorBootImage<'c>>, &'a mut [PartitionRamMap<'b, 'c>], )156*5225e6b1SAndroid Build Coastguard Worker pub fn get_images<'a: 'b, 'b: 'c, 'c, 'd>(
157*5225e6b1SAndroid Build Coastguard Worker partitions_ram_map: &'a mut [PartitionRamMap<'b, 'c>],
158*5225e6b1SAndroid Build Coastguard Worker ) -> (
159*5225e6b1SAndroid Build Coastguard Worker Option<BootImage<'c>>,
160*5225e6b1SAndroid Build Coastguard Worker Option<InitBootImage<'c>>,
161*5225e6b1SAndroid Build Coastguard Worker Option<VendorBootImage<'c>>,
162*5225e6b1SAndroid Build Coastguard Worker &'a mut [PartitionRamMap<'b, 'c>],
163*5225e6b1SAndroid Build Coastguard Worker ) {
164*5225e6b1SAndroid Build Coastguard Worker let (boot_image, partitions_ram_map) = get_boot_image(partitions_ram_map);
165*5225e6b1SAndroid Build Coastguard Worker let (init_boot_image, partitions_ram_map) = get_init_boot_image(partitions_ram_map);
166*5225e6b1SAndroid Build Coastguard Worker let (vendor_boot_image, partitions_ram_map) = get_vendor_boot_image(partitions_ram_map);
167*5225e6b1SAndroid Build Coastguard Worker (boot_image, init_boot_image, vendor_boot_image, partitions_ram_map)
168*5225e6b1SAndroid Build Coastguard Worker }
169*5225e6b1SAndroid Build Coastguard Worker
170*5225e6b1SAndroid Build Coastguard Worker /// GBL object that provides implementation of helpers for boot process.
171*5225e6b1SAndroid Build Coastguard Worker pub struct Gbl<'a, 'd, G>
172*5225e6b1SAndroid Build Coastguard Worker where
173*5225e6b1SAndroid Build Coastguard Worker G: GblOps<'a, 'd>,
174*5225e6b1SAndroid Build Coastguard Worker {
175*5225e6b1SAndroid Build Coastguard Worker ops: &'a mut G,
176*5225e6b1SAndroid Build Coastguard Worker boot_token: Option<BootToken>,
177*5225e6b1SAndroid Build Coastguard Worker _get_image_buffer_lifetime: PhantomData<&'d ()>,
178*5225e6b1SAndroid Build Coastguard Worker }
179*5225e6b1SAndroid Build Coastguard Worker
180*5225e6b1SAndroid Build Coastguard Worker // TODO(b/312610985): Investigate whether to deprecate this and remove this allow.
181*5225e6b1SAndroid Build Coastguard Worker #[allow(unused_variables)]
182*5225e6b1SAndroid Build Coastguard Worker impl<'a, 'f, G> Gbl<'a, 'f, G>
183*5225e6b1SAndroid Build Coastguard Worker where
184*5225e6b1SAndroid Build Coastguard Worker G: GblOps<'a, 'f>,
185*5225e6b1SAndroid Build Coastguard Worker {
186*5225e6b1SAndroid Build Coastguard Worker /// Returns a new [Gbl] object.
187*5225e6b1SAndroid Build Coastguard Worker ///
188*5225e6b1SAndroid Build Coastguard Worker /// # Arguments
189*5225e6b1SAndroid Build Coastguard Worker /// * `ops` - the [GblOps] callbacks to use
new(ops: &'a mut G) -> Self190*5225e6b1SAndroid Build Coastguard Worker pub fn new(ops: &'a mut G) -> Self {
191*5225e6b1SAndroid Build Coastguard Worker Self { ops, boot_token: Some(BootToken(())), _get_image_buffer_lifetime: PhantomData }
192*5225e6b1SAndroid Build Coastguard Worker }
193*5225e6b1SAndroid Build Coastguard Worker
194*5225e6b1SAndroid Build Coastguard Worker /// Verify + Load Image Into memory
195*5225e6b1SAndroid Build Coastguard Worker ///
196*5225e6b1SAndroid Build Coastguard Worker /// Load from disk, validate with AVB
197*5225e6b1SAndroid Build Coastguard Worker ///
198*5225e6b1SAndroid Build Coastguard Worker /// # Arguments
199*5225e6b1SAndroid Build Coastguard Worker /// * `avb_ops` - implementation for `avb::Ops`
200*5225e6b1SAndroid Build Coastguard Worker /// * `partitions_to_verify` - names of all the partitions to verify with libavb.
201*5225e6b1SAndroid Build Coastguard Worker /// * `slot_verify_flags` - AVB slot verification flags
202*5225e6b1SAndroid Build Coastguard Worker /// * `boot_target` - [Optional] Boot Target
203*5225e6b1SAndroid Build Coastguard Worker ///
204*5225e6b1SAndroid Build Coastguard Worker /// # Returns
205*5225e6b1SAndroid Build Coastguard Worker /// * `Ok(SlotVerifyData)` - avb verification data
206*5225e6b1SAndroid Build Coastguard Worker /// * `Err(Error)` - on failure
load_and_verify_image<'b>( &mut self, avb_ops: &mut impl avb::Ops<'b>, partitions_to_verify: &[&CStr], slot_verify_flags: SlotVerifyFlags, boot_target: Option<BootTarget>, ) -> Result<SlotVerifyData<'b>>207*5225e6b1SAndroid Build Coastguard Worker pub fn load_and_verify_image<'b>(
208*5225e6b1SAndroid Build Coastguard Worker &mut self,
209*5225e6b1SAndroid Build Coastguard Worker avb_ops: &mut impl avb::Ops<'b>,
210*5225e6b1SAndroid Build Coastguard Worker partitions_to_verify: &[&CStr],
211*5225e6b1SAndroid Build Coastguard Worker slot_verify_flags: SlotVerifyFlags,
212*5225e6b1SAndroid Build Coastguard Worker boot_target: Option<BootTarget>,
213*5225e6b1SAndroid Build Coastguard Worker ) -> Result<SlotVerifyData<'b>> {
214*5225e6b1SAndroid Build Coastguard Worker let bytes: SuffixBytes =
215*5225e6b1SAndroid Build Coastguard Worker if let Some(tgt) = boot_target { tgt.suffix().into() } else { Default::default() };
216*5225e6b1SAndroid Build Coastguard Worker
217*5225e6b1SAndroid Build Coastguard Worker let avb_suffix = CStr::from_bytes_until_nul(&bytes).map_err(Error::from)?;
218*5225e6b1SAndroid Build Coastguard Worker
219*5225e6b1SAndroid Build Coastguard Worker Ok(avb::slot_verify(
220*5225e6b1SAndroid Build Coastguard Worker avb_ops,
221*5225e6b1SAndroid Build Coastguard Worker partitions_to_verify,
222*5225e6b1SAndroid Build Coastguard Worker Some(avb_suffix),
223*5225e6b1SAndroid Build Coastguard Worker slot_verify_flags,
224*5225e6b1SAndroid Build Coastguard Worker HashtreeErrorMode::AVB_HASHTREE_ERROR_MODE_EIO,
225*5225e6b1SAndroid Build Coastguard Worker )
226*5225e6b1SAndroid Build Coastguard Worker .map_err(|v| v.without_verify_data())?)
227*5225e6b1SAndroid Build Coastguard Worker }
228*5225e6b1SAndroid Build Coastguard Worker
229*5225e6b1SAndroid Build Coastguard Worker /// Load Slot Manager Interface
230*5225e6b1SAndroid Build Coastguard Worker ///
231*5225e6b1SAndroid Build Coastguard Worker /// The default implementation loads from the `durable_boot` partition
232*5225e6b1SAndroid Build Coastguard Worker /// and writes changes back on the destruction of the cursor.
233*5225e6b1SAndroid Build Coastguard Worker ///
234*5225e6b1SAndroid Build Coastguard Worker /// # Returns
235*5225e6b1SAndroid Build Coastguard Worker ///
236*5225e6b1SAndroid Build Coastguard Worker /// * `Ok(Cursor)` - Cursor object that manages a Manager
237*5225e6b1SAndroid Build Coastguard Worker /// * `Err(Error)` - on failure
load_slot_interface( &'a mut self, persist: &'a mut dyn FnMut(&mut [u8]) -> core::result::Result<(), Error>, ) -> Result<Cursor<'a>>238*5225e6b1SAndroid Build Coastguard Worker pub fn load_slot_interface(
239*5225e6b1SAndroid Build Coastguard Worker &'a mut self,
240*5225e6b1SAndroid Build Coastguard Worker persist: &'a mut dyn FnMut(&mut [u8]) -> core::result::Result<(), Error>,
241*5225e6b1SAndroid Build Coastguard Worker ) -> Result<Cursor<'a>> {
242*5225e6b1SAndroid Build Coastguard Worker let boot_token = self.boot_token.take().ok_or(Error::OperationProhibited)?;
243*5225e6b1SAndroid Build Coastguard Worker self.ops.load_slot_interface(persist, boot_token)
244*5225e6b1SAndroid Build Coastguard Worker }
245*5225e6b1SAndroid Build Coastguard Worker
246*5225e6b1SAndroid Build Coastguard Worker /// Info Load
247*5225e6b1SAndroid Build Coastguard Worker ///
248*5225e6b1SAndroid Build Coastguard Worker /// Unpack boot image in RAM
249*5225e6b1SAndroid Build Coastguard Worker ///
250*5225e6b1SAndroid Build Coastguard Worker /// # Arguments
251*5225e6b1SAndroid Build Coastguard Worker /// * `boot_image_buffer` - Buffer that contains (Optionally Verified) Boot Image
252*5225e6b1SAndroid Build Coastguard Worker /// * `boot_mode` - Boot Mode
253*5225e6b1SAndroid Build Coastguard Worker /// * `boot_target` - [Optional] Boot Target
254*5225e6b1SAndroid Build Coastguard Worker ///
255*5225e6b1SAndroid Build Coastguard Worker /// # Returns
256*5225e6b1SAndroid Build Coastguard Worker ///
257*5225e6b1SAndroid Build Coastguard Worker /// * `Ok(InfoStruct)` - Info Struct (Concatenated kernel commandline - includes slot,
258*5225e6b1SAndroid Build Coastguard Worker /// bootconfig selection, normal_mode, Concatenated bootconfig) on success
259*5225e6b1SAndroid Build Coastguard Worker /// * `Err(Error)` - on failure
unpack_boot_image( &self, boot_image_buffer: &BootImage, boot_target: Option<BootTarget>, ) -> Result<InfoStruct>260*5225e6b1SAndroid Build Coastguard Worker pub fn unpack_boot_image(
261*5225e6b1SAndroid Build Coastguard Worker &self,
262*5225e6b1SAndroid Build Coastguard Worker boot_image_buffer: &BootImage,
263*5225e6b1SAndroid Build Coastguard Worker boot_target: Option<BootTarget>,
264*5225e6b1SAndroid Build Coastguard Worker ) -> Result<InfoStruct> {
265*5225e6b1SAndroid Build Coastguard Worker unimplemented!();
266*5225e6b1SAndroid Build Coastguard Worker }
267*5225e6b1SAndroid Build Coastguard Worker
268*5225e6b1SAndroid Build Coastguard Worker /// Kernel Load
269*5225e6b1SAndroid Build Coastguard Worker ///
270*5225e6b1SAndroid Build Coastguard Worker /// Prepare kernel in RAM for booting
271*5225e6b1SAndroid Build Coastguard Worker ///
272*5225e6b1SAndroid Build Coastguard Worker /// # Arguments
273*5225e6b1SAndroid Build Coastguard Worker /// * `info` - Info Struct from Info Load
274*5225e6b1SAndroid Build Coastguard Worker /// * `image_buffer` - Buffer that contains (Verified) Boot Image
275*5225e6b1SAndroid Build Coastguard Worker /// * `load_buffer` - Kernel Load buffer
276*5225e6b1SAndroid Build Coastguard Worker ///
277*5225e6b1SAndroid Build Coastguard Worker /// # Returns
278*5225e6b1SAndroid Build Coastguard Worker ///
279*5225e6b1SAndroid Build Coastguard Worker /// * `Ok(())` - on success
280*5225e6b1SAndroid Build Coastguard Worker /// * `Err(Error)` - on failure
kernel_load<'b>( &self, info: &InfoStruct, image_buffer: BootImage, load_buffer: &'b mut [u8], ) -> Result<KernelImage<'b>>281*5225e6b1SAndroid Build Coastguard Worker pub fn kernel_load<'b>(
282*5225e6b1SAndroid Build Coastguard Worker &self,
283*5225e6b1SAndroid Build Coastguard Worker info: &InfoStruct,
284*5225e6b1SAndroid Build Coastguard Worker image_buffer: BootImage,
285*5225e6b1SAndroid Build Coastguard Worker load_buffer: &'b mut [u8],
286*5225e6b1SAndroid Build Coastguard Worker ) -> Result<KernelImage<'b>> {
287*5225e6b1SAndroid Build Coastguard Worker unimplemented!();
288*5225e6b1SAndroid Build Coastguard Worker }
289*5225e6b1SAndroid Build Coastguard Worker
290*5225e6b1SAndroid Build Coastguard Worker /// Ramdisk + Bootconfig Load
291*5225e6b1SAndroid Build Coastguard Worker ///
292*5225e6b1SAndroid Build Coastguard Worker /// Kernel Load
293*5225e6b1SAndroid Build Coastguard Worker /// (Could break this into a RD and Bootconfig specific function each, TBD)
294*5225e6b1SAndroid Build Coastguard Worker /// Prepare ramdisk/bootconfig in RAM for booting
295*5225e6b1SAndroid Build Coastguard Worker ///
296*5225e6b1SAndroid Build Coastguard Worker /// # Arguments
297*5225e6b1SAndroid Build Coastguard Worker /// * `info` - Info Struct from Info Load
298*5225e6b1SAndroid Build Coastguard Worker /// * `vendor_boot_image` - Buffer that contains (Verified) Vendor Boot Image
299*5225e6b1SAndroid Build Coastguard Worker /// * `init_boot_image` - Buffer that contains (Verified) Init Boot Image
300*5225e6b1SAndroid Build Coastguard Worker /// * `ramdisk_load_buffer` - Ramdisk Load buffer (not compressed). It will be filled with
301*5225e6b1SAndroid Build Coastguard Worker /// a concatenation of `vendor_boot_image`, `init_boot_image` and bootconfig at the end.
302*5225e6b1SAndroid Build Coastguard Worker ///
303*5225e6b1SAndroid Build Coastguard Worker /// # Returns
304*5225e6b1SAndroid Build Coastguard Worker ///
305*5225e6b1SAndroid Build Coastguard Worker /// * `Ok(&str)` - on success returns Kernel command line
306*5225e6b1SAndroid Build Coastguard Worker /// * `Err(Error)` - on failure
ramdisk_bootconfig_load( &self, info: &InfoStruct, vendor_boot_image: &VendorBootImage, init_boot_image: &InitBootImage, ramdisk: &mut Ramdisk, ) -> Result<&'static str>307*5225e6b1SAndroid Build Coastguard Worker pub fn ramdisk_bootconfig_load(
308*5225e6b1SAndroid Build Coastguard Worker &self,
309*5225e6b1SAndroid Build Coastguard Worker info: &InfoStruct,
310*5225e6b1SAndroid Build Coastguard Worker vendor_boot_image: &VendorBootImage,
311*5225e6b1SAndroid Build Coastguard Worker init_boot_image: &InitBootImage,
312*5225e6b1SAndroid Build Coastguard Worker ramdisk: &mut Ramdisk,
313*5225e6b1SAndroid Build Coastguard Worker ) -> Result<&'static str> {
314*5225e6b1SAndroid Build Coastguard Worker unimplemented!();
315*5225e6b1SAndroid Build Coastguard Worker }
316*5225e6b1SAndroid Build Coastguard Worker
317*5225e6b1SAndroid Build Coastguard Worker /// DTB Update And Load
318*5225e6b1SAndroid Build Coastguard Worker ///
319*5225e6b1SAndroid Build Coastguard Worker /// Prepare DTB in RAM for booting
320*5225e6b1SAndroid Build Coastguard Worker ///
321*5225e6b1SAndroid Build Coastguard Worker /// # Arguments
322*5225e6b1SAndroid Build Coastguard Worker /// * `info` - Info Struct from Info Load
323*5225e6b1SAndroid Build Coastguard Worker /// * `vendor_boot_image_buffer` - Buffer that contains (Verified) Vendor Boot Image
324*5225e6b1SAndroid Build Coastguard Worker ///
325*5225e6b1SAndroid Build Coastguard Worker /// # Returns
326*5225e6b1SAndroid Build Coastguard Worker ///
327*5225e6b1SAndroid Build Coastguard Worker /// * `Ok()` - on success
328*5225e6b1SAndroid Build Coastguard Worker /// * `Err(Error)` - on failure
dtb_update_and_load( &self, info: &InfoStruct, vendor_boot_image_buffer: VendorBootImage, ) -> Result<Dtb>329*5225e6b1SAndroid Build Coastguard Worker pub fn dtb_update_and_load(
330*5225e6b1SAndroid Build Coastguard Worker &self,
331*5225e6b1SAndroid Build Coastguard Worker info: &InfoStruct,
332*5225e6b1SAndroid Build Coastguard Worker vendor_boot_image_buffer: VendorBootImage,
333*5225e6b1SAndroid Build Coastguard Worker ) -> Result<Dtb> {
334*5225e6b1SAndroid Build Coastguard Worker unimplemented!();
335*5225e6b1SAndroid Build Coastguard Worker }
336*5225e6b1SAndroid Build Coastguard Worker
337*5225e6b1SAndroid Build Coastguard Worker /// Kernel Jump
338*5225e6b1SAndroid Build Coastguard Worker ///
339*5225e6b1SAndroid Build Coastguard Worker ///
340*5225e6b1SAndroid Build Coastguard Worker /// # Arguments
341*5225e6b1SAndroid Build Coastguard Worker /// * `kernel_load_buffer` - Kernel Load buffer
342*5225e6b1SAndroid Build Coastguard Worker /// * `ramdisk_bootconfi_load_buffer` - Concatenated Ramdisk, (Bootconfig if present) Load
343*5225e6b1SAndroid Build Coastguard Worker /// buffer
344*5225e6b1SAndroid Build Coastguard Worker /// * `dtb_load_buffer` - DTB Load buffer
345*5225e6b1SAndroid Build Coastguard Worker /// * `boot_token` - Consumable boot token
346*5225e6b1SAndroid Build Coastguard Worker ///
347*5225e6b1SAndroid Build Coastguard Worker /// # Returns
348*5225e6b1SAndroid Build Coastguard Worker ///
349*5225e6b1SAndroid Build Coastguard Worker /// * doesn't return on success
350*5225e6b1SAndroid Build Coastguard Worker /// * `Err(Error)` - on failure
351*5225e6b1SAndroid Build Coastguard Worker // 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<()>352*5225e6b1SAndroid Build Coastguard Worker pub fn kernel_jump(
353*5225e6b1SAndroid Build Coastguard Worker &self,
354*5225e6b1SAndroid Build Coastguard Worker kernel_load_buffer: KernelImage,
355*5225e6b1SAndroid Build Coastguard Worker ramdisk_load_buffer: Ramdisk,
356*5225e6b1SAndroid Build Coastguard Worker dtb_load_buffer: Dtb,
357*5225e6b1SAndroid Build Coastguard Worker boot_token: BootToken,
358*5225e6b1SAndroid Build Coastguard Worker ) -> Result<()> {
359*5225e6b1SAndroid Build Coastguard Worker unimplemented!();
360*5225e6b1SAndroid Build Coastguard Worker }
361*5225e6b1SAndroid Build Coastguard Worker
362*5225e6b1SAndroid Build Coastguard Worker /// Load, verify, and boot
363*5225e6b1SAndroid Build Coastguard Worker ///
364*5225e6b1SAndroid Build Coastguard Worker /// Wrapper around the above functions for devices that don't need custom behavior between each
365*5225e6b1SAndroid Build Coastguard Worker /// step
366*5225e6b1SAndroid Build Coastguard Worker ///
367*5225e6b1SAndroid Build Coastguard Worker /// Warning: If the call to load_verify_boot fails, the device MUST
368*5225e6b1SAndroid Build Coastguard Worker /// be restarted in order to make forward boot progress.
369*5225e6b1SAndroid Build Coastguard Worker /// Callers MAY log the error, enter an interactive mode,
370*5225e6b1SAndroid Build Coastguard Worker /// or take other actions before rebooting.
371*5225e6b1SAndroid Build Coastguard Worker ///
372*5225e6b1SAndroid Build Coastguard Worker /// # Arguments
373*5225e6b1SAndroid Build Coastguard Worker /// * `avb_ops` - implementation for `avb::Ops` that would be borrowed in result to prevent
374*5225e6b1SAndroid Build Coastguard Worker /// changes to partitions until it is out of scope.
375*5225e6b1SAndroid Build Coastguard Worker /// * `partitions_to_verify` - names of all the partitions to verify with libavb.
376*5225e6b1SAndroid Build Coastguard Worker /// * `partitions_ram_map` - Partitions to verify and optional address for them to be loaded.
377*5225e6b1SAndroid Build Coastguard Worker /// * `slot_verify_flags` - AVB slot verification flags
378*5225e6b1SAndroid Build Coastguard Worker /// * `slot_cursor` - Cursor object that manages interactions with boot slot management
379*5225e6b1SAndroid Build Coastguard Worker /// * `kernel_load_buffer` - Buffer for loading the kernel.
380*5225e6b1SAndroid Build Coastguard Worker /// * `ramdisk_load_buffer` - Buffer for loading the ramdisk.
381*5225e6b1SAndroid Build Coastguard Worker /// * `fdt` - Buffer containing a flattened device tree blob.
382*5225e6b1SAndroid Build Coastguard Worker ///
383*5225e6b1SAndroid Build Coastguard Worker /// # Returns
384*5225e6b1SAndroid Build Coastguard Worker /// * doesn't return on success
385*5225e6b1SAndroid Build Coastguard Worker /// * `Err(Error)` - on failure
386*5225e6b1SAndroid Build Coastguard Worker // Nevertype could be used here when it is stable https://github.com/serde-rs/serde/issues/812
387*5225e6b1SAndroid Build Coastguard Worker #[allow(clippy::too_many_arguments)]
load_verify_boot<'b: 'c, 'c, 'd: 'b>( &mut self, avb_ops: &mut impl avb::Ops<'b>, partitions_to_verify: &[&CStr], partitions_ram_map: &'d mut [PartitionRamMap<'b, 'c>], slot_verify_flags: SlotVerifyFlags, slot_cursor: Cursor, kernel_load_buffer: &mut [u8], ramdisk_load_buffer: &mut [u8], fdt: &mut [u8], ) -> Result<()>388*5225e6b1SAndroid Build Coastguard Worker pub fn load_verify_boot<'b: 'c, 'c, 'd: 'b>(
389*5225e6b1SAndroid Build Coastguard Worker &mut self,
390*5225e6b1SAndroid Build Coastguard Worker avb_ops: &mut impl avb::Ops<'b>,
391*5225e6b1SAndroid Build Coastguard Worker partitions_to_verify: &[&CStr],
392*5225e6b1SAndroid Build Coastguard Worker partitions_ram_map: &'d mut [PartitionRamMap<'b, 'c>],
393*5225e6b1SAndroid Build Coastguard Worker slot_verify_flags: SlotVerifyFlags,
394*5225e6b1SAndroid Build Coastguard Worker slot_cursor: Cursor,
395*5225e6b1SAndroid Build Coastguard Worker kernel_load_buffer: &mut [u8],
396*5225e6b1SAndroid Build Coastguard Worker ramdisk_load_buffer: &mut [u8],
397*5225e6b1SAndroid Build Coastguard Worker fdt: &mut [u8],
398*5225e6b1SAndroid Build Coastguard Worker ) -> Result<()> {
399*5225e6b1SAndroid Build Coastguard Worker let dtb = Dtb(&mut fdt[..]);
400*5225e6b1SAndroid Build Coastguard Worker let mut ramdisk = Ramdisk(ramdisk_load_buffer);
401*5225e6b1SAndroid Build Coastguard Worker
402*5225e6b1SAndroid Build Coastguard Worker // Call the inner method which consumes the cursor
403*5225e6b1SAndroid Build Coastguard Worker // in order to properly manager cursor lifetime
404*5225e6b1SAndroid Build Coastguard Worker // and cleanup.
405*5225e6b1SAndroid Build Coastguard Worker let (kernel_image, token) = self.lvb_inner(
406*5225e6b1SAndroid Build Coastguard Worker avb_ops,
407*5225e6b1SAndroid Build Coastguard Worker &mut ramdisk,
408*5225e6b1SAndroid Build Coastguard Worker kernel_load_buffer,
409*5225e6b1SAndroid Build Coastguard Worker partitions_to_verify,
410*5225e6b1SAndroid Build Coastguard Worker partitions_ram_map,
411*5225e6b1SAndroid Build Coastguard Worker slot_verify_flags,
412*5225e6b1SAndroid Build Coastguard Worker slot_cursor,
413*5225e6b1SAndroid Build Coastguard Worker )?;
414*5225e6b1SAndroid Build Coastguard Worker
415*5225e6b1SAndroid Build Coastguard Worker self.kernel_jump(kernel_image, ramdisk, dtb, token)
416*5225e6b1SAndroid Build Coastguard Worker }
417*5225e6b1SAndroid Build Coastguard Worker
is_unrecoverable_error(error: &IntegrationError) -> bool418*5225e6b1SAndroid Build Coastguard Worker fn is_unrecoverable_error(error: &IntegrationError) -> bool {
419*5225e6b1SAndroid Build Coastguard Worker // Note: these ifs are nested instead of chained because multiple
420*5225e6b1SAndroid Build Coastguard Worker // expressions in an if-let is an unstable features
421*5225e6b1SAndroid Build Coastguard Worker if let IntegrationError::AvbSlotVerifyError(ref avb_error) = error {
422*5225e6b1SAndroid Build Coastguard Worker // These are the AVB errors that are not recoverable on a subsequent attempt.
423*5225e6b1SAndroid Build Coastguard Worker // If necessary in the future, this helper function can be moved to the GblOps trait
424*5225e6b1SAndroid Build Coastguard Worker // and customized for platform specific behavior.
425*5225e6b1SAndroid Build Coastguard Worker if matches!(
426*5225e6b1SAndroid Build Coastguard Worker avb_error,
427*5225e6b1SAndroid Build Coastguard Worker SlotVerifyError::Verification(_)
428*5225e6b1SAndroid Build Coastguard Worker | SlotVerifyError::PublicKeyRejected
429*5225e6b1SAndroid Build Coastguard Worker | SlotVerifyError::RollbackIndex
430*5225e6b1SAndroid Build Coastguard Worker ) {
431*5225e6b1SAndroid Build Coastguard Worker return true;
432*5225e6b1SAndroid Build Coastguard Worker }
433*5225e6b1SAndroid Build Coastguard Worker }
434*5225e6b1SAndroid Build Coastguard Worker false
435*5225e6b1SAndroid Build Coastguard Worker }
436*5225e6b1SAndroid Build Coastguard Worker
lvb_inner<'b: 'c, 'c, 'd: 'b, 'e>( &mut self, avb_ops: &mut impl avb::Ops<'b>, ramdisk: &mut Ramdisk, kernel_load_buffer: &'e mut [u8], partitions_to_verify: &[&CStr], partitions_ram_map: &'d mut [PartitionRamMap<'b, 'c>], slot_verify_flags: SlotVerifyFlags, slot_cursor: Cursor, ) -> Result<(KernelImage<'e>, BootToken)>437*5225e6b1SAndroid Build Coastguard Worker fn lvb_inner<'b: 'c, 'c, 'd: 'b, 'e>(
438*5225e6b1SAndroid Build Coastguard Worker &mut self,
439*5225e6b1SAndroid Build Coastguard Worker avb_ops: &mut impl avb::Ops<'b>,
440*5225e6b1SAndroid Build Coastguard Worker ramdisk: &mut Ramdisk,
441*5225e6b1SAndroid Build Coastguard Worker kernel_load_buffer: &'e mut [u8],
442*5225e6b1SAndroid Build Coastguard Worker partitions_to_verify: &[&CStr],
443*5225e6b1SAndroid Build Coastguard Worker partitions_ram_map: &'d mut [PartitionRamMap<'b, 'c>],
444*5225e6b1SAndroid Build Coastguard Worker slot_verify_flags: SlotVerifyFlags,
445*5225e6b1SAndroid Build Coastguard Worker slot_cursor: Cursor,
446*5225e6b1SAndroid Build Coastguard Worker ) -> Result<(KernelImage<'e>, BootToken)> {
447*5225e6b1SAndroid Build Coastguard Worker let oneshot_status = slot_cursor.ctx.get_oneshot_status();
448*5225e6b1SAndroid Build Coastguard Worker slot_cursor.ctx.clear_oneshot_status();
449*5225e6b1SAndroid Build Coastguard Worker
450*5225e6b1SAndroid Build Coastguard Worker let boot_target = match oneshot_status {
451*5225e6b1SAndroid Build Coastguard Worker None | Some(OneShot::Bootloader) => slot_cursor.ctx.get_boot_target()?,
452*5225e6b1SAndroid Build Coastguard Worker Some(OneShot::Continue(recovery)) => BootTarget::Recovery(recovery),
453*5225e6b1SAndroid Build Coastguard Worker };
454*5225e6b1SAndroid Build Coastguard Worker
455*5225e6b1SAndroid Build Coastguard Worker let verify_data = self
456*5225e6b1SAndroid Build Coastguard Worker .load_and_verify_image(
457*5225e6b1SAndroid Build Coastguard Worker avb_ops,
458*5225e6b1SAndroid Build Coastguard Worker partitions_to_verify,
459*5225e6b1SAndroid Build Coastguard Worker slot_verify_flags,
460*5225e6b1SAndroid Build Coastguard Worker Some(boot_target),
461*5225e6b1SAndroid Build Coastguard Worker )
462*5225e6b1SAndroid Build Coastguard Worker .map_err(|e: IntegrationError| {
463*5225e6b1SAndroid Build Coastguard Worker if let BootTarget::NormalBoot(slot) = boot_target {
464*5225e6b1SAndroid Build Coastguard Worker if Self::is_unrecoverable_error(&e) {
465*5225e6b1SAndroid Build Coastguard Worker let _ = slot_cursor.ctx.set_slot_unbootable(
466*5225e6b1SAndroid Build Coastguard Worker slot.suffix,
467*5225e6b1SAndroid Build Coastguard Worker UnbootableReason::VerificationFailure,
468*5225e6b1SAndroid Build Coastguard Worker );
469*5225e6b1SAndroid Build Coastguard Worker } else {
470*5225e6b1SAndroid Build Coastguard Worker // Note: the call to mark_boot_attempt will fail if any of the following occur:
471*5225e6b1SAndroid Build Coastguard Worker // * the target was already Unbootable before the call to load_and_verify_image
472*5225e6b1SAndroid Build Coastguard Worker // * policy, I/O, or other errors in mark_boot_attempt
473*5225e6b1SAndroid Build Coastguard Worker //
474*5225e6b1SAndroid Build Coastguard Worker // We don't really care about those circumstances.
475*5225e6b1SAndroid Build Coastguard Worker // The call here is a best effort attempt to decrement tries remaining.
476*5225e6b1SAndroid Build Coastguard Worker let _ = slot_cursor.ctx.mark_boot_attempt();
477*5225e6b1SAndroid Build Coastguard Worker }
478*5225e6b1SAndroid Build Coastguard Worker }
479*5225e6b1SAndroid Build Coastguard Worker e
480*5225e6b1SAndroid Build Coastguard Worker })?;
481*5225e6b1SAndroid Build Coastguard Worker
482*5225e6b1SAndroid Build Coastguard Worker let (boot_image, init_boot_image, vendor_boot_image, _) = get_images(partitions_ram_map);
483*5225e6b1SAndroid Build Coastguard Worker let boot_image = boot_image.ok_or(Error::MissingImage)?;
484*5225e6b1SAndroid Build Coastguard Worker let vendor_boot_image = vendor_boot_image.ok_or(Error::MissingImage)?;
485*5225e6b1SAndroid Build Coastguard Worker let init_boot_image = init_boot_image.ok_or(Error::MissingImage)?;
486*5225e6b1SAndroid Build Coastguard Worker
487*5225e6b1SAndroid Build Coastguard Worker if is_overlap(&[
488*5225e6b1SAndroid Build Coastguard Worker boot_image.0,
489*5225e6b1SAndroid Build Coastguard Worker vendor_boot_image.0,
490*5225e6b1SAndroid Build Coastguard Worker init_boot_image.0,
491*5225e6b1SAndroid Build Coastguard Worker &ramdisk.0,
492*5225e6b1SAndroid Build Coastguard Worker kernel_load_buffer,
493*5225e6b1SAndroid Build Coastguard Worker ]) {
494*5225e6b1SAndroid Build Coastguard Worker return Err(IntegrationError::UnificationError(Error::BufferOverlap));
495*5225e6b1SAndroid Build Coastguard Worker }
496*5225e6b1SAndroid Build Coastguard Worker
497*5225e6b1SAndroid Build Coastguard Worker let info_struct = self.unpack_boot_image(&boot_image, Some(boot_target))?;
498*5225e6b1SAndroid Build Coastguard Worker
499*5225e6b1SAndroid Build Coastguard Worker let kernel_image = self.kernel_load(&info_struct, boot_image, kernel_load_buffer)?;
500*5225e6b1SAndroid Build Coastguard Worker
501*5225e6b1SAndroid Build Coastguard Worker let cmd_line = self.ramdisk_bootconfig_load(
502*5225e6b1SAndroid Build Coastguard Worker &info_struct,
503*5225e6b1SAndroid Build Coastguard Worker &vendor_boot_image,
504*5225e6b1SAndroid Build Coastguard Worker &init_boot_image,
505*5225e6b1SAndroid Build Coastguard Worker ramdisk,
506*5225e6b1SAndroid Build Coastguard Worker )?;
507*5225e6b1SAndroid Build Coastguard Worker
508*5225e6b1SAndroid Build Coastguard Worker self.dtb_update_and_load(&info_struct, vendor_boot_image)?;
509*5225e6b1SAndroid Build Coastguard Worker
510*5225e6b1SAndroid Build Coastguard Worker let token = slot_cursor.ctx.mark_boot_attempt().map_err(|_| Error::OperationProhibited)?;
511*5225e6b1SAndroid Build Coastguard Worker
512*5225e6b1SAndroid Build Coastguard Worker Ok((kernel_image, token))
513*5225e6b1SAndroid Build Coastguard Worker }
514*5225e6b1SAndroid Build Coastguard Worker }
515*5225e6b1SAndroid Build Coastguard Worker
516*5225e6b1SAndroid Build Coastguard Worker #[cfg(test)]
517*5225e6b1SAndroid Build Coastguard Worker mod tests {
518*5225e6b1SAndroid Build Coastguard Worker extern crate avb_sysdeps;
519*5225e6b1SAndroid Build Coastguard Worker extern crate avb_test;
520*5225e6b1SAndroid Build Coastguard Worker use super::*;
521*5225e6b1SAndroid Build Coastguard Worker use crate::ops::test::FakeGblOps;
522*5225e6b1SAndroid Build Coastguard Worker use avb::{CertPermanentAttributes, SlotVerifyError};
523*5225e6b1SAndroid Build Coastguard Worker use avb_test::{FakeVbmetaKey, TestOps};
524*5225e6b1SAndroid Build Coastguard Worker use std::{fs, path::Path};
525*5225e6b1SAndroid Build Coastguard Worker use zerocopy::FromBytes;
526*5225e6b1SAndroid Build Coastguard Worker
527*5225e6b1SAndroid Build Coastguard Worker const TEST_ZIRCON_PARTITION_NAME: &str = "zircon_a";
528*5225e6b1SAndroid Build Coastguard Worker const TEST_ZIRCON_PARTITION_NAME_CSTR: &CStr = c"zircon_a";
529*5225e6b1SAndroid Build Coastguard Worker const TEST_ZIRCON_IMAGE_PATH: &str = "zircon_a.zbi";
530*5225e6b1SAndroid Build Coastguard Worker const TEST_ZIRCON_VBMETA_PATH: &str = "zircon_a.vbmeta";
531*5225e6b1SAndroid Build Coastguard Worker const TEST_ZIRCON_VBMETA_CERT_PATH: &str = "zircon_a.vbmeta.cert";
532*5225e6b1SAndroid Build Coastguard Worker const TEST_PUBLIC_KEY_PATH: &str = "testkey_rsa4096_pub.bin";
533*5225e6b1SAndroid Build Coastguard Worker const TEST_PERMANENT_ATTRIBUTES_PATH: &str = "cert_permanent_attributes.bin";
534*5225e6b1SAndroid Build Coastguard Worker const TEST_PERMANENT_ATTRIBUTES_HASH_PATH: &str = "cert_permanent_attributes.hash";
535*5225e6b1SAndroid Build Coastguard Worker const TEST_BAD_PERMANENT_ATTRIBUTES_PATH: &str = "cert_permanent_attributes.bad.bin";
536*5225e6b1SAndroid Build Coastguard Worker const TEST_BAD_PERMANENT_ATTRIBUTES_HASH_PATH: &str = "cert_permanent_attributes.bad.hash";
537*5225e6b1SAndroid Build Coastguard Worker const TEST_VBMETA_ROLLBACK_LOCATION: usize = 0; // Default value, we don't explicitly set this.
538*5225e6b1SAndroid Build Coastguard Worker pub const TEST_CERT_PIK_VERSION: u64 = 42;
539*5225e6b1SAndroid Build Coastguard Worker pub const TEST_CERT_PSK_VERSION: u64 = 42;
540*5225e6b1SAndroid Build Coastguard Worker
541*5225e6b1SAndroid Build Coastguard Worker /// Returns the contents of a test data file.
542*5225e6b1SAndroid Build Coastguard Worker ///
543*5225e6b1SAndroid Build Coastguard Worker /// Panicks if the requested file cannot be read.
544*5225e6b1SAndroid Build Coastguard Worker ///
545*5225e6b1SAndroid Build Coastguard Worker /// # Arguments
546*5225e6b1SAndroid Build Coastguard Worker /// * `path`: file path relative to libgbl's `testdata/` directory.
testdata(path: &str) -> Vec<u8>547*5225e6b1SAndroid Build Coastguard Worker fn testdata(path: &str) -> Vec<u8> {
548*5225e6b1SAndroid Build Coastguard Worker let full_path = Path::new("external/gbl/libgbl/testdata").join(path);
549*5225e6b1SAndroid Build Coastguard Worker fs::read(full_path).unwrap()
550*5225e6b1SAndroid Build Coastguard Worker }
551*5225e6b1SAndroid Build Coastguard Worker
552*5225e6b1SAndroid Build Coastguard Worker /// Creates and returns a configured avb `TestOps`.
553*5225e6b1SAndroid Build Coastguard Worker ///
554*5225e6b1SAndroid Build Coastguard Worker /// The initial state will verify successfully with:
555*5225e6b1SAndroid Build Coastguard Worker /// * a valid vbmeta image in the `vbmeta` partition, containing a hash descriptor for the
556*5225e6b1SAndroid Build Coastguard Worker /// `TEST_ZIRCON_PARTITION_NAME` partition
557*5225e6b1SAndroid Build Coastguard Worker /// * an image in the `TEST_ZIRCON_PARTITION_NAME` partition matching the vbmeta hash
558*5225e6b1SAndroid Build Coastguard Worker /// * no preloaded partition data
559*5225e6b1SAndroid Build Coastguard Worker /// * a public key matching the vbmeta image
560*5225e6b1SAndroid Build Coastguard Worker /// * a valid vbmeta rollback index
561*5225e6b1SAndroid Build Coastguard Worker /// * a locked bootloader state
562*5225e6b1SAndroid Build Coastguard Worker ///
563*5225e6b1SAndroid Build Coastguard Worker /// The caller can modify any of this state as needed for their particular test.
test_avb_ops() -> TestOps<'static>564*5225e6b1SAndroid Build Coastguard Worker fn test_avb_ops() -> TestOps<'static> {
565*5225e6b1SAndroid Build Coastguard Worker let mut avb_ops = TestOps::default();
566*5225e6b1SAndroid Build Coastguard Worker
567*5225e6b1SAndroid Build Coastguard Worker avb_ops.add_partition(TEST_ZIRCON_PARTITION_NAME, testdata(TEST_ZIRCON_IMAGE_PATH));
568*5225e6b1SAndroid Build Coastguard Worker avb_ops.add_partition("vbmeta", testdata(TEST_ZIRCON_VBMETA_PATH));
569*5225e6b1SAndroid Build Coastguard Worker avb_ops.default_vbmeta_key = Some(FakeVbmetaKey::Avb {
570*5225e6b1SAndroid Build Coastguard Worker public_key: testdata(TEST_PUBLIC_KEY_PATH),
571*5225e6b1SAndroid Build Coastguard Worker public_key_metadata: None,
572*5225e6b1SAndroid Build Coastguard Worker });
573*5225e6b1SAndroid Build Coastguard Worker avb_ops.rollbacks.insert(TEST_VBMETA_ROLLBACK_LOCATION, Ok(0));
574*5225e6b1SAndroid Build Coastguard Worker avb_ops.unlock_state = Ok(false);
575*5225e6b1SAndroid Build Coastguard Worker
576*5225e6b1SAndroid Build Coastguard Worker avb_ops
577*5225e6b1SAndroid Build Coastguard Worker }
578*5225e6b1SAndroid Build Coastguard Worker
579*5225e6b1SAndroid Build Coastguard Worker /// Similar to `test_avb_ops()`, but with the avb_cert extension enabled.
test_avb_cert_ops() -> TestOps<'static>580*5225e6b1SAndroid Build Coastguard Worker fn test_avb_cert_ops() -> TestOps<'static> {
581*5225e6b1SAndroid Build Coastguard Worker let mut avb_ops = test_avb_ops();
582*5225e6b1SAndroid Build Coastguard Worker
583*5225e6b1SAndroid Build Coastguard Worker // Replace vbmeta with the cert-signed version.
584*5225e6b1SAndroid Build Coastguard Worker avb_ops.add_partition("vbmeta", testdata(TEST_ZIRCON_VBMETA_CERT_PATH));
585*5225e6b1SAndroid Build Coastguard Worker
586*5225e6b1SAndroid Build Coastguard Worker // Tell `avb_ops` to use cert APIs and to route the default key through cert validation.
587*5225e6b1SAndroid Build Coastguard Worker avb_ops.use_cert = true;
588*5225e6b1SAndroid Build Coastguard Worker avb_ops.default_vbmeta_key = Some(FakeVbmetaKey::Cert);
589*5225e6b1SAndroid Build Coastguard Worker
590*5225e6b1SAndroid Build Coastguard Worker // Add the permanent attributes.
591*5225e6b1SAndroid Build Coastguard Worker let perm_attr_bytes = testdata(TEST_PERMANENT_ATTRIBUTES_PATH);
592*5225e6b1SAndroid Build Coastguard Worker let perm_attr_hash = testdata(TEST_PERMANENT_ATTRIBUTES_HASH_PATH);
593*5225e6b1SAndroid Build Coastguard Worker avb_ops.cert_permanent_attributes =
594*5225e6b1SAndroid Build Coastguard Worker Some(CertPermanentAttributes::read_from(&perm_attr_bytes[..]).unwrap());
595*5225e6b1SAndroid Build Coastguard Worker avb_ops.cert_permanent_attributes_hash = Some(perm_attr_hash.try_into().unwrap());
596*5225e6b1SAndroid Build Coastguard Worker
597*5225e6b1SAndroid Build Coastguard Worker // Add the rollbacks for the cert keys.
598*5225e6b1SAndroid Build Coastguard Worker avb_ops.rollbacks.insert(avb::CERT_PIK_VERSION_LOCATION, Ok(TEST_CERT_PIK_VERSION));
599*5225e6b1SAndroid Build Coastguard Worker avb_ops.rollbacks.insert(avb::CERT_PSK_VERSION_LOCATION, Ok(TEST_CERT_PSK_VERSION));
600*5225e6b1SAndroid Build Coastguard Worker
601*5225e6b1SAndroid Build Coastguard Worker avb_ops
602*5225e6b1SAndroid Build Coastguard Worker }
603*5225e6b1SAndroid Build Coastguard Worker
604*5225e6b1SAndroid Build Coastguard Worker #[test]
test_load_and_verify_image_success()605*5225e6b1SAndroid Build Coastguard Worker fn test_load_and_verify_image_success() {
606*5225e6b1SAndroid Build Coastguard Worker let mut gbl_ops = FakeGblOps::default();
607*5225e6b1SAndroid Build Coastguard Worker let mut gbl = Gbl::new(&mut gbl_ops);
608*5225e6b1SAndroid Build Coastguard Worker let mut avb_ops = test_avb_ops();
609*5225e6b1SAndroid Build Coastguard Worker
610*5225e6b1SAndroid Build Coastguard Worker let res = gbl.load_and_verify_image(
611*5225e6b1SAndroid Build Coastguard Worker &mut avb_ops,
612*5225e6b1SAndroid Build Coastguard Worker &mut [&TEST_ZIRCON_PARTITION_NAME_CSTR],
613*5225e6b1SAndroid Build Coastguard Worker SlotVerifyFlags::AVB_SLOT_VERIFY_FLAGS_NONE,
614*5225e6b1SAndroid Build Coastguard Worker None,
615*5225e6b1SAndroid Build Coastguard Worker );
616*5225e6b1SAndroid Build Coastguard Worker assert!(res.is_ok());
617*5225e6b1SAndroid Build Coastguard Worker }
618*5225e6b1SAndroid Build Coastguard Worker
619*5225e6b1SAndroid Build Coastguard Worker #[test]
test_load_and_verify_image_verification_error()620*5225e6b1SAndroid Build Coastguard Worker fn test_load_and_verify_image_verification_error() {
621*5225e6b1SAndroid Build Coastguard Worker let mut gbl_ops = FakeGblOps::default();
622*5225e6b1SAndroid Build Coastguard Worker let mut gbl = Gbl::new(&mut gbl_ops);
623*5225e6b1SAndroid Build Coastguard Worker let mut avb_ops = test_avb_ops();
624*5225e6b1SAndroid Build Coastguard Worker
625*5225e6b1SAndroid Build Coastguard Worker // Modify the kernel image, it should now fail to validate against the vbmeta image.
626*5225e6b1SAndroid Build Coastguard Worker avb_ops.partitions.get_mut(TEST_ZIRCON_PARTITION_NAME).unwrap().contents.as_mut_vec()[0] ^=
627*5225e6b1SAndroid Build Coastguard Worker 0x01;
628*5225e6b1SAndroid Build Coastguard Worker
629*5225e6b1SAndroid Build Coastguard Worker let res = gbl.load_and_verify_image(
630*5225e6b1SAndroid Build Coastguard Worker &mut avb_ops,
631*5225e6b1SAndroid Build Coastguard Worker &mut [&TEST_ZIRCON_PARTITION_NAME_CSTR],
632*5225e6b1SAndroid Build Coastguard Worker SlotVerifyFlags::AVB_SLOT_VERIFY_FLAGS_NONE,
633*5225e6b1SAndroid Build Coastguard Worker None,
634*5225e6b1SAndroid Build Coastguard Worker );
635*5225e6b1SAndroid Build Coastguard Worker assert_eq!(
636*5225e6b1SAndroid Build Coastguard Worker res.unwrap_err(),
637*5225e6b1SAndroid Build Coastguard Worker IntegrationError::AvbSlotVerifyError(SlotVerifyError::Verification(None))
638*5225e6b1SAndroid Build Coastguard Worker );
639*5225e6b1SAndroid Build Coastguard Worker }
640*5225e6b1SAndroid Build Coastguard Worker
641*5225e6b1SAndroid Build Coastguard Worker #[test]
test_load_and_verify_image_io_error()642*5225e6b1SAndroid Build Coastguard Worker fn test_load_and_verify_image_io_error() {
643*5225e6b1SAndroid Build Coastguard Worker let mut gbl_ops = FakeGblOps::default();
644*5225e6b1SAndroid Build Coastguard Worker let mut gbl = Gbl::new(&mut gbl_ops);
645*5225e6b1SAndroid Build Coastguard Worker let mut avb_ops = test_avb_ops();
646*5225e6b1SAndroid Build Coastguard Worker
647*5225e6b1SAndroid Build Coastguard Worker // Erase the fake rollbacks, which will result in an I/O error when attempting to access.
648*5225e6b1SAndroid Build Coastguard Worker avb_ops.rollbacks.clear();
649*5225e6b1SAndroid Build Coastguard Worker
650*5225e6b1SAndroid Build Coastguard Worker let res = gbl.load_and_verify_image(
651*5225e6b1SAndroid Build Coastguard Worker &mut avb_ops,
652*5225e6b1SAndroid Build Coastguard Worker &mut [&TEST_ZIRCON_PARTITION_NAME_CSTR],
653*5225e6b1SAndroid Build Coastguard Worker SlotVerifyFlags::AVB_SLOT_VERIFY_FLAGS_NONE,
654*5225e6b1SAndroid Build Coastguard Worker None,
655*5225e6b1SAndroid Build Coastguard Worker );
656*5225e6b1SAndroid Build Coastguard Worker assert_eq!(res.unwrap_err(), IntegrationError::AvbSlotVerifyError(SlotVerifyError::Io));
657*5225e6b1SAndroid Build Coastguard Worker }
658*5225e6b1SAndroid Build Coastguard Worker
659*5225e6b1SAndroid Build Coastguard Worker #[test]
test_load_and_verify_image_with_cert_success()660*5225e6b1SAndroid Build Coastguard Worker fn test_load_and_verify_image_with_cert_success() {
661*5225e6b1SAndroid Build Coastguard Worker let mut gbl_ops = FakeGblOps::default();
662*5225e6b1SAndroid Build Coastguard Worker let mut gbl = Gbl::new(&mut gbl_ops);
663*5225e6b1SAndroid Build Coastguard Worker let mut avb_ops = test_avb_cert_ops();
664*5225e6b1SAndroid Build Coastguard Worker
665*5225e6b1SAndroid Build Coastguard Worker let res = gbl.load_and_verify_image(
666*5225e6b1SAndroid Build Coastguard Worker &mut avb_ops,
667*5225e6b1SAndroid Build Coastguard Worker &mut [&TEST_ZIRCON_PARTITION_NAME_CSTR],
668*5225e6b1SAndroid Build Coastguard Worker SlotVerifyFlags::AVB_SLOT_VERIFY_FLAGS_NONE,
669*5225e6b1SAndroid Build Coastguard Worker None,
670*5225e6b1SAndroid Build Coastguard Worker );
671*5225e6b1SAndroid Build Coastguard Worker assert!(res.is_ok());
672*5225e6b1SAndroid Build Coastguard Worker }
673*5225e6b1SAndroid Build Coastguard Worker
674*5225e6b1SAndroid Build Coastguard Worker #[test]
test_load_and_verify_image_with_cert_permanent_attribute_mismatch_error()675*5225e6b1SAndroid Build Coastguard Worker fn test_load_and_verify_image_with_cert_permanent_attribute_mismatch_error() {
676*5225e6b1SAndroid Build Coastguard Worker let mut gbl_ops = FakeGblOps::default();
677*5225e6b1SAndroid Build Coastguard Worker let mut gbl = Gbl::new(&mut gbl_ops);
678*5225e6b1SAndroid Build Coastguard Worker let mut avb_ops = test_avb_cert_ops();
679*5225e6b1SAndroid Build Coastguard Worker
680*5225e6b1SAndroid Build Coastguard Worker // Swap in the corrupted permanent attributes, which should cause the vbmeta image to fail
681*5225e6b1SAndroid Build Coastguard Worker // validation due to key mismatch.
682*5225e6b1SAndroid Build Coastguard Worker let perm_attr_bytes = testdata(TEST_BAD_PERMANENT_ATTRIBUTES_PATH);
683*5225e6b1SAndroid Build Coastguard Worker let perm_attr_hash = testdata(TEST_BAD_PERMANENT_ATTRIBUTES_HASH_PATH);
684*5225e6b1SAndroid Build Coastguard Worker avb_ops.cert_permanent_attributes =
685*5225e6b1SAndroid Build Coastguard Worker Some(CertPermanentAttributes::read_from(&perm_attr_bytes[..]).unwrap());
686*5225e6b1SAndroid Build Coastguard Worker avb_ops.cert_permanent_attributes_hash = Some(perm_attr_hash.try_into().unwrap());
687*5225e6b1SAndroid Build Coastguard Worker
688*5225e6b1SAndroid Build Coastguard Worker let res = gbl.load_and_verify_image(
689*5225e6b1SAndroid Build Coastguard Worker &mut avb_ops,
690*5225e6b1SAndroid Build Coastguard Worker &mut [&TEST_ZIRCON_PARTITION_NAME_CSTR],
691*5225e6b1SAndroid Build Coastguard Worker SlotVerifyFlags::AVB_SLOT_VERIFY_FLAGS_NONE,
692*5225e6b1SAndroid Build Coastguard Worker None,
693*5225e6b1SAndroid Build Coastguard Worker );
694*5225e6b1SAndroid Build Coastguard Worker assert_eq!(
695*5225e6b1SAndroid Build Coastguard Worker res.unwrap_err(),
696*5225e6b1SAndroid Build Coastguard Worker IntegrationError::AvbSlotVerifyError(SlotVerifyError::PublicKeyRejected)
697*5225e6b1SAndroid Build Coastguard Worker );
698*5225e6b1SAndroid Build Coastguard Worker }
699*5225e6b1SAndroid Build Coastguard Worker }
700