// Copyright 2024, The Android Open Source Project // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. //! Kernel commandline descriptors. use super::{ util::{parse_descriptor, split_slice, ValidateAndByteswap, ValidationFunc}, DescriptorResult, }; use avb_bindgen::{ avb_kernel_cmdline_descriptor_validate_and_byteswap, AvbKernelCmdlineDescriptor, }; use core::str::from_utf8; /// `AvbKernelCmdlineFlags`; see libavb docs for details. pub use avb_bindgen::AvbKernelCmdlineFlags as KernelCommandlineDescriptorFlags; /// Wraps an `AvbKernelCmdlineDescriptor` stored in a vbmeta image. #[derive(Debug, PartialEq, Eq)] pub struct KernelCommandlineDescriptor<'a> { /// Flags. pub flags: KernelCommandlineDescriptorFlags, /// Kernel commandline. pub commandline: &'a str, } // SAFETY: `VALIDATE_AND_BYTESWAP_FUNC` is the correct libavb validator for this descriptor type. unsafe impl ValidateAndByteswap for AvbKernelCmdlineDescriptor { const VALIDATE_AND_BYTESWAP_FUNC: ValidationFunc = avb_kernel_cmdline_descriptor_validate_and_byteswap; } impl<'a> KernelCommandlineDescriptor<'a> { /// Extracts a `KernelCommandlineDescriptor` from the given descriptor contents. /// /// # Arguments /// * `contents`: descriptor contents, including the header, in raw big-endian format. /// /// # Returns /// The new descriptor, or `DescriptorError` if the given `contents` aren't a valid /// `AvbKernelCmdlineDescriptor`. pub(super) fn new(contents: &'a [u8]) -> DescriptorResult { // Descriptor contains: header + commandline. let descriptor = parse_descriptor::(contents)?; let (commandline, _) = split_slice(descriptor.body, descriptor.header.kernel_cmdline_length)?; Ok(Self { flags: KernelCommandlineDescriptorFlags(descriptor.header.flags), commandline: from_utf8(commandline)?, }) } } #[cfg(test)] mod tests { use super::*; use crate::DescriptorError; use std::{fs, mem::size_of}; /// A valid descriptor that we've pre-generated as test data. fn test_contents() -> Vec { fs::read("testdata/kernel_commandline_descriptor.bin").unwrap() } #[test] fn new_commandline_descriptor_success() { assert!(KernelCommandlineDescriptor::new(&test_contents()).is_ok()); } #[test] fn new_commandline_descriptor_too_short_header_fails() { let bad_header_size = size_of::() - 1; assert_eq!( KernelCommandlineDescriptor::new(&test_contents()[..bad_header_size]).unwrap_err(), DescriptorError::InvalidHeader ); } #[test] fn new_commandline_descriptor_too_short_contents_fails() { // The last 5 bytes are padding, so we need to drop 6 bytes to trigger an error. let bad_contents_size = test_contents().len() - 6; assert_eq!( KernelCommandlineDescriptor::new(&test_contents()[..bad_contents_size]).unwrap_err(), DescriptorError::InvalidSize ); } }