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