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