blob: b3e1ba1e1a5281d578c8ec293874bcfefa77436e [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 Wang45d98fa2023-01-11 09:39:45 +000017use crate::error::{slot_verify_result_to_verify_payload_result, AvbSlotVerifyError};
Alice Wang86383df2023-01-11 10:03:56 +000018use avb_bindgen::{
19 avb_descriptor_foreach, avb_hash_descriptor_validate_and_byteswap, avb_slot_verify,
20 avb_slot_verify_data_free, AvbDescriptor, AvbHashDescriptor, AvbHashtreeErrorMode, AvbIOResult,
21 AvbOps, AvbSlotVerifyData, AvbSlotVerifyFlags, AvbVBMetaData,
22};
Alice Wanga78279c2022-12-16 12:41:19 +000023use core::{
24 ffi::{c_char, c_void, CStr},
Alice Wang86383df2023-01-11 10:03:56 +000025 mem::{size_of, MaybeUninit},
Alice Wanga78279c2022-12-16 12:41:19 +000026 ptr::{self, NonNull},
27 slice,
28};
Alice Wang28cbcf12022-12-01 07:58:28 +000029
Alice Wang60ebaf22023-01-13 11:52:07 +000030const NULL_BYTE: &[u8] = b"\0";
Alice Wang6b486f12023-01-06 13:12:16 +000031
Alice Wang86383df2023-01-11 10:03:56 +000032#[derive(Debug)]
Alice Wanga78279c2022-12-16 12:41:19 +000033enum AvbIOError {
34 /// AVB_IO_RESULT_ERROR_OOM,
35 #[allow(dead_code)]
36 Oom,
37 /// AVB_IO_RESULT_ERROR_IO,
38 #[allow(dead_code)]
39 Io,
40 /// AVB_IO_RESULT_ERROR_NO_SUCH_PARTITION,
41 NoSuchPartition,
42 /// AVB_IO_RESULT_ERROR_RANGE_OUTSIDE_PARTITION,
43 RangeOutsidePartition,
44 /// AVB_IO_RESULT_ERROR_NO_SUCH_VALUE,
45 NoSuchValue,
46 /// AVB_IO_RESULT_ERROR_INVALID_VALUE_SIZE,
47 InvalidValueSize,
48 /// AVB_IO_RESULT_ERROR_INSUFFICIENT_SPACE,
49 #[allow(dead_code)]
50 InsufficientSpace,
51}
52
53impl From<AvbIOError> for AvbIOResult {
54 fn from(error: AvbIOError) -> Self {
55 match error {
56 AvbIOError::Oom => AvbIOResult::AVB_IO_RESULT_ERROR_OOM,
57 AvbIOError::Io => AvbIOResult::AVB_IO_RESULT_ERROR_IO,
58 AvbIOError::NoSuchPartition => AvbIOResult::AVB_IO_RESULT_ERROR_NO_SUCH_PARTITION,
59 AvbIOError::RangeOutsidePartition => {
60 AvbIOResult::AVB_IO_RESULT_ERROR_RANGE_OUTSIDE_PARTITION
61 }
62 AvbIOError::NoSuchValue => AvbIOResult::AVB_IO_RESULT_ERROR_NO_SUCH_VALUE,
63 AvbIOError::InvalidValueSize => AvbIOResult::AVB_IO_RESULT_ERROR_INVALID_VALUE_SIZE,
64 AvbIOError::InsufficientSpace => AvbIOResult::AVB_IO_RESULT_ERROR_INSUFFICIENT_SPACE,
65 }
66 }
67}
68
69fn to_avb_io_result(result: Result<(), AvbIOError>) -> AvbIOResult {
70 result.map_or_else(|e| e.into(), |_| AvbIOResult::AVB_IO_RESULT_OK)
71}
72
73extern "C" fn read_is_device_unlocked(
74 _ops: *mut AvbOps,
75 out_is_unlocked: *mut bool,
76) -> AvbIOResult {
Alice Wangfd217662023-01-13 12:07:53 +000077 to_avb_io_result(write(out_is_unlocked, false))
Alice Wanga78279c2022-12-16 12:41:19 +000078}
79
Alice Wang60ebaf22023-01-13 11:52:07 +000080extern "C" fn get_preloaded_partition(
Alice Wang563663d2023-01-10 08:22:29 +000081 ops: *mut AvbOps,
82 partition: *const c_char,
83 num_bytes: usize,
84 out_pointer: *mut *mut u8,
85 out_num_bytes_preloaded: *mut usize,
86) -> AvbIOResult {
87 to_avb_io_result(try_get_preloaded_partition(
88 ops,
89 partition,
90 num_bytes,
91 out_pointer,
92 out_num_bytes_preloaded,
93 ))
94}
95
96fn try_get_preloaded_partition(
97 ops: *mut AvbOps,
98 partition: *const c_char,
99 num_bytes: usize,
100 out_pointer: *mut *mut u8,
101 out_num_bytes_preloaded: *mut usize,
102) -> Result<(), AvbIOError> {
Alice Wangf0fe7052023-01-11 13:15:57 +0000103 let ops = as_ref(ops)?;
Alice Wang563663d2023-01-10 08:22:29 +0000104 let partition = ops.as_ref().get_partition(partition)?;
Alice Wangfd217662023-01-13 12:07:53 +0000105 write(out_pointer, partition.as_ptr() as *mut u8)?;
106 write(out_num_bytes_preloaded, partition.len().min(num_bytes))
Alice Wang563663d2023-01-10 08:22:29 +0000107}
108
Alice Wanga78279c2022-12-16 12:41:19 +0000109extern "C" fn read_from_partition(
110 ops: *mut AvbOps,
111 partition: *const c_char,
112 offset: i64,
113 num_bytes: usize,
114 buffer: *mut c_void,
115 out_num_read: *mut usize,
116) -> AvbIOResult {
117 to_avb_io_result(try_read_from_partition(
118 ops,
119 partition,
120 offset,
121 num_bytes,
122 buffer,
123 out_num_read,
124 ))
125}
126
127fn try_read_from_partition(
128 ops: *mut AvbOps,
129 partition: *const c_char,
130 offset: i64,
131 num_bytes: usize,
132 buffer: *mut c_void,
133 out_num_read: *mut usize,
134) -> Result<(), AvbIOError> {
Alice Wangf0fe7052023-01-11 13:15:57 +0000135 let ops = as_ref(ops)?;
Alice Wanga78279c2022-12-16 12:41:19 +0000136 let partition = ops.as_ref().get_partition(partition)?;
137 let buffer = to_nonnull(buffer)?;
138 // SAFETY: It is safe to copy the requested number of bytes to `buffer` as `buffer`
139 // is created to point to the `num_bytes` of bytes in memory.
140 let buffer_slice = unsafe { slice::from_raw_parts_mut(buffer.as_ptr() as *mut u8, num_bytes) };
141 copy_data_to_dst(partition, offset, buffer_slice)?;
Alice Wangfd217662023-01-13 12:07:53 +0000142 write(out_num_read, buffer_slice.len())
Alice Wanga78279c2022-12-16 12:41:19 +0000143}
144
145fn copy_data_to_dst(src: &[u8], offset: i64, dst: &mut [u8]) -> Result<(), AvbIOError> {
146 let start = to_copy_start(offset, src.len()).ok_or(AvbIOError::InvalidValueSize)?;
147 let end = start.checked_add(dst.len()).ok_or(AvbIOError::InvalidValueSize)?;
148 dst.copy_from_slice(src.get(start..end).ok_or(AvbIOError::RangeOutsidePartition)?);
149 Ok(())
150}
151
152fn to_copy_start(offset: i64, len: usize) -> Option<usize> {
153 usize::try_from(offset)
154 .ok()
155 .or_else(|| isize::try_from(offset).ok().and_then(|v| len.checked_add_signed(v)))
156}
157
158extern "C" fn get_size_of_partition(
159 ops: *mut AvbOps,
160 partition: *const c_char,
161 out_size_num_bytes: *mut u64,
162) -> AvbIOResult {
163 to_avb_io_result(try_get_size_of_partition(ops, partition, out_size_num_bytes))
164}
165
166fn try_get_size_of_partition(
167 ops: *mut AvbOps,
168 partition: *const c_char,
169 out_size_num_bytes: *mut u64,
170) -> Result<(), AvbIOError> {
Alice Wangf0fe7052023-01-11 13:15:57 +0000171 let ops = as_ref(ops)?;
Alice Wanga78279c2022-12-16 12:41:19 +0000172 let partition = ops.as_ref().get_partition(partition)?;
173 let partition_size =
174 u64::try_from(partition.len()).map_err(|_| AvbIOError::InvalidValueSize)?;
Alice Wangfd217662023-01-13 12:07:53 +0000175 write(out_size_num_bytes, partition_size)
Alice Wanga78279c2022-12-16 12:41:19 +0000176}
177
178extern "C" fn read_rollback_index(
179 _ops: *mut AvbOps,
180 _rollback_index_location: usize,
181 _out_rollback_index: *mut u64,
182) -> AvbIOResult {
183 // Rollback protection is not yet implemented, but
184 // this method is required by `avb_slot_verify()`.
185 AvbIOResult::AVB_IO_RESULT_OK
186}
187
188extern "C" fn get_unique_guid_for_partition(
189 _ops: *mut AvbOps,
190 _partition: *const c_char,
191 _guid_buf: *mut c_char,
192 _guid_buf_size: usize,
193) -> AvbIOResult {
194 // This method is required by `avb_slot_verify()`.
195 AvbIOResult::AVB_IO_RESULT_OK
196}
197
198extern "C" fn validate_public_key_for_partition(
199 ops: *mut AvbOps,
200 partition: *const c_char,
201 public_key_data: *const u8,
202 public_key_length: usize,
203 public_key_metadata: *const u8,
204 public_key_metadata_length: usize,
205 out_is_trusted: *mut bool,
206 out_rollback_index_location: *mut u32,
207) -> AvbIOResult {
208 to_avb_io_result(try_validate_public_key_for_partition(
209 ops,
210 partition,
211 public_key_data,
212 public_key_length,
213 public_key_metadata,
214 public_key_metadata_length,
215 out_is_trusted,
216 out_rollback_index_location,
217 ))
218}
219
220#[allow(clippy::too_many_arguments)]
221fn try_validate_public_key_for_partition(
222 ops: *mut AvbOps,
223 partition: *const c_char,
224 public_key_data: *const u8,
225 public_key_length: usize,
226 _public_key_metadata: *const u8,
227 _public_key_metadata_length: usize,
228 out_is_trusted: *mut bool,
229 _out_rollback_index_location: *mut u32,
230) -> Result<(), AvbIOError> {
231 is_not_null(public_key_data)?;
232 // SAFETY: It is safe to create a slice with the given pointer and length as
233 // `public_key_data` is a valid pointer and it points to an array of length
234 // `public_key_length`.
235 let public_key = unsafe { slice::from_raw_parts(public_key_data, public_key_length) };
Alice Wangf0fe7052023-01-11 13:15:57 +0000236 let ops = as_ref(ops)?;
Alice Wanga78279c2022-12-16 12:41:19 +0000237 // Verifies the public key for the known partitions only.
238 ops.as_ref().get_partition(partition)?;
239 let trusted_public_key = ops.as_ref().trusted_public_key;
Alice Wangfd217662023-01-13 12:07:53 +0000240 write(out_is_trusted, public_key == trusted_public_key)
241}
242
Alice Wang86383df2023-01-11 10:03:56 +0000243extern "C" fn search_initrd_hash_descriptor(
244 descriptor: *const AvbDescriptor,
245 user_data: *mut c_void,
246) -> bool {
247 try_search_initrd_hash_descriptor(descriptor, user_data).is_ok()
248}
249
250fn try_search_initrd_hash_descriptor(
251 descriptor: *const AvbDescriptor,
252 user_data: *mut c_void,
253) -> Result<(), AvbIOError> {
254 let hash_desc = AvbHashDescriptorRef::try_from(descriptor)?;
255 if matches!(
256 hash_desc.partition_name()?.try_into(),
257 Ok(PartitionName::InitrdDebug) | Ok(PartitionName::InitrdNormal),
258 ) {
259 write(user_data as *mut bool, true)?;
260 }
261 Ok(())
262}
263
264/// `hash_desc` only contains the metadata like fields length and flags of the descriptor.
265/// The data itself is contained in `ptr`.
266struct AvbHashDescriptorRef {
267 hash_desc: AvbHashDescriptor,
268 ptr: *const AvbDescriptor,
269}
270
271impl TryFrom<*const AvbDescriptor> for AvbHashDescriptorRef {
272 type Error = AvbIOError;
273
274 fn try_from(descriptor: *const AvbDescriptor) -> Result<Self, Self::Error> {
275 is_not_null(descriptor)?;
276 // SAFETY: It is safe as the raw pointer `descriptor` is a nonnull pointer and
277 // we have validated that it is of hash descriptor type.
278 let hash_desc = unsafe {
279 let mut desc = MaybeUninit::uninit();
280 if !avb_hash_descriptor_validate_and_byteswap(
281 descriptor as *const AvbHashDescriptor,
282 desc.as_mut_ptr(),
283 ) {
284 return Err(AvbIOError::Io);
285 }
286 desc.assume_init()
287 };
288 Ok(Self { hash_desc, ptr: descriptor })
289 }
290}
291
292impl AvbHashDescriptorRef {
293 fn check_is_in_range(&self, index: usize) -> Result<(), AvbIOError> {
294 let parent_desc = self.hash_desc.parent_descriptor;
295 let total_len = usize_checked_add(
296 size_of::<AvbDescriptor>(),
297 to_usize(parent_desc.num_bytes_following)?,
298 )?;
299 if index <= total_len {
300 Ok(())
301 } else {
302 Err(AvbIOError::Io)
303 }
304 }
305
306 /// Returns the non null-terminated partition name.
307 fn partition_name(&self) -> Result<&[u8], AvbIOError> {
308 let partition_name_offset = size_of::<AvbHashDescriptor>();
309 let partition_name_len = to_usize(self.hash_desc.partition_name_len)?;
310 self.check_is_in_range(usize_checked_add(partition_name_offset, partition_name_len)?)?;
311 let desc = self.ptr as *const u8;
312 // SAFETY: The descriptor has been validated as nonnull and the partition name is
313 // contained within the image.
314 unsafe { Ok(slice::from_raw_parts(desc.add(partition_name_offset), partition_name_len)) }
315 }
316}
317
318fn to_usize<T: TryInto<usize>>(num: T) -> Result<usize, AvbIOError> {
319 num.try_into().map_err(|_| AvbIOError::InvalidValueSize)
320}
321
322fn usize_checked_add(x: usize, y: usize) -> Result<usize, AvbIOError> {
323 x.checked_add(y).ok_or(AvbIOError::InvalidValueSize)
324}
325
Alice Wangfd217662023-01-13 12:07:53 +0000326fn write<T>(ptr: *mut T, value: T) -> Result<(), AvbIOError> {
327 let ptr = to_nonnull(ptr)?;
328 // SAFETY: It is safe as the raw pointer `ptr` is a nonnull pointer.
Alice Wanga78279c2022-12-16 12:41:19 +0000329 unsafe {
Alice Wangfd217662023-01-13 12:07:53 +0000330 *ptr.as_ptr() = value;
Alice Wanga78279c2022-12-16 12:41:19 +0000331 }
332 Ok(())
333}
334
Alice Wangf0fe7052023-01-11 13:15:57 +0000335fn as_ref<'a, T>(ptr: *mut T) -> Result<&'a T, AvbIOError> {
336 let ptr = to_nonnull(ptr)?;
337 // SAFETY: It is safe as the raw pointer `ptr` is a nonnull pointer.
338 unsafe { Ok(ptr.as_ref()) }
Alice Wanga78279c2022-12-16 12:41:19 +0000339}
340
Alice Wangf0fe7052023-01-11 13:15:57 +0000341fn to_nonnull<T>(ptr: *mut T) -> Result<NonNull<T>, AvbIOError> {
342 NonNull::new(ptr).ok_or(AvbIOError::NoSuchValue)
Alice Wanga78279c2022-12-16 12:41:19 +0000343}
344
345fn is_not_null<T>(ptr: *const T) -> Result<(), AvbIOError> {
346 if ptr.is_null() {
347 Err(AvbIOError::NoSuchValue)
348 } else {
349 Ok(())
350 }
351}
352
Alice Wang951de3a2023-01-11 14:13:29 +0000353#[derive(Clone, Debug, PartialEq, Eq)]
354enum PartitionName {
355 Kernel,
356 InitrdNormal,
357 InitrdDebug,
358}
359
360impl PartitionName {
Alice Wang8aa3cb12023-01-11 09:04:04 +0000361 const KERNEL_PARTITION_NAME: &[u8] = b"boot\0";
Alice Wang951de3a2023-01-11 14:13:29 +0000362 const INITRD_NORMAL_PARTITION_NAME: &[u8] = b"initrd_normal\0";
363 const INITRD_DEBUG_PARTITION_NAME: &[u8] = b"initrd_debug\0";
364
365 fn as_cstr(&self) -> &CStr {
Alice Wang86383df2023-01-11 10:03:56 +0000366 CStr::from_bytes_with_nul(self.as_bytes()).unwrap()
367 }
368
369 fn as_non_null_terminated_bytes(&self) -> &[u8] {
370 let partition_name = self.as_bytes();
371 &partition_name[..partition_name.len() - 1]
372 }
373
374 fn as_bytes(&self) -> &[u8] {
375 match self {
Alice Wang951de3a2023-01-11 14:13:29 +0000376 Self::Kernel => Self::KERNEL_PARTITION_NAME,
377 Self::InitrdNormal => Self::INITRD_NORMAL_PARTITION_NAME,
378 Self::InitrdDebug => Self::INITRD_DEBUG_PARTITION_NAME,
Alice Wang86383df2023-01-11 10:03:56 +0000379 }
Alice Wang951de3a2023-01-11 14:13:29 +0000380 }
381}
382
Alice Wang9dfb2962023-01-18 10:01:34 +0000383impl TryFrom<*const c_char> for PartitionName {
384 type Error = AvbIOError;
385
386 fn try_from(partition_name: *const c_char) -> Result<Self, Self::Error> {
387 is_not_null(partition_name)?;
388 // SAFETY: It is safe as the raw pointer `partition_name` is a nonnull pointer.
389 let partition_name = unsafe { CStr::from_ptr(partition_name) };
390 partition_name.try_into()
391 }
392}
393
Alice Wang951de3a2023-01-11 14:13:29 +0000394impl TryFrom<&CStr> for PartitionName {
395 type Error = AvbIOError;
396
397 fn try_from(partition_name: &CStr) -> Result<Self, Self::Error> {
398 match partition_name.to_bytes_with_nul() {
399 Self::KERNEL_PARTITION_NAME => Ok(Self::Kernel),
400 Self::INITRD_NORMAL_PARTITION_NAME => Ok(Self::InitrdNormal),
401 Self::INITRD_DEBUG_PARTITION_NAME => Ok(Self::InitrdDebug),
402 _ => Err(AvbIOError::NoSuchPartition),
403 }
404 }
405}
406
Alice Wang86383df2023-01-11 10:03:56 +0000407impl TryFrom<&[u8]> for PartitionName {
408 type Error = AvbIOError;
409
410 fn try_from(non_null_terminated_name: &[u8]) -> Result<Self, Self::Error> {
411 match non_null_terminated_name {
412 x if x == Self::Kernel.as_non_null_terminated_bytes() => Ok(Self::Kernel),
413 x if x == Self::InitrdNormal.as_non_null_terminated_bytes() => Ok(Self::InitrdNormal),
414 x if x == Self::InitrdDebug.as_non_null_terminated_bytes() => Ok(Self::InitrdDebug),
415 _ => Err(AvbIOError::NoSuchPartition),
416 }
417 }
418}
419
420struct AvbSlotVerifyDataWrap(*mut AvbSlotVerifyData);
421
422impl TryFrom<*mut AvbSlotVerifyData> for AvbSlotVerifyDataWrap {
423 type Error = AvbSlotVerifyError;
424
425 fn try_from(data: *mut AvbSlotVerifyData) -> Result<Self, Self::Error> {
426 is_not_null(data).map_err(|_| AvbSlotVerifyError::Io)?;
427 Ok(Self(data))
428 }
429}
430
431impl Drop for AvbSlotVerifyDataWrap {
432 fn drop(&mut self) {
433 // SAFETY: This is safe because `self.0` is checked nonnull when the
434 // instance is created. We can free this pointer when the instance is
435 // no longer needed.
436 unsafe {
437 avb_slot_verify_data_free(self.0);
438 }
439 }
440}
441
442impl AsRef<AvbSlotVerifyData> for AvbSlotVerifyDataWrap {
443 fn as_ref(&self) -> &AvbSlotVerifyData {
444 // This is safe because `self.0` is checked nonnull when the instance is created.
445 as_ref(self.0).unwrap()
446 }
447}
448
449impl AvbSlotVerifyDataWrap {
450 fn vbmeta_images(&self) -> Result<&[AvbVBMetaData], AvbSlotVerifyError> {
451 let data = self.as_ref();
452 is_not_null(data.vbmeta_images).map_err(|_| AvbSlotVerifyError::Io)?;
453 // SAFETY: It is safe as the raw pointer `data.vbmeta_images` is a nonnull pointer.
454 let vbmeta_images =
455 unsafe { slice::from_raw_parts(data.vbmeta_images, data.num_vbmeta_images) };
456 Ok(vbmeta_images)
457 }
458}
459
Alice Wanga78279c2022-12-16 12:41:19 +0000460struct Payload<'a> {
461 kernel: &'a [u8],
Alice Wang6b486f12023-01-06 13:12:16 +0000462 initrd: Option<&'a [u8]>,
Alice Wanga78279c2022-12-16 12:41:19 +0000463 trusted_public_key: &'a [u8],
464}
465
466impl<'a> AsRef<Payload<'a>> for AvbOps {
467 fn as_ref(&self) -> &Payload<'a> {
468 let payload = self.user_data as *const Payload;
469 // SAFETY: It is safe to cast the `AvbOps.user_data` to Payload as we have saved a
470 // pointer to a valid value of Payload in user_data when creating AvbOps, and
471 // assume that the Payload isn't used beyond the lifetime of the AvbOps that it
472 // belongs to.
473 unsafe { &*payload }
474 }
475}
476
477impl<'a> Payload<'a> {
Alice Wanga78279c2022-12-16 12:41:19 +0000478 fn get_partition(&self, partition_name: *const c_char) -> Result<&[u8], AvbIOError> {
Alice Wang951de3a2023-01-11 14:13:29 +0000479 match partition_name.try_into()? {
480 PartitionName::Kernel => Ok(self.kernel),
481 PartitionName::InitrdNormal | PartitionName::InitrdDebug => {
Alice Wang6b486f12023-01-06 13:12:16 +0000482 self.initrd.ok_or(AvbIOError::NoSuchPartition)
483 }
Alice Wanga78279c2022-12-16 12:41:19 +0000484 }
485 }
Alice Wang6b486f12023-01-06 13:12:16 +0000486
Alice Wang8aca6f92023-01-16 12:50:19 +0000487 fn verify_partition(
Alice Wang86383df2023-01-11 10:03:56 +0000488 &mut self,
Alice Wang8aca6f92023-01-16 12:50:19 +0000489 partition_name: &CStr,
Alice Wang86383df2023-01-11 10:03:56 +0000490 ) -> Result<AvbSlotVerifyDataWrap, AvbSlotVerifyError> {
Alice Wang8aca6f92023-01-16 12:50:19 +0000491 let requested_partitions = [partition_name.as_ptr(), ptr::null()];
Alice Wang6b486f12023-01-06 13:12:16 +0000492 let mut avb_ops = AvbOps {
493 user_data: self as *mut _ as *mut c_void,
494 ab_ops: ptr::null_mut(),
495 atx_ops: ptr::null_mut(),
496 read_from_partition: Some(read_from_partition),
497 get_preloaded_partition: Some(get_preloaded_partition),
498 write_to_partition: None,
499 validate_vbmeta_public_key: None,
500 read_rollback_index: Some(read_rollback_index),
501 write_rollback_index: None,
502 read_is_device_unlocked: Some(read_is_device_unlocked),
503 get_unique_guid_for_partition: Some(get_unique_guid_for_partition),
504 get_size_of_partition: Some(get_size_of_partition),
505 read_persistent_value: None,
506 write_persistent_value: None,
507 validate_public_key_for_partition: Some(validate_public_key_for_partition),
508 };
509 let ab_suffix = CStr::from_bytes_with_nul(NULL_BYTE).unwrap();
Alice Wang86383df2023-01-11 10:03:56 +0000510 let mut out_data = MaybeUninit::uninit();
Alice Wang6b486f12023-01-06 13:12:16 +0000511 // SAFETY: It is safe to call `avb_slot_verify()` as the pointer arguments (`ops`,
512 // `requested_partitions` and `ab_suffix`) passed to the method are all valid and
513 // initialized. The last argument `out_data` is allowed to be null so that nothing
514 // will be written to it.
515 let result = unsafe {
516 avb_slot_verify(
517 &mut avb_ops,
518 requested_partitions.as_ptr(),
519 ab_suffix.as_ptr(),
520 AvbSlotVerifyFlags::AVB_SLOT_VERIFY_FLAGS_NO_VBMETA_PARTITION,
521 AvbHashtreeErrorMode::AVB_HASHTREE_ERROR_MODE_RESTART_AND_INVALIDATE,
Alice Wang86383df2023-01-11 10:03:56 +0000522 out_data.as_mut_ptr(),
Alice Wang6b486f12023-01-06 13:12:16 +0000523 )
524 };
Alice Wang86383df2023-01-11 10:03:56 +0000525 slot_verify_result_to_verify_payload_result(result)?;
526 // SAFETY: This is safe because `out_data` has been properly initialized after
527 // calling `avb_slot_verify` and it returns OK.
528 let out_data = unsafe { out_data.assume_init() };
529 out_data.try_into()
530 }
531}
532
533fn verify_vbmeta_has_no_initrd_descriptor(
534 vbmeta_image: &AvbVBMetaData,
535) -> Result<(), AvbSlotVerifyError> {
536 is_not_null(vbmeta_image.vbmeta_data).map_err(|_| AvbSlotVerifyError::Io)?;
537 let mut has_unexpected_descriptor = false;
538 // SAFETY: It is safe as the raw pointer `vbmeta_image.vbmeta_data` is a nonnull pointer.
539 if !unsafe {
540 avb_descriptor_foreach(
541 vbmeta_image.vbmeta_data,
542 vbmeta_image.vbmeta_size,
543 Some(search_initrd_hash_descriptor),
544 &mut has_unexpected_descriptor as *mut _ as *mut c_void,
545 )
546 } {
547 return Err(AvbSlotVerifyError::InvalidMetadata);
548 }
549 if has_unexpected_descriptor {
550 Err(AvbSlotVerifyError::InvalidMetadata)
551 } else {
552 Ok(())
Alice Wang6b486f12023-01-06 13:12:16 +0000553 }
Alice Wanga78279c2022-12-16 12:41:19 +0000554}
555
Alice Wang9dfb2962023-01-18 10:01:34 +0000556fn verify_vbmeta_is_from_kernel_partition(
557 vbmeta_image: &AvbVBMetaData,
558) -> Result<(), AvbSlotVerifyError> {
559 match (vbmeta_image.partition_name as *const c_char).try_into() {
560 Ok(PartitionName::Kernel) => Ok(()),
561 _ => Err(AvbSlotVerifyError::InvalidMetadata),
562 }
563}
564
Alice Wangf3d96b12022-12-15 13:10:47 +0000565/// Verifies the payload (signed kernel + initrd) against the trusted public key.
Alice Wang6b486f12023-01-06 13:12:16 +0000566pub fn verify_payload(
567 kernel: &[u8],
568 initrd: Option<&[u8]>,
569 trusted_public_key: &[u8],
Alice Wang45d98fa2023-01-11 09:39:45 +0000570) -> Result<(), AvbSlotVerifyError> {
Alice Wang6b486f12023-01-06 13:12:16 +0000571 let mut payload = Payload { kernel, initrd, trusted_public_key };
Alice Wang8aca6f92023-01-16 12:50:19 +0000572 let kernel_verify_result = payload.verify_partition(PartitionName::Kernel.as_cstr())?;
Alice Wang86383df2023-01-11 10:03:56 +0000573 let vbmeta_images = kernel_verify_result.vbmeta_images()?;
574 if vbmeta_images.len() != 1 {
Alice Wang9dfb2962023-01-18 10:01:34 +0000575 // There can only be one VBMeta.
Alice Wang86383df2023-01-11 10:03:56 +0000576 return Err(AvbSlotVerifyError::InvalidMetadata);
577 }
Alice Wang9dfb2962023-01-18 10:01:34 +0000578 let vbmeta_image = vbmeta_images[0];
579 verify_vbmeta_is_from_kernel_partition(&vbmeta_image)?;
Alice Wang86383df2023-01-11 10:03:56 +0000580 if payload.initrd.is_none() {
Alice Wang9dfb2962023-01-18 10:01:34 +0000581 verify_vbmeta_has_no_initrd_descriptor(&vbmeta_image)?;
Alice Wang86383df2023-01-11 10:03:56 +0000582 }
583 // TODO(b/256148034): Check the vbmeta doesn't have hash descriptors other than
584 // boot, initrd_normal, initrd_debug.
585 Ok(())
Alice Wang28cbcf12022-12-01 07:58:28 +0000586}