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 //! Hashtree descriptors. 16 17 use super::{ 18 util::{parse_descriptor, split_slice, ValidateAndByteswap, ValidationFunc}, 19 DescriptorResult, 20 }; 21 use avb_bindgen::{avb_hashtree_descriptor_validate_and_byteswap, AvbHashtreeDescriptor}; 22 use core::{ffi::CStr, str::from_utf8}; 23 24 /// `AvbHashtreeDescriptorFlags`; see libavb docs for details. 25 pub use avb_bindgen::AvbHashtreeDescriptorFlags as HashtreeDescriptorFlags; 26 27 /// Wraps a Hashtree descriptor stored in a vbmeta image. 28 #[derive(Debug, PartialEq, Eq)] 29 pub struct HashtreeDescriptor<'a> { 30 /// DM-Verity version. 31 pub dm_verity_version: u32, 32 33 /// Hashed image size. 34 pub image_size: u64, 35 36 /// Offset to the root block of the hash tree. 37 pub tree_offset: u64, 38 39 /// Hash tree size. 40 pub tree_size: u64, 41 42 /// Data block size in bytes. 43 pub data_block_size: u32, 44 45 /// Hash block size in bytes. 46 pub hash_block_size: u32, 47 48 /// Number of forward error correction roots. 49 pub fec_num_roots: u32, 50 51 /// Offset to the forward error correction data. 52 pub fec_offset: u64, 53 54 /// Forward error correction data size. 55 pub fec_size: u64, 56 57 /// Hash algorithm name. 58 pub hash_algorithm: &'a str, 59 60 /// Flags. 61 pub flags: HashtreeDescriptorFlags, 62 63 /// Partition name. 64 pub partition_name: &'a str, 65 66 /// Salt used to hash the image. 67 pub salt: &'a [u8], 68 69 /// Image root hash digest. 70 pub root_digest: &'a [u8], 71 } 72 73 // SAFETY: `VALIDATE_AND_BYTESWAP_FUNC` is the correct libavb validator for this descriptor type. 74 unsafe impl ValidateAndByteswap for AvbHashtreeDescriptor { 75 const VALIDATE_AND_BYTESWAP_FUNC: ValidationFunc<Self> = 76 avb_hashtree_descriptor_validate_and_byteswap; 77 } 78 79 impl<'a> HashtreeDescriptor<'a> { 80 /// Extract a `HashtreeDescriptor` from the given descriptor contents. 81 /// 82 /// # Arguments 83 /// * `contents`: descriptor contents, including the header, in raw big-endian format. 84 /// 85 /// # Returns 86 /// The new descriptor, or `DescriptorError` if the given `contents` aren't a valid 87 /// `AvbHashtreeDescriptor`. new(contents: &'a [u8]) -> DescriptorResult<Self>88 pub(super) fn new(contents: &'a [u8]) -> DescriptorResult<Self> { 89 // Descriptor contains: header + name + salt + digest. 90 let descriptor = parse_descriptor::<AvbHashtreeDescriptor>(contents)?; 91 let (partition_name, remainder) = 92 split_slice(descriptor.body, descriptor.header.partition_name_len)?; 93 let (salt, remainder) = split_slice(remainder, descriptor.header.salt_len)?; 94 let (root_digest, _) = split_slice(remainder, descriptor.header.root_digest_len)?; 95 96 // Extract the hash algorithm from the original raw header since the temporary 97 // byte-swapped header doesn't live past this function. 98 // The hash algorithm is a nul-terminated UTF-8 string which is identical in the raw 99 // and byteswapped headers. 100 let hash_algorithm = 101 CStr::from_bytes_until_nul(&descriptor.raw_header.hash_algorithm)?.to_str()?; 102 103 Ok(Self { 104 dm_verity_version: descriptor.header.dm_verity_version, 105 image_size: descriptor.header.image_size, 106 tree_offset: descriptor.header.tree_offset, 107 tree_size: descriptor.header.tree_size, 108 data_block_size: descriptor.header.data_block_size, 109 hash_block_size: descriptor.header.hash_block_size, 110 fec_num_roots: descriptor.header.fec_num_roots, 111 fec_offset: descriptor.header.fec_offset, 112 fec_size: descriptor.header.fec_size, 113 hash_algorithm, 114 partition_name: from_utf8(partition_name)?, 115 salt, 116 root_digest, 117 flags: HashtreeDescriptorFlags(descriptor.header.flags), 118 }) 119 } 120 } 121 122 #[cfg(test)] 123 mod tests { 124 use super::*; 125 126 use crate::DescriptorError; 127 use std::{fs, mem::size_of}; 128 129 /// A valid descriptor that we've pre-generated as test data. test_contents() -> Vec<u8>130 fn test_contents() -> Vec<u8> { 131 fs::read("testdata/hashtree_descriptor.bin").unwrap() 132 } 133 134 #[test] new_hashtree_descriptor_success()135 fn new_hashtree_descriptor_success() { 136 assert!(HashtreeDescriptor::new(&test_contents()).is_ok()); 137 } 138 139 #[test] new_hashtree_descriptor_too_short_header_fails()140 fn new_hashtree_descriptor_too_short_header_fails() { 141 let bad_header_size = size_of::<AvbHashtreeDescriptor>() - 1; 142 assert_eq!( 143 HashtreeDescriptor::new(&test_contents()[..bad_header_size]).unwrap_err(), 144 DescriptorError::InvalidHeader 145 ); 146 } 147 148 #[test] new_hashtree_descriptor_too_short_contents_fails()149 fn new_hashtree_descriptor_too_short_contents_fails() { 150 // The last 2 bytes are padding, so we need to drop 3 bytes to trigger an error. 151 let bad_contents_size = test_contents().len() - 3; 152 assert_eq!( 153 HashtreeDescriptor::new(&test_contents()[..bad_contents_size]).unwrap_err(), 154 DescriptorError::InvalidSize 155 ); 156 } 157 } 158