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