1*d289c2baSAndroid Build Coastguard Worker // Copyright 2023, The Android Open Source Project
2*d289c2baSAndroid Build Coastguard Worker //
3*d289c2baSAndroid Build Coastguard Worker // Licensed under the Apache License, Version 2.0 (the "License");
4*d289c2baSAndroid Build Coastguard Worker // you may not use this file except in compliance with the License.
5*d289c2baSAndroid Build Coastguard Worker // You may obtain a copy of the License at
6*d289c2baSAndroid Build Coastguard Worker //
7*d289c2baSAndroid Build Coastguard Worker // http://www.apache.org/licenses/LICENSE-2.0
8*d289c2baSAndroid Build Coastguard Worker //
9*d289c2baSAndroid Build Coastguard Worker // Unless required by applicable law or agreed to in writing, software
10*d289c2baSAndroid Build Coastguard Worker // distributed under the License is distributed on an "AS IS" BASIS,
11*d289c2baSAndroid Build Coastguard Worker // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12*d289c2baSAndroid Build Coastguard Worker // See the License for the specific language governing permissions and
13*d289c2baSAndroid Build Coastguard Worker // limitations under the License.
14*d289c2baSAndroid Build Coastguard Worker
15*d289c2baSAndroid Build Coastguard Worker //! Verification APIs.
16*d289c2baSAndroid Build Coastguard Worker //!
17*d289c2baSAndroid Build Coastguard Worker //! This module is responsible for all the conversions required to pass information between
18*d289c2baSAndroid Build Coastguard Worker //! libavb and Rust for verifying images.
19*d289c2baSAndroid Build Coastguard Worker
20*d289c2baSAndroid Build Coastguard Worker extern crate alloc;
21*d289c2baSAndroid Build Coastguard Worker
22*d289c2baSAndroid Build Coastguard Worker use crate::{
23*d289c2baSAndroid Build Coastguard Worker descriptor::{get_descriptors, Descriptor, DescriptorResult},
24*d289c2baSAndroid Build Coastguard Worker error::{
25*d289c2baSAndroid Build Coastguard Worker slot_verify_enum_to_result, vbmeta_verify_enum_to_result, SlotVerifyError,
26*d289c2baSAndroid Build Coastguard Worker SlotVerifyNoDataResult, SlotVerifyResult, VbmetaVerifyResult,
27*d289c2baSAndroid Build Coastguard Worker },
28*d289c2baSAndroid Build Coastguard Worker ops, Ops,
29*d289c2baSAndroid Build Coastguard Worker };
30*d289c2baSAndroid Build Coastguard Worker use alloc::vec::Vec;
31*d289c2baSAndroid Build Coastguard Worker use avb_bindgen::{
32*d289c2baSAndroid Build Coastguard Worker avb_slot_verify, avb_slot_verify_data_free, AvbPartitionData, AvbSlotVerifyData, AvbVBMetaData,
33*d289c2baSAndroid Build Coastguard Worker };
34*d289c2baSAndroid Build Coastguard Worker use core::{
35*d289c2baSAndroid Build Coastguard Worker ffi::{c_char, CStr},
36*d289c2baSAndroid Build Coastguard Worker fmt,
37*d289c2baSAndroid Build Coastguard Worker marker::PhantomData,
38*d289c2baSAndroid Build Coastguard Worker pin::pin,
39*d289c2baSAndroid Build Coastguard Worker ptr::{self, null, null_mut, NonNull},
40*d289c2baSAndroid Build Coastguard Worker slice,
41*d289c2baSAndroid Build Coastguard Worker };
42*d289c2baSAndroid Build Coastguard Worker
43*d289c2baSAndroid Build Coastguard Worker /// `AvbHashtreeErrorMode`; see libavb docs for descriptions of each mode.
44*d289c2baSAndroid Build Coastguard Worker pub use avb_bindgen::AvbHashtreeErrorMode as HashtreeErrorMode;
45*d289c2baSAndroid Build Coastguard Worker /// `AvbSlotVerifyFlags`; see libavb docs for descriptions of each flag.
46*d289c2baSAndroid Build Coastguard Worker pub use avb_bindgen::AvbSlotVerifyFlags as SlotVerifyFlags;
47*d289c2baSAndroid Build Coastguard Worker
48*d289c2baSAndroid Build Coastguard Worker /// Returns `Err(SlotVerifyError::Internal)` if the given pointer is `NULL`.
check_nonnull<T>(ptr: *const T) -> SlotVerifyNoDataResult<()>49*d289c2baSAndroid Build Coastguard Worker fn check_nonnull<T>(ptr: *const T) -> SlotVerifyNoDataResult<()> {
50*d289c2baSAndroid Build Coastguard Worker match ptr.is_null() {
51*d289c2baSAndroid Build Coastguard Worker true => Err(SlotVerifyError::Internal),
52*d289c2baSAndroid Build Coastguard Worker false => Ok(()),
53*d289c2baSAndroid Build Coastguard Worker }
54*d289c2baSAndroid Build Coastguard Worker }
55*d289c2baSAndroid Build Coastguard Worker
56*d289c2baSAndroid Build Coastguard Worker /// Wraps a raw C `AvbVBMetaData` struct.
57*d289c2baSAndroid Build Coastguard Worker ///
58*d289c2baSAndroid Build Coastguard Worker /// This provides a Rust safe view over the raw data; no copies are made.
59*d289c2baSAndroid Build Coastguard Worker //
60*d289c2baSAndroid Build Coastguard Worker // `repr(transparent)` guarantees that size and alignment match the underlying type exactly, so that
61*d289c2baSAndroid Build Coastguard Worker // we can cast the array of `AvbVBMetaData` structs directly into a slice of `VbmetaData` wrappers
62*d289c2baSAndroid Build Coastguard Worker // without allocating any additional memory.
63*d289c2baSAndroid Build Coastguard Worker #[repr(transparent)]
64*d289c2baSAndroid Build Coastguard Worker pub struct VbmetaData(AvbVBMetaData);
65*d289c2baSAndroid Build Coastguard Worker
66*d289c2baSAndroid Build Coastguard Worker impl VbmetaData {
67*d289c2baSAndroid Build Coastguard Worker /// Validates the internal data so the accessors can be fail-free. This should be called on all
68*d289c2baSAndroid Build Coastguard Worker /// `VbmetaData` objects before they are handed to the user.
69*d289c2baSAndroid Build Coastguard Worker ///
70*d289c2baSAndroid Build Coastguard Worker /// Normally this would be done in a `new()` function but we never instantiate `VbmetaData`
71*d289c2baSAndroid Build Coastguard Worker /// objects ourselves, we just cast them from the C structs provided by libavb.
72*d289c2baSAndroid Build Coastguard Worker ///
73*d289c2baSAndroid Build Coastguard Worker /// Returns `Err(SlotVerifyError::Internal)` on failure.
validate(&self) -> SlotVerifyNoDataResult<()>74*d289c2baSAndroid Build Coastguard Worker fn validate(&self) -> SlotVerifyNoDataResult<()> {
75*d289c2baSAndroid Build Coastguard Worker check_nonnull(self.0.partition_name)?;
76*d289c2baSAndroid Build Coastguard Worker check_nonnull(self.0.vbmeta_data)?;
77*d289c2baSAndroid Build Coastguard Worker Ok(())
78*d289c2baSAndroid Build Coastguard Worker }
79*d289c2baSAndroid Build Coastguard Worker
80*d289c2baSAndroid Build Coastguard Worker /// Returns the name of the partition this vbmeta image was loaded from.
partition_name(&self) -> &CStr81*d289c2baSAndroid Build Coastguard Worker pub fn partition_name(&self) -> &CStr {
82*d289c2baSAndroid Build Coastguard Worker // SAFETY:
83*d289c2baSAndroid Build Coastguard Worker // * libavb gives us a properly-allocated and nul-terminated string.
84*d289c2baSAndroid Build Coastguard Worker // * the returned contents remain valid and unmodified while we exist.
85*d289c2baSAndroid Build Coastguard Worker unsafe { CStr::from_ptr(self.0.partition_name) }
86*d289c2baSAndroid Build Coastguard Worker }
87*d289c2baSAndroid Build Coastguard Worker
88*d289c2baSAndroid Build Coastguard Worker /// Returns the vbmeta image contents.
data(&self) -> &[u8]89*d289c2baSAndroid Build Coastguard Worker pub fn data(&self) -> &[u8] {
90*d289c2baSAndroid Build Coastguard Worker // SAFETY:
91*d289c2baSAndroid Build Coastguard Worker // * libavb gives us a properly-allocated byte array.
92*d289c2baSAndroid Build Coastguard Worker // * the returned contents remain valid and unmodified while we exist.
93*d289c2baSAndroid Build Coastguard Worker unsafe { slice::from_raw_parts(self.0.vbmeta_data, self.0.vbmeta_size) }
94*d289c2baSAndroid Build Coastguard Worker }
95*d289c2baSAndroid Build Coastguard Worker
96*d289c2baSAndroid Build Coastguard Worker /// Returns the vbmeta verification result.
verify_result(&self) -> VbmetaVerifyResult<()>97*d289c2baSAndroid Build Coastguard Worker pub fn verify_result(&self) -> VbmetaVerifyResult<()> {
98*d289c2baSAndroid Build Coastguard Worker vbmeta_verify_enum_to_result(self.0.verify_result)
99*d289c2baSAndroid Build Coastguard Worker }
100*d289c2baSAndroid Build Coastguard Worker
101*d289c2baSAndroid Build Coastguard Worker /// Extracts the descriptors from the vbmeta image.
102*d289c2baSAndroid Build Coastguard Worker ///
103*d289c2baSAndroid Build Coastguard Worker /// Note that this function allocates memory to hold the `Descriptor` objects.
104*d289c2baSAndroid Build Coastguard Worker ///
105*d289c2baSAndroid Build Coastguard Worker /// # Returns
106*d289c2baSAndroid Build Coastguard Worker /// A vector of descriptors, or `DescriptorError` on failure.
descriptors(&self) -> DescriptorResult<Vec<Descriptor>>107*d289c2baSAndroid Build Coastguard Worker pub fn descriptors(&self) -> DescriptorResult<Vec<Descriptor>> {
108*d289c2baSAndroid Build Coastguard Worker // SAFETY: the only way to get a `VbmetaData` object is via the return value of
109*d289c2baSAndroid Build Coastguard Worker // `slot_verify()`, so we know we have been properly validated.
110*d289c2baSAndroid Build Coastguard Worker unsafe { get_descriptors(self) }
111*d289c2baSAndroid Build Coastguard Worker }
112*d289c2baSAndroid Build Coastguard Worker
113*d289c2baSAndroid Build Coastguard Worker /// Gets a property from the vbmeta image for the given key
114*d289c2baSAndroid Build Coastguard Worker ///
115*d289c2baSAndroid Build Coastguard Worker /// This function re-implements the libavb avb_property_lookup logic.
116*d289c2baSAndroid Build Coastguard Worker ///
117*d289c2baSAndroid Build Coastguard Worker /// # Returns
118*d289c2baSAndroid Build Coastguard Worker /// Byte array with property data or None in case property not found or failure.
get_property_value(&self, key: &str) -> Option<&[u8]>119*d289c2baSAndroid Build Coastguard Worker pub fn get_property_value(&self, key: &str) -> Option<&[u8]> {
120*d289c2baSAndroid Build Coastguard Worker self.descriptors().ok()?.iter().find_map(|d| match d {
121*d289c2baSAndroid Build Coastguard Worker Descriptor::Property(p) if p.key == key => Some(p.value),
122*d289c2baSAndroid Build Coastguard Worker _ => None,
123*d289c2baSAndroid Build Coastguard Worker })
124*d289c2baSAndroid Build Coastguard Worker }
125*d289c2baSAndroid Build Coastguard Worker }
126*d289c2baSAndroid Build Coastguard Worker
127*d289c2baSAndroid Build Coastguard Worker impl fmt::Display for VbmetaData {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result128*d289c2baSAndroid Build Coastguard Worker fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
129*d289c2baSAndroid Build Coastguard Worker write!(f, "{:?}: {:?}", self.partition_name(), self.verify_result())
130*d289c2baSAndroid Build Coastguard Worker }
131*d289c2baSAndroid Build Coastguard Worker }
132*d289c2baSAndroid Build Coastguard Worker
133*d289c2baSAndroid Build Coastguard Worker /// Forwards to `Display` formatting; the default `Debug` formatting implementation isn't very
134*d289c2baSAndroid Build Coastguard Worker /// useful as it's mostly raw pointer addresses.
135*d289c2baSAndroid Build Coastguard Worker impl fmt::Debug for VbmetaData {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result136*d289c2baSAndroid Build Coastguard Worker fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
137*d289c2baSAndroid Build Coastguard Worker fmt::Display::fmt(self, f)
138*d289c2baSAndroid Build Coastguard Worker }
139*d289c2baSAndroid Build Coastguard Worker }
140*d289c2baSAndroid Build Coastguard Worker
141*d289c2baSAndroid Build Coastguard Worker /// Wraps a raw C `AvbPartitionData` struct.
142*d289c2baSAndroid Build Coastguard Worker ///
143*d289c2baSAndroid Build Coastguard Worker /// This provides a Rust safe view over the raw data; no copies are made.
144*d289c2baSAndroid Build Coastguard Worker #[repr(transparent)]
145*d289c2baSAndroid Build Coastguard Worker pub struct PartitionData(AvbPartitionData);
146*d289c2baSAndroid Build Coastguard Worker
147*d289c2baSAndroid Build Coastguard Worker impl PartitionData {
148*d289c2baSAndroid Build Coastguard Worker /// Validates the internal data so the accessors can be fail-free. This should be called on all
149*d289c2baSAndroid Build Coastguard Worker /// `PartitionData` objects before they are handed to the user.
150*d289c2baSAndroid Build Coastguard Worker ///
151*d289c2baSAndroid Build Coastguard Worker /// Normally this would be done in a `new()` function but we never instantiate `PartitionData`
152*d289c2baSAndroid Build Coastguard Worker /// objects ourselves, we just cast them from the C structs provided by libavb.
153*d289c2baSAndroid Build Coastguard Worker ///
154*d289c2baSAndroid Build Coastguard Worker /// Returns `Err(SlotVerifyError::Internal)` on failure.
validate(&self) -> SlotVerifyNoDataResult<()>155*d289c2baSAndroid Build Coastguard Worker fn validate(&self) -> SlotVerifyNoDataResult<()> {
156*d289c2baSAndroid Build Coastguard Worker check_nonnull(self.0.partition_name)?;
157*d289c2baSAndroid Build Coastguard Worker check_nonnull(self.0.data)?;
158*d289c2baSAndroid Build Coastguard Worker Ok(())
159*d289c2baSAndroid Build Coastguard Worker }
160*d289c2baSAndroid Build Coastguard Worker
161*d289c2baSAndroid Build Coastguard Worker /// Returns the name of the partition this image was loaded from.
partition_name(&self) -> &CStr162*d289c2baSAndroid Build Coastguard Worker pub fn partition_name(&self) -> &CStr {
163*d289c2baSAndroid Build Coastguard Worker // SAFETY:
164*d289c2baSAndroid Build Coastguard Worker // * libavb gives us a properly-allocated and nul-terminated string.
165*d289c2baSAndroid Build Coastguard Worker // * the returned contents remain valid and unmodified while we exist.
166*d289c2baSAndroid Build Coastguard Worker unsafe { CStr::from_ptr(self.0.partition_name) }
167*d289c2baSAndroid Build Coastguard Worker }
168*d289c2baSAndroid Build Coastguard Worker
169*d289c2baSAndroid Build Coastguard Worker /// Returns the image contents.
data(&self) -> &[u8]170*d289c2baSAndroid Build Coastguard Worker pub fn data(&self) -> &[u8] {
171*d289c2baSAndroid Build Coastguard Worker // SAFETY:
172*d289c2baSAndroid Build Coastguard Worker // * libavb gives us a properly-allocated byte array.
173*d289c2baSAndroid Build Coastguard Worker // * the returned contents remain valid and unmodified while we exist.
174*d289c2baSAndroid Build Coastguard Worker unsafe { slice::from_raw_parts(self.0.data, self.0.data_size) }
175*d289c2baSAndroid Build Coastguard Worker }
176*d289c2baSAndroid Build Coastguard Worker
177*d289c2baSAndroid Build Coastguard Worker /// Returns whether this partition was preloaded via `get_preloaded_partition()`.
preloaded(&self) -> bool178*d289c2baSAndroid Build Coastguard Worker pub fn preloaded(&self) -> bool {
179*d289c2baSAndroid Build Coastguard Worker self.0.preloaded
180*d289c2baSAndroid Build Coastguard Worker }
181*d289c2baSAndroid Build Coastguard Worker
182*d289c2baSAndroid Build Coastguard Worker /// Returns the verification result for this partition.
183*d289c2baSAndroid Build Coastguard Worker ///
184*d289c2baSAndroid Build Coastguard Worker /// Only top-level `Verification` errors will contain valid `SlotVerifyData` objects, if this
185*d289c2baSAndroid Build Coastguard Worker /// individual partition returns a `Verification` error the error will always contain `None`.
verify_result(&self) -> SlotVerifyNoDataResult<()>186*d289c2baSAndroid Build Coastguard Worker pub fn verify_result(&self) -> SlotVerifyNoDataResult<()> {
187*d289c2baSAndroid Build Coastguard Worker slot_verify_enum_to_result(self.0.verify_result)
188*d289c2baSAndroid Build Coastguard Worker }
189*d289c2baSAndroid Build Coastguard Worker }
190*d289c2baSAndroid Build Coastguard Worker
191*d289c2baSAndroid Build Coastguard Worker /// A "(p)" after the partition name indicates a preloaded partition.
192*d289c2baSAndroid Build Coastguard Worker impl fmt::Display for PartitionData {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result193*d289c2baSAndroid Build Coastguard Worker fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
194*d289c2baSAndroid Build Coastguard Worker write!(
195*d289c2baSAndroid Build Coastguard Worker f,
196*d289c2baSAndroid Build Coastguard Worker "{:?}{}: {:?}",
197*d289c2baSAndroid Build Coastguard Worker self.partition_name(),
198*d289c2baSAndroid Build Coastguard Worker match self.preloaded() {
199*d289c2baSAndroid Build Coastguard Worker true => "(p)",
200*d289c2baSAndroid Build Coastguard Worker false => "",
201*d289c2baSAndroid Build Coastguard Worker },
202*d289c2baSAndroid Build Coastguard Worker self.verify_result()
203*d289c2baSAndroid Build Coastguard Worker )
204*d289c2baSAndroid Build Coastguard Worker }
205*d289c2baSAndroid Build Coastguard Worker }
206*d289c2baSAndroid Build Coastguard Worker
207*d289c2baSAndroid Build Coastguard Worker /// Forwards to `Display` formatting; the default `Debug` formatting implementation isn't very
208*d289c2baSAndroid Build Coastguard Worker /// useful as it's mostly raw pointer addresses.
209*d289c2baSAndroid Build Coastguard Worker impl fmt::Debug for PartitionData {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result210*d289c2baSAndroid Build Coastguard Worker fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
211*d289c2baSAndroid Build Coastguard Worker fmt::Display::fmt(self, f)
212*d289c2baSAndroid Build Coastguard Worker }
213*d289c2baSAndroid Build Coastguard Worker }
214*d289c2baSAndroid Build Coastguard Worker
215*d289c2baSAndroid Build Coastguard Worker /// Wraps a raw C `AvbSlotVerifyData` struct.
216*d289c2baSAndroid Build Coastguard Worker ///
217*d289c2baSAndroid Build Coastguard Worker /// This provides a Rust safe view over the raw data; no copies are made.
218*d289c2baSAndroid Build Coastguard Worker ///
219*d289c2baSAndroid Build Coastguard Worker /// # Lifetimes
220*d289c2baSAndroid Build Coastguard Worker /// * `'a`: the lifetime of any preloaded partition data borrowed from an `Ops<'a>` object.
221*d289c2baSAndroid Build Coastguard Worker ///
222*d289c2baSAndroid Build Coastguard Worker /// If the `Ops` doesn't provide any preloaded data, `SlotVerifyData` doesn't borrow anything
223*d289c2baSAndroid Build Coastguard Worker /// and instead allocates and owns all data internally, freeing it accordingly on `Drop`. In this
224*d289c2baSAndroid Build Coastguard Worker /// case, `'a` can be `'static` which imposes no lifetime restrictions on `SlotVerifyData`.
225*d289c2baSAndroid Build Coastguard Worker pub struct SlotVerifyData<'a> {
226*d289c2baSAndroid Build Coastguard Worker /// Internally owns the underlying data and deletes it on drop.
227*d289c2baSAndroid Build Coastguard Worker raw_data: NonNull<AvbSlotVerifyData>,
228*d289c2baSAndroid Build Coastguard Worker
229*d289c2baSAndroid Build Coastguard Worker /// This provides the necessary lifetimes so the compiler can make sure that the preloaded
230*d289c2baSAndroid Build Coastguard Worker /// partition data stays alive at least as long as we do, since the underlying
231*d289c2baSAndroid Build Coastguard Worker /// `AvbSlotVerifyData` may wrap this data rather than making a copy.
232*d289c2baSAndroid Build Coastguard Worker //
233*d289c2baSAndroid Build Coastguard Worker // We do not want to actually borrow an `Ops` here, since in some cases `Ops` is just a
234*d289c2baSAndroid Build Coastguard Worker // temporary object and may go out of scope before us. The only shared data is the preloaded
235*d289c2baSAndroid Build Coastguard Worker // partition contents, not the entire `Ops` object.
236*d289c2baSAndroid Build Coastguard Worker _preloaded: PhantomData<&'a [u8]>,
237*d289c2baSAndroid Build Coastguard Worker }
238*d289c2baSAndroid Build Coastguard Worker
239*d289c2baSAndroid Build Coastguard Worker // Useful so that `SlotVerifyError`, which may hold a `SlotVerifyData`, can derive `PartialEq`.
240*d289c2baSAndroid Build Coastguard Worker impl<'a> PartialEq for SlotVerifyData<'a> {
eq(&self, other: &Self) -> bool241*d289c2baSAndroid Build Coastguard Worker fn eq(&self, other: &Self) -> bool {
242*d289c2baSAndroid Build Coastguard Worker // A `SlotVerifyData` uniquely owns the underlying data so is only equal to itself.
243*d289c2baSAndroid Build Coastguard Worker ptr::eq(self, other)
244*d289c2baSAndroid Build Coastguard Worker }
245*d289c2baSAndroid Build Coastguard Worker }
246*d289c2baSAndroid Build Coastguard Worker
247*d289c2baSAndroid Build Coastguard Worker impl<'a> Eq for SlotVerifyData<'a> {}
248*d289c2baSAndroid Build Coastguard Worker
249*d289c2baSAndroid Build Coastguard Worker impl<'a> SlotVerifyData<'a> {
250*d289c2baSAndroid Build Coastguard Worker /// Creates a `SlotVerifyData` wrapping the given raw `AvbSlotVerifyData`.
251*d289c2baSAndroid Build Coastguard Worker ///
252*d289c2baSAndroid Build Coastguard Worker /// The returned `SlotVerifyData` will take ownership of the given `AvbSlotVerifyData` and
253*d289c2baSAndroid Build Coastguard Worker /// properly release the allocated memory when it drops.
254*d289c2baSAndroid Build Coastguard Worker ///
255*d289c2baSAndroid Build Coastguard Worker /// If `ops` provided any preloaded data, the returned `SlotVerifyData` also borrows the data to
256*d289c2baSAndroid Build Coastguard Worker /// account for the underlying `AvbSlotVerifyData` holding a pointer to it. If there was no
257*d289c2baSAndroid Build Coastguard Worker /// preloaded data, then `SlotVerifyData` owns all its data.
258*d289c2baSAndroid Build Coastguard Worker ///
259*d289c2baSAndroid Build Coastguard Worker /// # Arguments
260*d289c2baSAndroid Build Coastguard Worker /// * `data`: a `AvbSlotVerifyData` object created by libavb using `ops`.
261*d289c2baSAndroid Build Coastguard Worker /// * `ops`: the user-provided `Ops` object that was used for verification; only used here to
262*d289c2baSAndroid Build Coastguard Worker /// grab the preloaded data lifetime.
263*d289c2baSAndroid Build Coastguard Worker ///
264*d289c2baSAndroid Build Coastguard Worker /// # Returns
265*d289c2baSAndroid Build Coastguard Worker /// The new object, or `Err(SlotVerifyError::Internal)` if the data looks invalid.
266*d289c2baSAndroid Build Coastguard Worker ///
267*d289c2baSAndroid Build Coastguard Worker /// # Safety
268*d289c2baSAndroid Build Coastguard Worker /// * `data` must be a valid `AvbSlotVerifyData` object created by libavb using `ops`.
269*d289c2baSAndroid Build Coastguard Worker /// * after calling this function, do not access `data` except through the returned object
new( data: *mut AvbSlotVerifyData, _ops: &dyn Ops<'a>, ) -> SlotVerifyNoDataResult<Self>270*d289c2baSAndroid Build Coastguard Worker unsafe fn new(
271*d289c2baSAndroid Build Coastguard Worker data: *mut AvbSlotVerifyData,
272*d289c2baSAndroid Build Coastguard Worker _ops: &dyn Ops<'a>,
273*d289c2baSAndroid Build Coastguard Worker ) -> SlotVerifyNoDataResult<Self> {
274*d289c2baSAndroid Build Coastguard Worker let ret = Self {
275*d289c2baSAndroid Build Coastguard Worker raw_data: NonNull::new(data).ok_or(SlotVerifyError::Internal)?,
276*d289c2baSAndroid Build Coastguard Worker _preloaded: PhantomData,
277*d289c2baSAndroid Build Coastguard Worker };
278*d289c2baSAndroid Build Coastguard Worker
279*d289c2baSAndroid Build Coastguard Worker // Validate all the contained data here so accessors will never fail.
280*d289c2baSAndroid Build Coastguard Worker // SAFETY: `raw_data` points to a valid `AvbSlotVerifyData` object owned by us.
281*d289c2baSAndroid Build Coastguard Worker let data = unsafe { ret.raw_data.as_ref() };
282*d289c2baSAndroid Build Coastguard Worker check_nonnull(data.ab_suffix)?;
283*d289c2baSAndroid Build Coastguard Worker check_nonnull(data.vbmeta_images)?;
284*d289c2baSAndroid Build Coastguard Worker check_nonnull(data.loaded_partitions)?;
285*d289c2baSAndroid Build Coastguard Worker check_nonnull(data.cmdline)?;
286*d289c2baSAndroid Build Coastguard Worker ret.vbmeta_data().iter().try_for_each(|v| v.validate())?;
287*d289c2baSAndroid Build Coastguard Worker ret.partition_data().iter().try_for_each(|i| i.validate())?;
288*d289c2baSAndroid Build Coastguard Worker
289*d289c2baSAndroid Build Coastguard Worker Ok(ret)
290*d289c2baSAndroid Build Coastguard Worker }
291*d289c2baSAndroid Build Coastguard Worker
292*d289c2baSAndroid Build Coastguard Worker /// Returns the slot suffix string.
ab_suffix(&self) -> &CStr293*d289c2baSAndroid Build Coastguard Worker pub fn ab_suffix(&self) -> &CStr {
294*d289c2baSAndroid Build Coastguard Worker // SAFETY:
295*d289c2baSAndroid Build Coastguard Worker // * `raw_data` points to a valid `AvbSlotVerifyData` object owned by us.
296*d289c2baSAndroid Build Coastguard Worker // * libavb gives us a properly-allocated and nul-terminated string.
297*d289c2baSAndroid Build Coastguard Worker // * the returned contents remain valid and unmodified while we exist.
298*d289c2baSAndroid Build Coastguard Worker unsafe { CStr::from_ptr(self.raw_data.as_ref().ab_suffix) }
299*d289c2baSAndroid Build Coastguard Worker }
300*d289c2baSAndroid Build Coastguard Worker
301*d289c2baSAndroid Build Coastguard Worker /// Returns the `VbmetaData` structs.
vbmeta_data(&self) -> &[VbmetaData]302*d289c2baSAndroid Build Coastguard Worker pub fn vbmeta_data(&self) -> &[VbmetaData] {
303*d289c2baSAndroid Build Coastguard Worker // SAFETY:
304*d289c2baSAndroid Build Coastguard Worker // * `raw_data` points to a valid `AvbSlotVerifyData` object owned by us.
305*d289c2baSAndroid Build Coastguard Worker // * libavb gives us a properly-allocated array of structs.
306*d289c2baSAndroid Build Coastguard Worker // * the returned contents remain valid and unmodified while we exist.
307*d289c2baSAndroid Build Coastguard Worker unsafe {
308*d289c2baSAndroid Build Coastguard Worker slice::from_raw_parts(
309*d289c2baSAndroid Build Coastguard Worker // `repr(transparent)` means we can cast between these types.
310*d289c2baSAndroid Build Coastguard Worker self.raw_data.as_ref().vbmeta_images as *const VbmetaData,
311*d289c2baSAndroid Build Coastguard Worker self.raw_data.as_ref().num_vbmeta_images,
312*d289c2baSAndroid Build Coastguard Worker )
313*d289c2baSAndroid Build Coastguard Worker }
314*d289c2baSAndroid Build Coastguard Worker }
315*d289c2baSAndroid Build Coastguard Worker
316*d289c2baSAndroid Build Coastguard Worker /// Returns the `PartitionData` structs.
partition_data(&self) -> &[PartitionData]317*d289c2baSAndroid Build Coastguard Worker pub fn partition_data(&self) -> &[PartitionData] {
318*d289c2baSAndroid Build Coastguard Worker // SAFETY:
319*d289c2baSAndroid Build Coastguard Worker // * `raw_data` points to a valid `AvbSlotVerifyData` object owned by us.
320*d289c2baSAndroid Build Coastguard Worker // * libavb gives us a properly-allocated array of structs.
321*d289c2baSAndroid Build Coastguard Worker // * the returned contents remain valid and unmodified while we exist.
322*d289c2baSAndroid Build Coastguard Worker unsafe {
323*d289c2baSAndroid Build Coastguard Worker slice::from_raw_parts(
324*d289c2baSAndroid Build Coastguard Worker // `repr(transparent)` means we can cast between these types.
325*d289c2baSAndroid Build Coastguard Worker self.raw_data.as_ref().loaded_partitions as *const PartitionData,
326*d289c2baSAndroid Build Coastguard Worker self.raw_data.as_ref().num_loaded_partitions,
327*d289c2baSAndroid Build Coastguard Worker )
328*d289c2baSAndroid Build Coastguard Worker }
329*d289c2baSAndroid Build Coastguard Worker }
330*d289c2baSAndroid Build Coastguard Worker
331*d289c2baSAndroid Build Coastguard Worker /// Returns the kernel commandline.
cmdline(&self) -> &CStr332*d289c2baSAndroid Build Coastguard Worker pub fn cmdline(&self) -> &CStr {
333*d289c2baSAndroid Build Coastguard Worker // SAFETY:
334*d289c2baSAndroid Build Coastguard Worker // * `raw_data` points to a valid `AvbSlotVerifyData` object owned by us.
335*d289c2baSAndroid Build Coastguard Worker // * libavb gives us a properly-allocated and nul-terminated string.
336*d289c2baSAndroid Build Coastguard Worker // * the returned contents remain valid and unmodified while we exist.
337*d289c2baSAndroid Build Coastguard Worker unsafe { CStr::from_ptr(self.raw_data.as_ref().cmdline) }
338*d289c2baSAndroid Build Coastguard Worker }
339*d289c2baSAndroid Build Coastguard Worker
340*d289c2baSAndroid Build Coastguard Worker /// Returns the rollback indices.
rollback_indexes(&self) -> &[u64]341*d289c2baSAndroid Build Coastguard Worker pub fn rollback_indexes(&self) -> &[u64] {
342*d289c2baSAndroid Build Coastguard Worker // SAFETY: `raw_data` points to a valid `AvbSlotVerifyData` object owned by us.
343*d289c2baSAndroid Build Coastguard Worker &unsafe { self.raw_data.as_ref() }.rollback_indexes[..]
344*d289c2baSAndroid Build Coastguard Worker }
345*d289c2baSAndroid Build Coastguard Worker
346*d289c2baSAndroid Build Coastguard Worker /// Returns the resolved hashtree error mode.
resolved_hashtree_error_mode(&self) -> HashtreeErrorMode347*d289c2baSAndroid Build Coastguard Worker pub fn resolved_hashtree_error_mode(&self) -> HashtreeErrorMode {
348*d289c2baSAndroid Build Coastguard Worker // SAFETY: `raw_data` points to a valid `AvbSlotVerifyData` object owned by us.
349*d289c2baSAndroid Build Coastguard Worker unsafe { self.raw_data.as_ref() }.resolved_hashtree_error_mode
350*d289c2baSAndroid Build Coastguard Worker }
351*d289c2baSAndroid Build Coastguard Worker }
352*d289c2baSAndroid Build Coastguard Worker
353*d289c2baSAndroid Build Coastguard Worker /// Frees any internally-allocated and owned data.
354*d289c2baSAndroid Build Coastguard Worker impl<'a> Drop for SlotVerifyData<'a> {
drop(&mut self)355*d289c2baSAndroid Build Coastguard Worker fn drop(&mut self) {
356*d289c2baSAndroid Build Coastguard Worker // SAFETY:
357*d289c2baSAndroid Build Coastguard Worker // * `raw_data` points to a valid `AvbSlotVerifyData` object owned by us.
358*d289c2baSAndroid Build Coastguard Worker // * libavb created the object and requires us to free it by calling this function.
359*d289c2baSAndroid Build Coastguard Worker unsafe { avb_slot_verify_data_free(self.raw_data.as_ptr()) };
360*d289c2baSAndroid Build Coastguard Worker }
361*d289c2baSAndroid Build Coastguard Worker }
362*d289c2baSAndroid Build Coastguard Worker
363*d289c2baSAndroid Build Coastguard Worker /// Implements `Display` to make it easy to print some basic information.
364*d289c2baSAndroid Build Coastguard Worker ///
365*d289c2baSAndroid Build Coastguard Worker /// This implementation will print the slot, partition name, and verification status for all
366*d289c2baSAndroid Build Coastguard Worker /// vbmetadata and images.
367*d289c2baSAndroid Build Coastguard Worker impl<'a> fmt::Display for SlotVerifyData<'a> {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result368*d289c2baSAndroid Build Coastguard Worker fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
369*d289c2baSAndroid Build Coastguard Worker write!(
370*d289c2baSAndroid Build Coastguard Worker f,
371*d289c2baSAndroid Build Coastguard Worker "slot: {:?}, vbmeta: {:?}, images: {:?}",
372*d289c2baSAndroid Build Coastguard Worker self.ab_suffix(),
373*d289c2baSAndroid Build Coastguard Worker self.vbmeta_data(),
374*d289c2baSAndroid Build Coastguard Worker self.partition_data()
375*d289c2baSAndroid Build Coastguard Worker )
376*d289c2baSAndroid Build Coastguard Worker }
377*d289c2baSAndroid Build Coastguard Worker }
378*d289c2baSAndroid Build Coastguard Worker
379*d289c2baSAndroid Build Coastguard Worker /// Forwards to `Display` formatting; the default `Debug` formatting implementation isn't very
380*d289c2baSAndroid Build Coastguard Worker /// useful as it's mostly raw pointer addresses.
381*d289c2baSAndroid Build Coastguard Worker impl<'a> fmt::Debug for SlotVerifyData<'a> {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result382*d289c2baSAndroid Build Coastguard Worker fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
383*d289c2baSAndroid Build Coastguard Worker fmt::Display::fmt(self, f)
384*d289c2baSAndroid Build Coastguard Worker }
385*d289c2baSAndroid Build Coastguard Worker }
386*d289c2baSAndroid Build Coastguard Worker
387*d289c2baSAndroid Build Coastguard Worker /// Performs verification of the requested images.
388*d289c2baSAndroid Build Coastguard Worker ///
389*d289c2baSAndroid Build Coastguard Worker /// This wraps `avb_slot_verify()` for Rust, see the original docs for more details.
390*d289c2baSAndroid Build Coastguard Worker ///
391*d289c2baSAndroid Build Coastguard Worker /// # Arguments
392*d289c2baSAndroid Build Coastguard Worker /// * `ops`: implementation of the required verification callbacks.
393*d289c2baSAndroid Build Coastguard Worker /// * `requested_partition`: the set of partition names to verify.
394*d289c2baSAndroid Build Coastguard Worker /// * `ab_suffix`: the slot suffix to append to the partition names, or None.
395*d289c2baSAndroid Build Coastguard Worker /// * `flags`: flags to configure verification.
396*d289c2baSAndroid Build Coastguard Worker /// * `hashtree_error_mode`: desired error handling behavior.
397*d289c2baSAndroid Build Coastguard Worker ///
398*d289c2baSAndroid Build Coastguard Worker /// # Returns
399*d289c2baSAndroid Build Coastguard Worker /// `Ok` if verification completed successfully, the verification error otherwise. `SlotVerifyData`
400*d289c2baSAndroid Build Coastguard Worker /// will be returned in two cases:
401*d289c2baSAndroid Build Coastguard Worker ///
402*d289c2baSAndroid Build Coastguard Worker /// 1. always returned on verification success
403*d289c2baSAndroid Build Coastguard Worker /// 2. if `AllowVerificationError` is given in `flags`, it will also be returned on verification
404*d289c2baSAndroid Build Coastguard Worker /// failure
405*d289c2baSAndroid Build Coastguard Worker ///
406*d289c2baSAndroid Build Coastguard Worker /// A returned `SlotVerifyData` will also borrow any preloaded data provided by `ops`. The `ops`
407*d289c2baSAndroid Build Coastguard Worker /// object itself can go out of scope, but any preloaded data it could provide must outlive the
408*d289c2baSAndroid Build Coastguard Worker /// returned object.
slot_verify<'a>( ops: &mut dyn Ops<'a>, requested_partitions: &[&CStr], ab_suffix: Option<&CStr>, flags: SlotVerifyFlags, hashtree_error_mode: HashtreeErrorMode, ) -> SlotVerifyResult<'a, SlotVerifyData<'a>>409*d289c2baSAndroid Build Coastguard Worker pub fn slot_verify<'a>(
410*d289c2baSAndroid Build Coastguard Worker ops: &mut dyn Ops<'a>,
411*d289c2baSAndroid Build Coastguard Worker requested_partitions: &[&CStr],
412*d289c2baSAndroid Build Coastguard Worker ab_suffix: Option<&CStr>,
413*d289c2baSAndroid Build Coastguard Worker flags: SlotVerifyFlags,
414*d289c2baSAndroid Build Coastguard Worker hashtree_error_mode: HashtreeErrorMode,
415*d289c2baSAndroid Build Coastguard Worker ) -> SlotVerifyResult<'a, SlotVerifyData<'a>> {
416*d289c2baSAndroid Build Coastguard Worker // libavb detects the size of the `requested_partitions` array by NULL termination. Expecting
417*d289c2baSAndroid Build Coastguard Worker // the Rust caller to do this would make the API much more awkward, so we populate a
418*d289c2baSAndroid Build Coastguard Worker // NULL-terminated array of c-string pointers ourselves. For now we use a fixed-sized array
419*d289c2baSAndroid Build Coastguard Worker // rather than dynamically allocating, 8 should be more than enough.
420*d289c2baSAndroid Build Coastguard Worker const MAX_PARTITION_ARRAY_SIZE: usize = 8 + 1; // Max 8 partition names + 1 for NULL terminator.
421*d289c2baSAndroid Build Coastguard Worker if requested_partitions.len() >= MAX_PARTITION_ARRAY_SIZE {
422*d289c2baSAndroid Build Coastguard Worker return Err(SlotVerifyError::Internal);
423*d289c2baSAndroid Build Coastguard Worker }
424*d289c2baSAndroid Build Coastguard Worker let mut partitions_array = [null() as *const c_char; MAX_PARTITION_ARRAY_SIZE];
425*d289c2baSAndroid Build Coastguard Worker for (source, dest) in requested_partitions.iter().zip(partitions_array.iter_mut()) {
426*d289c2baSAndroid Build Coastguard Worker *dest = source.as_ptr();
427*d289c2baSAndroid Build Coastguard Worker }
428*d289c2baSAndroid Build Coastguard Worker
429*d289c2baSAndroid Build Coastguard Worker // To be more Rust idiomatic we allow `ab_suffix` to be `None`, but libavb requires a valid
430*d289c2baSAndroid Build Coastguard Worker // pointer to an empty string in this case, not NULL.
431*d289c2baSAndroid Build Coastguard Worker let ab_suffix = ab_suffix.unwrap_or(CStr::from_bytes_with_nul(b"\0").unwrap());
432*d289c2baSAndroid Build Coastguard Worker
433*d289c2baSAndroid Build Coastguard Worker let ops_bridge = pin!(ops::OpsBridge::new(ops));
434*d289c2baSAndroid Build Coastguard Worker let mut out_data: *mut AvbSlotVerifyData = null_mut();
435*d289c2baSAndroid Build Coastguard Worker
436*d289c2baSAndroid Build Coastguard Worker // Call the libavb verification function.
437*d289c2baSAndroid Build Coastguard Worker //
438*d289c2baSAndroid Build Coastguard Worker // Note: do not use the `?` operator to return-early here; in some cases `out_data` will be
439*d289c2baSAndroid Build Coastguard Worker // allocated and returned even on verification failure, and we need to take ownership of it
440*d289c2baSAndroid Build Coastguard Worker // or else the memory will leak.
441*d289c2baSAndroid Build Coastguard Worker //
442*d289c2baSAndroid Build Coastguard Worker // SAFETY:
443*d289c2baSAndroid Build Coastguard Worker // * `ops_bridge.init_and_get_c_ops()` gives us a valid `AvbOps`.
444*d289c2baSAndroid Build Coastguard Worker // * we've properly initialized all objects passed into libavb.
445*d289c2baSAndroid Build Coastguard Worker // * if `out_data` is non-null on return, we take ownership via `SlotVerifyData`.
446*d289c2baSAndroid Build Coastguard Worker let result = slot_verify_enum_to_result(unsafe {
447*d289c2baSAndroid Build Coastguard Worker avb_slot_verify(
448*d289c2baSAndroid Build Coastguard Worker ops_bridge.init_and_get_c_ops(),
449*d289c2baSAndroid Build Coastguard Worker partitions_array.as_ptr(),
450*d289c2baSAndroid Build Coastguard Worker ab_suffix.as_ptr(),
451*d289c2baSAndroid Build Coastguard Worker flags,
452*d289c2baSAndroid Build Coastguard Worker hashtree_error_mode,
453*d289c2baSAndroid Build Coastguard Worker &mut out_data,
454*d289c2baSAndroid Build Coastguard Worker )
455*d289c2baSAndroid Build Coastguard Worker });
456*d289c2baSAndroid Build Coastguard Worker
457*d289c2baSAndroid Build Coastguard Worker // If `out_data` is non-null, take ownership so memory gets released on drop.
458*d289c2baSAndroid Build Coastguard Worker let data = match out_data.is_null() {
459*d289c2baSAndroid Build Coastguard Worker true => None,
460*d289c2baSAndroid Build Coastguard Worker // SAFETY: `out_data` was properly allocated by libavb and ownership has passed to us.
461*d289c2baSAndroid Build Coastguard Worker false => Some(unsafe { SlotVerifyData::new(out_data, ops)? }),
462*d289c2baSAndroid Build Coastguard Worker };
463*d289c2baSAndroid Build Coastguard Worker
464*d289c2baSAndroid Build Coastguard Worker // Fold the verify data into the result.
465*d289c2baSAndroid Build Coastguard Worker match result {
466*d289c2baSAndroid Build Coastguard Worker // libavb will always provide verification data on success.
467*d289c2baSAndroid Build Coastguard Worker Ok(()) => Ok(data.unwrap()),
468*d289c2baSAndroid Build Coastguard Worker // Data may also be provided on verification failure, fold it into the error.
469*d289c2baSAndroid Build Coastguard Worker Err(SlotVerifyError::Verification(None)) => Err(SlotVerifyError::Verification(data)),
470*d289c2baSAndroid Build Coastguard Worker // No other error provides verification data.
471*d289c2baSAndroid Build Coastguard Worker Err(e) => Err(e),
472*d289c2baSAndroid Build Coastguard Worker }
473*d289c2baSAndroid Build Coastguard Worker }
474