Alice Wang | 167ab3f | 2023-01-23 13:39: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 | |
David Pursell | b59bcc4 | 2023-11-10 16:59:19 -0800 | [diff] [blame] | 15 | //! Structs and functions relating to AVB callback operations. |
Alice Wang | 167ab3f | 2023-01-23 13:39:25 +0000 | [diff] [blame] | 16 | |
Alice Wang | 167ab3f | 2023-01-23 13:39:25 +0000 | [diff] [blame] | 17 | use crate::partition::PartitionName; |
David Pursell | b59bcc4 | 2023-11-10 16:59:19 -0800 | [diff] [blame] | 18 | use avb::{ |
| 19 | slot_verify, HashtreeErrorMode, IoError, IoResult, PublicKeyForPartitionInfo, SlotVerifyData, |
| 20 | SlotVerifyFlags, SlotVerifyResult, |
Alice Wang | 167ab3f | 2023-01-23 13:39:25 +0000 | [diff] [blame] | 21 | }; |
David Pursell | b59bcc4 | 2023-11-10 16:59:19 -0800 | [diff] [blame] | 22 | use core::ffi::CStr; |
Alice Wang | 167ab3f | 2023-01-23 13:39:25 +0000 | [diff] [blame] | 23 | |
| 24 | pub(crate) struct Payload<'a> { |
| 25 | kernel: &'a [u8], |
| 26 | initrd: Option<&'a [u8]>, |
| 27 | trusted_public_key: &'a [u8], |
| 28 | } |
| 29 | |
Alice Wang | 167ab3f | 2023-01-23 13:39:25 +0000 | [diff] [blame] | 30 | impl<'a> Payload<'a> { |
| 31 | pub(crate) fn new( |
| 32 | kernel: &'a [u8], |
| 33 | initrd: Option<&'a [u8]>, |
| 34 | trusted_public_key: &'a [u8], |
| 35 | ) -> Self { |
| 36 | Self { kernel, initrd, trusted_public_key } |
| 37 | } |
| 38 | |
David Pursell | b59bcc4 | 2023-11-10 16:59:19 -0800 | [diff] [blame] | 39 | fn get_partition(&self, partition_name: &CStr) -> IoResult<&[u8]> { |
Alice Wang | 167ab3f | 2023-01-23 13:39:25 +0000 | [diff] [blame] | 40 | match partition_name.try_into()? { |
| 41 | PartitionName::Kernel => Ok(self.kernel), |
| 42 | PartitionName::InitrdNormal | PartitionName::InitrdDebug => { |
David Pursell | b59bcc4 | 2023-11-10 16:59:19 -0800 | [diff] [blame] | 43 | self.initrd.ok_or(IoError::NoSuchPartition) |
Alice Wang | 167ab3f | 2023-01-23 13:39:25 +0000 | [diff] [blame] | 44 | } |
| 45 | } |
| 46 | } |
| 47 | } |
| 48 | |
David Pursell | b59bcc4 | 2023-11-10 16:59:19 -0800 | [diff] [blame] | 49 | /// Pvmfw customized operations used in the verification. |
| 50 | pub(crate) struct Ops<'a> { |
| 51 | payload: &'a Payload<'a>, |
Alice Wang | 167ab3f | 2023-01-23 13:39:25 +0000 | [diff] [blame] | 52 | } |
| 53 | |
David Pursell | b59bcc4 | 2023-11-10 16:59:19 -0800 | [diff] [blame] | 54 | impl<'a> Ops<'a> { |
| 55 | pub(crate) fn new(payload: &'a Payload<'a>) -> Self { |
| 56 | Self { payload } |
| 57 | } |
| 58 | |
Alice Wang | 167ab3f | 2023-01-23 13:39:25 +0000 | [diff] [blame] | 59 | pub(crate) fn verify_partition( |
| 60 | &mut self, |
| 61 | partition_name: &CStr, |
David Pursell | 09bfc85 | 2024-02-02 11:24:24 -0800 | [diff] [blame] | 62 | ) -> SlotVerifyResult<SlotVerifyData<'a>> { |
Pierre-Clément Tosi | 781afee | 2025-01-27 20:51:27 +0000 | [diff] [blame] | 63 | // Note that this call manages to verify the initrd images using hashes contained in the |
| 64 | // (unique) VBMeta from the end of self.kernel because if |
| 65 | // |
| 66 | // - read_from_partition("vbmeta") returns AVB_IO_RESULT_ERROR_NO_SUCH_PARTITION and |
| 67 | // - we do NOT pass AVB_SLOT_VERIFY_FLAGS_NO_VBMETA_PARTITION to slot_verify() |
| 68 | // |
| 69 | // then libavb (specifically, avb_slot_verify()) falls back to retrieving VBMeta from the |
| 70 | // footer of the "boot" partition i.e. self.kernel (see PartitionName::Kernel). |
David Pursell | b59bcc4 | 2023-11-10 16:59:19 -0800 | [diff] [blame] | 71 | slot_verify( |
| 72 | self, |
| 73 | &[partition_name], |
| 74 | None, // No partition slot suffix. |
| 75 | SlotVerifyFlags::AVB_SLOT_VERIFY_FLAGS_NONE, |
| 76 | HashtreeErrorMode::AVB_HASHTREE_ERROR_MODE_RESTART_AND_INVALIDATE, |
| 77 | ) |
Alice Wang | 167ab3f | 2023-01-23 13:39:25 +0000 | [diff] [blame] | 78 | } |
| 79 | } |
| 80 | |
David Pursell | 09bfc85 | 2024-02-02 11:24:24 -0800 | [diff] [blame] | 81 | impl<'a> avb::Ops<'a> for Ops<'a> { |
David Pursell | b59bcc4 | 2023-11-10 16:59:19 -0800 | [diff] [blame] | 82 | fn read_from_partition( |
| 83 | &mut self, |
| 84 | partition: &CStr, |
| 85 | offset: i64, |
| 86 | buffer: &mut [u8], |
| 87 | ) -> IoResult<usize> { |
| 88 | let partition = self.payload.get_partition(partition)?; |
| 89 | copy_data_to_dst(partition, offset, buffer)?; |
| 90 | Ok(buffer.len()) |
| 91 | } |
| 92 | |
David Pursell | 09bfc85 | 2024-02-02 11:24:24 -0800 | [diff] [blame] | 93 | fn get_preloaded_partition(&mut self, partition: &CStr) -> IoResult<&'a [u8]> { |
David Pursell | b59bcc4 | 2023-11-10 16:59:19 -0800 | [diff] [blame] | 94 | self.payload.get_partition(partition) |
| 95 | } |
| 96 | |
| 97 | fn validate_vbmeta_public_key( |
| 98 | &mut self, |
| 99 | public_key: &[u8], |
| 100 | _public_key_metadata: Option<&[u8]>, |
| 101 | ) -> IoResult<bool> { |
| 102 | // The public key metadata is not used when we build the VBMeta. |
| 103 | Ok(self.payload.trusted_public_key == public_key) |
| 104 | } |
| 105 | |
| 106 | fn read_rollback_index(&mut self, _rollback_index_location: usize) -> IoResult<u64> { |
| 107 | // TODO(291213394) : Refine this comment once capability for rollback protection is defined. |
| 108 | // pvmfw does not compare stored_rollback_index with rollback_index for Antirollback |
| 109 | // protection. Hence, we set `out_rollback_index` to 0 to ensure that the rollback_index |
| 110 | // (including default: 0) is never smaller than it, thus the rollback index check will pass. |
| 111 | Ok(0) |
| 112 | } |
| 113 | |
| 114 | fn write_rollback_index( |
| 115 | &mut self, |
| 116 | _rollback_index_location: usize, |
| 117 | _index: u64, |
| 118 | ) -> IoResult<()> { |
| 119 | Err(IoError::NotImplemented) |
| 120 | } |
| 121 | |
| 122 | fn read_is_device_unlocked(&mut self) -> IoResult<bool> { |
| 123 | Ok(false) |
| 124 | } |
| 125 | |
| 126 | fn get_size_of_partition(&mut self, partition: &CStr) -> IoResult<u64> { |
| 127 | let partition = self.payload.get_partition(partition)?; |
| 128 | u64::try_from(partition.len()).map_err(|_| IoError::InvalidValueSize) |
| 129 | } |
| 130 | |
| 131 | fn read_persistent_value(&mut self, _name: &CStr, _value: &mut [u8]) -> IoResult<usize> { |
| 132 | Err(IoError::NotImplemented) |
| 133 | } |
| 134 | |
| 135 | fn write_persistent_value(&mut self, _name: &CStr, _value: &[u8]) -> IoResult<()> { |
| 136 | Err(IoError::NotImplemented) |
| 137 | } |
| 138 | |
| 139 | fn erase_persistent_value(&mut self, _name: &CStr) -> IoResult<()> { |
| 140 | Err(IoError::NotImplemented) |
| 141 | } |
| 142 | |
| 143 | fn validate_public_key_for_partition( |
| 144 | &mut self, |
| 145 | _partition: &CStr, |
| 146 | _public_key: &[u8], |
| 147 | _public_key_metadata: Option<&[u8]>, |
| 148 | ) -> IoResult<PublicKeyForPartitionInfo> { |
| 149 | Err(IoError::NotImplemented) |
| 150 | } |
Alice Wang | 167ab3f | 2023-01-23 13:39:25 +0000 | [diff] [blame] | 151 | } |
| 152 | |
David Pursell | b59bcc4 | 2023-11-10 16:59:19 -0800 | [diff] [blame] | 153 | fn copy_data_to_dst(src: &[u8], offset: i64, dst: &mut [u8]) -> IoResult<()> { |
| 154 | let start = to_copy_start(offset, src.len()).ok_or(IoError::InvalidValueSize)?; |
| 155 | let end = start.checked_add(dst.len()).ok_or(IoError::InvalidValueSize)?; |
| 156 | dst.copy_from_slice(src.get(start..end).ok_or(IoError::RangeOutsidePartition)?); |
Alice Wang | 167ab3f | 2023-01-23 13:39:25 +0000 | [diff] [blame] | 157 | Ok(()) |
| 158 | } |
| 159 | |
| 160 | fn to_copy_start(offset: i64, len: usize) -> Option<usize> { |
| 161 | usize::try_from(offset) |
| 162 | .ok() |
| 163 | .or_else(|| isize::try_from(offset).ok().and_then(|v| len.checked_add_signed(v))) |
| 164 | } |