xref: /aosp_15_r20/external/avb/rust/src/descriptor/mod.rs (revision d289c2ba6de359471b23d594623b906876bc48a0)
1 // Copyright 2023, The Android Open Source Project
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 //! Descriptor extraction and handling.
16 //!
17 //! Descriptors are information encoded into vbmeta images which can be
18 //! extracted from the resulting data after performing verification.
19 
20 extern crate alloc;
21 
22 mod chain;
23 mod commandline;
24 mod hash;
25 mod hashtree;
26 mod property;
27 mod util;
28 
29 use crate::VbmetaData;
30 use alloc::vec::Vec;
31 use avb_bindgen::{
32     avb_descriptor_foreach, avb_descriptor_validate_and_byteswap, AvbDescriptor, AvbDescriptorTag,
33 };
34 use core::{
35     ffi::{c_void, FromBytesUntilNulError},
36     mem::size_of,
37     slice,
38     str::Utf8Error,
39 };
40 
41 pub use chain::{ChainPartitionDescriptor, ChainPartitionDescriptorFlags};
42 pub use commandline::{KernelCommandlineDescriptor, KernelCommandlineDescriptorFlags};
43 pub use hash::{HashDescriptor, HashDescriptorFlags};
44 pub use hashtree::{HashtreeDescriptor, HashtreeDescriptorFlags};
45 pub use property::PropertyDescriptor;
46 
47 /// A single descriptor.
48 #[derive(Debug, PartialEq, Eq)]
49 pub enum Descriptor<'a> {
50     /// Wraps `AvbPropertyDescriptor`.
51     Property(PropertyDescriptor<'a>),
52     /// Wraps `AvbHashtreeDescriptor`.
53     Hashtree(HashtreeDescriptor<'a>),
54     /// Wraps `AvbHashDescriptor`.
55     Hash(HashDescriptor<'a>),
56     /// Wraps `AvbKernelCmdlineDescriptor`.
57     KernelCommandline(KernelCommandlineDescriptor<'a>),
58     /// Wraps `AvbChainPartitionDescriptor`.
59     ChainPartition(ChainPartitionDescriptor<'a>),
60     /// Unknown descriptor type.
61     Unknown(&'a [u8]),
62 }
63 
64 /// Possible errors when extracting descriptors.
65 #[derive(Clone, Debug, PartialEq, Eq)]
66 pub enum DescriptorError {
67     /// libavb rejected the descriptor header.
68     InvalidHeader,
69     /// A value in the descriptor was invalid.
70     InvalidValue,
71     /// The descriptor claimed to be larger than the available data.
72     InvalidSize,
73     /// A field that was supposed to be valid UTF-8 was not.
74     InvalidUtf8,
75     /// Descriptor contents don't match what we expect.
76     InvalidContents,
77 }
78 
79 impl From<Utf8Error> for DescriptorError {
from(_: Utf8Error) -> Self80     fn from(_: Utf8Error) -> Self {
81         Self::InvalidUtf8
82     }
83 }
84 
85 impl From<FromBytesUntilNulError> for DescriptorError {
from(_: FromBytesUntilNulError) -> Self86     fn from(_: FromBytesUntilNulError) -> Self {
87         Self::InvalidContents
88     }
89 }
90 
91 /// `Result` type for `DescriptorError` errors.
92 pub type DescriptorResult<T> = Result<T, DescriptorError>;
93 
94 impl<'a> Descriptor<'a> {
95     /// Extracts the fully-typed descriptor from the generic `AvbDescriptor` header.
96     ///
97     /// # Arguments
98     /// * `raw_descriptor`: the raw `AvbDescriptor` pointing into the vbmeta image.
99     ///
100     /// # Returns
101     /// The fully-typed `Descriptor`, or `DescriptorError` if parsing the descriptor failed.
102     ///
103     /// # Safety
104     /// `raw_descriptor` must point to a valid `AvbDescriptor`, including the `num_bytes_following`
105     /// data contents, that lives at least as long as `'a`.
new(raw_descriptor: *const AvbDescriptor) -> DescriptorResult<Self>106     unsafe fn new(raw_descriptor: *const AvbDescriptor) -> DescriptorResult<Self> {
107         // Transform header to host-endian.
108         let mut descriptor = AvbDescriptor {
109             tag: 0,
110             num_bytes_following: 0,
111         };
112         // SAFETY: both args point to valid `AvbDescriptor` objects.
113         if !unsafe { avb_descriptor_validate_and_byteswap(raw_descriptor, &mut descriptor) } {
114             return Err(DescriptorError::InvalidHeader);
115         }
116 
117         // Extract the descriptor header and contents bytes. The descriptor sub-type headers
118         // include the top-level header as the first member, so we need to grab the entire
119         // descriptor including the top-level header.
120         let num_bytes_following = descriptor
121             .num_bytes_following
122             .try_into()
123             .map_err(|_| DescriptorError::InvalidValue)?;
124         let total_size = size_of::<AvbDescriptor>()
125             .checked_add(num_bytes_following)
126             .ok_or(DescriptorError::InvalidValue)?;
127 
128         // SAFETY: `raw_descriptor` points to the header plus `num_bytes_following` bytes.
129         let contents = unsafe { slice::from_raw_parts(raw_descriptor as *const u8, total_size) };
130 
131         match descriptor.tag.try_into() {
132             Ok(AvbDescriptorTag::AVB_DESCRIPTOR_TAG_PROPERTY) => {
133                 Ok(Descriptor::Property(PropertyDescriptor::new(contents)?))
134             }
135             Ok(AvbDescriptorTag::AVB_DESCRIPTOR_TAG_HASHTREE) => {
136                 Ok(Descriptor::Hashtree(HashtreeDescriptor::new(contents)?))
137             }
138             Ok(AvbDescriptorTag::AVB_DESCRIPTOR_TAG_HASH) => {
139                 Ok(Descriptor::Hash(HashDescriptor::new(contents)?))
140             }
141             Ok(AvbDescriptorTag::AVB_DESCRIPTOR_TAG_KERNEL_CMDLINE) => Ok(
142                 Descriptor::KernelCommandline(KernelCommandlineDescriptor::new(contents)?),
143             ),
144             Ok(AvbDescriptorTag::AVB_DESCRIPTOR_TAG_CHAIN_PARTITION) => Ok(
145                 Descriptor::ChainPartition(ChainPartitionDescriptor::new(contents)?),
146             ),
147             _ => Ok(Descriptor::Unknown(contents)),
148         }
149     }
150 }
151 
152 /// Returns a vector of descriptors extracted from the given vbmeta image.
153 ///
154 /// # Arguments
155 /// * `vbmeta`: the `VbmetaData` object to extract descriptors from.
156 ///
157 /// # Returns
158 /// The descriptors, or `DescriptorError` if any error occurred.
159 ///
160 /// # Safety
161 /// `vbmeta` must have been validated by `slot_verify()`.
get_descriptors(vbmeta: &VbmetaData) -> DescriptorResult<Vec<Descriptor>>162 pub(crate) unsafe fn get_descriptors(vbmeta: &VbmetaData) -> DescriptorResult<Vec<Descriptor>> {
163     let mut result = Ok(Vec::new());
164 
165     // Use `avb_descriptor_foreach()` to grab all the descriptor pointers in `vmbeta.data()`.
166     // This implementation processes all the descriptors immediately, so that any error is
167     // detected here and working with descriptors can be error-free.
168     //
169     // SAFETY:
170     // * the caller ensures that `vbmeta` has been validated by `slot_verify()`, which satisfies
171     //   the libavb `avb_vbmeta_image_verify()` requirement.
172     // * `avb_descriptor_foreach()` ensures the validity of each descriptor pointer passed to
173     //   the `fill_descriptors_vec()` callback.
174     // * our lifetimes guarantee that the raw descriptor data in `vbmeta` will remain unchanged for
175     //   the lifetime of the returned `Descriptor` objects.
176     // * the `user_data` param is a valid `DescriptorResult<Vec<Descriptor>>` with no other
177     //   concurrent access.
178     unsafe {
179         // We can ignore the return value of this function since we use the passed-in `result`
180         // to convey success/failure as well as more detailed error info.
181         avb_descriptor_foreach(
182             vbmeta.data().as_ptr(),
183             vbmeta.data().len(),
184             Some(fill_descriptors_vec),
185             &mut result as *mut _ as *mut c_void,
186         );
187     }
188 
189     result
190 }
191 
192 /// Adds the given descriptor to the `Vec` pointed to by `user_data`.
193 ///
194 /// Serves as a C callback for use with `avb_descriptor_foreach()`.
195 ///
196 /// # Returns
197 /// True on success, false on failure (which will stop iteration early).
198 ///
199 /// # Safety
200 /// * `descriptor` must point to a valid `AvbDescriptor`, including the `num_bytes_following`
201 ///   data contents, which remains valid and unmodified for the lifetime of the `Descriptor` objects
202 ///   in `user_data`.
203 /// * `user_data` must point to a valid `DescriptorResult<Vec<Descriptor>>` with no other concurrent
204 ///   access.
fill_descriptors_vec( descriptor: *const AvbDescriptor, user_data: *mut c_void, ) -> bool205 unsafe extern "C" fn fill_descriptors_vec(
206     descriptor: *const AvbDescriptor,
207     user_data: *mut c_void,
208 ) -> bool {
209     // SAFETY: `user_data` gives exclusive access to a valid `DescriptorResult<Vec<Descriptor>>`.
210     let result = unsafe { (user_data as *mut DescriptorResult<Vec<Descriptor>>).as_mut() };
211     // We can always unwrap here because we never pass a NULL pointer as `user_data`.
212     let result = result.unwrap();
213 
214     // SAFETY: caller ensures that `descriptor` points to a valid `AvbDescriptor` with header and
215     // body contents, which remains unmodified at least as long as the new `Descriptor`.
216     match unsafe { Descriptor::new(descriptor) } {
217         Ok(d) => {
218             // We can always unwrap here because this function will never be called with an error
219             // in `result`, since we stop iteration as soon as we encounter an error.
220             result.as_mut().unwrap().push(d);
221             true
222         }
223         Err(e) => {
224             // Set the error and stop iteration early.
225             *result = Err(e);
226             false
227         }
228     }
229 }
230 
231 #[cfg(test)]
232 mod tests {
233     use super::*;
234 
235     #[test]
new_unknown_descriptor()236     fn new_unknown_descriptor() {
237         // A fake descriptor which is valid but with an unknown tag.
238         let data: &[u8] = &[
239             0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, // tag = 0x42u64 (BE)
240             0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, // num_bytes_following = 8u64 (BE)
241             0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, // fake contents
242         ];
243 
244         // SAFETY: we've crafted a valid descriptor in `data`.
245         let descriptor = unsafe { Descriptor::new(data.as_ptr() as *const _) }.unwrap();
246 
247         let contents = match descriptor {
248             Descriptor::Unknown(c) => c,
249             d => panic!("Expected Unknown descriptor, got {d:?}"),
250         };
251         assert_eq!(data, contents);
252     }
253 
254     #[test]
new_invalid_descriptor_length_fails()255     fn new_invalid_descriptor_length_fails() {
256         // `avb_descriptor_validate_and_byteswap()` should detect and reject descriptors whose
257         // `num_bytes_following` is not 8-byte aligned.
258         let data: &[u8] = &[
259             0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, // tag = 0x42u64 (BE)
260             0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, // num_bytes_following = 7u64 (BE)
261             0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, // fake contents
262         ];
263 
264         assert_eq!(
265             // SAFETY: we've created an invalid descriptor in a way that should be detected and
266             // fail safely without triggering any undefined behavior.
267             unsafe { Descriptor::new(data.as_ptr() as *const _) }.unwrap_err(),
268             DescriptorError::InvalidHeader
269         );
270     }
271 }
272