• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2024, 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 // This is an example implementation of the libavb rust wrapper backend in the EFI environment. It
16 // is mainly for use by the boot demo. Eventually, these backends will be implemented from the
17 // `GblOps` interface in libgbl, where EFI services will be one level lower as its backend instead.
18 
19 use crate::utils::EfiMultiBlockDevices;
20 use avb::{IoError, IoResult, Ops, PublicKeyForPartitionInfo};
21 use core::ffi::CStr;
22 use gbl_storage::AsMultiBlockDevices;
23 use uuid::Uuid;
24 
25 extern crate avb_sysdeps;
26 
27 pub struct GblEfiAvbOps<'a, 'b> {
28     gpt_dev: &'b mut EfiMultiBlockDevices<'a>,
29     preloaded_partitions: Option<&'b [(&'b str, &'b [u8])]>,
30 }
31 
32 impl<'a, 'b> GblEfiAvbOps<'a, 'b> {
new( gpt_dev: &'b mut EfiMultiBlockDevices<'a>, preloaded_partitions: Option<&'b [(&'b str, &'b [u8])]>, ) -> Self33     pub fn new(
34         gpt_dev: &'b mut EfiMultiBlockDevices<'a>,
35         preloaded_partitions: Option<&'b [(&'b str, &'b [u8])]>,
36     ) -> Self {
37         Self { gpt_dev, preloaded_partitions }
38     }
39 }
40 
41 /// A helper function for converting CStr to str
cstr_to_str<E>(s: &CStr, err: E) -> Result<&str, E>42 fn cstr_to_str<E>(s: &CStr, err: E) -> Result<&str, E> {
43     Ok(s.to_str().map_err(|_| err)?)
44 }
45 
46 impl<'b> Ops<'b> for GblEfiAvbOps<'_, 'b> {
read_from_partition( &mut self, partition: &CStr, offset: i64, buffer: &mut [u8], ) -> IoResult<usize>47     fn read_from_partition(
48         &mut self,
49         partition: &CStr,
50         offset: i64,
51         buffer: &mut [u8],
52     ) -> IoResult<usize> {
53         let part_str = cstr_to_str(partition, IoError::NoSuchPartition)?;
54         let partition_size: u64 = self
55             .gpt_dev
56             .find_partition(part_str)
57             .and_then(|v| v.size())
58             .map_err(|_| IoError::NoSuchPartition)?
59             .try_into()
60             .map_err(|_| IoError::Oom)?;
61         let read_off: u64 = match offset < 0 {
62             true => {
63                 partition_size.checked_sub(offset.abs() as u64).ok_or(IoError::InvalidValueSize)?
64             }
65             _ => offset.try_into().map_err(|_| IoError::InvalidValueSize)?,
66         };
67         self.gpt_dev.read_gpt_partition(part_str, read_off, buffer).map_err(|_| IoError::Io)?;
68         Ok(buffer.len())
69     }
70 
get_preloaded_partition(&mut self, partition: &CStr) -> IoResult<&'b [u8]>71     fn get_preloaded_partition(&mut self, partition: &CStr) -> IoResult<&'b [u8]> {
72         let part_str = cstr_to_str(partition, IoError::NotImplemented)?;
73         Ok(self
74             .preloaded_partitions
75             .ok_or(IoError::NotImplemented)?
76             .iter()
77             .find(|(name, _)| *name == part_str)
78             .ok_or(IoError::NotImplemented)?
79             .1)
80     }
81 
validate_vbmeta_public_key( &mut self, _public_key: &[u8], _public_key_metadata: Option<&[u8]>, ) -> IoResult<bool>82     fn validate_vbmeta_public_key(
83         &mut self,
84         _public_key: &[u8],
85         _public_key_metadata: Option<&[u8]>,
86     ) -> IoResult<bool> {
87         // Not supported until we add our GBL specific EFI protocol that does this.
88         Ok(true)
89     }
90 
read_rollback_index(&mut self, _rollback_index_location: usize) -> IoResult<u64>91     fn read_rollback_index(&mut self, _rollback_index_location: usize) -> IoResult<u64> {
92         // Not supported until we add our GBL specific EFI protocol that does this.
93         Ok(0)
94     }
95 
write_rollback_index( &mut self, _rollback_index_location: usize, _index: u64, ) -> IoResult<()>96     fn write_rollback_index(
97         &mut self,
98         _rollback_index_location: usize,
99         _index: u64,
100     ) -> IoResult<()> {
101         // Not supported until we add our GBL specific EFI protocol that does this.
102         Ok(())
103     }
104 
read_is_device_unlocked(&mut self) -> IoResult<bool>105     fn read_is_device_unlocked(&mut self) -> IoResult<bool> {
106         // Not supported until we add our GBL specific EFI protocol that does this.
107         // For now always consider unlocked.
108         Ok(true)
109     }
110 
get_unique_guid_for_partition(&mut self, partition: &CStr) -> IoResult<Uuid>111     fn get_unique_guid_for_partition(&mut self, partition: &CStr) -> IoResult<Uuid> {
112         let part_str = cstr_to_str(partition, IoError::NoSuchPartition)?;
113         let ptn = self.gpt_dev.find_partition(part_str).map_err(|_| IoError::NoSuchPartition)?;
114         Ok(Uuid::from_bytes(ptn.gpt_entry().guid))
115     }
116 
get_size_of_partition(&mut self, partition: &CStr) -> IoResult<u64>117     fn get_size_of_partition(&mut self, partition: &CStr) -> IoResult<u64> {
118         match self.get_preloaded_partition(partition) {
119             Ok(img) => Ok(img.len().try_into().unwrap()),
120             _ => {
121                 let part_str = cstr_to_str(partition, IoError::NoSuchPartition)?;
122                 Ok(self
123                     .gpt_dev
124                     .find_partition(part_str)
125                     .and_then(|v| v.size())
126                     .map_err(|_| IoError::NoSuchPartition)?
127                     .try_into()
128                     .map_err(|_| IoError::NoSuchPartition)?)
129             }
130         }
131     }
132 
read_persistent_value(&mut self, _name: &CStr, _value: &mut [u8]) -> IoResult<usize>133     fn read_persistent_value(&mut self, _name: &CStr, _value: &mut [u8]) -> IoResult<usize> {
134         // Not supported until we add our GBL specific EFI protocol that does this.
135         unimplemented!();
136     }
137 
write_persistent_value(&mut self, _name: &CStr, _value: &[u8]) -> IoResult<()>138     fn write_persistent_value(&mut self, _name: &CStr, _value: &[u8]) -> IoResult<()> {
139         // Not supported until we add our GBL specific EFI protocol that does this.
140         unimplemented!();
141     }
142 
erase_persistent_value(&mut self, _name: &CStr) -> IoResult<()>143     fn erase_persistent_value(&mut self, _name: &CStr) -> IoResult<()> {
144         // Not supported until we add our GBL specific EFI protocol that does this.
145         unimplemented!();
146     }
147 
validate_public_key_for_partition( &mut self, _partition: &CStr, _public_key: &[u8], _public_key_metadata: Option<&[u8]>, ) -> IoResult<PublicKeyForPartitionInfo>148     fn validate_public_key_for_partition(
149         &mut self,
150         _partition: &CStr,
151         _public_key: &[u8],
152         _public_key_metadata: Option<&[u8]>,
153     ) -> IoResult<PublicKeyForPartitionInfo> {
154         // Not supported until we add our GBL specific EFI protocol that does this.
155         unimplemented!();
156     }
157 }
158