blob: b6519cdd8cad19cf6cecaeaed02587a8a1da0c10 [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 Wang18655632023-01-18 09:11:34 +000017use crate::error::{
18 slot_verify_result_to_verify_payload_result, to_avb_io_result, AvbIOError, AvbSlotVerifyError,
19};
Alice Wang8077a862023-01-18 16:06:37 +000020use crate::partition::PartitionName;
21use crate::utils::{as_ref, is_not_null, to_nonnull, to_usize, usize_checked_add, write};
Alice Wang86383df2023-01-11 10:03:56 +000022use avb_bindgen::{
23 avb_descriptor_foreach, avb_hash_descriptor_validate_and_byteswap, avb_slot_verify,
24 avb_slot_verify_data_free, AvbDescriptor, AvbHashDescriptor, AvbHashtreeErrorMode, AvbIOResult,
25 AvbOps, AvbSlotVerifyData, AvbSlotVerifyFlags, AvbVBMetaData,
26};
Alice Wanga78279c2022-12-16 12:41:19 +000027use core::{
28 ffi::{c_char, c_void, CStr},
Alice Wang86383df2023-01-11 10:03:56 +000029 mem::{size_of, MaybeUninit},
Alice Wang8077a862023-01-18 16:06:37 +000030 ptr, slice,
Alice Wanga78279c2022-12-16 12:41:19 +000031};
Alice Wang28cbcf12022-12-01 07:58:28 +000032
Alice Wang60ebaf22023-01-13 11:52:07 +000033const NULL_BYTE: &[u8] = b"\0";
Alice Wang6b486f12023-01-06 13:12:16 +000034
Alice Wanga78279c2022-12-16 12:41:19 +000035extern "C" fn read_is_device_unlocked(
36 _ops: *mut AvbOps,
37 out_is_unlocked: *mut bool,
38) -> AvbIOResult {
Alice Wangfd217662023-01-13 12:07:53 +000039 to_avb_io_result(write(out_is_unlocked, false))
Alice Wanga78279c2022-12-16 12:41:19 +000040}
41
Alice Wang60ebaf22023-01-13 11:52:07 +000042extern "C" fn get_preloaded_partition(
Alice Wang563663d2023-01-10 08:22:29 +000043 ops: *mut AvbOps,
44 partition: *const c_char,
45 num_bytes: usize,
46 out_pointer: *mut *mut u8,
47 out_num_bytes_preloaded: *mut usize,
48) -> AvbIOResult {
49 to_avb_io_result(try_get_preloaded_partition(
50 ops,
51 partition,
52 num_bytes,
53 out_pointer,
54 out_num_bytes_preloaded,
55 ))
56}
57
58fn try_get_preloaded_partition(
59 ops: *mut AvbOps,
60 partition: *const c_char,
61 num_bytes: usize,
62 out_pointer: *mut *mut u8,
63 out_num_bytes_preloaded: *mut usize,
64) -> Result<(), AvbIOError> {
Alice Wangf0fe7052023-01-11 13:15:57 +000065 let ops = as_ref(ops)?;
Alice Wang563663d2023-01-10 08:22:29 +000066 let partition = ops.as_ref().get_partition(partition)?;
Alice Wangfd217662023-01-13 12:07:53 +000067 write(out_pointer, partition.as_ptr() as *mut u8)?;
68 write(out_num_bytes_preloaded, partition.len().min(num_bytes))
Alice Wang563663d2023-01-10 08:22:29 +000069}
70
Alice Wanga78279c2022-12-16 12:41:19 +000071extern "C" fn read_from_partition(
72 ops: *mut AvbOps,
73 partition: *const c_char,
74 offset: i64,
75 num_bytes: usize,
76 buffer: *mut c_void,
77 out_num_read: *mut usize,
78) -> AvbIOResult {
79 to_avb_io_result(try_read_from_partition(
80 ops,
81 partition,
82 offset,
83 num_bytes,
84 buffer,
85 out_num_read,
86 ))
87}
88
89fn try_read_from_partition(
90 ops: *mut AvbOps,
91 partition: *const c_char,
92 offset: i64,
93 num_bytes: usize,
94 buffer: *mut c_void,
95 out_num_read: *mut usize,
96) -> Result<(), AvbIOError> {
Alice Wangf0fe7052023-01-11 13:15:57 +000097 let ops = as_ref(ops)?;
Alice Wanga78279c2022-12-16 12:41:19 +000098 let partition = ops.as_ref().get_partition(partition)?;
99 let buffer = to_nonnull(buffer)?;
100 // SAFETY: It is safe to copy the requested number of bytes to `buffer` as `buffer`
101 // is created to point to the `num_bytes` of bytes in memory.
102 let buffer_slice = unsafe { slice::from_raw_parts_mut(buffer.as_ptr() as *mut u8, num_bytes) };
103 copy_data_to_dst(partition, offset, buffer_slice)?;
Alice Wangfd217662023-01-13 12:07:53 +0000104 write(out_num_read, buffer_slice.len())
Alice Wanga78279c2022-12-16 12:41:19 +0000105}
106
107fn copy_data_to_dst(src: &[u8], offset: i64, dst: &mut [u8]) -> Result<(), AvbIOError> {
108 let start = to_copy_start(offset, src.len()).ok_or(AvbIOError::InvalidValueSize)?;
109 let end = start.checked_add(dst.len()).ok_or(AvbIOError::InvalidValueSize)?;
110 dst.copy_from_slice(src.get(start..end).ok_or(AvbIOError::RangeOutsidePartition)?);
111 Ok(())
112}
113
114fn to_copy_start(offset: i64, len: usize) -> Option<usize> {
115 usize::try_from(offset)
116 .ok()
117 .or_else(|| isize::try_from(offset).ok().and_then(|v| len.checked_add_signed(v)))
118}
119
120extern "C" fn get_size_of_partition(
121 ops: *mut AvbOps,
122 partition: *const c_char,
123 out_size_num_bytes: *mut u64,
124) -> AvbIOResult {
125 to_avb_io_result(try_get_size_of_partition(ops, partition, out_size_num_bytes))
126}
127
128fn try_get_size_of_partition(
129 ops: *mut AvbOps,
130 partition: *const c_char,
131 out_size_num_bytes: *mut u64,
132) -> Result<(), AvbIOError> {
Alice Wangf0fe7052023-01-11 13:15:57 +0000133 let ops = as_ref(ops)?;
Alice Wanga78279c2022-12-16 12:41:19 +0000134 let partition = ops.as_ref().get_partition(partition)?;
135 let partition_size =
136 u64::try_from(partition.len()).map_err(|_| AvbIOError::InvalidValueSize)?;
Alice Wangfd217662023-01-13 12:07:53 +0000137 write(out_size_num_bytes, partition_size)
Alice Wanga78279c2022-12-16 12:41:19 +0000138}
139
140extern "C" fn read_rollback_index(
141 _ops: *mut AvbOps,
142 _rollback_index_location: usize,
143 _out_rollback_index: *mut u64,
144) -> AvbIOResult {
145 // Rollback protection is not yet implemented, but
146 // this method is required by `avb_slot_verify()`.
147 AvbIOResult::AVB_IO_RESULT_OK
148}
149
150extern "C" fn get_unique_guid_for_partition(
151 _ops: *mut AvbOps,
152 _partition: *const c_char,
153 _guid_buf: *mut c_char,
154 _guid_buf_size: usize,
155) -> AvbIOResult {
156 // This method is required by `avb_slot_verify()`.
157 AvbIOResult::AVB_IO_RESULT_OK
158}
159
160extern "C" fn validate_public_key_for_partition(
161 ops: *mut AvbOps,
162 partition: *const c_char,
163 public_key_data: *const u8,
164 public_key_length: usize,
165 public_key_metadata: *const u8,
166 public_key_metadata_length: usize,
167 out_is_trusted: *mut bool,
168 out_rollback_index_location: *mut u32,
169) -> AvbIOResult {
170 to_avb_io_result(try_validate_public_key_for_partition(
171 ops,
172 partition,
173 public_key_data,
174 public_key_length,
175 public_key_metadata,
176 public_key_metadata_length,
177 out_is_trusted,
178 out_rollback_index_location,
179 ))
180}
181
182#[allow(clippy::too_many_arguments)]
183fn try_validate_public_key_for_partition(
184 ops: *mut AvbOps,
185 partition: *const c_char,
186 public_key_data: *const u8,
187 public_key_length: usize,
188 _public_key_metadata: *const u8,
189 _public_key_metadata_length: usize,
190 out_is_trusted: *mut bool,
191 _out_rollback_index_location: *mut u32,
192) -> Result<(), AvbIOError> {
193 is_not_null(public_key_data)?;
194 // SAFETY: It is safe to create a slice with the given pointer and length as
195 // `public_key_data` is a valid pointer and it points to an array of length
196 // `public_key_length`.
197 let public_key = unsafe { slice::from_raw_parts(public_key_data, public_key_length) };
Alice Wangf0fe7052023-01-11 13:15:57 +0000198 let ops = as_ref(ops)?;
Alice Wanga78279c2022-12-16 12:41:19 +0000199 // Verifies the public key for the known partitions only.
200 ops.as_ref().get_partition(partition)?;
201 let trusted_public_key = ops.as_ref().trusted_public_key;
Alice Wangfd217662023-01-13 12:07:53 +0000202 write(out_is_trusted, public_key == trusted_public_key)
203}
204
Alice Wang86383df2023-01-11 10:03:56 +0000205extern "C" fn search_initrd_hash_descriptor(
206 descriptor: *const AvbDescriptor,
207 user_data: *mut c_void,
208) -> bool {
209 try_search_initrd_hash_descriptor(descriptor, user_data).is_ok()
210}
211
212fn try_search_initrd_hash_descriptor(
213 descriptor: *const AvbDescriptor,
214 user_data: *mut c_void,
215) -> Result<(), AvbIOError> {
216 let hash_desc = AvbHashDescriptorRef::try_from(descriptor)?;
217 if matches!(
218 hash_desc.partition_name()?.try_into(),
219 Ok(PartitionName::InitrdDebug) | Ok(PartitionName::InitrdNormal),
220 ) {
221 write(user_data as *mut bool, true)?;
222 }
223 Ok(())
224}
225
226/// `hash_desc` only contains the metadata like fields length and flags of the descriptor.
227/// The data itself is contained in `ptr`.
228struct AvbHashDescriptorRef {
229 hash_desc: AvbHashDescriptor,
230 ptr: *const AvbDescriptor,
231}
232
233impl TryFrom<*const AvbDescriptor> for AvbHashDescriptorRef {
234 type Error = AvbIOError;
235
236 fn try_from(descriptor: *const AvbDescriptor) -> Result<Self, Self::Error> {
237 is_not_null(descriptor)?;
238 // SAFETY: It is safe as the raw pointer `descriptor` is a nonnull pointer and
239 // we have validated that it is of hash descriptor type.
240 let hash_desc = unsafe {
241 let mut desc = MaybeUninit::uninit();
242 if !avb_hash_descriptor_validate_and_byteswap(
243 descriptor as *const AvbHashDescriptor,
244 desc.as_mut_ptr(),
245 ) {
246 return Err(AvbIOError::Io);
247 }
248 desc.assume_init()
249 };
250 Ok(Self { hash_desc, ptr: descriptor })
251 }
252}
253
254impl AvbHashDescriptorRef {
255 fn check_is_in_range(&self, index: usize) -> Result<(), AvbIOError> {
256 let parent_desc = self.hash_desc.parent_descriptor;
257 let total_len = usize_checked_add(
258 size_of::<AvbDescriptor>(),
259 to_usize(parent_desc.num_bytes_following)?,
260 )?;
261 if index <= total_len {
262 Ok(())
263 } else {
264 Err(AvbIOError::Io)
265 }
266 }
267
268 /// Returns the non null-terminated partition name.
269 fn partition_name(&self) -> Result<&[u8], AvbIOError> {
270 let partition_name_offset = size_of::<AvbHashDescriptor>();
271 let partition_name_len = to_usize(self.hash_desc.partition_name_len)?;
272 self.check_is_in_range(usize_checked_add(partition_name_offset, partition_name_len)?)?;
273 let desc = self.ptr as *const u8;
274 // SAFETY: The descriptor has been validated as nonnull and the partition name is
275 // contained within the image.
276 unsafe { Ok(slice::from_raw_parts(desc.add(partition_name_offset), partition_name_len)) }
277 }
278}
279
Alice Wang86383df2023-01-11 10:03:56 +0000280struct AvbSlotVerifyDataWrap(*mut AvbSlotVerifyData);
281
282impl TryFrom<*mut AvbSlotVerifyData> for AvbSlotVerifyDataWrap {
283 type Error = AvbSlotVerifyError;
284
285 fn try_from(data: *mut AvbSlotVerifyData) -> Result<Self, Self::Error> {
286 is_not_null(data).map_err(|_| AvbSlotVerifyError::Io)?;
287 Ok(Self(data))
288 }
289}
290
291impl Drop for AvbSlotVerifyDataWrap {
292 fn drop(&mut self) {
293 // SAFETY: This is safe because `self.0` is checked nonnull when the
294 // instance is created. We can free this pointer when the instance is
295 // no longer needed.
296 unsafe {
297 avb_slot_verify_data_free(self.0);
298 }
299 }
300}
301
302impl AsRef<AvbSlotVerifyData> for AvbSlotVerifyDataWrap {
303 fn as_ref(&self) -> &AvbSlotVerifyData {
304 // This is safe because `self.0` is checked nonnull when the instance is created.
305 as_ref(self.0).unwrap()
306 }
307}
308
309impl AvbSlotVerifyDataWrap {
310 fn vbmeta_images(&self) -> Result<&[AvbVBMetaData], AvbSlotVerifyError> {
311 let data = self.as_ref();
312 is_not_null(data.vbmeta_images).map_err(|_| AvbSlotVerifyError::Io)?;
313 // SAFETY: It is safe as the raw pointer `data.vbmeta_images` is a nonnull pointer.
314 let vbmeta_images =
315 unsafe { slice::from_raw_parts(data.vbmeta_images, data.num_vbmeta_images) };
316 Ok(vbmeta_images)
317 }
318}
319
Alice Wanga78279c2022-12-16 12:41:19 +0000320struct Payload<'a> {
321 kernel: &'a [u8],
Alice Wang6b486f12023-01-06 13:12:16 +0000322 initrd: Option<&'a [u8]>,
Alice Wanga78279c2022-12-16 12:41:19 +0000323 trusted_public_key: &'a [u8],
324}
325
326impl<'a> AsRef<Payload<'a>> for AvbOps {
327 fn as_ref(&self) -> &Payload<'a> {
328 let payload = self.user_data as *const Payload;
329 // SAFETY: It is safe to cast the `AvbOps.user_data` to Payload as we have saved a
330 // pointer to a valid value of Payload in user_data when creating AvbOps, and
331 // assume that the Payload isn't used beyond the lifetime of the AvbOps that it
332 // belongs to.
333 unsafe { &*payload }
334 }
335}
336
337impl<'a> Payload<'a> {
Alice Wanga78279c2022-12-16 12:41:19 +0000338 fn get_partition(&self, partition_name: *const c_char) -> Result<&[u8], AvbIOError> {
Alice Wang951de3a2023-01-11 14:13:29 +0000339 match partition_name.try_into()? {
340 PartitionName::Kernel => Ok(self.kernel),
341 PartitionName::InitrdNormal | PartitionName::InitrdDebug => {
Alice Wang6b486f12023-01-06 13:12:16 +0000342 self.initrd.ok_or(AvbIOError::NoSuchPartition)
343 }
Alice Wanga78279c2022-12-16 12:41:19 +0000344 }
345 }
Alice Wang6b486f12023-01-06 13:12:16 +0000346
Alice Wang8aca6f92023-01-16 12:50:19 +0000347 fn verify_partition(
Alice Wang86383df2023-01-11 10:03:56 +0000348 &mut self,
Alice Wang8aca6f92023-01-16 12:50:19 +0000349 partition_name: &CStr,
Alice Wang86383df2023-01-11 10:03:56 +0000350 ) -> Result<AvbSlotVerifyDataWrap, AvbSlotVerifyError> {
Alice Wang8aca6f92023-01-16 12:50:19 +0000351 let requested_partitions = [partition_name.as_ptr(), ptr::null()];
Alice Wang6b486f12023-01-06 13:12:16 +0000352 let mut avb_ops = AvbOps {
353 user_data: self as *mut _ as *mut c_void,
354 ab_ops: ptr::null_mut(),
355 atx_ops: ptr::null_mut(),
356 read_from_partition: Some(read_from_partition),
357 get_preloaded_partition: Some(get_preloaded_partition),
358 write_to_partition: None,
359 validate_vbmeta_public_key: None,
360 read_rollback_index: Some(read_rollback_index),
361 write_rollback_index: None,
362 read_is_device_unlocked: Some(read_is_device_unlocked),
363 get_unique_guid_for_partition: Some(get_unique_guid_for_partition),
364 get_size_of_partition: Some(get_size_of_partition),
365 read_persistent_value: None,
366 write_persistent_value: None,
367 validate_public_key_for_partition: Some(validate_public_key_for_partition),
368 };
369 let ab_suffix = CStr::from_bytes_with_nul(NULL_BYTE).unwrap();
Alice Wang86383df2023-01-11 10:03:56 +0000370 let mut out_data = MaybeUninit::uninit();
Alice Wang6b486f12023-01-06 13:12:16 +0000371 // SAFETY: It is safe to call `avb_slot_verify()` as the pointer arguments (`ops`,
372 // `requested_partitions` and `ab_suffix`) passed to the method are all valid and
373 // initialized. The last argument `out_data` is allowed to be null so that nothing
374 // will be written to it.
375 let result = unsafe {
376 avb_slot_verify(
377 &mut avb_ops,
378 requested_partitions.as_ptr(),
379 ab_suffix.as_ptr(),
380 AvbSlotVerifyFlags::AVB_SLOT_VERIFY_FLAGS_NO_VBMETA_PARTITION,
381 AvbHashtreeErrorMode::AVB_HASHTREE_ERROR_MODE_RESTART_AND_INVALIDATE,
Alice Wang86383df2023-01-11 10:03:56 +0000382 out_data.as_mut_ptr(),
Alice Wang6b486f12023-01-06 13:12:16 +0000383 )
384 };
Alice Wang86383df2023-01-11 10:03:56 +0000385 slot_verify_result_to_verify_payload_result(result)?;
386 // SAFETY: This is safe because `out_data` has been properly initialized after
387 // calling `avb_slot_verify` and it returns OK.
388 let out_data = unsafe { out_data.assume_init() };
389 out_data.try_into()
390 }
391}
392
393fn verify_vbmeta_has_no_initrd_descriptor(
394 vbmeta_image: &AvbVBMetaData,
395) -> Result<(), AvbSlotVerifyError> {
396 is_not_null(vbmeta_image.vbmeta_data).map_err(|_| AvbSlotVerifyError::Io)?;
397 let mut has_unexpected_descriptor = false;
398 // SAFETY: It is safe as the raw pointer `vbmeta_image.vbmeta_data` is a nonnull pointer.
399 if !unsafe {
400 avb_descriptor_foreach(
401 vbmeta_image.vbmeta_data,
402 vbmeta_image.vbmeta_size,
403 Some(search_initrd_hash_descriptor),
404 &mut has_unexpected_descriptor as *mut _ as *mut c_void,
405 )
406 } {
407 return Err(AvbSlotVerifyError::InvalidMetadata);
408 }
409 if has_unexpected_descriptor {
410 Err(AvbSlotVerifyError::InvalidMetadata)
411 } else {
412 Ok(())
Alice Wang6b486f12023-01-06 13:12:16 +0000413 }
Alice Wanga78279c2022-12-16 12:41:19 +0000414}
415
Alice Wang9dfb2962023-01-18 10:01:34 +0000416fn verify_vbmeta_is_from_kernel_partition(
417 vbmeta_image: &AvbVBMetaData,
418) -> Result<(), AvbSlotVerifyError> {
419 match (vbmeta_image.partition_name as *const c_char).try_into() {
420 Ok(PartitionName::Kernel) => Ok(()),
421 _ => Err(AvbSlotVerifyError::InvalidMetadata),
422 }
423}
424
Alice Wangf3d96b12022-12-15 13:10:47 +0000425/// Verifies the payload (signed kernel + initrd) against the trusted public key.
Alice Wang6b486f12023-01-06 13:12:16 +0000426pub fn verify_payload(
427 kernel: &[u8],
428 initrd: Option<&[u8]>,
429 trusted_public_key: &[u8],
Alice Wang45d98fa2023-01-11 09:39:45 +0000430) -> Result<(), AvbSlotVerifyError> {
Alice Wang6b486f12023-01-06 13:12:16 +0000431 let mut payload = Payload { kernel, initrd, trusted_public_key };
Alice Wang8aca6f92023-01-16 12:50:19 +0000432 let kernel_verify_result = payload.verify_partition(PartitionName::Kernel.as_cstr())?;
Alice Wang86383df2023-01-11 10:03:56 +0000433 let vbmeta_images = kernel_verify_result.vbmeta_images()?;
434 if vbmeta_images.len() != 1 {
Alice Wang9dfb2962023-01-18 10:01:34 +0000435 // There can only be one VBMeta.
Alice Wang86383df2023-01-11 10:03:56 +0000436 return Err(AvbSlotVerifyError::InvalidMetadata);
437 }
Alice Wang9dfb2962023-01-18 10:01:34 +0000438 let vbmeta_image = vbmeta_images[0];
439 verify_vbmeta_is_from_kernel_partition(&vbmeta_image)?;
Alice Wang86383df2023-01-11 10:03:56 +0000440 if payload.initrd.is_none() {
Alice Wang9dfb2962023-01-18 10:01:34 +0000441 verify_vbmeta_has_no_initrd_descriptor(&vbmeta_image)?;
Alice Wang86383df2023-01-11 10:03:56 +0000442 }
443 // TODO(b/256148034): Check the vbmeta doesn't have hash descriptors other than
444 // boot, initrd_normal, initrd_debug.
445 Ok(())
Alice Wang28cbcf12022-12-01 07:58:28 +0000446}