summaryrefslogtreecommitdiff
path: root/libavb/avb_slot_verify.c (plain)
blob: 469a788545e0b08dcc25bc49ebfbc476c64a39c8
1/*
2 * Copyright (C) 2016 The Android Open Source Project
3 *
4 * Permission is hereby granted, free of charge, to any person
5 * obtaining a copy of this software and associated documentation
6 * files (the "Software"), to deal in the Software without
7 * restriction, including without limitation the rights to use, copy,
8 * modify, merge, publish, distribute, sublicense, and/or sell copies
9 * of the Software, and to permit persons to whom the Software is
10 * furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice shall be
13 * included in all copies or substantial portions of the Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
19 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
20 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
21 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 * SOFTWARE.
23 */
24
25#include "avb_slot_verify.h"
26#include "avb_chain_partition_descriptor.h"
27#include "avb_footer.h"
28#include "avb_hash_descriptor.h"
29#include "avb_kernel_cmdline_descriptor.h"
30#include "avb_sha.h"
31#include "avb_util.h"
32#include "avb_vbmeta_image.h"
33#include "avb_version.h"
34
35/* Maximum allow length (in bytes) of a partition name, including
36 * ab_suffix.
37 */
38#define PART_NAME_MAX_SIZE 32
39
40/* Maximum number of partitions that can be loaded with avb_slot_verify(). */
41#define MAX_NUMBER_OF_LOADED_PARTITIONS 32
42
43/* Maximum number of vbmeta images that can be loaded with avb_slot_verify(). */
44#define MAX_NUMBER_OF_VBMETA_IMAGES 32
45
46/* Maximum size of a vbmeta image - 64 KiB. */
47#define VBMETA_MAX_SIZE (64 * 1024)
48
49/* Helper function to see if we should continue with verification in
50 * allow_verification_error=true mode if something goes wrong. See the
51 * comments for the avb_slot_verify() function for more information.
52 */
53static inline bool result_should_continue(AvbSlotVerifyResult result) {
54 switch (result) {
55 case AVB_SLOT_VERIFY_RESULT_ERROR_OOM:
56 case AVB_SLOT_VERIFY_RESULT_ERROR_IO:
57 case AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA:
58 case AVB_SLOT_VERIFY_RESULT_ERROR_UNSUPPORTED_VERSION:
59 return false;
60
61 case AVB_SLOT_VERIFY_RESULT_OK:
62 case AVB_SLOT_VERIFY_RESULT_ERROR_VERIFICATION:
63 case AVB_SLOT_VERIFY_RESULT_ERROR_ROLLBACK_INDEX:
64 case AVB_SLOT_VERIFY_RESULT_ERROR_PUBLIC_KEY_REJECTED:
65 return true;
66 }
67
68 return false;
69}
70
71static AvbSlotVerifyResult load_and_verify_hash_partition(
72 AvbOps* ops,
73 const char* const* requested_partitions,
74 const char* ab_suffix,
75 bool allow_verification_error,
76 const AvbDescriptor* descriptor,
77 AvbSlotVerifyData* slot_data) {
78 AvbHashDescriptor hash_desc;
79 const uint8_t* desc_partition_name = NULL;
80 const uint8_t* desc_salt;
81 const uint8_t* desc_digest;
82 char part_name[PART_NAME_MAX_SIZE];
83 AvbSlotVerifyResult ret;
84 AvbIOResult io_ret;
85 uint8_t* image_buf = NULL;
86 size_t part_num_read;
87 uint8_t* digest;
88 size_t digest_len;
89 const char* found;
90
91 if (!avb_hash_descriptor_validate_and_byteswap(
92 (const AvbHashDescriptor*)descriptor, &hash_desc)) {
93 ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;
94 goto out;
95 }
96
97 desc_partition_name =
98 ((const uint8_t*)descriptor) + sizeof(AvbHashDescriptor);
99 desc_salt = desc_partition_name + hash_desc.partition_name_len;
100 desc_digest = desc_salt + hash_desc.salt_len;
101
102 if (!avb_validate_utf8(desc_partition_name, hash_desc.partition_name_len)) {
103 avb_error("Partition name is not valid UTF-8.\n");
104 ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;
105 goto out;
106 }
107
108 if (!avb_str_concat(part_name,
109 sizeof part_name,
110 (const char*)desc_partition_name,
111 hash_desc.partition_name_len,
112 ab_suffix,
113 avb_strlen(ab_suffix))) {
114 avb_error("Partition name and suffix does not fit.\n");
115 ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;
116 goto out;
117 }
118
119 image_buf = avb_malloc(hash_desc.image_size);
120 if (image_buf == NULL) {
121 ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
122 goto out;
123 }
124
125 io_ret = ops->read_from_partition(ops,
126 part_name,
127 0 /* offset */,
128 hash_desc.image_size,
129 image_buf,
130 &part_num_read);
131 if (io_ret == AVB_IO_RESULT_ERROR_OOM) {
132 ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
133 goto out;
134 } else if (io_ret != AVB_IO_RESULT_OK) {
135 avb_errorv(part_name, ": Error loading data from partition.\n", NULL);
136 ret = AVB_SLOT_VERIFY_RESULT_ERROR_IO;
137 goto out;
138 }
139 if (part_num_read != hash_desc.image_size) {
140 avb_errorv(part_name, ": Read fewer than requested bytes.\n", NULL);
141 ret = AVB_SLOT_VERIFY_RESULT_ERROR_IO;
142 goto out;
143 }
144
145 if (avb_strcmp((const char*)hash_desc.hash_algorithm, "sha256") == 0) {
146 AvbSHA256Ctx sha256_ctx;
147 avb_sha256_init(&sha256_ctx);
148 avb_sha256_update(&sha256_ctx, desc_salt, hash_desc.salt_len);
149 avb_sha256_update(&sha256_ctx, image_buf, hash_desc.image_size);
150 digest = avb_sha256_final(&sha256_ctx);
151 digest_len = AVB_SHA256_DIGEST_SIZE;
152 } else if (avb_strcmp((const char*)hash_desc.hash_algorithm, "sha512") == 0) {
153 AvbSHA512Ctx sha512_ctx;
154 avb_sha512_init(&sha512_ctx);
155 avb_sha512_update(&sha512_ctx, desc_salt, hash_desc.salt_len);
156 avb_sha512_update(&sha512_ctx, image_buf, hash_desc.image_size);
157 digest = avb_sha512_final(&sha512_ctx);
158 digest_len = AVB_SHA512_DIGEST_SIZE;
159 } else {
160 avb_errorv(part_name, ": Unsupported hash algorithm.\n", NULL);
161 ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;
162 goto out;
163 }
164
165 if (digest_len != hash_desc.digest_len) {
166 avb_errorv(
167 part_name, ": Digest in descriptor not of expected size.\n", NULL);
168 ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;
169 goto out;
170 }
171
172 if (avb_safe_memcmp(digest, desc_digest, digest_len) != 0) {
173 avb_errorv(part_name,
174 ": Hash of data does not match digest in descriptor.\n",
175 NULL);
176 ret = AVB_SLOT_VERIFY_RESULT_ERROR_VERIFICATION;
177 goto out;
178 }
179
180 ret = AVB_SLOT_VERIFY_RESULT_OK;
181
182out:
183
184 if (ret == AVB_SLOT_VERIFY_RESULT_OK || result_should_continue(ret)) {
185 /* If this is the requested partition, copy to slot_data. */
186 found = avb_strv_find_str(requested_partitions,
187 (const char*)desc_partition_name,
188 hash_desc.partition_name_len);
189 if (found != NULL) {
190 AvbPartitionData* loaded_partition;
191 if (slot_data->num_loaded_partitions == MAX_NUMBER_OF_LOADED_PARTITIONS) {
192 avb_errorv(part_name, ": Too many loaded partitions.\n", NULL);
193 ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
194 goto fail;
195 }
196 loaded_partition =
197 &slot_data->loaded_partitions[slot_data->num_loaded_partitions++];
198 loaded_partition->partition_name = avb_strdup(found);
199 loaded_partition->data_size = hash_desc.image_size;
200 loaded_partition->data = image_buf;
201 image_buf = NULL;
202 }
203 }
204
205fail:
206 if (image_buf != NULL) {
207 avb_free(image_buf);
208 }
209 return ret;
210}
211
212static AvbSlotVerifyResult load_and_verify_vbmeta(
213 AvbOps* ops,
214 const char* const* requested_partitions,
215 const char* ab_suffix,
216 bool allow_verification_error,
217 AvbVBMetaImageFlags toplevel_vbmeta_flags,
218 int rollback_index_location,
219 const char* partition_name,
220 size_t partition_name_len,
221 const uint8_t* expected_public_key,
222 size_t expected_public_key_length,
223 AvbSlotVerifyData* slot_data,
224 AvbAlgorithmType* out_algorithm_type) {
225 char full_partition_name[PART_NAME_MAX_SIZE];
226 AvbSlotVerifyResult ret;
227 AvbIOResult io_ret;
228 size_t vbmeta_offset;
229 size_t vbmeta_size;
230 uint8_t* vbmeta_buf = NULL;
231 size_t vbmeta_num_read;
232 AvbVBMetaVerifyResult vbmeta_ret;
233 const uint8_t* pk_data;
234 size_t pk_len;
235 AvbVBMetaImageHeader vbmeta_header;
236 uint64_t stored_rollback_index;
237 const AvbDescriptor** descriptors = NULL;
238 size_t num_descriptors;
239 size_t n;
240 bool is_main_vbmeta;
241 bool is_vbmeta_partition;
242 AvbVBMetaData* vbmeta_image_data = NULL;
243
244 ret = AVB_SLOT_VERIFY_RESULT_OK;
245
246 avb_assert(slot_data != NULL);
247
248 /* Since we allow top-level vbmeta in 'boot', use
249 * rollback_index_location to determine whether we're the main
250 * vbmeta struct.
251 */
252 is_main_vbmeta = (rollback_index_location == 0);
253 is_vbmeta_partition = (avb_strcmp(partition_name, "vbmeta") == 0);
254
255 if (!avb_validate_utf8((const uint8_t*)partition_name, partition_name_len)) {
256 avb_error("Partition name is not valid UTF-8.\n");
257 ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;
258 goto out;
259 }
260
261 /* Construct full partition name. */
262 if (!avb_str_concat(full_partition_name,
263 sizeof full_partition_name,
264 partition_name,
265 partition_name_len,
266 ab_suffix,
267 avb_strlen(ab_suffix))) {
268 avb_error("Partition name and suffix does not fit.\n");
269 ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;
270 goto out;
271 }
272
273 avb_debugv("Loading vbmeta struct from partition '",
274 full_partition_name,
275 "'.\n",
276 NULL);
277
278 /* If we're loading from the main vbmeta partition, the vbmeta
279 * struct is in the beginning. Otherwise we have to locate it via a
280 * footer.
281 */
282 if (is_vbmeta_partition) {
283 vbmeta_offset = 0;
284 vbmeta_size = VBMETA_MAX_SIZE;
285 } else {
286 uint8_t footer_buf[AVB_FOOTER_SIZE];
287 size_t footer_num_read;
288 AvbFooter footer;
289
290 io_ret = ops->read_from_partition(ops,
291 full_partition_name,
292 -AVB_FOOTER_SIZE,
293 AVB_FOOTER_SIZE,
294 footer_buf,
295 &footer_num_read);
296 if (io_ret == AVB_IO_RESULT_ERROR_OOM) {
297 ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
298 goto out;
299 } else if (io_ret != AVB_IO_RESULT_OK) {
300 avb_errorv(full_partition_name, ": Error loading footer.\n", NULL);
301 ret = AVB_SLOT_VERIFY_RESULT_ERROR_IO;
302 goto out;
303 }
304 avb_assert(footer_num_read == AVB_FOOTER_SIZE);
305
306 if (!avb_footer_validate_and_byteswap((const AvbFooter*)footer_buf,
307 &footer)) {
308 avb_errorv(full_partition_name, ": Error validating footer.\n", NULL);
309 ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;
310 goto out;
311 }
312
313 /* Basic footer sanity check since the data is untrusted. */
314 if (footer.vbmeta_size > VBMETA_MAX_SIZE) {
315 avb_errorv(
316 full_partition_name, ": Invalid vbmeta size in footer.\n", NULL);
317 ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;
318 goto out;
319 }
320
321 vbmeta_offset = footer.vbmeta_offset;
322 vbmeta_size = footer.vbmeta_size;
323 }
324
325 vbmeta_buf = avb_malloc(vbmeta_size);
326 if (vbmeta_buf == NULL) {
327 ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
328 goto out;
329 }
330
331 io_ret = ops->read_from_partition(ops,
332 full_partition_name,
333 vbmeta_offset,
334 vbmeta_size,
335 vbmeta_buf,
336 &vbmeta_num_read);
337 if (io_ret == AVB_IO_RESULT_ERROR_OOM) {
338 ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
339 goto out;
340 } else if (io_ret != AVB_IO_RESULT_OK) {
341 /* If we're looking for 'vbmeta' but there is no such partition,
342 * go try to get it from the boot partition instead.
343 */
344 if (is_main_vbmeta && io_ret == AVB_IO_RESULT_ERROR_NO_SUCH_PARTITION &&
345 is_vbmeta_partition) {
346 avb_debugv(full_partition_name,
347 ": No such partition. Trying 'boot' instead.\n",
348 NULL);
349 ret = load_and_verify_vbmeta(ops,
350 requested_partitions,
351 ab_suffix,
352 allow_verification_error,
353 0 /* toplevel_vbmeta_flags */,
354 0 /* rollback_index_location */,
355 "boot",
356 avb_strlen("boot"),
357 NULL /* expected_public_key */,
358 0 /* expected_public_key_length */,
359 slot_data,
360 out_algorithm_type);
361 goto out;
362 } else {
363 avb_errorv(full_partition_name, ": Error loading vbmeta data.\n", NULL);
364 ret = AVB_SLOT_VERIFY_RESULT_ERROR_IO;
365 goto out;
366 }
367 }
368 avb_assert(vbmeta_num_read <= vbmeta_size);
369
370 /* Check if the image is properly signed and get the public key used
371 * to sign the image.
372 */
373 vbmeta_ret =
374 avb_vbmeta_image_verify(vbmeta_buf, vbmeta_num_read, &pk_data, &pk_len);
375 switch (vbmeta_ret) {
376 case AVB_VBMETA_VERIFY_RESULT_OK:
377 avb_assert(pk_data != NULL && pk_len > 0);
378 break;
379
380 case AVB_VBMETA_VERIFY_RESULT_OK_NOT_SIGNED:
381 case AVB_VBMETA_VERIFY_RESULT_HASH_MISMATCH:
382 case AVB_VBMETA_VERIFY_RESULT_SIGNATURE_MISMATCH:
383 ret = AVB_SLOT_VERIFY_RESULT_ERROR_VERIFICATION;
384 avb_errorv(full_partition_name,
385 ": Error verifying vbmeta image: ",
386 avb_vbmeta_verify_result_to_string(vbmeta_ret),
387 "\n",
388 NULL);
389 if (!allow_verification_error) {
390 goto out;
391 }
392 break;
393
394 case AVB_VBMETA_VERIFY_RESULT_INVALID_VBMETA_HEADER:
395 /* No way to continue this case. */
396 ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;
397 avb_errorv(full_partition_name,
398 ": Error verifying vbmeta image: invalid vbmeta header\n",
399 NULL);
400 goto out;
401
402 case AVB_VBMETA_VERIFY_RESULT_UNSUPPORTED_VERSION:
403 /* No way to continue this case. */
404 ret = AVB_SLOT_VERIFY_RESULT_ERROR_UNSUPPORTED_VERSION;
405 avb_errorv(full_partition_name,
406 ": Error verifying vbmeta image: unsupported AVB version\n",
407 NULL);
408 goto out;
409 }
410
411 /* Byteswap the header. */
412 avb_vbmeta_image_header_to_host_byte_order((AvbVBMetaImageHeader*)vbmeta_buf,
413 &vbmeta_header);
414
415 /* If we're the toplevel, assign flags so they'll be passed down. */
416 if (is_main_vbmeta) {
417 toplevel_vbmeta_flags = (AvbVBMetaImageFlags)vbmeta_header.flags;
418 } else {
419 if (vbmeta_header.flags != 0) {
420 ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;
421 avb_errorv(full_partition_name,
422 ": chained vbmeta image has non-zero flags\n",
423 NULL);
424 goto out;
425 }
426 }
427
428 /* Check if key used to make signature matches what is expected. */
429 if (pk_data != NULL) {
430 if (expected_public_key != NULL) {
431 avb_assert(!is_main_vbmeta);
432 if (expected_public_key_length != pk_len ||
433 avb_safe_memcmp(expected_public_key, pk_data, pk_len) != 0) {
434 avb_errorv(full_partition_name,
435 ": Public key used to sign data does not match key in chain "
436 "partition descriptor.\n",
437 NULL);
438 ret = AVB_SLOT_VERIFY_RESULT_ERROR_PUBLIC_KEY_REJECTED;
439 if (!allow_verification_error) {
440 goto out;
441 }
442 }
443 } else {
444 bool key_is_trusted = false;
445 const uint8_t* pk_metadata = NULL;
446 size_t pk_metadata_len = 0;
447
448 if (vbmeta_header.public_key_metadata_size > 0) {
449 pk_metadata = vbmeta_buf + sizeof(AvbVBMetaImageHeader) +
450 vbmeta_header.authentication_data_block_size +
451 vbmeta_header.public_key_metadata_offset;
452 pk_metadata_len = vbmeta_header.public_key_metadata_size;
453 }
454
455 avb_assert(is_main_vbmeta);
456 io_ret = ops->validate_vbmeta_public_key(
457 ops, pk_data, pk_len, pk_metadata, pk_metadata_len, &key_is_trusted);
458 if (io_ret == AVB_IO_RESULT_ERROR_OOM) {
459 ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
460 goto out;
461 } else if (io_ret != AVB_IO_RESULT_OK) {
462 avb_errorv(full_partition_name,
463 ": Error while checking public key used to sign data.\n",
464 NULL);
465 ret = AVB_SLOT_VERIFY_RESULT_ERROR_IO;
466 goto out;
467 }
468 if (!key_is_trusted) {
469 avb_errorv(full_partition_name,
470 ": Public key used to sign data rejected.\n",
471 NULL);
472 ret = AVB_SLOT_VERIFY_RESULT_ERROR_PUBLIC_KEY_REJECTED;
473 if (!allow_verification_error) {
474 goto out;
475 }
476 }
477 }
478 }
479
480 /* Check rollback index. */
481 io_ret = ops->read_rollback_index(
482 ops, rollback_index_location, &stored_rollback_index);
483 if (io_ret == AVB_IO_RESULT_ERROR_OOM) {
484 ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
485 goto out;
486 } else if (io_ret != AVB_IO_RESULT_OK) {
487 avb_errorv(full_partition_name,
488 ": Error getting rollback index for location.\n",
489 NULL);
490 ret = AVB_SLOT_VERIFY_RESULT_ERROR_IO;
491 goto out;
492 }
493 if (vbmeta_header.rollback_index < stored_rollback_index) {
494 avb_errorv(
495 full_partition_name,
496 ": Image rollback index is less than the stored rollback index.\n",
497 NULL);
498 ret = AVB_SLOT_VERIFY_RESULT_ERROR_ROLLBACK_INDEX;
499 if (!allow_verification_error) {
500 goto out;
501 }
502 }
503
504 /* Copy vbmeta to vbmeta_images before recursing. */
505 if (is_main_vbmeta) {
506 avb_assert(slot_data->num_vbmeta_images == 0);
507 } else {
508 avb_assert(slot_data->num_vbmeta_images > 0);
509 }
510 if (slot_data->num_vbmeta_images == MAX_NUMBER_OF_VBMETA_IMAGES) {
511 avb_errorv(full_partition_name, ": Too many vbmeta images.\n", NULL);
512 ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
513 goto out;
514 }
515 vbmeta_image_data = &slot_data->vbmeta_images[slot_data->num_vbmeta_images++];
516 vbmeta_image_data->partition_name = avb_strdup(partition_name);
517 vbmeta_image_data->vbmeta_data = vbmeta_buf;
518 /* Note that |vbmeta_buf| is actually |vbmeta_num_read| bytes long
519 * and this includes data past the end of the image. Pass the
520 * actual size of the vbmeta image. Also, no need to use
521 * avb_safe_add() since the header has already been verified.
522 */
523 vbmeta_image_data->vbmeta_size =
524 sizeof(AvbVBMetaImageHeader) +
525 vbmeta_header.authentication_data_block_size +
526 vbmeta_header.auxiliary_data_block_size;
527 vbmeta_image_data->verify_result = vbmeta_ret;
528
529 /* Now go through all descriptors and take the appropriate action:
530 *
531 * - hash descriptor: Load data from partition, calculate hash, and
532 * checks that it matches what's in the hash descriptor.
533 *
534 * - hashtree descriptor: Do nothing since verification happens
535 * on-the-fly from within the OS.
536 *
537 * - chained partition descriptor: Load the footer, load the vbmeta
538 * image, verify vbmeta image (includes rollback checks, hash
539 * checks, bail on chained partitions).
540 */
541 descriptors =
542 avb_descriptor_get_all(vbmeta_buf, vbmeta_num_read, &num_descriptors);
543 for (n = 0; n < num_descriptors; n++) {
544 AvbDescriptor desc;
545
546 if (!avb_descriptor_validate_and_byteswap(descriptors[n], &desc)) {
547 avb_errorv(full_partition_name, ": Descriptor is invalid.\n", NULL);
548 ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;
549 goto out;
550 }
551
552 switch (desc.tag) {
553 case AVB_DESCRIPTOR_TAG_HASH: {
554 AvbSlotVerifyResult sub_ret;
555 sub_ret = load_and_verify_hash_partition(ops,
556 requested_partitions,
557 ab_suffix,
558 allow_verification_error,
559 descriptors[n],
560 slot_data);
561 if (sub_ret != AVB_SLOT_VERIFY_RESULT_OK) {
562 ret = sub_ret;
563 if (!allow_verification_error || !result_should_continue(ret)) {
564 goto out;
565 }
566 }
567 } break;
568
569 case AVB_DESCRIPTOR_TAG_CHAIN_PARTITION: {
570 AvbSlotVerifyResult sub_ret;
571 AvbChainPartitionDescriptor chain_desc;
572 const uint8_t* chain_partition_name;
573 const uint8_t* chain_public_key;
574
575 /* Only allow CHAIN_PARTITION descriptors in the main vbmeta image. */
576 if (!is_main_vbmeta) {
577 avb_errorv(full_partition_name,
578 ": Encountered chain descriptor not in main image.\n",
579 NULL);
580 ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;
581 goto out;
582 }
583
584 if (!avb_chain_partition_descriptor_validate_and_byteswap(
585 (AvbChainPartitionDescriptor*)descriptors[n], &chain_desc)) {
586 avb_errorv(full_partition_name,
587 ": Chain partition descriptor is invalid.\n",
588 NULL);
589 ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;
590 goto out;
591 }
592
593 if (chain_desc.rollback_index_location == 0) {
594 avb_errorv(full_partition_name,
595 ": Chain partition has invalid "
596 "rollback_index_location field.\n",
597 NULL);
598 ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;
599 goto out;
600 }
601
602 chain_partition_name = ((const uint8_t*)descriptors[n]) +
603 sizeof(AvbChainPartitionDescriptor);
604 chain_public_key = chain_partition_name + chain_desc.partition_name_len;
605
606 sub_ret = load_and_verify_vbmeta(ops,
607 requested_partitions,
608 ab_suffix,
609 allow_verification_error,
610 toplevel_vbmeta_flags,
611 chain_desc.rollback_index_location,
612 (const char*)chain_partition_name,
613 chain_desc.partition_name_len,
614 chain_public_key,
615 chain_desc.public_key_len,
616 slot_data,
617 NULL /* out_algorithm_type */);
618 if (sub_ret != AVB_SLOT_VERIFY_RESULT_OK) {
619 ret = sub_ret;
620 if (!result_should_continue(ret)) {
621 goto out;
622 }
623 }
624 } break;
625
626 case AVB_DESCRIPTOR_TAG_KERNEL_CMDLINE: {
627 const uint8_t* kernel_cmdline;
628 AvbKernelCmdlineDescriptor kernel_cmdline_desc;
629 bool apply_cmdline;
630
631 if (!avb_kernel_cmdline_descriptor_validate_and_byteswap(
632 (AvbKernelCmdlineDescriptor*)descriptors[n],
633 &kernel_cmdline_desc)) {
634 avb_errorv(full_partition_name,
635 ": Kernel cmdline descriptor is invalid.\n",
636 NULL);
637 ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;
638 goto out;
639 }
640
641 kernel_cmdline = ((const uint8_t*)descriptors[n]) +
642 sizeof(AvbKernelCmdlineDescriptor);
643
644 if (!avb_validate_utf8(kernel_cmdline,
645 kernel_cmdline_desc.kernel_cmdline_length)) {
646 avb_errorv(full_partition_name,
647 ": Kernel cmdline is not valid UTF-8.\n",
648 NULL);
649 ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;
650 goto out;
651 }
652
653 /* Compare the flags for top-level VBMeta struct with flags in
654 * the command-line descriptor so command-line snippets only
655 * intended for a certain mode (dm-verity enabled/disabled)
656 * are skipped if applicable.
657 */
658 apply_cmdline = true;
659 if (toplevel_vbmeta_flags & AVB_VBMETA_IMAGE_FLAGS_HASHTREE_DISABLED) {
660 if (kernel_cmdline_desc.flags &
661 AVB_KERNEL_CMDLINE_FLAGS_USE_ONLY_IF_HASHTREE_NOT_DISABLED) {
662 apply_cmdline = false;
663 }
664 } else {
665 if (kernel_cmdline_desc.flags &
666 AVB_KERNEL_CMDLINE_FLAGS_USE_ONLY_IF_HASHTREE_DISABLED) {
667 apply_cmdline = false;
668 }
669 }
670
671 if (apply_cmdline) {
672 if (slot_data->cmdline == NULL) {
673 slot_data->cmdline =
674 avb_calloc(kernel_cmdline_desc.kernel_cmdline_length + 1);
675 if (slot_data->cmdline == NULL) {
676 ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
677 goto out;
678 }
679 avb_memcpy(slot_data->cmdline,
680 kernel_cmdline,
681 kernel_cmdline_desc.kernel_cmdline_length);
682 } else {
683 /* new cmdline is: <existing_cmdline> + ' ' + <newcmdline> + '\0' */
684 size_t orig_size = avb_strlen(slot_data->cmdline);
685 size_t new_size =
686 orig_size + 1 + kernel_cmdline_desc.kernel_cmdline_length + 1;
687 char* new_cmdline = avb_calloc(new_size);
688 if (new_cmdline == NULL) {
689 ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
690 goto out;
691 }
692 avb_memcpy(new_cmdline, slot_data->cmdline, orig_size);
693 new_cmdline[orig_size] = ' ';
694 avb_memcpy(new_cmdline + orig_size + 1,
695 kernel_cmdline,
696 kernel_cmdline_desc.kernel_cmdline_length);
697 avb_free(slot_data->cmdline);
698 slot_data->cmdline = new_cmdline;
699 }
700 }
701 } break;
702
703 /* Explicit fall-through */
704 case AVB_DESCRIPTOR_TAG_PROPERTY:
705 case AVB_DESCRIPTOR_TAG_HASHTREE:
706 /* Do nothing. */
707 break;
708 }
709 }
710
711 if (rollback_index_location >= AVB_MAX_NUMBER_OF_ROLLBACK_INDEX_LOCATIONS) {
712 avb_errorv(
713 full_partition_name, ": Invalid rollback_index_location.\n", NULL);
714 ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;
715 goto out;
716 }
717
718 slot_data->rollback_indexes[rollback_index_location] =
719 vbmeta_header.rollback_index;
720
721 if (out_algorithm_type != NULL) {
722 *out_algorithm_type = (AvbAlgorithmType)vbmeta_header.algorithm_type;
723 }
724
725out:
726 /* If |vbmeta_image_data| isn't NULL it means that it adopted
727 * |vbmeta_buf| so in that case don't free it here.
728 */
729 if (vbmeta_image_data == NULL) {
730 if (vbmeta_buf != NULL) {
731 avb_free(vbmeta_buf);
732 }
733 }
734 if (descriptors != NULL) {
735 avb_free(descriptors);
736 }
737 return ret;
738}
739
740#define NUM_GUIDS 3
741
742/* Substitutes all variables (e.g. $(ANDROID_SYSTEM_PARTUUID)) with
743 * values. Returns NULL on OOM, otherwise the cmdline with values
744 * replaced.
745 */
746static char* sub_cmdline(AvbOps* ops,
747 const char* cmdline,
748 const char* ab_suffix,
749 bool using_boot_for_vbmeta) {
750 const char* part_name_str[NUM_GUIDS] = {"system", "boot", "vbmeta"};
751 const char* replace_str[NUM_GUIDS] = {"$(ANDROID_SYSTEM_PARTUUID)",
752 "$(ANDROID_BOOT_PARTUUID)",
753 "$(ANDROID_VBMETA_PARTUUID)"};
754 char* ret = NULL;
755 AvbIOResult io_ret;
756
757 /* Special-case for when the top-level vbmeta struct is in the boot
758 * partition.
759 */
760 if (using_boot_for_vbmeta) {
761 part_name_str[2] = "boot";
762 }
763
764 /* Replace unique partition GUIDs */
765 for (size_t n = 0; n < NUM_GUIDS; n++) {
766 char part_name[PART_NAME_MAX_SIZE];
767 char guid_buf[37];
768
769 if (!avb_str_concat(part_name,
770 sizeof part_name,
771 part_name_str[n],
772 avb_strlen(part_name_str[n]),
773 ab_suffix,
774 avb_strlen(ab_suffix))) {
775 avb_error("Partition name and suffix does not fit.\n");
776 goto fail;
777 }
778
779 io_ret = ops->get_unique_guid_for_partition(
780 ops, part_name, guid_buf, sizeof guid_buf);
781 if (io_ret == AVB_IO_RESULT_ERROR_OOM) {
782 return NULL;
783 } else if (io_ret != AVB_IO_RESULT_OK) {
784 avb_error("Error getting unique GUID for partition.\n");
785 goto fail;
786 }
787
788 if (ret == NULL) {
789 ret = avb_replace(cmdline, replace_str[n], guid_buf);
790 } else {
791 char* new_ret = avb_replace(ret, replace_str[n], guid_buf);
792 avb_free(ret);
793 ret = new_ret;
794 }
795 if (ret == NULL) {
796 goto fail;
797 }
798 }
799
800 return ret;
801
802fail:
803 if (ret != NULL) {
804 avb_free(ret);
805 }
806 return NULL;
807}
808
809static int cmdline_append_option(AvbSlotVerifyData* slot_data,
810 const char* key,
811 const char* value) {
812 size_t offset, key_len, value_len;
813 char* new_cmdline;
814
815 key_len = avb_strlen(key);
816 value_len = avb_strlen(value);
817
818 offset = 0;
819 if (slot_data->cmdline != NULL) {
820 offset = avb_strlen(slot_data->cmdline);
821 if (offset > 0) {
822 offset += 1;
823 }
824 }
825
826 new_cmdline = avb_calloc(offset + key_len + value_len + 2);
827 if (new_cmdline == NULL) {
828 return 0;
829 }
830 if (offset > 0) {
831 avb_memcpy(new_cmdline, slot_data->cmdline, offset - 1);
832 new_cmdline[offset - 1] = ' ';
833 }
834 avb_memcpy(new_cmdline + offset, key, key_len);
835 new_cmdline[offset + key_len] = '=';
836 avb_memcpy(new_cmdline + offset + key_len + 1, value, value_len);
837 if (slot_data->cmdline != NULL) {
838 avb_free(slot_data->cmdline);
839 }
840 slot_data->cmdline = new_cmdline;
841
842 return 1;
843}
844
845#define AVB_MAX_DIGITS_UINT64 32
846
847/* Writes |value| to |digits| in base 10 followed by a NUL byte.
848 * Returns number of characters written excluding the NUL byte.
849 */
850static size_t uint64_to_base10(uint64_t value,
851 char digits[AVB_MAX_DIGITS_UINT64]) {
852 char rev_digits[AVB_MAX_DIGITS_UINT64];
853 size_t n, num_digits;
854
855 for (num_digits = 0; num_digits < AVB_MAX_DIGITS_UINT64 - 1;) {
856 rev_digits[num_digits++] = (value % 10) + '0';
857 value /= 10;
858 if (value == 0) {
859 break;
860 }
861 }
862
863 for (n = 0; n < num_digits; n++) {
864 digits[n] = rev_digits[num_digits - 1 - n];
865 }
866 digits[n] = '\0';
867 return n;
868}
869
870static int cmdline_append_version(AvbSlotVerifyData* slot_data,
871 const char* key,
872 uint64_t major_version,
873 uint64_t minor_version) {
874 char major_digits[AVB_MAX_DIGITS_UINT64];
875 char minor_digits[AVB_MAX_DIGITS_UINT64];
876 char combined[AVB_MAX_DIGITS_UINT64 * 2 + 1];
877 size_t num_major_digits, num_minor_digits;
878
879 num_major_digits = uint64_to_base10(major_version, major_digits);
880 num_minor_digits = uint64_to_base10(minor_version, minor_digits);
881 avb_memcpy(combined, major_digits, num_major_digits);
882 combined[num_major_digits] = '.';
883 avb_memcpy(combined + num_major_digits + 1, minor_digits, num_minor_digits);
884 combined[num_major_digits + 1 + num_minor_digits] = '\0';
885
886 return cmdline_append_option(slot_data, key, combined);
887}
888
889static int cmdline_append_uint64_base10(AvbSlotVerifyData* slot_data,
890 const char* key,
891 uint64_t value) {
892 char digits[AVB_MAX_DIGITS_UINT64];
893 uint64_to_base10(value, digits);
894 return cmdline_append_option(slot_data, key, digits);
895}
896
897static int cmdline_append_hex(AvbSlotVerifyData* slot_data,
898 const char* key,
899 const uint8_t* data,
900 size_t data_len) {
901 char hex_digits[17] = "0123456789abcdef";
902 char* hex_data;
903 int ret;
904 size_t n;
905
906 hex_data = avb_malloc(data_len * 2 + 1);
907 if (hex_data == NULL) {
908 return 0;
909 }
910
911 for (n = 0; n < data_len; n++) {
912 hex_data[n * 2] = hex_digits[data[n] >> 4];
913 hex_data[n * 2 + 1] = hex_digits[data[n] & 0x0f];
914 }
915 hex_data[n * 2] = '\0';
916
917 ret = cmdline_append_option(slot_data, key, hex_data);
918 avb_free(hex_data);
919 return ret;
920}
921
922AvbSlotVerifyResult avb_slot_verify(AvbOps* ops,
923 const char* const* requested_partitions,
924 const char* ab_suffix,
925 bool allow_verification_error,
926 AvbSlotVerifyData** out_data) {
927 AvbSlotVerifyResult ret;
928 AvbSlotVerifyData* slot_data = NULL;
929 AvbAlgorithmType algorithm_type = AVB_ALGORITHM_TYPE_NONE;
930 AvbIOResult io_ret;
931 bool using_boot_for_vbmeta = false;
932
933 if (out_data != NULL) {
934 *out_data = NULL;
935 }
936
937 slot_data = avb_calloc(sizeof(AvbSlotVerifyData));
938 if (slot_data == NULL) {
939 ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
940 goto fail;
941 }
942 slot_data->vbmeta_images =
943 avb_calloc(sizeof(AvbVBMetaData) * MAX_NUMBER_OF_VBMETA_IMAGES);
944 if (slot_data->vbmeta_images == NULL) {
945 ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
946 goto fail;
947 }
948 slot_data->loaded_partitions =
949 avb_calloc(sizeof(AvbPartitionData) * MAX_NUMBER_OF_LOADED_PARTITIONS);
950 if (slot_data->loaded_partitions == NULL) {
951 ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
952 goto fail;
953 }
954
955 ret = load_and_verify_vbmeta(ops,
956 requested_partitions,
957 ab_suffix,
958 allow_verification_error,
959 0 /* toplevel_vbmeta_flags */,
960 0 /* rollback_index_location */,
961 "vbmeta",
962 avb_strlen("vbmeta"),
963 NULL /* expected_public_key */,
964 0 /* expected_public_key_length */,
965 slot_data,
966 &algorithm_type);
967 if (!allow_verification_error && ret != AVB_SLOT_VERIFY_RESULT_OK) {
968 goto fail;
969 }
970
971 if (avb_strcmp(slot_data->vbmeta_images[0].partition_name, "vbmeta") != 0) {
972 avb_assert(avb_strcmp(slot_data->vbmeta_images[0].partition_name, "boot") ==
973 0);
974 using_boot_for_vbmeta = true;
975 }
976
977 /* If things check out, mangle the kernel command-line as needed. */
978 if (result_should_continue(ret)) {
979 /* Fill in |ab_suffix| field. */
980 slot_data->ab_suffix = avb_strdup(ab_suffix);
981 if (slot_data->ab_suffix == NULL) {
982 ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
983 goto fail;
984 }
985
986 /* Add androidboot.vbmeta.device option. */
987 if (!cmdline_append_option(slot_data,
988 "androidboot.vbmeta.device",
989 "PARTUUID=$(ANDROID_VBMETA_PARTUUID)")) {
990 ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
991 goto fail;
992 }
993
994 /* Add androidboot.vbmeta.avb_version option. */
995 if (!cmdline_append_version(slot_data,
996 "androidboot.vbmeta.avb_version",
997 AVB_VERSION_MAJOR,
998 AVB_VERSION_MINOR)) {
999 ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
1000 goto fail;
1001 }
1002
1003 /* Substitute $(ANDROID_SYSTEM_PARTUUID) and friends. */
1004 if (slot_data->cmdline != NULL) {
1005 char* new_cmdline;
1006 new_cmdline = sub_cmdline(
1007 ops, slot_data->cmdline, ab_suffix, using_boot_for_vbmeta);
1008 if (new_cmdline == NULL) {
1009 ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
1010 goto fail;
1011 }
1012 avb_free(slot_data->cmdline);
1013 slot_data->cmdline = new_cmdline;
1014 }
1015
1016 /* Set androidboot.avb.device_state to "locked" or "unlocked". */
1017 bool is_device_unlocked;
1018 io_ret = ops->read_is_device_unlocked(ops, &is_device_unlocked);
1019 if (io_ret == AVB_IO_RESULT_ERROR_OOM) {
1020 ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
1021 goto fail;
1022 } else if (io_ret != AVB_IO_RESULT_OK) {
1023 avb_error("Error getting device state.\n");
1024 ret = AVB_SLOT_VERIFY_RESULT_ERROR_IO;
1025 goto fail;
1026 }
1027 if (!cmdline_append_option(slot_data,
1028 "androidboot.vbmeta.device_state",
1029 is_device_unlocked ? "unlocked" : "locked")) {
1030 ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
1031 goto fail;
1032 }
1033
1034 /* Set androidboot.vbmeta.{hash_alg, size, digest} - use same hash
1035 * function as is used to sign vbmeta.
1036 */
1037 switch (algorithm_type) {
1038 /* Explicit fallthrough. */
1039 case AVB_ALGORITHM_TYPE_NONE:
1040 case AVB_ALGORITHM_TYPE_SHA256_RSA2048:
1041 case AVB_ALGORITHM_TYPE_SHA256_RSA4096:
1042 case AVB_ALGORITHM_TYPE_SHA256_RSA8192: {
1043 AvbSHA256Ctx ctx;
1044 size_t n, total_size = 0;
1045 avb_sha256_init(&ctx);
1046 for (n = 0; n < slot_data->num_vbmeta_images; n++) {
1047 avb_sha256_update(&ctx,
1048 slot_data->vbmeta_images[n].vbmeta_data,
1049 slot_data->vbmeta_images[n].vbmeta_size);
1050 total_size += slot_data->vbmeta_images[n].vbmeta_size;
1051 }
1052 if (!cmdline_append_option(
1053 slot_data, "androidboot.vbmeta.hash_alg", "sha256") ||
1054 !cmdline_append_uint64_base10(
1055 slot_data, "androidboot.vbmeta.size", total_size) ||
1056 !cmdline_append_hex(slot_data,
1057 "androidboot.vbmeta.digest",
1058 avb_sha256_final(&ctx),
1059 AVB_SHA256_DIGEST_SIZE)) {
1060 ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
1061 goto fail;
1062 }
1063 } break;
1064 /* Explicit fallthrough. */
1065 case AVB_ALGORITHM_TYPE_SHA512_RSA2048:
1066 case AVB_ALGORITHM_TYPE_SHA512_RSA4096:
1067 case AVB_ALGORITHM_TYPE_SHA512_RSA8192: {
1068 AvbSHA512Ctx ctx;
1069 size_t n, total_size = 0;
1070 avb_sha512_init(&ctx);
1071 for (n = 0; n < slot_data->num_vbmeta_images; n++) {
1072 avb_sha512_update(&ctx,
1073 slot_data->vbmeta_images[n].vbmeta_data,
1074 slot_data->vbmeta_images[n].vbmeta_size);
1075 total_size += slot_data->vbmeta_images[n].vbmeta_size;
1076 }
1077 if (!cmdline_append_option(
1078 slot_data, "androidboot.vbmeta.hash_alg", "sha512") ||
1079 !cmdline_append_uint64_base10(
1080 slot_data, "androidboot.vbmeta.size", total_size) ||
1081 !cmdline_append_hex(slot_data,
1082 "androidboot.vbmeta.digest",
1083 avb_sha512_final(&ctx),
1084 AVB_SHA512_DIGEST_SIZE)) {
1085 ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
1086 goto fail;
1087 }
1088 } break;
1089 case _AVB_ALGORITHM_NUM_TYPES:
1090 avb_assert_not_reached();
1091 break;
1092 }
1093
1094 if (out_data != NULL) {
1095 *out_data = slot_data;
1096 } else {
1097 avb_slot_verify_data_free(slot_data);
1098 }
1099 }
1100
1101 if (!allow_verification_error) {
1102 avb_assert(ret == AVB_SLOT_VERIFY_RESULT_OK);
1103 }
1104
1105 return ret;
1106
1107fail:
1108 if (slot_data != NULL) {
1109 avb_slot_verify_data_free(slot_data);
1110 }
1111 return ret;
1112}
1113
1114void avb_slot_verify_data_free(AvbSlotVerifyData* data) {
1115 if (data->ab_suffix != NULL) {
1116 avb_free(data->ab_suffix);
1117 }
1118 if (data->cmdline != NULL) {
1119 avb_free(data->cmdline);
1120 }
1121 if (data->vbmeta_images != NULL) {
1122 size_t n;
1123 for (n = 0; n < data->num_vbmeta_images; n++) {
1124 AvbVBMetaData* vbmeta_image = &data->vbmeta_images[n];
1125 if (vbmeta_image->partition_name != NULL) {
1126 avb_free(vbmeta_image->partition_name);
1127 }
1128 if (vbmeta_image->vbmeta_data != NULL) {
1129 avb_free(vbmeta_image->vbmeta_data);
1130 }
1131 }
1132 avb_free(data->vbmeta_images);
1133 }
1134 if (data->loaded_partitions != NULL) {
1135 size_t n;
1136 for (n = 0; n < data->num_loaded_partitions; n++) {
1137 AvbPartitionData* loaded_partition = &data->loaded_partitions[n];
1138 if (loaded_partition->partition_name != NULL) {
1139 avb_free(loaded_partition->partition_name);
1140 }
1141 if (loaded_partition->data != NULL) {
1142 avb_free(loaded_partition->data);
1143 }
1144 }
1145 avb_free(data->loaded_partitions);
1146 }
1147 avb_free(data);
1148}
1149
1150const char* avb_slot_verify_result_to_string(AvbSlotVerifyResult result) {
1151 const char* ret = NULL;
1152
1153 switch (result) {
1154 case AVB_SLOT_VERIFY_RESULT_OK:
1155 ret = "OK";
1156 break;
1157 case AVB_SLOT_VERIFY_RESULT_ERROR_OOM:
1158 ret = "ERROR_OOM";
1159 break;
1160 case AVB_SLOT_VERIFY_RESULT_ERROR_IO:
1161 ret = "ERROR_IO";
1162 break;
1163 case AVB_SLOT_VERIFY_RESULT_ERROR_VERIFICATION:
1164 ret = "ERROR_VERIFICATION";
1165 break;
1166 case AVB_SLOT_VERIFY_RESULT_ERROR_ROLLBACK_INDEX:
1167 ret = "ERROR_ROLLBACK_INDEX";
1168 break;
1169 case AVB_SLOT_VERIFY_RESULT_ERROR_PUBLIC_KEY_REJECTED:
1170 ret = "ERROR_PUBLIC_KEY_REJECTED";
1171 break;
1172 case AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA:
1173 ret = "ERROR_INVALID_METADATA";
1174 break;
1175 case AVB_SLOT_VERIFY_RESULT_ERROR_UNSUPPORTED_VERSION:
1176 ret = "ERROR_UNSUPPORTED_VERSION";
1177 break;
1178 /* Do not add a 'default:' case here because of -Wswitch. */
1179 }
1180
1181 if (ret == NULL) {
1182 avb_error("Unknown AvbSlotVerifyResult value.\n");
1183 ret = "(unknown)";
1184 }
1185
1186 return ret;
1187}
1188