blob: cd623ac4eeeac1e3854d3b01012fd206c5d225c2 [file] [log] [blame]
Alice Wangf2752862023-01-18 11:51:25 +00001// 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//! Structs and functions relating to the descriptors.
16
Alice Wangf2752862023-01-18 11:51:25 +000017use crate::error::{AvbIOError, AvbSlotVerifyError};
18use crate::partition::PartitionName;
19use crate::utils::{self, is_not_null, to_nonnull, to_usize, usize_checked_add};
20use avb_bindgen::{
21 avb_descriptor_foreach, avb_hash_descriptor_validate_and_byteswap, AvbDescriptor,
22 AvbHashDescriptor, AvbVBMetaData, AVB_SHA256_DIGEST_SIZE,
23};
24use core::{
25 ffi::c_void,
26 mem::{size_of, MaybeUninit},
27 ops::Range,
28 slice,
29};
30use tinyvec::ArrayVec;
31
Alice Wang1f0add02023-01-23 16:22:53 +000032/// Digest type for kernel and initrd.
33pub type Digest = [u8; AVB_SHA256_DIGEST_SIZE as usize];
Alice Wangf2752862023-01-18 11:51:25 +000034
35/// `HashDescriptors` can have maximum one `HashDescriptor` per known partition.
36#[derive(Default)]
37pub(crate) struct HashDescriptors(
38 ArrayVec<[HashDescriptor; PartitionName::NUM_OF_KNOWN_PARTITIONS]>,
39);
40
41impl HashDescriptors {
42 /// Builds `HashDescriptors` from `AvbVBMetaData`.
43 /// Returns an error if the given `AvbVBMetaData` contains non-hash descriptor, hash
44 /// descriptor of unknown `PartitionName` or duplicated hash descriptors.
45 ///
46 /// # Safety
47 ///
48 /// Behavior is undefined if any of the following conditions are violated:
49 /// * `vbmeta.vbmeta_data` must be non-null and points to a valid VBMeta.
50 /// * `vbmeta.vbmeta_data` must be valid for reading `vbmeta.vbmeta_size` bytes.
51 pub(crate) unsafe fn from_vbmeta(vbmeta: AvbVBMetaData) -> Result<Self, AvbSlotVerifyError> {
52 is_not_null(vbmeta.vbmeta_data).map_err(|_| AvbSlotVerifyError::Io)?;
53 let mut descriptors = Self::default();
54 // SAFETY: It is safe as the raw pointer `vbmeta.vbmeta_data` is a non-null pointer and
55 // points to a valid VBMeta structure.
56 if !unsafe {
57 avb_descriptor_foreach(
58 vbmeta.vbmeta_data,
59 vbmeta.vbmeta_size,
60 Some(check_and_save_descriptor),
61 &mut descriptors as *mut _ as *mut c_void,
62 )
63 } {
64 return Err(AvbSlotVerifyError::InvalidMetadata);
65 }
66 Ok(descriptors)
67 }
68
69 fn push(&mut self, descriptor: HashDescriptor) -> utils::Result<()> {
70 if self.0.iter().any(|d| d.partition_name_eq(&descriptor)) {
71 return Err(AvbIOError::Io);
72 }
73 self.0.push(descriptor);
74 Ok(())
75 }
76
77 pub(crate) fn len(&self) -> usize {
78 self.0.len()
79 }
80
81 /// Finds the `HashDescriptor` for the given `PartitionName`.
82 /// Throws an error if no corresponding descriptor found.
83 pub(crate) fn find(
84 &self,
85 partition_name: PartitionName,
86 ) -> Result<&HashDescriptor, AvbSlotVerifyError> {
87 self.0
88 .iter()
89 .find(|d| d.partition_name == partition_name)
90 .ok_or(AvbSlotVerifyError::InvalidMetadata)
91 }
92}
93
94/// # Safety
95///
96/// Behavior is undefined if any of the following conditions are violated:
97/// * The `descriptor` pointer must be non-null and points to a valid `AvbDescriptor` struct.
98/// * The `user_data` pointer must be non-null and points to a valid `HashDescriptors` struct.
99unsafe extern "C" fn check_and_save_descriptor(
100 descriptor: *const AvbDescriptor,
101 user_data: *mut c_void,
102) -> bool {
103 // SAFETY: It is safe because the caller must ensure that the `descriptor` pointer and
104 // the `user_data` are non-null and valid.
105 unsafe { try_check_and_save_descriptor(descriptor, user_data).is_ok() }
106}
107
108/// # Safety
109///
110/// Behavior is undefined if any of the following conditions are violated:
111/// * The `descriptor` pointer must be non-null and points to a valid `AvbDescriptor` struct.
112/// * The `user_data` pointer must be non-null and points to a valid `HashDescriptors` struct.
113unsafe fn try_check_and_save_descriptor(
114 descriptor: *const AvbDescriptor,
115 user_data: *mut c_void,
116) -> utils::Result<()> {
117 is_not_null(descriptor)?;
118 // SAFETY: It is safe because the caller ensures that `descriptor` is a non-null pointer
119 // pointing to a valid struct.
120 let desc = unsafe { AvbHashDescriptorWrap::from_descriptor_ptr(descriptor)? };
121 // SAFETY: It is safe because the caller ensures that `descriptor` is a non-null pointer
122 // pointing to a valid struct.
123 let data = unsafe { slice::from_raw_parts(descriptor as *const u8, desc.len()?) };
124 let mut descriptors = to_nonnull(user_data as *mut HashDescriptors)?;
125 // SAFETY: It is safe because the caller ensures that `user_data` is a non-null pointer
126 // pointing to a valid struct.
127 let descriptors = unsafe { descriptors.as_mut() };
128 descriptors.push(HashDescriptor::new(&desc, data)?)
129}
130
131#[derive(Default)]
132pub(crate) struct HashDescriptor {
133 partition_name: PartitionName,
Alice Wang1f0add02023-01-23 16:22:53 +0000134 pub(crate) digest: Digest,
Alice Wangf2752862023-01-18 11:51:25 +0000135}
136
137impl HashDescriptor {
138 fn new(desc: &AvbHashDescriptorWrap, data: &[u8]) -> utils::Result<Self> {
139 let partition_name = data
140 .get(desc.partition_name_range()?)
141 .ok_or(AvbIOError::RangeOutsidePartition)?
142 .try_into()?;
143 let partition_digest =
144 data.get(desc.digest_range()?).ok_or(AvbIOError::RangeOutsidePartition)?;
Alice Wang1f0add02023-01-23 16:22:53 +0000145 let mut digest = [0u8; size_of::<Digest>()];
Alice Wangf2752862023-01-18 11:51:25 +0000146 digest.copy_from_slice(partition_digest);
147 Ok(Self { partition_name, digest })
148 }
149
150 fn partition_name_eq(&self, other: &HashDescriptor) -> bool {
151 self.partition_name == other.partition_name
152 }
153}
154
155/// `AvbHashDescriptor` contains the metadata for the given descriptor.
156struct AvbHashDescriptorWrap(AvbHashDescriptor);
157
158impl AvbHashDescriptorWrap {
159 /// # Safety
160 ///
161 /// Behavior is undefined if any of the following conditions are violated:
162 /// * The `descriptor` pointer must be non-null and point to a valid `AvbDescriptor`.
163 unsafe fn from_descriptor_ptr(descriptor: *const AvbDescriptor) -> utils::Result<Self> {
164 is_not_null(descriptor)?;
165 // SAFETY: It is safe as the raw pointer `descriptor` is non-null and points to
166 // a valid `AvbDescriptor`.
167 let desc = unsafe {
168 let mut desc = MaybeUninit::uninit();
169 if !avb_hash_descriptor_validate_and_byteswap(
170 descriptor as *const AvbHashDescriptor,
171 desc.as_mut_ptr(),
172 ) {
173 return Err(AvbIOError::Io);
174 }
175 desc.assume_init()
176 };
177 Ok(Self(desc))
178 }
179
180 fn len(&self) -> utils::Result<usize> {
181 usize_checked_add(
182 size_of::<AvbDescriptor>(),
183 to_usize(self.0.parent_descriptor.num_bytes_following)?,
184 )
185 }
186
187 fn partition_name_end(&self) -> utils::Result<usize> {
188 usize_checked_add(size_of::<AvbHashDescriptor>(), to_usize(self.0.partition_name_len)?)
189 }
190
191 fn partition_name_range(&self) -> utils::Result<Range<usize>> {
192 let start = size_of::<AvbHashDescriptor>();
193 Ok(start..(self.partition_name_end()?))
194 }
195
196 fn digest_range(&self) -> utils::Result<Range<usize>> {
197 let start = usize_checked_add(self.partition_name_end()?, to_usize(self.0.salt_len)?)?;
198 let end = usize_checked_add(start, to_usize(self.0.digest_len)?)?;
199 Ok(start..end)
200 }
201}