xref: /aosp_15_r20/external/avb/rust/src/descriptor/chain.rs (revision d289c2ba6de359471b23d594623b906876bc48a0)
1*d289c2baSAndroid Build Coastguard Worker // Copyright 2024, The Android Open Source Project
2*d289c2baSAndroid Build Coastguard Worker //
3*d289c2baSAndroid Build Coastguard Worker // Licensed under the Apache License, Version 2.0 (the "License");
4*d289c2baSAndroid Build Coastguard Worker // you may not use this file except in compliance with the License.
5*d289c2baSAndroid Build Coastguard Worker // You may obtain a copy of the License at
6*d289c2baSAndroid Build Coastguard Worker //
7*d289c2baSAndroid Build Coastguard Worker //     http://www.apache.org/licenses/LICENSE-2.0
8*d289c2baSAndroid Build Coastguard Worker //
9*d289c2baSAndroid Build Coastguard Worker // Unless required by applicable law or agreed to in writing, software
10*d289c2baSAndroid Build Coastguard Worker // distributed under the License is distributed on an "AS IS" BASIS,
11*d289c2baSAndroid Build Coastguard Worker // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12*d289c2baSAndroid Build Coastguard Worker // See the License for the specific language governing permissions and
13*d289c2baSAndroid Build Coastguard Worker // limitations under the License.
14*d289c2baSAndroid Build Coastguard Worker 
15*d289c2baSAndroid Build Coastguard Worker //! Chain partition descriptors.
16*d289c2baSAndroid Build Coastguard Worker 
17*d289c2baSAndroid Build Coastguard Worker use super::{
18*d289c2baSAndroid Build Coastguard Worker     util::{parse_descriptor, split_slice, ValidateAndByteswap, ValidationFunc},
19*d289c2baSAndroid Build Coastguard Worker     DescriptorResult,
20*d289c2baSAndroid Build Coastguard Worker };
21*d289c2baSAndroid Build Coastguard Worker use avb_bindgen::{
22*d289c2baSAndroid Build Coastguard Worker     avb_chain_partition_descriptor_validate_and_byteswap, AvbChainPartitionDescriptor,
23*d289c2baSAndroid Build Coastguard Worker };
24*d289c2baSAndroid Build Coastguard Worker use core::str::from_utf8;
25*d289c2baSAndroid Build Coastguard Worker 
26*d289c2baSAndroid Build Coastguard Worker /// `AvbChainPartitionDescriptorFlags`; see libavb docs for details.
27*d289c2baSAndroid Build Coastguard Worker pub use avb_bindgen::AvbChainPartitionDescriptorFlags as ChainPartitionDescriptorFlags;
28*d289c2baSAndroid Build Coastguard Worker 
29*d289c2baSAndroid Build Coastguard Worker /// Wraps a chain partition descriptor stored in a vbmeta image.
30*d289c2baSAndroid Build Coastguard Worker #[derive(Debug, PartialEq, Eq)]
31*d289c2baSAndroid Build Coastguard Worker pub struct ChainPartitionDescriptor<'a> {
32*d289c2baSAndroid Build Coastguard Worker     /// Chained partition rollback index location.
33*d289c2baSAndroid Build Coastguard Worker     pub rollback_index_location: u32,
34*d289c2baSAndroid Build Coastguard Worker 
35*d289c2baSAndroid Build Coastguard Worker     /// Chained partition name.
36*d289c2baSAndroid Build Coastguard Worker     ///
37*d289c2baSAndroid Build Coastguard Worker     /// Most partition names in this library are passed as `&CStr`, but inside
38*d289c2baSAndroid Build Coastguard Worker     /// descriptors the partition names are not nul-terminated making them
39*d289c2baSAndroid Build Coastguard Worker     /// ineligible for use directly as `&CStr`. If `&CStr` is required, one
40*d289c2baSAndroid Build Coastguard Worker     /// option is to allocate a nul-terminated copy of this string via
41*d289c2baSAndroid Build Coastguard Worker     /// `CString::new()` which can then be converted to `&CStr`.
42*d289c2baSAndroid Build Coastguard Worker     pub partition_name: &'a str,
43*d289c2baSAndroid Build Coastguard Worker 
44*d289c2baSAndroid Build Coastguard Worker     /// Chained partition public key.
45*d289c2baSAndroid Build Coastguard Worker     pub public_key: &'a [u8],
46*d289c2baSAndroid Build Coastguard Worker 
47*d289c2baSAndroid Build Coastguard Worker     /// Flags.
48*d289c2baSAndroid Build Coastguard Worker     pub flags: ChainPartitionDescriptorFlags,
49*d289c2baSAndroid Build Coastguard Worker }
50*d289c2baSAndroid Build Coastguard Worker 
51*d289c2baSAndroid Build Coastguard Worker // SAFETY: `VALIDATE_AND_BYTESWAP_FUNC` is the correct libavb validator for this descriptor type.
52*d289c2baSAndroid Build Coastguard Worker unsafe impl ValidateAndByteswap for AvbChainPartitionDescriptor {
53*d289c2baSAndroid Build Coastguard Worker     const VALIDATE_AND_BYTESWAP_FUNC: ValidationFunc<Self> =
54*d289c2baSAndroid Build Coastguard Worker         avb_chain_partition_descriptor_validate_and_byteswap;
55*d289c2baSAndroid Build Coastguard Worker }
56*d289c2baSAndroid Build Coastguard Worker 
57*d289c2baSAndroid Build Coastguard Worker impl<'a> ChainPartitionDescriptor<'a> {
58*d289c2baSAndroid Build Coastguard Worker     /// Extract a `ChainPartitionDescriptor` from the given descriptor contents.
59*d289c2baSAndroid Build Coastguard Worker     ///
60*d289c2baSAndroid Build Coastguard Worker     /// # Arguments
61*d289c2baSAndroid Build Coastguard Worker     /// * `contents`: descriptor contents, including the header, in raw big-endian format.
62*d289c2baSAndroid Build Coastguard Worker     ///
63*d289c2baSAndroid Build Coastguard Worker     /// # Returns
64*d289c2baSAndroid Build Coastguard Worker     /// The new descriptor, or `DescriptorError` if the given `contents` aren't a valid
65*d289c2baSAndroid Build Coastguard Worker     /// `AvbChainPartitionDescriptor`.
new(contents: &'a [u8]) -> DescriptorResult<Self>66*d289c2baSAndroid Build Coastguard Worker     pub(super) fn new(contents: &'a [u8]) -> DescriptorResult<Self> {
67*d289c2baSAndroid Build Coastguard Worker         // Descriptor contains: header + partition name + public key.
68*d289c2baSAndroid Build Coastguard Worker         let descriptor = parse_descriptor::<AvbChainPartitionDescriptor>(contents)?;
69*d289c2baSAndroid Build Coastguard Worker         let (partition_name, remainder) =
70*d289c2baSAndroid Build Coastguard Worker             split_slice(descriptor.body, descriptor.header.partition_name_len)?;
71*d289c2baSAndroid Build Coastguard Worker         let (public_key, _) = split_slice(remainder, descriptor.header.public_key_len)?;
72*d289c2baSAndroid Build Coastguard Worker 
73*d289c2baSAndroid Build Coastguard Worker         Ok(Self {
74*d289c2baSAndroid Build Coastguard Worker             flags: ChainPartitionDescriptorFlags(descriptor.header.flags),
75*d289c2baSAndroid Build Coastguard Worker             partition_name: from_utf8(partition_name)?,
76*d289c2baSAndroid Build Coastguard Worker             rollback_index_location: descriptor.header.rollback_index_location,
77*d289c2baSAndroid Build Coastguard Worker             public_key,
78*d289c2baSAndroid Build Coastguard Worker         })
79*d289c2baSAndroid Build Coastguard Worker     }
80*d289c2baSAndroid Build Coastguard Worker }
81*d289c2baSAndroid Build Coastguard Worker 
82*d289c2baSAndroid Build Coastguard Worker #[cfg(test)]
83*d289c2baSAndroid Build Coastguard Worker mod tests {
84*d289c2baSAndroid Build Coastguard Worker     use super::*;
85*d289c2baSAndroid Build Coastguard Worker 
86*d289c2baSAndroid Build Coastguard Worker     use crate::DescriptorError;
87*d289c2baSAndroid Build Coastguard Worker     use std::{fs, mem::size_of};
88*d289c2baSAndroid Build Coastguard Worker 
89*d289c2baSAndroid Build Coastguard Worker     /// A valid descriptor that we've pre-generated as test data.
test_contents() -> Vec<u8>90*d289c2baSAndroid Build Coastguard Worker     fn test_contents() -> Vec<u8> {
91*d289c2baSAndroid Build Coastguard Worker         fs::read("testdata/chain_partition_descriptor.bin").unwrap()
92*d289c2baSAndroid Build Coastguard Worker     }
93*d289c2baSAndroid Build Coastguard Worker 
94*d289c2baSAndroid Build Coastguard Worker     #[test]
new_chain_partition_descriptor_success()95*d289c2baSAndroid Build Coastguard Worker     fn new_chain_partition_descriptor_success() {
96*d289c2baSAndroid Build Coastguard Worker         assert!(ChainPartitionDescriptor::new(&test_contents()).is_ok());
97*d289c2baSAndroid Build Coastguard Worker     }
98*d289c2baSAndroid Build Coastguard Worker 
99*d289c2baSAndroid Build Coastguard Worker     #[test]
new_chain_partition_descriptor_too_short_header_fails()100*d289c2baSAndroid Build Coastguard Worker     fn new_chain_partition_descriptor_too_short_header_fails() {
101*d289c2baSAndroid Build Coastguard Worker         let bad_header_size = size_of::<AvbChainPartitionDescriptor>() - 1;
102*d289c2baSAndroid Build Coastguard Worker         assert_eq!(
103*d289c2baSAndroid Build Coastguard Worker             ChainPartitionDescriptor::new(&test_contents()[..bad_header_size]).unwrap_err(),
104*d289c2baSAndroid Build Coastguard Worker             DescriptorError::InvalidHeader
105*d289c2baSAndroid Build Coastguard Worker         );
106*d289c2baSAndroid Build Coastguard Worker     }
107*d289c2baSAndroid Build Coastguard Worker 
108*d289c2baSAndroid Build Coastguard Worker     #[test]
new_chain_partition_descriptor_too_short_contents_fails()109*d289c2baSAndroid Build Coastguard Worker     fn new_chain_partition_descriptor_too_short_contents_fails() {
110*d289c2baSAndroid Build Coastguard Worker         // The last byte is padding, so we need to drop 2 bytes to trigger an error.
111*d289c2baSAndroid Build Coastguard Worker         let bad_contents_size = test_contents().len() - 2;
112*d289c2baSAndroid Build Coastguard Worker         assert_eq!(
113*d289c2baSAndroid Build Coastguard Worker             ChainPartitionDescriptor::new(&test_contents()[..bad_contents_size]).unwrap_err(),
114*d289c2baSAndroid Build Coastguard Worker             DescriptorError::InvalidSize
115*d289c2baSAndroid Build Coastguard Worker         );
116*d289c2baSAndroid Build Coastguard Worker     }
117*d289c2baSAndroid Build Coastguard Worker }
118