Home | History | Annotate | Download | only in libavb
      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  */
     53 static 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 
     71 static 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 
    182 out:
    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 
    205 fail:
    206   if (image_buf != NULL) {
    207     avb_free(image_buf);
    208   }
    209   return ret;
    210 }
    211 
    212 static 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 
    725 out:
    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  */
    746 static 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 
    802 fail:
    803   if (ret != NULL) {
    804     avb_free(ret);
    805   }
    806   return NULL;
    807 }
    808 
    809 static 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  */
    850 static 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 
    870 static 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 
    889 static 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 
    897 static 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 
    922 AvbSlotVerifyResult 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 
   1107 fail:
   1108   if (slot_data != NULL) {
   1109     avb_slot_verify_data_free(slot_data);
   1110   }
   1111   return ret;
   1112 }
   1113 
   1114 void 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 
   1150 const 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