blob: 10484ffa3526928940fb1e771b6f4b27638444c4 [file] [log] [blame]
Andrew Scull38127252022-06-13 13:11:00 +00001// 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
15use avb_bindgen::{
16 avb_descriptor_foreach, avb_descriptor_validate_and_byteswap,
17 avb_hashtree_descriptor_validate_and_byteswap, AvbDescriptor, AvbHashtreeDescriptor,
18};
19use std::ffi::c_void;
20use std::mem::{size_of, MaybeUninit};
21use std::slice;
22
23use super::VbMetaImageParseError;
24
25// TODO: import these with bindgen
26const AVB_DESCRIPTOR_TAG_PROPERTY: u64 = 0;
27const AVB_DESCRIPTOR_TAG_HASHTREE: u64 = 1;
28const AVB_DESCRIPTOR_TAG_HASH: u64 = 2;
29const AVB_DESCRIPTOR_TAG_KERNEL_CMDLINE: u64 = 3;
30const AVB_DESCRIPTOR_TAG_CHAIN_PARTITION: u64 = 4;
31
32/// The descriptors from a VBMeta image.
33pub struct Descriptors<'a> {
34 descriptors: Vec<Descriptor<'a>>,
35}
36
37/// Enumeration of the possible descriptors.
38#[allow(missing_docs)]
39pub 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.
49pub struct HashtreeDescriptor<'a> {
50 descriptor: AvbHashtreeDescriptor,
51 data: &'a [u8],
52}
53
54impl Descriptors<'_> {
55 /// Find the descriptors in a well-formed VBMeta image.
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.
101 pub fn iter(&self) -> slice::Iter<Descriptor> {
102 self.descriptors.iter()
103 }
104}
105
106impl<'a> IntoIterator for Descriptors<'a> {
107 type Item = Descriptor<'a>;
108 type IntoIter = std::vec::IntoIter<Self::Item>;
109
110 fn into_iter(self) -> Self::IntoIter {
111 self.descriptors.into_iter()
112 }
113}
114
115impl Descriptor<'_> {
116 /// Parse the descriptor as a hashtree descriptor.
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
138impl HashtreeDescriptor<'_> {
139 /// Get the root digest of the hashtree.
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}