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 AVB callback operations.
16
17 use crate::partition::PartitionName;
18 use avb::{
19 slot_verify, HashtreeErrorMode, IoError, IoResult, PublicKeyForPartitionInfo, SlotVerifyData,
20 SlotVerifyFlags, SlotVerifyResult,
21 };
22 use core::ffi::CStr;
23
24 pub(crate) struct Payload<'a> {
25 kernel: &'a [u8],
26 initrd: Option<&'a [u8]>,
27 trusted_public_key: &'a [u8],
28 }
29
30 impl<'a> Payload<'a> {
new( kernel: &'a [u8], initrd: Option<&'a [u8]>, trusted_public_key: &'a [u8], ) -> Self31 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
get_partition(&self, partition_name: &CStr) -> IoResult<&[u8]>39 fn get_partition(&self, partition_name: &CStr) -> IoResult<&[u8]> {
40 match partition_name.try_into()? {
41 PartitionName::Kernel => Ok(self.kernel),
42 PartitionName::InitrdNormal | PartitionName::InitrdDebug => {
43 self.initrd.ok_or(IoError::NoSuchPartition)
44 }
45 }
46 }
47 }
48
49 /// Pvmfw customized operations used in the verification.
50 pub(crate) struct Ops<'a> {
51 payload: &'a Payload<'a>,
52 }
53
54 impl<'a> Ops<'a> {
new(payload: &'a Payload<'a>) -> Self55 pub(crate) fn new(payload: &'a Payload<'a>) -> Self {
56 Self { payload }
57 }
58
verify_partition( &mut self, partition_name: &CStr, ) -> SlotVerifyResult<SlotVerifyData<'a>>59 pub(crate) fn verify_partition(
60 &mut self,
61 partition_name: &CStr,
62 ) -> SlotVerifyResult<SlotVerifyData<'a>> {
63 slot_verify(
64 self,
65 &[partition_name],
66 None, // No partition slot suffix.
67 SlotVerifyFlags::AVB_SLOT_VERIFY_FLAGS_NONE,
68 HashtreeErrorMode::AVB_HASHTREE_ERROR_MODE_RESTART_AND_INVALIDATE,
69 )
70 }
71 }
72
73 impl<'a> avb::Ops<'a> for Ops<'a> {
read_from_partition( &mut self, partition: &CStr, offset: i64, buffer: &mut [u8], ) -> IoResult<usize>74 fn read_from_partition(
75 &mut self,
76 partition: &CStr,
77 offset: i64,
78 buffer: &mut [u8],
79 ) -> IoResult<usize> {
80 let partition = self.payload.get_partition(partition)?;
81 copy_data_to_dst(partition, offset, buffer)?;
82 Ok(buffer.len())
83 }
84
get_preloaded_partition(&mut self, partition: &CStr) -> IoResult<&'a [u8]>85 fn get_preloaded_partition(&mut self, partition: &CStr) -> IoResult<&'a [u8]> {
86 self.payload.get_partition(partition)
87 }
88
validate_vbmeta_public_key( &mut self, public_key: &[u8], _public_key_metadata: Option<&[u8]>, ) -> IoResult<bool>89 fn validate_vbmeta_public_key(
90 &mut self,
91 public_key: &[u8],
92 _public_key_metadata: Option<&[u8]>,
93 ) -> IoResult<bool> {
94 // The public key metadata is not used when we build the VBMeta.
95 Ok(self.payload.trusted_public_key == public_key)
96 }
97
read_rollback_index(&mut self, _rollback_index_location: usize) -> IoResult<u64>98 fn read_rollback_index(&mut self, _rollback_index_location: usize) -> IoResult<u64> {
99 // TODO(291213394) : Refine this comment once capability for rollback protection is defined.
100 // pvmfw does not compare stored_rollback_index with rollback_index for Antirollback
101 // protection. Hence, we set `out_rollback_index` to 0 to ensure that the rollback_index
102 // (including default: 0) is never smaller than it, thus the rollback index check will pass.
103 Ok(0)
104 }
105
write_rollback_index( &mut self, _rollback_index_location: usize, _index: u64, ) -> IoResult<()>106 fn write_rollback_index(
107 &mut self,
108 _rollback_index_location: usize,
109 _index: u64,
110 ) -> IoResult<()> {
111 Err(IoError::NotImplemented)
112 }
113
read_is_device_unlocked(&mut self) -> IoResult<bool>114 fn read_is_device_unlocked(&mut self) -> IoResult<bool> {
115 Ok(false)
116 }
117
get_size_of_partition(&mut self, partition: &CStr) -> IoResult<u64>118 fn get_size_of_partition(&mut self, partition: &CStr) -> IoResult<u64> {
119 let partition = self.payload.get_partition(partition)?;
120 u64::try_from(partition.len()).map_err(|_| IoError::InvalidValueSize)
121 }
122
read_persistent_value(&mut self, _name: &CStr, _value: &mut [u8]) -> IoResult<usize>123 fn read_persistent_value(&mut self, _name: &CStr, _value: &mut [u8]) -> IoResult<usize> {
124 Err(IoError::NotImplemented)
125 }
126
write_persistent_value(&mut self, _name: &CStr, _value: &[u8]) -> IoResult<()>127 fn write_persistent_value(&mut self, _name: &CStr, _value: &[u8]) -> IoResult<()> {
128 Err(IoError::NotImplemented)
129 }
130
erase_persistent_value(&mut self, _name: &CStr) -> IoResult<()>131 fn erase_persistent_value(&mut self, _name: &CStr) -> IoResult<()> {
132 Err(IoError::NotImplemented)
133 }
134
validate_public_key_for_partition( &mut self, _partition: &CStr, _public_key: &[u8], _public_key_metadata: Option<&[u8]>, ) -> IoResult<PublicKeyForPartitionInfo>135 fn validate_public_key_for_partition(
136 &mut self,
137 _partition: &CStr,
138 _public_key: &[u8],
139 _public_key_metadata: Option<&[u8]>,
140 ) -> IoResult<PublicKeyForPartitionInfo> {
141 Err(IoError::NotImplemented)
142 }
143 }
144
copy_data_to_dst(src: &[u8], offset: i64, dst: &mut [u8]) -> IoResult<()>145 fn copy_data_to_dst(src: &[u8], offset: i64, dst: &mut [u8]) -> IoResult<()> {
146 let start = to_copy_start(offset, src.len()).ok_or(IoError::InvalidValueSize)?;
147 let end = start.checked_add(dst.len()).ok_or(IoError::InvalidValueSize)?;
148 dst.copy_from_slice(src.get(start..end).ok_or(IoError::RangeOutsidePartition)?);
149 Ok(())
150 }
151
to_copy_start(offset: i64, len: usize) -> Option<usize>152 fn to_copy_start(offset: i64, len: usize) -> Option<usize> {
153 usize::try_from(offset)
154 .ok()
155 .or_else(|| isize::try_from(offset).ok().and_then(|v| len.checked_add_signed(v)))
156 }
157