xref: /aosp_15_r20/external/avb/rust/src/descriptor/commandline.rs (revision d289c2ba6de359471b23d594623b906876bc48a0)
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