blob: 780e23b10951e45d887d5c0508eef2525826cca9 [file] [log] [blame]
Alice Wang167ab3f2023-01-23 13:39: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
David Pursellb59bcc42023-11-10 16:59:19 -080015//! Structs and functions relating to AVB callback operations.
Alice Wang167ab3f2023-01-23 13:39:25 +000016
Alice Wang167ab3f2023-01-23 13:39:25 +000017use crate::partition::PartitionName;
David Pursellb59bcc42023-11-10 16:59:19 -080018use avb::{
19 slot_verify, HashtreeErrorMode, IoError, IoResult, PublicKeyForPartitionInfo, SlotVerifyData,
20 SlotVerifyFlags, SlotVerifyResult,
Alice Wang167ab3f2023-01-23 13:39:25 +000021};
David Pursellb59bcc42023-11-10 16:59:19 -080022use core::ffi::CStr;
Alice Wang167ab3f2023-01-23 13:39:25 +000023
24pub(crate) struct Payload<'a> {
25 kernel: &'a [u8],
26 initrd: Option<&'a [u8]>,
27 trusted_public_key: &'a [u8],
28}
29
Alice Wang167ab3f2023-01-23 13:39:25 +000030impl<'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 Pursellb59bcc42023-11-10 16:59:19 -080039 fn get_partition(&self, partition_name: &CStr) -> IoResult<&[u8]> {
Alice Wang167ab3f2023-01-23 13:39:25 +000040 match partition_name.try_into()? {
41 PartitionName::Kernel => Ok(self.kernel),
42 PartitionName::InitrdNormal | PartitionName::InitrdDebug => {
David Pursellb59bcc42023-11-10 16:59:19 -080043 self.initrd.ok_or(IoError::NoSuchPartition)
Alice Wang167ab3f2023-01-23 13:39:25 +000044 }
45 }
46 }
47}
48
David Pursellb59bcc42023-11-10 16:59:19 -080049/// Pvmfw customized operations used in the verification.
50pub(crate) struct Ops<'a> {
51 payload: &'a Payload<'a>,
Alice Wang167ab3f2023-01-23 13:39:25 +000052}
53
David Pursellb59bcc42023-11-10 16:59:19 -080054impl<'a> Ops<'a> {
55 pub(crate) fn new(payload: &'a Payload<'a>) -> Self {
56 Self { payload }
57 }
58
Alice Wang167ab3f2023-01-23 13:39:25 +000059 pub(crate) fn verify_partition(
60 &mut self,
61 partition_name: &CStr,
David Pursell09bfc852024-02-02 11:24:24 -080062 ) -> SlotVerifyResult<SlotVerifyData<'a>> {
Pierre-Clément Tosi781afee2025-01-27 20:51:27 +000063 // 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 Pursellb59bcc42023-11-10 16:59:19 -080071 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 Wang167ab3f2023-01-23 13:39:25 +000078 }
79}
80
David Pursell09bfc852024-02-02 11:24:24 -080081impl<'a> avb::Ops<'a> for Ops<'a> {
David Pursellb59bcc42023-11-10 16:59:19 -080082 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 Pursell09bfc852024-02-02 11:24:24 -080093 fn get_preloaded_partition(&mut self, partition: &CStr) -> IoResult<&'a [u8]> {
David Pursellb59bcc42023-11-10 16:59:19 -080094 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 Wang167ab3f2023-01-23 13:39:25 +0000151}
152
David Pursellb59bcc42023-11-10 16:59:19 -0800153fn 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 Wang167ab3f2023-01-23 13:39:25 +0000157 Ok(())
158}
159
160fn 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}