• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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         // 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).
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         )
78     }
79 }
80 
81 impl<'a> avb::Ops<'a> for Ops<'a> {
read_from_partition( &mut self, partition: &CStr, offset: i64, buffer: &mut [u8], ) -> IoResult<usize>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 
get_preloaded_partition(&mut self, partition: &CStr) -> IoResult<&'a [u8]>93     fn get_preloaded_partition(&mut self, partition: &CStr) -> IoResult<&'a [u8]> {
94         self.payload.get_partition(partition)
95     }
96 
validate_vbmeta_public_key( &mut self, public_key: &[u8], _public_key_metadata: Option<&[u8]>, ) -> IoResult<bool>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 
read_rollback_index(&mut self, _rollback_index_location: usize) -> IoResult<u64>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 
write_rollback_index( &mut self, _rollback_index_location: usize, _index: u64, ) -> IoResult<()>114     fn write_rollback_index(
115         &mut self,
116         _rollback_index_location: usize,
117         _index: u64,
118     ) -> IoResult<()> {
119         Err(IoError::NotImplemented)
120     }
121 
read_is_device_unlocked(&mut self) -> IoResult<bool>122     fn read_is_device_unlocked(&mut self) -> IoResult<bool> {
123         Ok(false)
124     }
125 
get_size_of_partition(&mut self, partition: &CStr) -> IoResult<u64>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 
read_persistent_value(&mut self, _name: &CStr, _value: &mut [u8]) -> IoResult<usize>131     fn read_persistent_value(&mut self, _name: &CStr, _value: &mut [u8]) -> IoResult<usize> {
132         Err(IoError::NotImplemented)
133     }
134 
write_persistent_value(&mut self, _name: &CStr, _value: &[u8]) -> IoResult<()>135     fn write_persistent_value(&mut self, _name: &CStr, _value: &[u8]) -> IoResult<()> {
136         Err(IoError::NotImplemented)
137     }
138 
erase_persistent_value(&mut self, _name: &CStr) -> IoResult<()>139     fn erase_persistent_value(&mut self, _name: &CStr) -> IoResult<()> {
140         Err(IoError::NotImplemented)
141     }
142 
validate_public_key_for_partition( &mut self, _partition: &CStr, _public_key: &[u8], _public_key_metadata: Option<&[u8]>, ) -> IoResult<PublicKeyForPartitionInfo>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     }
151 }
152 
copy_data_to_dst(src: &[u8], offset: i64, dst: &mut [u8]) -> IoResult<()>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)?);
157     Ok(())
158 }
159 
to_copy_start(offset: i64, len: usize) -> Option<usize>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 }
165