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