blob: bcc320a8fcb1a5f6e43a3e1908e37cb395e64b58 [file] [log] [blame]
Alice Wang28cbcf12022-12-01 07:58:28 +00001// Copyright 2022, 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
Alice Wangf3d96b12022-12-15 13:10:47 +000015//! This module handles the pvmfw payload verification.
Alice Wang28cbcf12022-12-01 07:58:28 +000016
Alice Wang167ab3f2023-01-23 13:39:25 +000017use crate::error::{AvbIOError, AvbSlotVerifyError};
18use crate::ops::{Ops, Payload};
Alice Wang8077a862023-01-18 16:06:37 +000019use crate::partition::PartitionName;
Alice Wang167ab3f2023-01-23 13:39:25 +000020use crate::utils::{is_not_null, to_usize, usize_checked_add, write};
Alice Wang86383df2023-01-11 10:03:56 +000021use avb_bindgen::{
Alice Wang167ab3f2023-01-23 13:39:25 +000022 avb_descriptor_foreach, avb_hash_descriptor_validate_and_byteswap, AvbDescriptor,
23 AvbHashDescriptor, AvbVBMetaData,
Alice Wang86383df2023-01-11 10:03:56 +000024};
Alice Wanga78279c2022-12-16 12:41:19 +000025use core::{
Alice Wang167ab3f2023-01-23 13:39:25 +000026 ffi::{c_char, c_void},
Alice Wang86383df2023-01-11 10:03:56 +000027 mem::{size_of, MaybeUninit},
Alice Wang167ab3f2023-01-23 13:39:25 +000028 slice,
Alice Wanga78279c2022-12-16 12:41:19 +000029};
Alice Wang28cbcf12022-12-01 07:58:28 +000030
Alice Wang5c1a7562023-01-13 17:19:57 +000031/// This enum corresponds to the `DebugLevel` in `VirtualMachineConfig`.
32#[derive(Clone, Debug, PartialEq, Eq)]
33pub enum DebugLevel {
34 /// Not debuggable at all.
35 None,
36 /// Fully debuggable.
37 Full,
38}
39
Alice Wang86383df2023-01-11 10:03:56 +000040extern "C" fn search_initrd_hash_descriptor(
41 descriptor: *const AvbDescriptor,
42 user_data: *mut c_void,
43) -> bool {
44 try_search_initrd_hash_descriptor(descriptor, user_data).is_ok()
45}
46
47fn try_search_initrd_hash_descriptor(
48 descriptor: *const AvbDescriptor,
49 user_data: *mut c_void,
50) -> Result<(), AvbIOError> {
51 let hash_desc = AvbHashDescriptorRef::try_from(descriptor)?;
52 if matches!(
53 hash_desc.partition_name()?.try_into(),
54 Ok(PartitionName::InitrdDebug) | Ok(PartitionName::InitrdNormal),
55 ) {
56 write(user_data as *mut bool, true)?;
57 }
58 Ok(())
59}
60
61/// `hash_desc` only contains the metadata like fields length and flags of the descriptor.
62/// The data itself is contained in `ptr`.
63struct AvbHashDescriptorRef {
64 hash_desc: AvbHashDescriptor,
65 ptr: *const AvbDescriptor,
66}
67
68impl TryFrom<*const AvbDescriptor> for AvbHashDescriptorRef {
69 type Error = AvbIOError;
70
71 fn try_from(descriptor: *const AvbDescriptor) -> Result<Self, Self::Error> {
72 is_not_null(descriptor)?;
73 // SAFETY: It is safe as the raw pointer `descriptor` is a nonnull pointer and
74 // we have validated that it is of hash descriptor type.
75 let hash_desc = unsafe {
76 let mut desc = MaybeUninit::uninit();
77 if !avb_hash_descriptor_validate_and_byteswap(
78 descriptor as *const AvbHashDescriptor,
79 desc.as_mut_ptr(),
80 ) {
81 return Err(AvbIOError::Io);
82 }
83 desc.assume_init()
84 };
85 Ok(Self { hash_desc, ptr: descriptor })
86 }
87}
88
89impl AvbHashDescriptorRef {
90 fn check_is_in_range(&self, index: usize) -> Result<(), AvbIOError> {
91 let parent_desc = self.hash_desc.parent_descriptor;
92 let total_len = usize_checked_add(
93 size_of::<AvbDescriptor>(),
94 to_usize(parent_desc.num_bytes_following)?,
95 )?;
96 if index <= total_len {
97 Ok(())
98 } else {
99 Err(AvbIOError::Io)
100 }
101 }
102
103 /// Returns the non null-terminated partition name.
104 fn partition_name(&self) -> Result<&[u8], AvbIOError> {
105 let partition_name_offset = size_of::<AvbHashDescriptor>();
106 let partition_name_len = to_usize(self.hash_desc.partition_name_len)?;
107 self.check_is_in_range(usize_checked_add(partition_name_offset, partition_name_len)?)?;
108 let desc = self.ptr as *const u8;
109 // SAFETY: The descriptor has been validated as nonnull and the partition name is
110 // contained within the image.
111 unsafe { Ok(slice::from_raw_parts(desc.add(partition_name_offset), partition_name_len)) }
112 }
113}
114
Alice Wang86383df2023-01-11 10:03:56 +0000115fn verify_vbmeta_has_no_initrd_descriptor(
116 vbmeta_image: &AvbVBMetaData,
117) -> Result<(), AvbSlotVerifyError> {
118 is_not_null(vbmeta_image.vbmeta_data).map_err(|_| AvbSlotVerifyError::Io)?;
119 let mut has_unexpected_descriptor = false;
120 // SAFETY: It is safe as the raw pointer `vbmeta_image.vbmeta_data` is a nonnull pointer.
121 if !unsafe {
122 avb_descriptor_foreach(
123 vbmeta_image.vbmeta_data,
124 vbmeta_image.vbmeta_size,
125 Some(search_initrd_hash_descriptor),
126 &mut has_unexpected_descriptor as *mut _ as *mut c_void,
127 )
128 } {
129 return Err(AvbSlotVerifyError::InvalidMetadata);
130 }
131 if has_unexpected_descriptor {
132 Err(AvbSlotVerifyError::InvalidMetadata)
133 } else {
134 Ok(())
Alice Wang6b486f12023-01-06 13:12:16 +0000135 }
Alice Wanga78279c2022-12-16 12:41:19 +0000136}
137
Alice Wangd3f28ae2023-01-25 10:41:40 +0000138fn verify_only_one_vbmeta_exists(
139 vbmeta_images: &[AvbVBMetaData],
140) -> Result<(), AvbSlotVerifyError> {
141 if vbmeta_images.len() == 1 {
142 Ok(())
143 } else {
144 Err(AvbSlotVerifyError::InvalidMetadata)
145 }
146}
147
Alice Wang9dfb2962023-01-18 10:01:34 +0000148fn verify_vbmeta_is_from_kernel_partition(
149 vbmeta_image: &AvbVBMetaData,
150) -> Result<(), AvbSlotVerifyError> {
151 match (vbmeta_image.partition_name as *const c_char).try_into() {
152 Ok(PartitionName::Kernel) => Ok(()),
153 _ => Err(AvbSlotVerifyError::InvalidMetadata),
154 }
155}
156
Alice Wangf3d96b12022-12-15 13:10:47 +0000157/// Verifies the payload (signed kernel + initrd) against the trusted public key.
Alice Wang6b486f12023-01-06 13:12:16 +0000158pub fn verify_payload(
159 kernel: &[u8],
160 initrd: Option<&[u8]>,
161 trusted_public_key: &[u8],
Alice Wang5c1a7562023-01-13 17:19:57 +0000162) -> Result<DebugLevel, AvbSlotVerifyError> {
Alice Wang167ab3f2023-01-23 13:39:25 +0000163 let mut payload = Payload::new(kernel, initrd, trusted_public_key);
164 let mut ops = Ops::from(&mut payload);
165 let kernel_verify_result = ops.verify_partition(PartitionName::Kernel.as_cstr())?;
Alice Wang86383df2023-01-11 10:03:56 +0000166 let vbmeta_images = kernel_verify_result.vbmeta_images()?;
Alice Wangd3f28ae2023-01-25 10:41:40 +0000167 verify_only_one_vbmeta_exists(vbmeta_images)?;
Alice Wang9dfb2962023-01-18 10:01:34 +0000168 let vbmeta_image = vbmeta_images[0];
169 verify_vbmeta_is_from_kernel_partition(&vbmeta_image)?;
Alice Wangd3f28ae2023-01-25 10:41:40 +0000170
Alice Wang167ab3f2023-01-23 13:39:25 +0000171 if initrd.is_none() {
Alice Wang9dfb2962023-01-18 10:01:34 +0000172 verify_vbmeta_has_no_initrd_descriptor(&vbmeta_image)?;
Alice Wang5c1a7562023-01-13 17:19:57 +0000173 return Ok(DebugLevel::None);
Alice Wang86383df2023-01-11 10:03:56 +0000174 }
175 // TODO(b/256148034): Check the vbmeta doesn't have hash descriptors other than
176 // boot, initrd_normal, initrd_debug.
Alice Wang5c1a7562023-01-13 17:19:57 +0000177
Alice Wang167ab3f2023-01-23 13:39:25 +0000178 let debug_level = if ops.verify_partition(PartitionName::InitrdNormal.as_cstr()).is_ok() {
Alice Wang5c1a7562023-01-13 17:19:57 +0000179 DebugLevel::None
Alice Wang167ab3f2023-01-23 13:39:25 +0000180 } else if ops.verify_partition(PartitionName::InitrdDebug.as_cstr()).is_ok() {
Alice Wang5c1a7562023-01-13 17:19:57 +0000181 DebugLevel::Full
182 } else {
183 return Err(AvbSlotVerifyError::Verification);
184 };
185 Ok(debug_level)
Alice Wang28cbcf12022-12-01 07:58:28 +0000186}