1 // Copyright 2022, 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 use avb_bindgen::{
16     avb_descriptor_foreach, avb_descriptor_validate_and_byteswap,
17     avb_hashtree_descriptor_validate_and_byteswap, AvbDescriptor, AvbDescriptorTag,
18     AvbHashtreeDescriptor,
19 };
20 use std::ffi::c_void;
21 use std::mem::{size_of, MaybeUninit};
22 use std::slice;
23 
24 use super::VbMetaImageParseError;
25 
26 /// The descriptors from a VBMeta image.
27 pub struct Descriptors<'a> {
28     descriptors: Vec<Descriptor<'a>>,
29 }
30 
31 /// Enumeration of the possible descriptors.
32 #[allow(missing_docs)]
33 pub enum Descriptor<'a> {
34     Property(&'a [u8]),
35     Hashtree(&'a [u8]),
36     Hash(&'a [u8]),
37     KernelCmdline(&'a [u8]),
38     ChainPartition(&'a [u8]),
39     Unknown,
40 }
41 
42 /// A hashtree descriptor.
43 pub struct HashtreeDescriptor<'a> {
44     descriptor: AvbHashtreeDescriptor,
45     data: &'a [u8],
46 }
47 
48 impl Descriptors<'_> {
49     /// Find the descriptors in a well-formed VBMeta image.
from_image(data: &[u8]) -> Result<Descriptors<'_>, VbMetaImageParseError>50     pub(super) fn from_image(data: &[u8]) -> Result<Descriptors<'_>, VbMetaImageParseError> {
51         extern "C" fn desc_cb(descriptor: *const AvbDescriptor, user_data: *mut c_void) -> bool {
52             // SAFETY: libavb gives a good pointer for us to work with.
53             let desc = unsafe {
54                 let mut desc = MaybeUninit::uninit();
55                 if !avb_descriptor_validate_and_byteswap(descriptor, desc.as_mut_ptr()) {
56                     return false;
57                 }
58                 desc.assume_init()
59             };
60             // SAFETY: the descriptor has been validated so it is contained within the image.
61             let data = unsafe {
62                 slice::from_raw_parts(
63                     descriptor as *const _ as *const u8,
64                     size_of::<AvbDescriptor>() + desc.num_bytes_following as usize,
65                 )
66             };
67             // SAFETY: this cast gets a reference to the Vec passed as the user_data below.
68             let descriptors = unsafe { &mut *(user_data as *mut Vec<Descriptor>) };
69             descriptors.push(match desc.tag.try_into() {
70                 Ok(AvbDescriptorTag::AVB_DESCRIPTOR_TAG_PROPERTY) => Descriptor::Property(data),
71                 Ok(AvbDescriptorTag::AVB_DESCRIPTOR_TAG_HASHTREE) => Descriptor::Hashtree(data),
72                 Ok(AvbDescriptorTag::AVB_DESCRIPTOR_TAG_HASH) => Descriptor::Hash(data),
73                 Ok(AvbDescriptorTag::AVB_DESCRIPTOR_TAG_KERNEL_CMDLINE) => {
74                     Descriptor::KernelCmdline(data)
75                 }
76                 Ok(AvbDescriptorTag::AVB_DESCRIPTOR_TAG_CHAIN_PARTITION) => {
77                     Descriptor::ChainPartition(data)
78                 }
79                 _ => Descriptor::Unknown,
80             });
81             true
82         }
83 
84         let mut descriptors = Vec::new();
85         // SAFETY: the function only reads from the provided data and passes the Vec pointer to the
86         // callback function, treating it as an opaque handle. The descriptors added to the Vec are
87         // contained within the provided data so the lifetime is bound accordingly.
88         if unsafe {
89             let desc = &mut descriptors as *mut _ as *mut c_void;
90             avb_descriptor_foreach(data.as_ptr(), data.len(), Some(desc_cb), desc)
91         } {
92             Ok(Descriptors { descriptors })
93         } else {
94             Err(VbMetaImageParseError::InvalidDescriptor)
95         }
96     }
97 
98     /// Get an iterator over the descriptors.
iter(&self) -> slice::Iter<Descriptor>99     pub fn iter(&self) -> slice::Iter<Descriptor> {
100         self.descriptors.iter()
101     }
102 }
103 
104 impl<'a> IntoIterator for Descriptors<'a> {
105     type Item = Descriptor<'a>;
106     type IntoIter = std::vec::IntoIter<Self::Item>;
107 
into_iter(self) -> Self::IntoIter108     fn into_iter(self) -> Self::IntoIter {
109         self.descriptors.into_iter()
110     }
111 }
112 
113 impl Descriptor<'_> {
114     /// Parse the descriptor as a hashtree descriptor.
to_hashtree(&self) -> Result<HashtreeDescriptor, VbMetaImageParseError>115     pub fn to_hashtree(&self) -> Result<HashtreeDescriptor, VbMetaImageParseError> {
116         match self {
117             Self::Hashtree(data) => {
118                 // SAFETY: data contains the entire descriptor.
119                 let descriptor = unsafe {
120                     let mut desc = MaybeUninit::uninit();
121                     let src = data.as_ptr() as *const _ as *const AvbHashtreeDescriptor;
122                     if !avb_hashtree_descriptor_validate_and_byteswap(src, desc.as_mut_ptr()) {
123                         return Err(VbMetaImageParseError::InvalidDescriptor);
124                     }
125                     desc.assume_init()
126                 };
127                 Ok(HashtreeDescriptor { descriptor, data })
128             }
129             _ => Err(VbMetaImageParseError::InvalidDescriptor),
130         }
131     }
132 
133     // TODO: handle other descriptor type as required
134 }
135 
136 impl HashtreeDescriptor<'_> {
137     /// Get the root digest of the hashtree.
root_digest(&self) -> &[u8]138     pub fn root_digest(&self) -> &[u8] {
139         let begin = size_of::<AvbHashtreeDescriptor>()
140             + self.descriptor.partition_name_len as usize
141             + self.descriptor.salt_len as usize;
142         let end = begin + self.descriptor.root_digest_len as usize;
143         &self.data[begin..end]
144     }
145 
146     // TODO: expose other fields as required
147 }
148