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