blob: a9afbb4519149d6b257fde9308d9635607335da4 [file] [edit]
// 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<Self> =
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<Self> {
// Descriptor contains: header + commandline.
let descriptor = parse_descriptor::<AvbKernelCmdlineDescriptor>(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<u8> {
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::<KernelCommandlineDescriptor>() - 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
);
}
}