blob: 664da27178ac1b4722040ed297c497bc38fd3444 [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
383impl TryFrom<&CStr> for PartitionName {
384 type Error = AvbIOError;
385
386 fn try_from(partition_name: &CStr) -> Result<Self, Self::Error> {
387 match partition_name.to_bytes_with_nul() {
388 Self::KERNEL_PARTITION_NAME => Ok(Self::Kernel),
389 Self::INITRD_NORMAL_PARTITION_NAME => Ok(Self::InitrdNormal),
390 Self::INITRD_DEBUG_PARTITION_NAME => Ok(Self::InitrdDebug),
391 _ => Err(AvbIOError::NoSuchPartition),
392 }
393 }
394}
395
Alice Wang86383df2023-01-11 10:03:56 +0000396impl TryFrom<&[u8]> for PartitionName {
397 type Error = AvbIOError;
398
399 fn try_from(non_null_terminated_name: &[u8]) -> Result<Self, Self::Error> {
400 match non_null_terminated_name {
401 x if x == Self::Kernel.as_non_null_terminated_bytes() => Ok(Self::Kernel),
402 x if x == Self::InitrdNormal.as_non_null_terminated_bytes() => Ok(Self::InitrdNormal),
403 x if x == Self::InitrdDebug.as_non_null_terminated_bytes() => Ok(Self::InitrdDebug),
404 _ => Err(AvbIOError::NoSuchPartition),
405 }
406 }
407}
408
409struct AvbSlotVerifyDataWrap(*mut AvbSlotVerifyData);
410
411impl TryFrom<*mut AvbSlotVerifyData> for AvbSlotVerifyDataWrap {
412 type Error = AvbSlotVerifyError;
413
414 fn try_from(data: *mut AvbSlotVerifyData) -> Result<Self, Self::Error> {
415 is_not_null(data).map_err(|_| AvbSlotVerifyError::Io)?;
416 Ok(Self(data))
417 }
418}
419
420impl Drop for AvbSlotVerifyDataWrap {
421 fn drop(&mut self) {
422 // SAFETY: This is safe because `self.0` is checked nonnull when the
423 // instance is created. We can free this pointer when the instance is
424 // no longer needed.
425 unsafe {
426 avb_slot_verify_data_free(self.0);
427 }
428 }
429}
430
431impl AsRef<AvbSlotVerifyData> for AvbSlotVerifyDataWrap {
432 fn as_ref(&self) -> &AvbSlotVerifyData {
433 // This is safe because `self.0` is checked nonnull when the instance is created.
434 as_ref(self.0).unwrap()
435 }
436}
437
438impl AvbSlotVerifyDataWrap {
439 fn vbmeta_images(&self) -> Result<&[AvbVBMetaData], AvbSlotVerifyError> {
440 let data = self.as_ref();
441 is_not_null(data.vbmeta_images).map_err(|_| AvbSlotVerifyError::Io)?;
442 // SAFETY: It is safe as the raw pointer `data.vbmeta_images` is a nonnull pointer.
443 let vbmeta_images =
444 unsafe { slice::from_raw_parts(data.vbmeta_images, data.num_vbmeta_images) };
445 Ok(vbmeta_images)
446 }
447}
448
Alice Wanga78279c2022-12-16 12:41:19 +0000449struct Payload<'a> {
450 kernel: &'a [u8],
Alice Wang6b486f12023-01-06 13:12:16 +0000451 initrd: Option<&'a [u8]>,
Alice Wanga78279c2022-12-16 12:41:19 +0000452 trusted_public_key: &'a [u8],
453}
454
455impl<'a> AsRef<Payload<'a>> for AvbOps {
456 fn as_ref(&self) -> &Payload<'a> {
457 let payload = self.user_data as *const Payload;
458 // SAFETY: It is safe to cast the `AvbOps.user_data` to Payload as we have saved a
459 // pointer to a valid value of Payload in user_data when creating AvbOps, and
460 // assume that the Payload isn't used beyond the lifetime of the AvbOps that it
461 // belongs to.
462 unsafe { &*payload }
463 }
464}
465
466impl<'a> Payload<'a> {
Alice Wang6b486f12023-01-06 13:12:16 +0000467 const MAX_NUM_OF_HASH_DESCRIPTORS: usize = 3;
Alice Wanga78279c2022-12-16 12:41:19 +0000468
469 fn get_partition(&self, partition_name: *const c_char) -> Result<&[u8], AvbIOError> {
470 is_not_null(partition_name)?;
471 // SAFETY: It is safe as the raw pointer `partition_name` is a nonnull pointer.
472 let partition_name = unsafe { CStr::from_ptr(partition_name) };
Alice Wang951de3a2023-01-11 14:13:29 +0000473 match partition_name.try_into()? {
474 PartitionName::Kernel => Ok(self.kernel),
475 PartitionName::InitrdNormal | PartitionName::InitrdDebug => {
Alice Wang6b486f12023-01-06 13:12:16 +0000476 self.initrd.ok_or(AvbIOError::NoSuchPartition)
477 }
Alice Wanga78279c2022-12-16 12:41:19 +0000478 }
479 }
Alice Wang6b486f12023-01-06 13:12:16 +0000480
Alice Wang86383df2023-01-11 10:03:56 +0000481 fn verify_partitions(
482 &mut self,
483 partition_names: &[&CStr],
484 ) -> Result<AvbSlotVerifyDataWrap, AvbSlotVerifyError> {
Alice Wang6b486f12023-01-06 13:12:16 +0000485 if partition_names.len() > Self::MAX_NUM_OF_HASH_DESCRIPTORS {
Alice Wang45d98fa2023-01-11 09:39:45 +0000486 return Err(AvbSlotVerifyError::InvalidArgument);
Alice Wang6b486f12023-01-06 13:12:16 +0000487 }
488 let mut requested_partitions = [ptr::null(); Self::MAX_NUM_OF_HASH_DESCRIPTORS + 1];
489 partition_names
490 .iter()
491 .enumerate()
492 .for_each(|(i, name)| requested_partitions[i] = name.as_ptr());
493
494 let mut avb_ops = AvbOps {
495 user_data: self as *mut _ as *mut c_void,
496 ab_ops: ptr::null_mut(),
497 atx_ops: ptr::null_mut(),
498 read_from_partition: Some(read_from_partition),
499 get_preloaded_partition: Some(get_preloaded_partition),
500 write_to_partition: None,
501 validate_vbmeta_public_key: None,
502 read_rollback_index: Some(read_rollback_index),
503 write_rollback_index: None,
504 read_is_device_unlocked: Some(read_is_device_unlocked),
505 get_unique_guid_for_partition: Some(get_unique_guid_for_partition),
506 get_size_of_partition: Some(get_size_of_partition),
507 read_persistent_value: None,
508 write_persistent_value: None,
509 validate_public_key_for_partition: Some(validate_public_key_for_partition),
510 };
511 let ab_suffix = CStr::from_bytes_with_nul(NULL_BYTE).unwrap();
Alice Wang86383df2023-01-11 10:03:56 +0000512 let mut out_data = MaybeUninit::uninit();
Alice Wang6b486f12023-01-06 13:12:16 +0000513 // SAFETY: It is safe to call `avb_slot_verify()` as the pointer arguments (`ops`,
514 // `requested_partitions` and `ab_suffix`) passed to the method are all valid and
515 // initialized. The last argument `out_data` is allowed to be null so that nothing
516 // will be written to it.
517 let result = unsafe {
518 avb_slot_verify(
519 &mut avb_ops,
520 requested_partitions.as_ptr(),
521 ab_suffix.as_ptr(),
522 AvbSlotVerifyFlags::AVB_SLOT_VERIFY_FLAGS_NO_VBMETA_PARTITION,
523 AvbHashtreeErrorMode::AVB_HASHTREE_ERROR_MODE_RESTART_AND_INVALIDATE,
Alice Wang86383df2023-01-11 10:03:56 +0000524 out_data.as_mut_ptr(),
Alice Wang6b486f12023-01-06 13:12:16 +0000525 )
526 };
Alice Wang86383df2023-01-11 10:03:56 +0000527 slot_verify_result_to_verify_payload_result(result)?;
528 // SAFETY: This is safe because `out_data` has been properly initialized after
529 // calling `avb_slot_verify` and it returns OK.
530 let out_data = unsafe { out_data.assume_init() };
531 out_data.try_into()
532 }
533}
534
535fn verify_vbmeta_has_no_initrd_descriptor(
536 vbmeta_image: &AvbVBMetaData,
537) -> Result<(), AvbSlotVerifyError> {
538 is_not_null(vbmeta_image.vbmeta_data).map_err(|_| AvbSlotVerifyError::Io)?;
539 let mut has_unexpected_descriptor = false;
540 // SAFETY: It is safe as the raw pointer `vbmeta_image.vbmeta_data` is a nonnull pointer.
541 if !unsafe {
542 avb_descriptor_foreach(
543 vbmeta_image.vbmeta_data,
544 vbmeta_image.vbmeta_size,
545 Some(search_initrd_hash_descriptor),
546 &mut has_unexpected_descriptor as *mut _ as *mut c_void,
547 )
548 } {
549 return Err(AvbSlotVerifyError::InvalidMetadata);
550 }
551 if has_unexpected_descriptor {
552 Err(AvbSlotVerifyError::InvalidMetadata)
553 } else {
554 Ok(())
Alice Wang6b486f12023-01-06 13:12:16 +0000555 }
Alice Wanga78279c2022-12-16 12:41:19 +0000556}
557
Alice Wangf3d96b12022-12-15 13:10:47 +0000558/// Verifies the payload (signed kernel + initrd) against the trusted public key.
Alice Wang6b486f12023-01-06 13:12:16 +0000559pub fn verify_payload(
560 kernel: &[u8],
561 initrd: Option<&[u8]>,
562 trusted_public_key: &[u8],
Alice Wang45d98fa2023-01-11 09:39:45 +0000563) -> Result<(), AvbSlotVerifyError> {
Alice Wang6b486f12023-01-06 13:12:16 +0000564 let mut payload = Payload { kernel, initrd, trusted_public_key };
Alice Wang86383df2023-01-11 10:03:56 +0000565 let kernel_verify_result = payload.verify_partitions(&[PartitionName::Kernel.as_cstr()])?;
566 let vbmeta_images = kernel_verify_result.vbmeta_images()?;
567 if vbmeta_images.len() != 1 {
568 // There can only be one VBMeta, from the 'boot' partition.
569 return Err(AvbSlotVerifyError::InvalidMetadata);
570 }
571 if payload.initrd.is_none() {
572 verify_vbmeta_has_no_initrd_descriptor(&vbmeta_images[0])?;
573 }
574 // TODO(b/256148034): Check the vbmeta doesn't have hash descriptors other than
575 // boot, initrd_normal, initrd_debug.
576 Ok(())
Alice Wang28cbcf12022-12-01 07:58:28 +0000577}