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 //! Kernel commandline descriptors. 16 17 use super::{ 18 util::{parse_descriptor, split_slice, ValidateAndByteswap, ValidationFunc}, 19 DescriptorResult, 20 }; 21 use avb_bindgen::{ 22 avb_kernel_cmdline_descriptor_validate_and_byteswap, AvbKernelCmdlineDescriptor, 23 }; 24 use core::str::from_utf8; 25 26 /// `AvbKernelCmdlineFlags`; see libavb docs for details. 27 pub use avb_bindgen::AvbKernelCmdlineFlags as KernelCommandlineDescriptorFlags; 28 29 /// Wraps an `AvbKernelCmdlineDescriptor` stored in a vbmeta image. 30 #[derive(Debug, PartialEq, Eq)] 31 pub struct KernelCommandlineDescriptor<'a> { 32 /// Flags. 33 pub flags: KernelCommandlineDescriptorFlags, 34 35 /// Kernel commandline. 36 pub commandline: &'a str, 37 } 38 39 // SAFETY: `VALIDATE_AND_BYTESWAP_FUNC` is the correct libavb validator for this descriptor type. 40 unsafe impl ValidateAndByteswap for AvbKernelCmdlineDescriptor { 41 const VALIDATE_AND_BYTESWAP_FUNC: ValidationFunc<Self> = 42 avb_kernel_cmdline_descriptor_validate_and_byteswap; 43 } 44 45 impl<'a> KernelCommandlineDescriptor<'a> { 46 /// Extracts a `KernelCommandlineDescriptor` from the given descriptor contents. 47 /// 48 /// # Arguments 49 /// * `contents`: descriptor contents, including the header, in raw big-endian format. 50 /// 51 /// # Returns 52 /// The new descriptor, or `DescriptorError` if the given `contents` aren't a valid 53 /// `AvbKernelCmdlineDescriptor`. new(contents: &'a [u8]) -> DescriptorResult<Self>54 pub(super) fn new(contents: &'a [u8]) -> DescriptorResult<Self> { 55 // Descriptor contains: header + commandline. 56 let descriptor = parse_descriptor::<AvbKernelCmdlineDescriptor>(contents)?; 57 let (commandline, _) = 58 split_slice(descriptor.body, descriptor.header.kernel_cmdline_length)?; 59 60 Ok(Self { 61 flags: KernelCommandlineDescriptorFlags(descriptor.header.flags), 62 commandline: from_utf8(commandline)?, 63 }) 64 } 65 } 66 67 #[cfg(test)] 68 mod tests { 69 use super::*; 70 71 use crate::DescriptorError; 72 use std::{fs, mem::size_of}; 73 74 /// A valid descriptor that we've pre-generated as test data. test_contents() -> Vec<u8>75 fn test_contents() -> Vec<u8> { 76 fs::read("testdata/kernel_commandline_descriptor.bin").unwrap() 77 } 78 79 #[test] new_commandline_descriptor_success()80 fn new_commandline_descriptor_success() { 81 assert!(KernelCommandlineDescriptor::new(&test_contents()).is_ok()); 82 } 83 84 #[test] new_commandline_descriptor_too_short_header_fails()85 fn new_commandline_descriptor_too_short_header_fails() { 86 let bad_header_size = size_of::<KernelCommandlineDescriptor>() - 1; 87 assert_eq!( 88 KernelCommandlineDescriptor::new(&test_contents()[..bad_header_size]).unwrap_err(), 89 DescriptorError::InvalidHeader 90 ); 91 } 92 93 #[test] new_commandline_descriptor_too_short_contents_fails()94 fn new_commandline_descriptor_too_short_contents_fails() { 95 // The last 5 bytes are padding, so we need to drop 6 bytes to trigger an error. 96 let bad_contents_size = test_contents().len() - 6; 97 assert_eq!( 98 KernelCommandlineDescriptor::new(&test_contents()[..bad_contents_size]).unwrap_err(), 99 DescriptorError::InvalidSize 100 ); 101 } 102 } 103