xref: /rk3399_rockchip-uboot/lib/avb/libavb/avb_slot_verify.c (revision 17d5ed3ee9dbbcbae06ad3a291a8f61c3cde3d5b)
137a7bc39SJason Zhu /*
237a7bc39SJason Zhu  * Copyright (C) 2016 The Android Open Source Project
337a7bc39SJason Zhu  *
437a7bc39SJason Zhu  * Permission is hereby granted, free of charge, to any person
537a7bc39SJason Zhu  * obtaining a copy of this software and associated documentation
637a7bc39SJason Zhu  * files (the "Software"), to deal in the Software without
737a7bc39SJason Zhu  * restriction, including without limitation the rights to use, copy,
837a7bc39SJason Zhu  * modify, merge, publish, distribute, sublicense, and/or sell copies
937a7bc39SJason Zhu  * of the Software, and to permit persons to whom the Software is
1037a7bc39SJason Zhu  * furnished to do so, subject to the following conditions:
1137a7bc39SJason Zhu  *
1237a7bc39SJason Zhu  * The above copyright notice and this permission notice shall be
1337a7bc39SJason Zhu  * included in all copies or substantial portions of the Software.
1437a7bc39SJason Zhu  *
1537a7bc39SJason Zhu  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
1637a7bc39SJason Zhu  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
1737a7bc39SJason Zhu  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
1837a7bc39SJason Zhu  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
1937a7bc39SJason Zhu  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
2037a7bc39SJason Zhu  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
2137a7bc39SJason Zhu  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
2237a7bc39SJason Zhu  * SOFTWARE.
2337a7bc39SJason Zhu  */
2489151b4aSJoseph Chen #include <common.h>
2528317110SJoseph Chen #include <android_image.h>
2637a7bc39SJason Zhu #include <android_avb/avb_slot_verify.h>
2737a7bc39SJason Zhu #include <android_avb/avb_chain_partition_descriptor.h>
2837a7bc39SJason Zhu #include <android_avb/avb_cmdline.h>
2937a7bc39SJason Zhu #include <android_avb/avb_footer.h>
3037a7bc39SJason Zhu #include <android_avb/avb_hash_descriptor.h>
31ab608f80SJason Zhu #include <android_avb/avb_hashtree_descriptor.h>
3237a7bc39SJason Zhu #include <android_avb/avb_kernel_cmdline_descriptor.h>
3328317110SJoseph Chen #include <android_avb/avb_ops_user.h>
3437a7bc39SJason Zhu #include <android_avb/avb_sha.h>
3537a7bc39SJason Zhu #include <android_avb/avb_util.h>
3637a7bc39SJason Zhu #include <android_avb/avb_vbmeta_image.h>
3737a7bc39SJason Zhu #include <android_avb/avb_version.h>
3837a7bc39SJason Zhu 
3937a7bc39SJason Zhu /* Maximum number of partitions that can be loaded with avb_slot_verify(). */
4037a7bc39SJason Zhu #define MAX_NUMBER_OF_LOADED_PARTITIONS 32
4137a7bc39SJason Zhu 
4237a7bc39SJason Zhu /* Maximum number of vbmeta images that can be loaded with avb_slot_verify(). */
4337a7bc39SJason Zhu #define MAX_NUMBER_OF_VBMETA_IMAGES 32
4437a7bc39SJason Zhu 
4537a7bc39SJason Zhu /* Maximum size of a vbmeta image - 64 KiB. */
4637a7bc39SJason Zhu #define VBMETA_MAX_SIZE (64 * 1024)
4737a7bc39SJason Zhu 
4869fdc596SJason Zhu static AvbSlotVerifyResult initialize_persistent_digest(
4969fdc596SJason Zhu     AvbOps* ops,
5069fdc596SJason Zhu     const char* part_name,
5169fdc596SJason Zhu     const char* persistent_value_name,
5269fdc596SJason Zhu     size_t digest_size,
5369fdc596SJason Zhu     const uint8_t* initial_digest,
5469fdc596SJason Zhu     uint8_t* out_digest);
5569fdc596SJason Zhu 
5637a7bc39SJason Zhu /* Helper function to see if we should continue with verification in
5737a7bc39SJason Zhu  * allow_verification_error=true mode if something goes wrong. See the
5837a7bc39SJason Zhu  * comments for the avb_slot_verify() function for more information.
5937a7bc39SJason Zhu  */
result_should_continue(AvbSlotVerifyResult result)6037a7bc39SJason Zhu static inline bool result_should_continue(AvbSlotVerifyResult result) {
6137a7bc39SJason Zhu   switch (result) {
6237a7bc39SJason Zhu     case AVB_SLOT_VERIFY_RESULT_ERROR_OOM:
6337a7bc39SJason Zhu     case AVB_SLOT_VERIFY_RESULT_ERROR_IO:
6437a7bc39SJason Zhu     case AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA:
6537a7bc39SJason Zhu     case AVB_SLOT_VERIFY_RESULT_ERROR_UNSUPPORTED_VERSION:
6637a7bc39SJason Zhu     case AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_ARGUMENT:
6737a7bc39SJason Zhu       return false;
6837a7bc39SJason Zhu 
6937a7bc39SJason Zhu     case AVB_SLOT_VERIFY_RESULT_OK:
7037a7bc39SJason Zhu     case AVB_SLOT_VERIFY_RESULT_ERROR_VERIFICATION:
7137a7bc39SJason Zhu     case AVB_SLOT_VERIFY_RESULT_ERROR_ROLLBACK_INDEX:
7237a7bc39SJason Zhu     case AVB_SLOT_VERIFY_RESULT_ERROR_PUBLIC_KEY_REJECTED:
7337a7bc39SJason Zhu       return true;
7437a7bc39SJason Zhu   }
7537a7bc39SJason Zhu 
7637a7bc39SJason Zhu   return false;
7737a7bc39SJason Zhu }
7837a7bc39SJason Zhu 
load_full_partition(AvbOps * ops,const char * part_name,uint64_t image_size,uint8_t ** out_image_buf,bool * out_image_preloaded,int allow_verification_error)79ab608f80SJason Zhu static AvbSlotVerifyResult load_full_partition(AvbOps* ops,
80ab608f80SJason Zhu                                                const char* part_name,
81ab608f80SJason Zhu                                                uint64_t image_size,
82ab608f80SJason Zhu                                                uint8_t** out_image_buf,
8327e62cd7SJoseph Chen                                                bool* out_image_preloaded,
8427e62cd7SJoseph Chen                                                int allow_verification_error) {
8537a7bc39SJason Zhu   size_t part_num_read;
8637a7bc39SJason Zhu   AvbIOResult io_ret;
8737a7bc39SJason Zhu 
8837a7bc39SJason Zhu   /* Make sure that we do not overwrite existing data. */
8937a7bc39SJason Zhu   avb_assert(*out_image_buf == NULL);
9037a7bc39SJason Zhu   avb_assert(!*out_image_preloaded);
9137a7bc39SJason Zhu 
9237a7bc39SJason Zhu   /* We are going to implicitly cast image_size from uint64_t to size_t in the
9337a7bc39SJason Zhu    * following code, so we need to make sure that the cast is safe. */
9437a7bc39SJason Zhu   if (image_size != (size_t)(image_size)) {
9537a7bc39SJason Zhu     avb_errorv(part_name, ": Partition size too large to load.\n", NULL);
9637a7bc39SJason Zhu     return AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;
9737a7bc39SJason Zhu   }
9837a7bc39SJason Zhu 
9937a7bc39SJason Zhu   /* Try use a preloaded one. */
10037a7bc39SJason Zhu   if (ops->get_preloaded_partition != NULL) {
10137a7bc39SJason Zhu     io_ret = ops->get_preloaded_partition(
10227e62cd7SJoseph Chen         ops, part_name, image_size, out_image_buf, &part_num_read,
10327e62cd7SJoseph Chen 	allow_verification_error);
10437a7bc39SJason Zhu     if (io_ret == AVB_IO_RESULT_ERROR_OOM) {
10537a7bc39SJason Zhu       return AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
10637a7bc39SJason Zhu     } else if (io_ret != AVB_IO_RESULT_OK) {
10737a7bc39SJason Zhu       avb_errorv(part_name, ": Error loading data from partition.\n", NULL);
10837a7bc39SJason Zhu       return AVB_SLOT_VERIFY_RESULT_ERROR_IO;
10937a7bc39SJason Zhu     }
11037a7bc39SJason Zhu 
11137a7bc39SJason Zhu     if (*out_image_buf != NULL) {
11237a7bc39SJason Zhu       if (part_num_read != image_size) {
11337a7bc39SJason Zhu         avb_errorv(part_name, ": Read incorrect number of bytes.\n", NULL);
11437a7bc39SJason Zhu         return AVB_SLOT_VERIFY_RESULT_ERROR_IO;
11537a7bc39SJason Zhu       }
11637a7bc39SJason Zhu       *out_image_preloaded = true;
11737a7bc39SJason Zhu     }
11837a7bc39SJason Zhu   }
11937a7bc39SJason Zhu 
12037a7bc39SJason Zhu   /* Allocate and copy the partition. */
12137a7bc39SJason Zhu   if (!*out_image_preloaded) {
12228317110SJoseph Chen     *out_image_buf = avb_malloc(image_size);
12337a7bc39SJason Zhu     if (*out_image_buf == NULL) {
12437a7bc39SJason Zhu       return AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
12537a7bc39SJason Zhu     }
12637a7bc39SJason Zhu 
127ab608f80SJason Zhu     io_ret = ops->read_from_partition(ops,
128ab608f80SJason Zhu                                       part_name,
129ab608f80SJason Zhu                                       0 /* offset */,
130ab608f80SJason Zhu                                       image_size,
131ab608f80SJason Zhu                                       *out_image_buf,
13237a7bc39SJason Zhu                                       &part_num_read);
13337a7bc39SJason Zhu     if (io_ret == AVB_IO_RESULT_ERROR_OOM) {
13437a7bc39SJason Zhu       return AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
13537a7bc39SJason Zhu     } else if (io_ret != AVB_IO_RESULT_OK) {
13637a7bc39SJason Zhu       avb_errorv(part_name, ": Error loading data from partition.\n", NULL);
13737a7bc39SJason Zhu       return AVB_SLOT_VERIFY_RESULT_ERROR_IO;
13837a7bc39SJason Zhu     }
13937a7bc39SJason Zhu     if (part_num_read != image_size) {
14037a7bc39SJason Zhu       avb_errorv(part_name, ": Read incorrect number of bytes.\n", NULL);
14137a7bc39SJason Zhu       return AVB_SLOT_VERIFY_RESULT_ERROR_IO;
14237a7bc39SJason Zhu     }
14337a7bc39SJason Zhu   }
14437a7bc39SJason Zhu 
14537a7bc39SJason Zhu   return AVB_SLOT_VERIFY_RESULT_OK;
14637a7bc39SJason Zhu }
14737a7bc39SJason Zhu 
14869fdc596SJason Zhu /* Reads a persistent digest stored as a named persistent value corresponding to
14969fdc596SJason Zhu  * the given |part_name|. The value is returned in |out_digest| which must point
15069fdc596SJason Zhu  * to |expected_digest_size| bytes. If there is no digest stored for |part_name|
15169fdc596SJason Zhu  * it can be initialized by providing a non-NULL |initial_digest| of length
15269fdc596SJason Zhu  * |expected_digest_size|. This automatic initialization will only occur if the
15369fdc596SJason Zhu  * device is currently locked. The |initial_digest| may be NULL.
15469fdc596SJason Zhu  *
15569fdc596SJason Zhu  * Returns AVB_SLOT_VERIFY_RESULT_OK on success, otherwise returns an
15669fdc596SJason Zhu  * AVB_SLOT_VERIFY_RESULT_ERROR_* error code.
15769fdc596SJason Zhu  *
15869fdc596SJason Zhu  * If the value does not exist, is not supported, or is not populated, and
15969fdc596SJason Zhu  * |initial_digest| is NULL, returns
16069fdc596SJason Zhu  * AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA. If |expected_digest_size| does
16169fdc596SJason Zhu  * not match the stored digest size, also returns
16269fdc596SJason Zhu  * AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA.
16369fdc596SJason Zhu  */
read_persistent_digest(AvbOps * ops,const char * part_name,size_t expected_digest_size,const uint8_t * initial_digest,uint8_t * out_digest)164ab608f80SJason Zhu static AvbSlotVerifyResult read_persistent_digest(AvbOps* ops,
165ab608f80SJason Zhu                                                   const char* part_name,
166ab608f80SJason Zhu                                                   size_t expected_digest_size,
16769fdc596SJason Zhu                                                   const uint8_t* initial_digest,
168ab608f80SJason Zhu                                                   uint8_t* out_digest) {
169ab608f80SJason Zhu   char* persistent_value_name = NULL;
170ab608f80SJason Zhu   AvbIOResult io_ret = AVB_IO_RESULT_OK;
171ab608f80SJason Zhu   size_t stored_digest_size = 0;
172ab608f80SJason Zhu 
173ab608f80SJason Zhu   if (ops->read_persistent_value == NULL) {
174ab608f80SJason Zhu     avb_errorv(part_name, ": Persistent values are not implemented.\n", NULL);
175ab608f80SJason Zhu     return AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;
176ab608f80SJason Zhu   }
177ab608f80SJason Zhu   persistent_value_name =
178ab608f80SJason Zhu       avb_strdupv(AVB_NPV_PERSISTENT_DIGEST_PREFIX, part_name, NULL);
179ab608f80SJason Zhu   if (persistent_value_name == NULL) {
180ab608f80SJason Zhu     return AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
181ab608f80SJason Zhu   }
18269fdc596SJason Zhu 
183ab608f80SJason Zhu   io_ret = ops->read_persistent_value(ops,
184ab608f80SJason Zhu                                       persistent_value_name,
185ab608f80SJason Zhu                                       expected_digest_size,
186ab608f80SJason Zhu                                       out_digest,
187ab608f80SJason Zhu                                       &stored_digest_size);
18869fdc596SJason Zhu 
18969fdc596SJason Zhu   // If no such named persistent value exists and an initial digest value was
19069fdc596SJason Zhu   // given, initialize the named persistent value with the given digest. If
19169fdc596SJason Zhu   // initialized successfully, this will recurse into this function but with a
19269fdc596SJason Zhu   // NULL initial_digest.
19369fdc596SJason Zhu   if (io_ret == AVB_IO_RESULT_ERROR_NO_SUCH_VALUE && initial_digest) {
19469fdc596SJason Zhu     AvbSlotVerifyResult ret =
19569fdc596SJason Zhu         initialize_persistent_digest(ops,
19669fdc596SJason Zhu                                      part_name,
19769fdc596SJason Zhu                                      persistent_value_name,
19869fdc596SJason Zhu                                      expected_digest_size,
19969fdc596SJason Zhu                                      initial_digest,
20069fdc596SJason Zhu                                      out_digest);
201ab608f80SJason Zhu     avb_free(persistent_value_name);
20269fdc596SJason Zhu     return ret;
20369fdc596SJason Zhu   }
20469fdc596SJason Zhu   avb_free(persistent_value_name);
20569fdc596SJason Zhu 
206ab608f80SJason Zhu   if (io_ret == AVB_IO_RESULT_ERROR_OOM) {
207ab608f80SJason Zhu     return AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
208ab608f80SJason Zhu   } else if (io_ret == AVB_IO_RESULT_ERROR_NO_SUCH_VALUE) {
20969fdc596SJason Zhu     // Treat a missing persistent value as a verification error, which is
21069fdc596SJason Zhu     // ignoreable, rather than a metadata error which is not.
211ab608f80SJason Zhu     avb_errorv(part_name, ": Persistent digest does not exist.\n", NULL);
21269fdc596SJason Zhu     return AVB_SLOT_VERIFY_RESULT_ERROR_VERIFICATION;
213ab608f80SJason Zhu   } else if (io_ret == AVB_IO_RESULT_ERROR_INVALID_VALUE_SIZE ||
21469fdc596SJason Zhu              io_ret == AVB_IO_RESULT_ERROR_INSUFFICIENT_SPACE) {
215ab608f80SJason Zhu     avb_errorv(
216ab608f80SJason Zhu         part_name, ": Persistent digest is not of expected size.\n", NULL);
217ab608f80SJason Zhu     return AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;
218ab608f80SJason Zhu   } else if (io_ret != AVB_IO_RESULT_OK) {
219ab608f80SJason Zhu     avb_errorv(part_name, ": Error reading persistent digest.\n", NULL);
220ab608f80SJason Zhu     return AVB_SLOT_VERIFY_RESULT_ERROR_IO;
22169fdc596SJason Zhu   } else if (expected_digest_size != stored_digest_size) {
22269fdc596SJason Zhu     avb_errorv(
22369fdc596SJason Zhu         part_name, ": Persistent digest is not of expected size.\n", NULL);
22469fdc596SJason Zhu     return AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;
225ab608f80SJason Zhu   }
226ab608f80SJason Zhu   return AVB_SLOT_VERIFY_RESULT_OK;
227ab608f80SJason Zhu }
228ab608f80SJason Zhu 
initialize_persistent_digest(AvbOps * ops,const char * part_name,const char * persistent_value_name,size_t digest_size,const uint8_t * initial_digest,uint8_t * out_digest)22969fdc596SJason Zhu static AvbSlotVerifyResult initialize_persistent_digest(
23069fdc596SJason Zhu     AvbOps* ops,
23169fdc596SJason Zhu     const char* part_name,
23269fdc596SJason Zhu     const char* persistent_value_name,
23369fdc596SJason Zhu     size_t digest_size,
23469fdc596SJason Zhu     const uint8_t* initial_digest,
23569fdc596SJason Zhu     uint8_t* out_digest) {
23669fdc596SJason Zhu   AvbSlotVerifyResult ret;
23769fdc596SJason Zhu   AvbIOResult io_ret = AVB_IO_RESULT_OK;
23869fdc596SJason Zhu   bool is_device_unlocked = true;
23969fdc596SJason Zhu 
24069fdc596SJason Zhu   io_ret = ops->read_is_device_unlocked(ops, &is_device_unlocked);
24169fdc596SJason Zhu   if (io_ret == AVB_IO_RESULT_ERROR_OOM) {
24269fdc596SJason Zhu     return AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
24369fdc596SJason Zhu   } else if (io_ret != AVB_IO_RESULT_OK) {
24469fdc596SJason Zhu     avb_error("Error getting device lock state.\n");
24569fdc596SJason Zhu     return AVB_SLOT_VERIFY_RESULT_ERROR_IO;
24669fdc596SJason Zhu   }
24769fdc596SJason Zhu 
24869fdc596SJason Zhu   if (is_device_unlocked) {
24969fdc596SJason Zhu     avb_debugv(part_name,
25069fdc596SJason Zhu                ": Digest does not exist, device unlocked so not initializing "
25169fdc596SJason Zhu                "digest.\n",
25269fdc596SJason Zhu                NULL);
25369fdc596SJason Zhu     return AVB_SLOT_VERIFY_RESULT_ERROR_VERIFICATION;
25469fdc596SJason Zhu   }
25569fdc596SJason Zhu 
25669fdc596SJason Zhu   // Device locked; initialize digest with given initial value.
25769fdc596SJason Zhu   avb_debugv(part_name,
25869fdc596SJason Zhu              ": Digest does not exist, initializing persistent digest.\n",
25969fdc596SJason Zhu              NULL);
26069fdc596SJason Zhu   io_ret = ops->write_persistent_value(
26169fdc596SJason Zhu       ops, persistent_value_name, digest_size, initial_digest);
26269fdc596SJason Zhu   if (io_ret == AVB_IO_RESULT_ERROR_OOM) {
26369fdc596SJason Zhu     return AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
26469fdc596SJason Zhu   } else if (io_ret != AVB_IO_RESULT_OK) {
26569fdc596SJason Zhu     avb_errorv(part_name, ": Error initializing persistent digest.\n", NULL);
26669fdc596SJason Zhu     return AVB_SLOT_VERIFY_RESULT_ERROR_IO;
26769fdc596SJason Zhu   }
26869fdc596SJason Zhu 
26969fdc596SJason Zhu   // To ensure that the digest value was written successfully - and avoid a
27069fdc596SJason Zhu   // scenario where the digest is simply 'initialized' on every verify - recurse
27169fdc596SJason Zhu   // into read_persistent_digest to read back the written value. The NULL
27269fdc596SJason Zhu   // initial_digest ensures that this will not recurse again.
27369fdc596SJason Zhu   ret = read_persistent_digest(ops, part_name, digest_size, NULL, out_digest);
27469fdc596SJason Zhu   if (ret != AVB_SLOT_VERIFY_RESULT_OK) {
27569fdc596SJason Zhu     avb_errorv(part_name,
27669fdc596SJason Zhu                ": Reading back initialized persistent digest failed!\n",
27769fdc596SJason Zhu                NULL);
27869fdc596SJason Zhu   }
27969fdc596SJason Zhu   return ret;
28069fdc596SJason Zhu }
28169fdc596SJason Zhu 
load_and_verify_hash_partition(AvbOps * ops,const char * const * requested_partitions,const char * ab_suffix,bool allow_verification_error,const AvbDescriptor * descriptor,AvbSlotVerifyData * slot_data)28237a7bc39SJason Zhu static AvbSlotVerifyResult load_and_verify_hash_partition(
28337a7bc39SJason Zhu     AvbOps* ops,
28437a7bc39SJason Zhu     const char* const* requested_partitions,
28537a7bc39SJason Zhu     const char* ab_suffix,
28637a7bc39SJason Zhu     bool allow_verification_error,
28737a7bc39SJason Zhu     const AvbDescriptor* descriptor,
28837a7bc39SJason Zhu     AvbSlotVerifyData* slot_data) {
28937a7bc39SJason Zhu   AvbHashDescriptor hash_desc;
29037a7bc39SJason Zhu   const uint8_t* desc_partition_name = NULL;
29137a7bc39SJason Zhu   const uint8_t* desc_salt;
29237a7bc39SJason Zhu   const uint8_t* desc_digest;
29337a7bc39SJason Zhu   char part_name[AVB_PART_NAME_MAX_SIZE];
29437a7bc39SJason Zhu   AvbSlotVerifyResult ret;
29537a7bc39SJason Zhu   AvbIOResult io_ret;
29637a7bc39SJason Zhu   uint8_t* image_buf = NULL;
29737a7bc39SJason Zhu   bool image_preloaded = false;
29837a7bc39SJason Zhu   uint8_t* digest;
29937a7bc39SJason Zhu   size_t digest_len;
300*17d5ed3eSJeffy Chen   const char* found = NULL;
30169fdc596SJason Zhu   uint64_t image_size;
302ab608f80SJason Zhu   size_t expected_digest_len = 0;
303ab608f80SJason Zhu   uint8_t expected_digest_buf[AVB_SHA512_DIGEST_SIZE];
304ab608f80SJason Zhu   const uint8_t* expected_digest = NULL;
30537a7bc39SJason Zhu 
30637a7bc39SJason Zhu   if (!avb_hash_descriptor_validate_and_byteswap(
30737a7bc39SJason Zhu           (const AvbHashDescriptor*)descriptor, &hash_desc)) {
30837a7bc39SJason Zhu     ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;
30937a7bc39SJason Zhu     goto out;
31037a7bc39SJason Zhu   }
31137a7bc39SJason Zhu 
31237a7bc39SJason Zhu   desc_partition_name =
31337a7bc39SJason Zhu       ((const uint8_t*)descriptor) + sizeof(AvbHashDescriptor);
31437a7bc39SJason Zhu   desc_salt = desc_partition_name + hash_desc.partition_name_len;
31537a7bc39SJason Zhu   desc_digest = desc_salt + hash_desc.salt_len;
31637a7bc39SJason Zhu 
31737a7bc39SJason Zhu   if (!avb_validate_utf8(desc_partition_name, hash_desc.partition_name_len)) {
31837a7bc39SJason Zhu     avb_error("Partition name is not valid UTF-8.\n");
31937a7bc39SJason Zhu     ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;
32037a7bc39SJason Zhu     goto out;
32137a7bc39SJason Zhu   }
32237a7bc39SJason Zhu 
32337a7bc39SJason Zhu   /* Don't bother loading or validating unless the partition was
32437a7bc39SJason Zhu    * requested in the first place.
32537a7bc39SJason Zhu    */
32637a7bc39SJason Zhu   found = avb_strv_find_str(requested_partitions,
32737a7bc39SJason Zhu                             (const char*)desc_partition_name,
32837a7bc39SJason Zhu                             hash_desc.partition_name_len);
32937a7bc39SJason Zhu   if (found == NULL) {
33037a7bc39SJason Zhu     ret = AVB_SLOT_VERIFY_RESULT_OK;
33137a7bc39SJason Zhu     goto out;
33237a7bc39SJason Zhu   }
33337a7bc39SJason Zhu 
334ab608f80SJason Zhu   if ((hash_desc.flags & AVB_HASH_DESCRIPTOR_FLAGS_DO_NOT_USE_AB) != 0) {
335ab608f80SJason Zhu     /* No ab_suffix, just copy the partition name as is. */
336ab608f80SJason Zhu     if (hash_desc.partition_name_len >= AVB_PART_NAME_MAX_SIZE) {
337ab608f80SJason Zhu       avb_error("Partition name does not fit.\n");
338ab608f80SJason Zhu       ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;
339ab608f80SJason Zhu       goto out;
340ab608f80SJason Zhu     }
341ab608f80SJason Zhu     avb_memcpy(part_name, desc_partition_name, hash_desc.partition_name_len);
342ab608f80SJason Zhu     part_name[hash_desc.partition_name_len] = '\0';
343ab608f80SJason Zhu   } else if (hash_desc.digest_len == 0 && avb_strlen(ab_suffix) != 0) {
344ab608f80SJason Zhu     /* No ab_suffix allowed for partitions without a digest in the descriptor
345ab608f80SJason Zhu      * because these partitions hold data unique to this device and are not
346ab608f80SJason Zhu      * updated using an A/B scheme.
347ab608f80SJason Zhu      */
348ab608f80SJason Zhu     avb_error("Cannot use A/B with a persistent digest.\n");
349ab608f80SJason Zhu     ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;
350ab608f80SJason Zhu     goto out;
351ab608f80SJason Zhu   } else {
352ab608f80SJason Zhu     /* Add ab_suffix to the partition name. */
35337a7bc39SJason Zhu     if (!avb_str_concat(part_name,
35437a7bc39SJason Zhu                         sizeof part_name,
35537a7bc39SJason Zhu                         (const char*)desc_partition_name,
35637a7bc39SJason Zhu                         hash_desc.partition_name_len,
35737a7bc39SJason Zhu                         ab_suffix,
35837a7bc39SJason Zhu                         avb_strlen(ab_suffix))) {
35937a7bc39SJason Zhu       avb_error("Partition name and suffix does not fit.\n");
36037a7bc39SJason Zhu       ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;
36137a7bc39SJason Zhu       goto out;
36237a7bc39SJason Zhu     }
363ab608f80SJason Zhu   }
36437a7bc39SJason Zhu 
36537a7bc39SJason Zhu   /* If we're allowing verification errors then hash_desc.image_size
36637a7bc39SJason Zhu    * may no longer match what's in the partition... so in this case
36737a7bc39SJason Zhu    * just load the entire partition.
36837a7bc39SJason Zhu    *
36937a7bc39SJason Zhu    * For example, this can happen if a developer does 'fastboot flash
37037a7bc39SJason Zhu    * boot /path/to/new/and/bigger/boot.img'. We want this to work
37137a7bc39SJason Zhu    * since it's such a common workflow.
37237a7bc39SJason Zhu    */
37337a7bc39SJason Zhu   image_size = hash_desc.image_size;
3744f2523c3SJason Zhu   if (allow_verification_error) {
37537a7bc39SJason Zhu     io_ret = ops->get_size_of_partition(ops, part_name, &image_size);
37637a7bc39SJason Zhu     if (io_ret == AVB_IO_RESULT_ERROR_OOM) {
37737a7bc39SJason Zhu       ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
37837a7bc39SJason Zhu       goto out;
37937a7bc39SJason Zhu     } else if (io_ret != AVB_IO_RESULT_OK) {
38037a7bc39SJason Zhu       avb_errorv(part_name, ": Error determining partition size.\n", NULL);
38137a7bc39SJason Zhu       ret = AVB_SLOT_VERIFY_RESULT_ERROR_IO;
38237a7bc39SJason Zhu       goto out;
38337a7bc39SJason Zhu     }
38437a7bc39SJason Zhu     avb_debugv(part_name, ": Loading entire partition.\n", NULL);
38537a7bc39SJason Zhu   }
38637a7bc39SJason Zhu 
38737a7bc39SJason Zhu   ret = load_full_partition(
38827e62cd7SJoseph Chen       ops, part_name, image_size, &image_buf, &image_preloaded,
38927e62cd7SJoseph Chen       allow_verification_error);
39037a7bc39SJason Zhu   if (ret != AVB_SLOT_VERIFY_RESULT_OK) {
39137a7bc39SJason Zhu     goto out;
39228317110SJoseph Chen   } else if (allow_verification_error) {
3931e9494b5SJoseph Chen     goto out;
39437a7bc39SJason Zhu   }
3951e9494b5SJoseph Chen 
39669fdc596SJason Zhu   // Although only one of the type might be used, we have to defined the
39769fdc596SJason Zhu   // structure here so that they would live outside the 'if/else' scope to be
39869fdc596SJason Zhu   // used later.
39937a7bc39SJason Zhu   AvbSHA256Ctx sha256_ctx;
40069fdc596SJason Zhu   AvbSHA512Ctx sha512_ctx;
40169fdc596SJason Zhu   size_t image_size_to_hash = hash_desc.image_size;
40269fdc596SJason Zhu   // If we allow verification error and the whole partition is smaller than
40369fdc596SJason Zhu   // image size in hash descriptor, we just hash the whole partition.
40469fdc596SJason Zhu   if (image_size_to_hash > image_size) {
40569fdc596SJason Zhu     image_size_to_hash = image_size;
40669fdc596SJason Zhu   }
40769fdc596SJason Zhu   if (avb_strcmp((const char*)hash_desc.hash_algorithm, "sha256") == 0) {
4085b0bc491SJoseph Chen     sha256_ctx.tot_len = hash_desc.salt_len + image_size_to_hash;
40937a7bc39SJason Zhu     avb_sha256_init(&sha256_ctx);
41037a7bc39SJason Zhu     avb_sha256_update(&sha256_ctx, desc_salt, hash_desc.salt_len);
41169fdc596SJason Zhu     avb_sha256_update(&sha256_ctx, image_buf, image_size_to_hash);
41237a7bc39SJason Zhu     digest = avb_sha256_final(&sha256_ctx);
41337a7bc39SJason Zhu     digest_len = AVB_SHA256_DIGEST_SIZE;
41437a7bc39SJason Zhu   } else if (avb_strcmp((const char*)hash_desc.hash_algorithm, "sha512") == 0) {
4155b0bc491SJoseph Chen     sha512_ctx.tot_len = hash_desc.salt_len + image_size_to_hash;
41637a7bc39SJason Zhu     avb_sha512_init(&sha512_ctx);
41737a7bc39SJason Zhu     avb_sha512_update(&sha512_ctx, desc_salt, hash_desc.salt_len);
41869fdc596SJason Zhu     avb_sha512_update(&sha512_ctx, image_buf, image_size_to_hash);
41937a7bc39SJason Zhu     digest = avb_sha512_final(&sha512_ctx);
42037a7bc39SJason Zhu     digest_len = AVB_SHA512_DIGEST_SIZE;
42137a7bc39SJason Zhu   } else {
42237a7bc39SJason Zhu     avb_errorv(part_name, ": Unsupported hash algorithm.\n", NULL);
42337a7bc39SJason Zhu     ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;
42437a7bc39SJason Zhu     goto out;
42537a7bc39SJason Zhu   }
42637a7bc39SJason Zhu 
427ab608f80SJason Zhu   if (hash_desc.digest_len == 0) {
42869fdc596SJason Zhu     /* Expect a match to a persistent digest. */
429ab608f80SJason Zhu     avb_debugv(part_name, ": No digest, using persistent digest.\n", NULL);
430ab608f80SJason Zhu     expected_digest_len = digest_len;
431ab608f80SJason Zhu     expected_digest = expected_digest_buf;
432ab608f80SJason Zhu     avb_assert(expected_digest_len <= sizeof(expected_digest_buf));
43369fdc596SJason Zhu     /* Pass |digest| as the |initial_digest| so devices not yet initialized get
43469fdc596SJason Zhu      * initialized to the current partition digest.
43569fdc596SJason Zhu      */
43669fdc596SJason Zhu     ret = read_persistent_digest(
43769fdc596SJason Zhu         ops, part_name, digest_len, digest, expected_digest_buf);
438ab608f80SJason Zhu     if (ret != AVB_SLOT_VERIFY_RESULT_OK) {
439ab608f80SJason Zhu       goto out;
440ab608f80SJason Zhu     }
441ab608f80SJason Zhu   } else {
44269fdc596SJason Zhu     /* Expect a match to the digest in the descriptor. */
443ab608f80SJason Zhu     expected_digest_len = hash_desc.digest_len;
444ab608f80SJason Zhu     expected_digest = desc_digest;
445ab608f80SJason Zhu   }
446ab608f80SJason Zhu 
447ab608f80SJason Zhu   if (digest_len != expected_digest_len) {
44837a7bc39SJason Zhu     avb_errorv(
44937a7bc39SJason Zhu         part_name, ": Digest in descriptor not of expected size.\n", NULL);
45037a7bc39SJason Zhu     ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;
45137a7bc39SJason Zhu     goto out;
45237a7bc39SJason Zhu   }
45337a7bc39SJason Zhu 
454ab608f80SJason Zhu   if (avb_safe_memcmp(digest, expected_digest, digest_len) != 0) {
45537a7bc39SJason Zhu     avb_errorv(part_name,
45637a7bc39SJason Zhu                ": Hash of data does not match digest in descriptor.\n",
45737a7bc39SJason Zhu                NULL);
45837a7bc39SJason Zhu     ret = AVB_SLOT_VERIFY_RESULT_ERROR_VERIFICATION;
45937a7bc39SJason Zhu     goto out;
46037a7bc39SJason Zhu   }
46137a7bc39SJason Zhu 
46237a7bc39SJason Zhu   ret = AVB_SLOT_VERIFY_RESULT_OK;
46337a7bc39SJason Zhu 
46437a7bc39SJason Zhu out:
46537a7bc39SJason Zhu 
46637a7bc39SJason Zhu   /* If it worked and something was loaded, copy to slot_data. */
46737a7bc39SJason Zhu   if ((ret == AVB_SLOT_VERIFY_RESULT_OK || result_should_continue(ret)) &&
46837a7bc39SJason Zhu       image_buf != NULL) {
46937a7bc39SJason Zhu     AvbPartitionData* loaded_partition;
47037a7bc39SJason Zhu     if (slot_data->num_loaded_partitions == MAX_NUMBER_OF_LOADED_PARTITIONS) {
47137a7bc39SJason Zhu       avb_errorv(part_name, ": Too many loaded partitions.\n", NULL);
47237a7bc39SJason Zhu       ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
47337a7bc39SJason Zhu       goto fail;
47437a7bc39SJason Zhu     }
47537a7bc39SJason Zhu     loaded_partition =
47637a7bc39SJason Zhu         &slot_data->loaded_partitions[slot_data->num_loaded_partitions++];
47737a7bc39SJason Zhu     loaded_partition->partition_name = avb_strdup(found);
47837a7bc39SJason Zhu     loaded_partition->data_size = image_size;
47937a7bc39SJason Zhu     loaded_partition->data = image_buf;
48037a7bc39SJason Zhu     loaded_partition->preloaded = image_preloaded;
48137a7bc39SJason Zhu     image_buf = NULL;
48237a7bc39SJason Zhu   }
48337a7bc39SJason Zhu 
48437a7bc39SJason Zhu fail:
48537a7bc39SJason Zhu   if (image_buf != NULL && !image_preloaded) {
48628317110SJoseph Chen     avb_free(image_buf);
48737a7bc39SJason Zhu   }
48837a7bc39SJason Zhu   return ret;
48937a7bc39SJason Zhu }
49037a7bc39SJason Zhu 
load_requested_partitions(AvbOps * ops,const char * const * requested_partitions,const char * ab_suffix,AvbSlotVerifyData * slot_data)49137a7bc39SJason Zhu static AvbSlotVerifyResult load_requested_partitions(
49237a7bc39SJason Zhu     AvbOps* ops,
49337a7bc39SJason Zhu     const char* const* requested_partitions,
49437a7bc39SJason Zhu     const char* ab_suffix,
49537a7bc39SJason Zhu     AvbSlotVerifyData* slot_data) {
49637a7bc39SJason Zhu   AvbSlotVerifyResult ret;
49737a7bc39SJason Zhu   uint8_t* image_buf = NULL;
49837a7bc39SJason Zhu   bool image_preloaded = false;
49937a7bc39SJason Zhu   size_t n;
50037a7bc39SJason Zhu 
50137a7bc39SJason Zhu   for (n = 0; requested_partitions[n] != NULL; n++) {
50237a7bc39SJason Zhu     char part_name[AVB_PART_NAME_MAX_SIZE];
50337a7bc39SJason Zhu     AvbIOResult io_ret;
50437a7bc39SJason Zhu     uint64_t image_size;
50537a7bc39SJason Zhu     AvbPartitionData* loaded_partition;
50637a7bc39SJason Zhu 
50737a7bc39SJason Zhu     if (!avb_str_concat(part_name,
50837a7bc39SJason Zhu                         sizeof part_name,
50937a7bc39SJason Zhu                         requested_partitions[n],
51037a7bc39SJason Zhu                         avb_strlen(requested_partitions[n]),
51137a7bc39SJason Zhu                         ab_suffix,
51237a7bc39SJason Zhu                         avb_strlen(ab_suffix))) {
51337a7bc39SJason Zhu       avb_error("Partition name and suffix does not fit.\n");
51437a7bc39SJason Zhu       ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;
51537a7bc39SJason Zhu       goto out;
51637a7bc39SJason Zhu     }
51737a7bc39SJason Zhu 
51837a7bc39SJason Zhu     io_ret = ops->get_size_of_partition(ops, part_name, &image_size);
51937a7bc39SJason Zhu     if (io_ret == AVB_IO_RESULT_ERROR_OOM) {
52037a7bc39SJason Zhu       ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
52137a7bc39SJason Zhu       goto out;
52237a7bc39SJason Zhu     } else if (io_ret != AVB_IO_RESULT_OK) {
52337a7bc39SJason Zhu       avb_errorv(part_name, ": Error determining partition size.\n", NULL);
52437a7bc39SJason Zhu       ret = AVB_SLOT_VERIFY_RESULT_ERROR_IO;
52537a7bc39SJason Zhu       goto out;
52637a7bc39SJason Zhu     }
52737a7bc39SJason Zhu     avb_debugv(part_name, ": Loading entire partition.\n", NULL);
52837a7bc39SJason Zhu 
52937a7bc39SJason Zhu     ret = load_full_partition(
53027e62cd7SJoseph Chen         ops, part_name, image_size, &image_buf, &image_preloaded, 1);
53137a7bc39SJason Zhu     if (ret != AVB_SLOT_VERIFY_RESULT_OK) {
53237a7bc39SJason Zhu       goto out;
53337a7bc39SJason Zhu     }
53437a7bc39SJason Zhu 
53537a7bc39SJason Zhu     /* Move to slot_data. */
53637a7bc39SJason Zhu     if (slot_data->num_loaded_partitions == MAX_NUMBER_OF_LOADED_PARTITIONS) {
53737a7bc39SJason Zhu       avb_errorv(part_name, ": Too many loaded partitions.\n", NULL);
53837a7bc39SJason Zhu       ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
53937a7bc39SJason Zhu       goto out;
54037a7bc39SJason Zhu     }
54137a7bc39SJason Zhu     loaded_partition =
54237a7bc39SJason Zhu         &slot_data->loaded_partitions[slot_data->num_loaded_partitions++];
54337a7bc39SJason Zhu     loaded_partition->partition_name = avb_strdup(requested_partitions[n]);
54437a7bc39SJason Zhu     if (loaded_partition->partition_name == NULL) {
54537a7bc39SJason Zhu       ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
54637a7bc39SJason Zhu       goto out;
54737a7bc39SJason Zhu     }
54837a7bc39SJason Zhu     loaded_partition->data_size = image_size;
54937a7bc39SJason Zhu     loaded_partition->data = image_buf; /* Transferring the owner. */
55037a7bc39SJason Zhu     loaded_partition->preloaded = image_preloaded;
55137a7bc39SJason Zhu     image_buf = NULL;
55237a7bc39SJason Zhu     image_preloaded = false;
55337a7bc39SJason Zhu   }
55437a7bc39SJason Zhu 
55537a7bc39SJason Zhu   ret = AVB_SLOT_VERIFY_RESULT_OK;
55637a7bc39SJason Zhu 
55737a7bc39SJason Zhu out:
55837a7bc39SJason Zhu   /* Free the current buffer if any. */
55937a7bc39SJason Zhu   if (image_buf != NULL && !image_preloaded) {
56028317110SJoseph Chen     avb_free(image_buf);
56137a7bc39SJason Zhu   }
56237a7bc39SJason Zhu   /* Buffers that are already saved in slot_data will be handled by the caller
56337a7bc39SJason Zhu    * even on failure. */
56437a7bc39SJason Zhu   return ret;
56537a7bc39SJason Zhu }
56637a7bc39SJason Zhu 
load_and_verify_vbmeta(AvbOps * ops,const char * const * requested_partitions,const char * ab_suffix,AvbSlotVerifyFlags flags,bool allow_verification_error,AvbVBMetaImageFlags toplevel_vbmeta_flags,int rollback_index_location,const char * partition_name,size_t partition_name_len,const uint8_t * expected_public_key,size_t expected_public_key_length,AvbSlotVerifyData * slot_data,AvbAlgorithmType * out_algorithm_type,AvbCmdlineSubstList * out_additional_cmdline_subst)56737a7bc39SJason Zhu static AvbSlotVerifyResult load_and_verify_vbmeta(
56837a7bc39SJason Zhu     AvbOps* ops,
56937a7bc39SJason Zhu     const char* const* requested_partitions,
57037a7bc39SJason Zhu     const char* ab_suffix,
57169fdc596SJason Zhu     AvbSlotVerifyFlags flags,
57237a7bc39SJason Zhu     bool allow_verification_error,
57337a7bc39SJason Zhu     AvbVBMetaImageFlags toplevel_vbmeta_flags,
57437a7bc39SJason Zhu     int rollback_index_location,
57537a7bc39SJason Zhu     const char* partition_name,
57637a7bc39SJason Zhu     size_t partition_name_len,
57737a7bc39SJason Zhu     const uint8_t* expected_public_key,
57837a7bc39SJason Zhu     size_t expected_public_key_length,
57937a7bc39SJason Zhu     AvbSlotVerifyData* slot_data,
580ab608f80SJason Zhu     AvbAlgorithmType* out_algorithm_type,
581ab608f80SJason Zhu     AvbCmdlineSubstList* out_additional_cmdline_subst) {
58237a7bc39SJason Zhu   char full_partition_name[AVB_PART_NAME_MAX_SIZE];
58337a7bc39SJason Zhu   AvbSlotVerifyResult ret;
58437a7bc39SJason Zhu   AvbIOResult io_ret;
58569fdc596SJason Zhu   uint64_t vbmeta_offset;
58637a7bc39SJason Zhu   size_t vbmeta_size;
58737a7bc39SJason Zhu   uint8_t* vbmeta_buf = NULL;
58837a7bc39SJason Zhu   size_t vbmeta_num_read;
58937a7bc39SJason Zhu   AvbVBMetaVerifyResult vbmeta_ret;
59037a7bc39SJason Zhu   const uint8_t* pk_data;
59137a7bc39SJason Zhu   size_t pk_len;
59237a7bc39SJason Zhu   AvbVBMetaImageHeader vbmeta_header;
59337a7bc39SJason Zhu   uint64_t stored_rollback_index;
59437a7bc39SJason Zhu   const AvbDescriptor** descriptors = NULL;
59537a7bc39SJason Zhu   size_t num_descriptors;
59637a7bc39SJason Zhu   size_t n;
59737a7bc39SJason Zhu   bool is_main_vbmeta;
59869fdc596SJason Zhu   bool look_for_vbmeta_footer;
59937a7bc39SJason Zhu   AvbVBMetaData* vbmeta_image_data = NULL;
60037a7bc39SJason Zhu 
60137a7bc39SJason Zhu   ret = AVB_SLOT_VERIFY_RESULT_OK;
60237a7bc39SJason Zhu 
60337a7bc39SJason Zhu   avb_assert(slot_data != NULL);
60437a7bc39SJason Zhu 
60537a7bc39SJason Zhu   /* Since we allow top-level vbmeta in 'boot', use
60637a7bc39SJason Zhu    * rollback_index_location to determine whether we're the main
60737a7bc39SJason Zhu    * vbmeta struct.
60837a7bc39SJason Zhu    */
60969fdc596SJason Zhu   is_main_vbmeta = false;
61069fdc596SJason Zhu   if (rollback_index_location == 0) {
61169fdc596SJason Zhu     if ((flags & AVB_SLOT_VERIFY_FLAGS_NO_VBMETA_PARTITION) == 0) {
61269fdc596SJason Zhu       is_main_vbmeta = true;
61369fdc596SJason Zhu     }
61469fdc596SJason Zhu   }
61569fdc596SJason Zhu 
61669fdc596SJason Zhu   /* Don't use footers for vbmeta partitions ('vbmeta' or
61769fdc596SJason Zhu    * 'vbmeta_<partition_name>').
61869fdc596SJason Zhu    */
61969fdc596SJason Zhu   look_for_vbmeta_footer = true;
62069fdc596SJason Zhu   if (avb_strncmp(partition_name, "vbmeta", avb_strlen("vbmeta")) == 0) {
62169fdc596SJason Zhu     look_for_vbmeta_footer = false;
62269fdc596SJason Zhu   }
62337a7bc39SJason Zhu 
62437a7bc39SJason Zhu   if (!avb_validate_utf8((const uint8_t*)partition_name, partition_name_len)) {
62537a7bc39SJason Zhu     avb_error("Partition name is not valid UTF-8.\n");
62637a7bc39SJason Zhu     ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;
62737a7bc39SJason Zhu     goto out;
62837a7bc39SJason Zhu   }
62937a7bc39SJason Zhu 
63069fdc596SJason Zhu   /* Construct full partition name e.g. system_a. */
63137a7bc39SJason Zhu   if (!avb_str_concat(full_partition_name,
63237a7bc39SJason Zhu                       sizeof full_partition_name,
63337a7bc39SJason Zhu                       partition_name,
63437a7bc39SJason Zhu                       partition_name_len,
63537a7bc39SJason Zhu                       ab_suffix,
63637a7bc39SJason Zhu                       avb_strlen(ab_suffix))) {
63737a7bc39SJason Zhu     avb_error("Partition name and suffix does not fit.\n");
63837a7bc39SJason Zhu     ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;
63937a7bc39SJason Zhu     goto out;
64037a7bc39SJason Zhu   }
64137a7bc39SJason Zhu 
64269fdc596SJason Zhu   /* If we're loading from the main vbmeta partition, the vbmeta struct is in
64369fdc596SJason Zhu    * the beginning. Otherwise we may have to locate it via a footer... if no
64469fdc596SJason Zhu    * footer is found, we look in the beginning to support e.g. vbmeta_<org>
64569fdc596SJason Zhu    * partitions holding data for e.g. super partitions (b/80195851 for
64669fdc596SJason Zhu    * rationale).
64737a7bc39SJason Zhu    */
64837a7bc39SJason Zhu   vbmeta_offset = 0;
64937a7bc39SJason Zhu   vbmeta_size = VBMETA_MAX_SIZE;
65069fdc596SJason Zhu   if (look_for_vbmeta_footer) {
65137a7bc39SJason Zhu     uint8_t footer_buf[AVB_FOOTER_SIZE];
65237a7bc39SJason Zhu     size_t footer_num_read;
65337a7bc39SJason Zhu     AvbFooter footer;
65437a7bc39SJason Zhu 
65537a7bc39SJason Zhu     io_ret = ops->read_from_partition(ops,
65637a7bc39SJason Zhu                                       full_partition_name,
65737a7bc39SJason Zhu                                       -AVB_FOOTER_SIZE,
65837a7bc39SJason Zhu                                       AVB_FOOTER_SIZE,
65937a7bc39SJason Zhu                                       footer_buf,
66037a7bc39SJason Zhu                                       &footer_num_read);
66137a7bc39SJason Zhu     if (io_ret == AVB_IO_RESULT_ERROR_OOM) {
66237a7bc39SJason Zhu       ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
66337a7bc39SJason Zhu       goto out;
66437a7bc39SJason Zhu     } else if (io_ret != AVB_IO_RESULT_OK) {
66537a7bc39SJason Zhu       avb_errorv(full_partition_name, ": Error loading footer.\n", NULL);
66637a7bc39SJason Zhu       ret = AVB_SLOT_VERIFY_RESULT_ERROR_IO;
66737a7bc39SJason Zhu       goto out;
66837a7bc39SJason Zhu     }
66937a7bc39SJason Zhu     avb_assert(footer_num_read == AVB_FOOTER_SIZE);
67037a7bc39SJason Zhu 
67137a7bc39SJason Zhu     if (!avb_footer_validate_and_byteswap((const AvbFooter*)footer_buf,
67237a7bc39SJason Zhu                                           &footer)) {
67369fdc596SJason Zhu       avb_debugv(full_partition_name, ": No footer detected.\n", NULL);
67469fdc596SJason Zhu     } else {
67537a7bc39SJason Zhu       /* Basic footer sanity check since the data is untrusted. */
67637a7bc39SJason Zhu       if (footer.vbmeta_size > VBMETA_MAX_SIZE) {
67737a7bc39SJason Zhu         avb_errorv(
67837a7bc39SJason Zhu             full_partition_name, ": Invalid vbmeta size in footer.\n", NULL);
67969fdc596SJason Zhu       } else {
68037a7bc39SJason Zhu         vbmeta_offset = footer.vbmeta_offset;
68137a7bc39SJason Zhu         vbmeta_size = footer.vbmeta_size;
68237a7bc39SJason Zhu       }
68369fdc596SJason Zhu     }
68469fdc596SJason Zhu   }
68537a7bc39SJason Zhu 
68637a7bc39SJason Zhu   vbmeta_buf = avb_malloc(vbmeta_size);
68737a7bc39SJason Zhu   if (vbmeta_buf == NULL) {
68837a7bc39SJason Zhu     ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
68937a7bc39SJason Zhu     goto out;
69037a7bc39SJason Zhu   }
69137a7bc39SJason Zhu 
69269fdc596SJason Zhu   if (vbmeta_offset != 0) {
69369fdc596SJason Zhu     avb_debugv("Loading vbmeta struct in footer from partition '",
69469fdc596SJason Zhu                full_partition_name,
69569fdc596SJason Zhu                "'.\n",
69669fdc596SJason Zhu                NULL);
69769fdc596SJason Zhu   } else {
69869fdc596SJason Zhu     avb_debugv("Loading vbmeta struct from partition '",
69969fdc596SJason Zhu                full_partition_name,
70069fdc596SJason Zhu                "'.\n",
70169fdc596SJason Zhu                NULL);
70269fdc596SJason Zhu   }
70369fdc596SJason Zhu 
70437a7bc39SJason Zhu   io_ret = ops->read_from_partition(ops,
70537a7bc39SJason Zhu                                     full_partition_name,
70637a7bc39SJason Zhu                                     vbmeta_offset,
70737a7bc39SJason Zhu                                     vbmeta_size,
70837a7bc39SJason Zhu                                     vbmeta_buf,
70937a7bc39SJason Zhu                                     &vbmeta_num_read);
71037a7bc39SJason Zhu   if (io_ret == AVB_IO_RESULT_ERROR_OOM) {
71137a7bc39SJason Zhu     ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
71237a7bc39SJason Zhu     goto out;
71337a7bc39SJason Zhu   } else if (io_ret != AVB_IO_RESULT_OK) {
71437a7bc39SJason Zhu     /* If we're looking for 'vbmeta' but there is no such partition,
71537a7bc39SJason Zhu      * go try to get it from the boot partition instead.
71637a7bc39SJason Zhu      */
71737a7bc39SJason Zhu     if (is_main_vbmeta && io_ret == AVB_IO_RESULT_ERROR_NO_SUCH_PARTITION &&
71869fdc596SJason Zhu         !look_for_vbmeta_footer) {
71937a7bc39SJason Zhu       avb_debugv(full_partition_name,
72037a7bc39SJason Zhu                  ": No such partition. Trying 'boot' instead.\n",
72137a7bc39SJason Zhu                  NULL);
72237a7bc39SJason Zhu       ret = load_and_verify_vbmeta(ops,
72337a7bc39SJason Zhu                                    requested_partitions,
72437a7bc39SJason Zhu                                    ab_suffix,
72569fdc596SJason Zhu                                    flags,
72637a7bc39SJason Zhu                                    allow_verification_error,
72737a7bc39SJason Zhu                                    0 /* toplevel_vbmeta_flags */,
72837a7bc39SJason Zhu                                    0 /* rollback_index_location */,
72937a7bc39SJason Zhu                                    "boot",
73037a7bc39SJason Zhu                                    avb_strlen("boot"),
73137a7bc39SJason Zhu                                    NULL /* expected_public_key */,
73237a7bc39SJason Zhu                                    0 /* expected_public_key_length */,
73337a7bc39SJason Zhu                                    slot_data,
734ab608f80SJason Zhu                                    out_algorithm_type,
735ab608f80SJason Zhu                                    out_additional_cmdline_subst);
73637a7bc39SJason Zhu       goto out;
73737a7bc39SJason Zhu     } else {
73837a7bc39SJason Zhu       avb_errorv(full_partition_name, ": Error loading vbmeta data.\n", NULL);
73937a7bc39SJason Zhu       ret = AVB_SLOT_VERIFY_RESULT_ERROR_IO;
74037a7bc39SJason Zhu       goto out;
74137a7bc39SJason Zhu     }
74237a7bc39SJason Zhu   }
74337a7bc39SJason Zhu   avb_assert(vbmeta_num_read <= vbmeta_size);
74437a7bc39SJason Zhu 
74537a7bc39SJason Zhu   /* Check if the image is properly signed and get the public key used
74637a7bc39SJason Zhu    * to sign the image.
74737a7bc39SJason Zhu    */
74837a7bc39SJason Zhu   vbmeta_ret =
74937a7bc39SJason Zhu       avb_vbmeta_image_verify(vbmeta_buf, vbmeta_num_read, &pk_data, &pk_len);
75037a7bc39SJason Zhu   switch (vbmeta_ret) {
75137a7bc39SJason Zhu     case AVB_VBMETA_VERIFY_RESULT_OK:
75237a7bc39SJason Zhu       avb_assert(pk_data != NULL && pk_len > 0);
75337a7bc39SJason Zhu       break;
75437a7bc39SJason Zhu 
75537a7bc39SJason Zhu     case AVB_VBMETA_VERIFY_RESULT_OK_NOT_SIGNED:
75637a7bc39SJason Zhu     case AVB_VBMETA_VERIFY_RESULT_HASH_MISMATCH:
75737a7bc39SJason Zhu     case AVB_VBMETA_VERIFY_RESULT_SIGNATURE_MISMATCH:
75837a7bc39SJason Zhu       ret = AVB_SLOT_VERIFY_RESULT_ERROR_VERIFICATION;
75937a7bc39SJason Zhu       avb_errorv(full_partition_name,
76037a7bc39SJason Zhu                  ": Error verifying vbmeta image: ",
76137a7bc39SJason Zhu                  avb_vbmeta_verify_result_to_string(vbmeta_ret),
76237a7bc39SJason Zhu                  "\n",
76337a7bc39SJason Zhu                  NULL);
76437a7bc39SJason Zhu       if (!allow_verification_error) {
76537a7bc39SJason Zhu         goto out;
76637a7bc39SJason Zhu       }
76737a7bc39SJason Zhu       break;
76837a7bc39SJason Zhu 
76937a7bc39SJason Zhu     case AVB_VBMETA_VERIFY_RESULT_INVALID_VBMETA_HEADER:
77037a7bc39SJason Zhu       /* No way to continue this case. */
77137a7bc39SJason Zhu       ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;
77237a7bc39SJason Zhu       avb_errorv(full_partition_name,
77337a7bc39SJason Zhu                  ": Error verifying vbmeta image: invalid vbmeta header\n",
77437a7bc39SJason Zhu                  NULL);
77537a7bc39SJason Zhu       goto out;
77637a7bc39SJason Zhu 
77737a7bc39SJason Zhu     case AVB_VBMETA_VERIFY_RESULT_UNSUPPORTED_VERSION:
77837a7bc39SJason Zhu       /* No way to continue this case. */
77937a7bc39SJason Zhu       ret = AVB_SLOT_VERIFY_RESULT_ERROR_UNSUPPORTED_VERSION;
78037a7bc39SJason Zhu       avb_errorv(full_partition_name,
78137a7bc39SJason Zhu                  ": Error verifying vbmeta image: unsupported AVB version\n",
78237a7bc39SJason Zhu                  NULL);
78337a7bc39SJason Zhu       goto out;
78437a7bc39SJason Zhu   }
78537a7bc39SJason Zhu 
78637a7bc39SJason Zhu   /* Byteswap the header. */
78737a7bc39SJason Zhu   avb_vbmeta_image_header_to_host_byte_order((AvbVBMetaImageHeader*)vbmeta_buf,
78837a7bc39SJason Zhu                                              &vbmeta_header);
78937a7bc39SJason Zhu 
79037a7bc39SJason Zhu   /* If we're the toplevel, assign flags so they'll be passed down. */
79137a7bc39SJason Zhu   if (is_main_vbmeta) {
79237a7bc39SJason Zhu     toplevel_vbmeta_flags = (AvbVBMetaImageFlags)vbmeta_header.flags;
79337a7bc39SJason Zhu   } else {
79437a7bc39SJason Zhu     if (vbmeta_header.flags != 0) {
79537a7bc39SJason Zhu       ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;
79637a7bc39SJason Zhu       avb_errorv(full_partition_name,
79737a7bc39SJason Zhu                  ": chained vbmeta image has non-zero flags\n",
79837a7bc39SJason Zhu                  NULL);
79937a7bc39SJason Zhu       goto out;
80037a7bc39SJason Zhu     }
80137a7bc39SJason Zhu   }
80237a7bc39SJason Zhu 
80369fdc596SJason Zhu   uint32_t rollback_index_location_to_use = rollback_index_location;
80469fdc596SJason Zhu 
80537a7bc39SJason Zhu   /* Check if key used to make signature matches what is expected. */
80637a7bc39SJason Zhu   if (pk_data != NULL) {
80737a7bc39SJason Zhu     if (expected_public_key != NULL) {
80837a7bc39SJason Zhu       avb_assert(!is_main_vbmeta);
80937a7bc39SJason Zhu       if (expected_public_key_length != pk_len ||
81037a7bc39SJason Zhu           avb_safe_memcmp(expected_public_key, pk_data, pk_len) != 0) {
81137a7bc39SJason Zhu         avb_errorv(full_partition_name,
81237a7bc39SJason Zhu                    ": Public key used to sign data does not match key in chain "
81337a7bc39SJason Zhu                    "partition descriptor.\n",
81437a7bc39SJason Zhu                    NULL);
81537a7bc39SJason Zhu         ret = AVB_SLOT_VERIFY_RESULT_ERROR_PUBLIC_KEY_REJECTED;
81637a7bc39SJason Zhu         if (!allow_verification_error) {
81737a7bc39SJason Zhu           goto out;
81837a7bc39SJason Zhu         }
81937a7bc39SJason Zhu       }
82037a7bc39SJason Zhu     } else {
82137a7bc39SJason Zhu       bool key_is_trusted = false;
82237a7bc39SJason Zhu       const uint8_t* pk_metadata = NULL;
82337a7bc39SJason Zhu       size_t pk_metadata_len = 0;
82437a7bc39SJason Zhu 
82537a7bc39SJason Zhu       if (vbmeta_header.public_key_metadata_size > 0) {
82637a7bc39SJason Zhu         pk_metadata = vbmeta_buf + sizeof(AvbVBMetaImageHeader) +
82737a7bc39SJason Zhu                       vbmeta_header.authentication_data_block_size +
82837a7bc39SJason Zhu                       vbmeta_header.public_key_metadata_offset;
82937a7bc39SJason Zhu         pk_metadata_len = vbmeta_header.public_key_metadata_size;
83037a7bc39SJason Zhu       }
83137a7bc39SJason Zhu 
83269fdc596SJason Zhu       // If we're not using a vbmeta partition, need to use another AvbOps...
83369fdc596SJason Zhu       if (flags & AVB_SLOT_VERIFY_FLAGS_NO_VBMETA_PARTITION) {
83469fdc596SJason Zhu         io_ret = ops->validate_public_key_for_partition(
83569fdc596SJason Zhu             ops,
83669fdc596SJason Zhu             full_partition_name,
83769fdc596SJason Zhu             pk_data,
83869fdc596SJason Zhu             pk_len,
83969fdc596SJason Zhu             pk_metadata,
84069fdc596SJason Zhu             pk_metadata_len,
84169fdc596SJason Zhu             &key_is_trusted,
84269fdc596SJason Zhu             &rollback_index_location_to_use);
84369fdc596SJason Zhu       } else {
84437a7bc39SJason Zhu         avb_assert(is_main_vbmeta);
84569fdc596SJason Zhu         io_ret = ops->validate_vbmeta_public_key(ops,
84669fdc596SJason Zhu                                                  pk_data,
84769fdc596SJason Zhu                                                  pk_len,
84869fdc596SJason Zhu                                                  pk_metadata,
84969fdc596SJason Zhu                                                  pk_metadata_len,
85069fdc596SJason Zhu                                                  &key_is_trusted);
85169fdc596SJason Zhu       }
85269fdc596SJason Zhu 
85337a7bc39SJason Zhu       if (io_ret == AVB_IO_RESULT_ERROR_OOM) {
85437a7bc39SJason Zhu         ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
85537a7bc39SJason Zhu         goto out;
85637a7bc39SJason Zhu       } else if (io_ret != AVB_IO_RESULT_OK) {
85737a7bc39SJason Zhu         avb_errorv(full_partition_name,
85837a7bc39SJason Zhu                    ": Error while checking public key used to sign data.\n",
85937a7bc39SJason Zhu                    NULL);
86037a7bc39SJason Zhu         ret = AVB_SLOT_VERIFY_RESULT_ERROR_IO;
86137a7bc39SJason Zhu         goto out;
86237a7bc39SJason Zhu       }
86337a7bc39SJason Zhu       if (!key_is_trusted) {
86437a7bc39SJason Zhu         avb_errorv(full_partition_name,
86537a7bc39SJason Zhu                    ": Public key used to sign data rejected.\n",
86637a7bc39SJason Zhu                    NULL);
86737a7bc39SJason Zhu         ret = AVB_SLOT_VERIFY_RESULT_ERROR_PUBLIC_KEY_REJECTED;
86837a7bc39SJason Zhu         if (!allow_verification_error) {
86937a7bc39SJason Zhu           goto out;
87037a7bc39SJason Zhu         }
87137a7bc39SJason Zhu       }
87237a7bc39SJason Zhu     }
87337a7bc39SJason Zhu   }
87437a7bc39SJason Zhu 
87537a7bc39SJason Zhu   /* Check rollback index. */
87637a7bc39SJason Zhu   io_ret = ops->read_rollback_index(
87769fdc596SJason Zhu       ops, rollback_index_location_to_use, &stored_rollback_index);
87837a7bc39SJason Zhu   if (io_ret == AVB_IO_RESULT_ERROR_OOM) {
87937a7bc39SJason Zhu     ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
88037a7bc39SJason Zhu     goto out;
88137a7bc39SJason Zhu   } else if (io_ret != AVB_IO_RESULT_OK) {
88237a7bc39SJason Zhu     avb_errorv(full_partition_name,
88337a7bc39SJason Zhu                ": Error getting rollback index for location.\n",
88437a7bc39SJason Zhu                NULL);
88537a7bc39SJason Zhu     ret = AVB_SLOT_VERIFY_RESULT_ERROR_IO;
88637a7bc39SJason Zhu     goto out;
88737a7bc39SJason Zhu   }
88837a7bc39SJason Zhu   if (vbmeta_header.rollback_index < stored_rollback_index) {
88937a7bc39SJason Zhu     avb_errorv(
89037a7bc39SJason Zhu         full_partition_name,
89137a7bc39SJason Zhu         ": Image rollback index is less than the stored rollback index.\n",
89237a7bc39SJason Zhu         NULL);
89337a7bc39SJason Zhu     ret = AVB_SLOT_VERIFY_RESULT_ERROR_ROLLBACK_INDEX;
89437a7bc39SJason Zhu     if (!allow_verification_error) {
89537a7bc39SJason Zhu       goto out;
89637a7bc39SJason Zhu     }
89737a7bc39SJason Zhu   }
89837a7bc39SJason Zhu 
89937a7bc39SJason Zhu   /* Copy vbmeta to vbmeta_images before recursing. */
90037a7bc39SJason Zhu   if (is_main_vbmeta) {
90137a7bc39SJason Zhu     avb_assert(slot_data->num_vbmeta_images == 0);
90237a7bc39SJason Zhu   } else {
90369fdc596SJason Zhu     if (!(flags & AVB_SLOT_VERIFY_FLAGS_NO_VBMETA_PARTITION)) {
90437a7bc39SJason Zhu       avb_assert(slot_data->num_vbmeta_images > 0);
90537a7bc39SJason Zhu     }
90669fdc596SJason Zhu   }
90737a7bc39SJason Zhu   if (slot_data->num_vbmeta_images == MAX_NUMBER_OF_VBMETA_IMAGES) {
90837a7bc39SJason Zhu     avb_errorv(full_partition_name, ": Too many vbmeta images.\n", NULL);
90937a7bc39SJason Zhu     ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
91037a7bc39SJason Zhu     goto out;
91137a7bc39SJason Zhu   }
91237a7bc39SJason Zhu   vbmeta_image_data = &slot_data->vbmeta_images[slot_data->num_vbmeta_images++];
91337a7bc39SJason Zhu   vbmeta_image_data->partition_name = avb_strdup(partition_name);
91437a7bc39SJason Zhu   vbmeta_image_data->vbmeta_data = vbmeta_buf;
91537a7bc39SJason Zhu   /* Note that |vbmeta_buf| is actually |vbmeta_num_read| bytes long
91637a7bc39SJason Zhu    * and this includes data past the end of the image. Pass the
91737a7bc39SJason Zhu    * actual size of the vbmeta image. Also, no need to use
91837a7bc39SJason Zhu    * avb_safe_add() since the header has already been verified.
91937a7bc39SJason Zhu    */
92037a7bc39SJason Zhu   vbmeta_image_data->vbmeta_size =
92137a7bc39SJason Zhu       sizeof(AvbVBMetaImageHeader) +
92237a7bc39SJason Zhu       vbmeta_header.authentication_data_block_size +
92337a7bc39SJason Zhu       vbmeta_header.auxiliary_data_block_size;
92437a7bc39SJason Zhu   vbmeta_image_data->verify_result = vbmeta_ret;
92537a7bc39SJason Zhu 
92637a7bc39SJason Zhu   /* If verification has been disabled by setting a bit in the image,
92737a7bc39SJason Zhu    * we're done... except that we need to load the entirety of the
92837a7bc39SJason Zhu    * requested partitions.
92937a7bc39SJason Zhu    */
93037a7bc39SJason Zhu   if (vbmeta_header.flags & AVB_VBMETA_IMAGE_FLAGS_VERIFICATION_DISABLED) {
93137a7bc39SJason Zhu     AvbSlotVerifyResult sub_ret;
93237a7bc39SJason Zhu     avb_debugv(
93337a7bc39SJason Zhu         full_partition_name, ": VERIFICATION_DISABLED bit is set.\n", NULL);
93437a7bc39SJason Zhu     /* If load_requested_partitions() fail it is always a fatal
93537a7bc39SJason Zhu      * failure (e.g. ERROR_INVALID_ARGUMENT, ERROR_OOM, etc.) rather
93637a7bc39SJason Zhu      * than recoverable (e.g. one where result_should_continue()
93737a7bc39SJason Zhu      * returns true) and we want to convey that error.
93837a7bc39SJason Zhu      */
93937a7bc39SJason Zhu     sub_ret = load_requested_partitions(
94037a7bc39SJason Zhu         ops, requested_partitions, ab_suffix, slot_data);
94137a7bc39SJason Zhu     if (sub_ret != AVB_SLOT_VERIFY_RESULT_OK) {
94237a7bc39SJason Zhu       ret = sub_ret;
94337a7bc39SJason Zhu     }
94437a7bc39SJason Zhu     goto out;
94537a7bc39SJason Zhu   }
94637a7bc39SJason Zhu 
94737a7bc39SJason Zhu   /* Now go through all descriptors and take the appropriate action:
94837a7bc39SJason Zhu    *
94937a7bc39SJason Zhu    * - hash descriptor: Load data from partition, calculate hash, and
95037a7bc39SJason Zhu    *   checks that it matches what's in the hash descriptor.
95137a7bc39SJason Zhu    *
95237a7bc39SJason Zhu    * - hashtree descriptor: Do nothing since verification happens
953ab608f80SJason Zhu    *   on-the-fly from within the OS. (Unless the descriptor uses a
954ab608f80SJason Zhu    *   persistent digest, in which case we need to find it).
95537a7bc39SJason Zhu    *
95637a7bc39SJason Zhu    * - chained partition descriptor: Load the footer, load the vbmeta
95737a7bc39SJason Zhu    *   image, verify vbmeta image (includes rollback checks, hash
95837a7bc39SJason Zhu    *   checks, bail on chained partitions).
95937a7bc39SJason Zhu    */
96037a7bc39SJason Zhu   descriptors =
96137a7bc39SJason Zhu       avb_descriptor_get_all(vbmeta_buf, vbmeta_num_read, &num_descriptors);
96237a7bc39SJason Zhu   for (n = 0; n < num_descriptors; n++) {
96337a7bc39SJason Zhu     AvbDescriptor desc;
96437a7bc39SJason Zhu 
96537a7bc39SJason Zhu     if (!avb_descriptor_validate_and_byteswap(descriptors[n], &desc)) {
96637a7bc39SJason Zhu       avb_errorv(full_partition_name, ": Descriptor is invalid.\n", NULL);
96737a7bc39SJason Zhu       ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;
96837a7bc39SJason Zhu       goto out;
96937a7bc39SJason Zhu     }
97037a7bc39SJason Zhu 
97137a7bc39SJason Zhu     switch (desc.tag) {
97237a7bc39SJason Zhu       case AVB_DESCRIPTOR_TAG_HASH: {
97337a7bc39SJason Zhu         AvbSlotVerifyResult sub_ret;
97437a7bc39SJason Zhu         sub_ret = load_and_verify_hash_partition(ops,
97537a7bc39SJason Zhu                                                  requested_partitions,
97637a7bc39SJason Zhu                                                  ab_suffix,
97737a7bc39SJason Zhu                                                  allow_verification_error,
97837a7bc39SJason Zhu                                                  descriptors[n],
97937a7bc39SJason Zhu                                                  slot_data);
98037a7bc39SJason Zhu         if (sub_ret != AVB_SLOT_VERIFY_RESULT_OK) {
98137a7bc39SJason Zhu           ret = sub_ret;
98237a7bc39SJason Zhu           if (!allow_verification_error || !result_should_continue(ret)) {
98337a7bc39SJason Zhu             goto out;
98437a7bc39SJason Zhu           }
98537a7bc39SJason Zhu         }
98637a7bc39SJason Zhu       } break;
98737a7bc39SJason Zhu 
98837a7bc39SJason Zhu       case AVB_DESCRIPTOR_TAG_CHAIN_PARTITION: {
98937a7bc39SJason Zhu         AvbSlotVerifyResult sub_ret;
99037a7bc39SJason Zhu         AvbChainPartitionDescriptor chain_desc;
99137a7bc39SJason Zhu         const uint8_t* chain_partition_name;
99237a7bc39SJason Zhu         const uint8_t* chain_public_key;
99337a7bc39SJason Zhu 
99437a7bc39SJason Zhu         /* Only allow CHAIN_PARTITION descriptors in the main vbmeta image. */
99537a7bc39SJason Zhu         if (!is_main_vbmeta) {
99637a7bc39SJason Zhu           avb_errorv(full_partition_name,
99737a7bc39SJason Zhu                      ": Encountered chain descriptor not in main image.\n",
99837a7bc39SJason Zhu                      NULL);
99937a7bc39SJason Zhu           ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;
100037a7bc39SJason Zhu           goto out;
100137a7bc39SJason Zhu         }
100237a7bc39SJason Zhu 
100337a7bc39SJason Zhu         if (!avb_chain_partition_descriptor_validate_and_byteswap(
100437a7bc39SJason Zhu                 (AvbChainPartitionDescriptor*)descriptors[n], &chain_desc)) {
100537a7bc39SJason Zhu           avb_errorv(full_partition_name,
100637a7bc39SJason Zhu                      ": Chain partition descriptor is invalid.\n",
100737a7bc39SJason Zhu                      NULL);
100837a7bc39SJason Zhu           ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;
100937a7bc39SJason Zhu           goto out;
101037a7bc39SJason Zhu         }
101137a7bc39SJason Zhu 
101237a7bc39SJason Zhu         if (chain_desc.rollback_index_location == 0) {
101337a7bc39SJason Zhu           avb_errorv(full_partition_name,
101437a7bc39SJason Zhu                      ": Chain partition has invalid "
101537a7bc39SJason Zhu                      "rollback_index_location field.\n",
101637a7bc39SJason Zhu                      NULL);
101737a7bc39SJason Zhu           ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;
101837a7bc39SJason Zhu           goto out;
101937a7bc39SJason Zhu         }
102037a7bc39SJason Zhu 
102137a7bc39SJason Zhu         chain_partition_name = ((const uint8_t*)descriptors[n]) +
102237a7bc39SJason Zhu                                sizeof(AvbChainPartitionDescriptor);
102337a7bc39SJason Zhu         chain_public_key = chain_partition_name + chain_desc.partition_name_len;
102437a7bc39SJason Zhu 
1025ab608f80SJason Zhu         sub_ret =
1026ab608f80SJason Zhu             load_and_verify_vbmeta(ops,
102737a7bc39SJason Zhu                                    requested_partitions,
102837a7bc39SJason Zhu                                    ab_suffix,
102969fdc596SJason Zhu                                    flags,
103037a7bc39SJason Zhu                                    allow_verification_error,
103137a7bc39SJason Zhu                                    toplevel_vbmeta_flags,
103237a7bc39SJason Zhu                                    chain_desc.rollback_index_location,
103337a7bc39SJason Zhu                                    (const char*)chain_partition_name,
103437a7bc39SJason Zhu                                    chain_desc.partition_name_len,
103537a7bc39SJason Zhu                                    chain_public_key,
103637a7bc39SJason Zhu                                    chain_desc.public_key_len,
103737a7bc39SJason Zhu                                    slot_data,
1038ab608f80SJason Zhu                                    NULL, /* out_algorithm_type */
1039ab608f80SJason Zhu                                    NULL /* out_additional_cmdline_subst */);
104037a7bc39SJason Zhu         if (sub_ret != AVB_SLOT_VERIFY_RESULT_OK) {
104137a7bc39SJason Zhu           ret = sub_ret;
104237a7bc39SJason Zhu           if (!result_should_continue(ret)) {
104337a7bc39SJason Zhu             goto out;
104437a7bc39SJason Zhu           }
104537a7bc39SJason Zhu         }
104637a7bc39SJason Zhu       } break;
104737a7bc39SJason Zhu 
104837a7bc39SJason Zhu       case AVB_DESCRIPTOR_TAG_KERNEL_CMDLINE: {
104937a7bc39SJason Zhu         const uint8_t* kernel_cmdline;
105037a7bc39SJason Zhu         AvbKernelCmdlineDescriptor kernel_cmdline_desc;
105137a7bc39SJason Zhu         bool apply_cmdline;
105237a7bc39SJason Zhu 
105337a7bc39SJason Zhu         if (!avb_kernel_cmdline_descriptor_validate_and_byteswap(
105437a7bc39SJason Zhu                 (AvbKernelCmdlineDescriptor*)descriptors[n],
105537a7bc39SJason Zhu                 &kernel_cmdline_desc)) {
105637a7bc39SJason Zhu           avb_errorv(full_partition_name,
105737a7bc39SJason Zhu                      ": Kernel cmdline descriptor is invalid.\n",
105837a7bc39SJason Zhu                      NULL);
105937a7bc39SJason Zhu           ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;
106037a7bc39SJason Zhu           goto out;
106137a7bc39SJason Zhu         }
106237a7bc39SJason Zhu 
106337a7bc39SJason Zhu         kernel_cmdline = ((const uint8_t*)descriptors[n]) +
106437a7bc39SJason Zhu                          sizeof(AvbKernelCmdlineDescriptor);
106537a7bc39SJason Zhu 
106637a7bc39SJason Zhu         if (!avb_validate_utf8(kernel_cmdline,
106737a7bc39SJason Zhu                                kernel_cmdline_desc.kernel_cmdline_length)) {
106837a7bc39SJason Zhu           avb_errorv(full_partition_name,
106937a7bc39SJason Zhu                      ": Kernel cmdline is not valid UTF-8.\n",
107037a7bc39SJason Zhu                      NULL);
107137a7bc39SJason Zhu           ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;
107237a7bc39SJason Zhu           goto out;
107337a7bc39SJason Zhu         }
107437a7bc39SJason Zhu 
107537a7bc39SJason Zhu         /* Compare the flags for top-level VBMeta struct with flags in
107637a7bc39SJason Zhu          * the command-line descriptor so command-line snippets only
107737a7bc39SJason Zhu          * intended for a certain mode (dm-verity enabled/disabled)
107837a7bc39SJason Zhu          * are skipped if applicable.
107937a7bc39SJason Zhu          */
108037a7bc39SJason Zhu         apply_cmdline = true;
108137a7bc39SJason Zhu         if (toplevel_vbmeta_flags & AVB_VBMETA_IMAGE_FLAGS_HASHTREE_DISABLED) {
108237a7bc39SJason Zhu           if (kernel_cmdline_desc.flags &
108337a7bc39SJason Zhu               AVB_KERNEL_CMDLINE_FLAGS_USE_ONLY_IF_HASHTREE_NOT_DISABLED) {
108437a7bc39SJason Zhu             apply_cmdline = false;
108537a7bc39SJason Zhu           }
108637a7bc39SJason Zhu         } else {
108737a7bc39SJason Zhu           if (kernel_cmdline_desc.flags &
108837a7bc39SJason Zhu               AVB_KERNEL_CMDLINE_FLAGS_USE_ONLY_IF_HASHTREE_DISABLED) {
108937a7bc39SJason Zhu             apply_cmdline = false;
109037a7bc39SJason Zhu           }
109137a7bc39SJason Zhu         }
109237a7bc39SJason Zhu 
109337a7bc39SJason Zhu         if (apply_cmdline) {
109437a7bc39SJason Zhu           if (slot_data->cmdline == NULL) {
109537a7bc39SJason Zhu             slot_data->cmdline =
109637a7bc39SJason Zhu                 avb_calloc(kernel_cmdline_desc.kernel_cmdline_length + 1);
109737a7bc39SJason Zhu             if (slot_data->cmdline == NULL) {
109837a7bc39SJason Zhu               ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
109937a7bc39SJason Zhu               goto out;
110037a7bc39SJason Zhu             }
110137a7bc39SJason Zhu             avb_memcpy(slot_data->cmdline,
110237a7bc39SJason Zhu                        kernel_cmdline,
110337a7bc39SJason Zhu                        kernel_cmdline_desc.kernel_cmdline_length);
110437a7bc39SJason Zhu           } else {
110537a7bc39SJason Zhu             /* new cmdline is: <existing_cmdline> + ' ' + <newcmdline> + '\0' */
110637a7bc39SJason Zhu             size_t orig_size = avb_strlen(slot_data->cmdline);
110737a7bc39SJason Zhu             size_t new_size =
110837a7bc39SJason Zhu                 orig_size + 1 + kernel_cmdline_desc.kernel_cmdline_length + 1;
110937a7bc39SJason Zhu             char* new_cmdline = avb_calloc(new_size);
111037a7bc39SJason Zhu             if (new_cmdline == NULL) {
111137a7bc39SJason Zhu               ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
111237a7bc39SJason Zhu               goto out;
111337a7bc39SJason Zhu             }
111437a7bc39SJason Zhu             avb_memcpy(new_cmdline, slot_data->cmdline, orig_size);
111537a7bc39SJason Zhu             new_cmdline[orig_size] = ' ';
111637a7bc39SJason Zhu             avb_memcpy(new_cmdline + orig_size + 1,
111737a7bc39SJason Zhu                        kernel_cmdline,
111837a7bc39SJason Zhu                        kernel_cmdline_desc.kernel_cmdline_length);
111937a7bc39SJason Zhu             avb_free(slot_data->cmdline);
112037a7bc39SJason Zhu             slot_data->cmdline = new_cmdline;
112137a7bc39SJason Zhu           }
112237a7bc39SJason Zhu         }
112337a7bc39SJason Zhu       } break;
112437a7bc39SJason Zhu 
1125ab608f80SJason Zhu       case AVB_DESCRIPTOR_TAG_HASHTREE: {
1126ab608f80SJason Zhu         AvbHashtreeDescriptor hashtree_desc;
1127ab608f80SJason Zhu 
1128ab608f80SJason Zhu         if (!avb_hashtree_descriptor_validate_and_byteswap(
1129ab608f80SJason Zhu                 (AvbHashtreeDescriptor*)descriptors[n], &hashtree_desc)) {
1130ab608f80SJason Zhu           avb_errorv(
1131ab608f80SJason Zhu               full_partition_name, ": Hashtree descriptor is invalid.\n", NULL);
1132ab608f80SJason Zhu           ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;
1133ab608f80SJason Zhu           goto out;
1134ab608f80SJason Zhu         }
1135ab608f80SJason Zhu 
1136ab608f80SJason Zhu         /* We only need to continue when there is no digest in the descriptor.
1137ab608f80SJason Zhu          * This is because the only processing here is to find the digest and
1138ab608f80SJason Zhu          * make it available on the kernel command line.
1139ab608f80SJason Zhu          */
1140ab608f80SJason Zhu         if (hashtree_desc.root_digest_len == 0) {
1141ab608f80SJason Zhu           char part_name[AVB_PART_NAME_MAX_SIZE];
1142ab608f80SJason Zhu           size_t digest_len = 0;
1143ab608f80SJason Zhu           uint8_t digest_buf[AVB_SHA512_DIGEST_SIZE];
1144ab608f80SJason Zhu           const uint8_t* desc_partition_name =
1145ab608f80SJason Zhu               ((const uint8_t*)descriptors[n]) + sizeof(AvbHashtreeDescriptor);
1146ab608f80SJason Zhu 
1147ab608f80SJason Zhu           if (!avb_validate_utf8(desc_partition_name,
1148ab608f80SJason Zhu                                  hashtree_desc.partition_name_len)) {
1149ab608f80SJason Zhu             avb_error("Partition name is not valid UTF-8.\n");
1150ab608f80SJason Zhu             ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;
1151ab608f80SJason Zhu             goto out;
1152ab608f80SJason Zhu           }
1153ab608f80SJason Zhu 
1154ab608f80SJason Zhu           /* No ab_suffix for partitions without a digest in the descriptor
1155ab608f80SJason Zhu            * because these partitions hold data unique to this device and are
1156ab608f80SJason Zhu            * not updated using an A/B scheme.
1157ab608f80SJason Zhu            */
1158ab608f80SJason Zhu           if ((hashtree_desc.flags &
1159ab608f80SJason Zhu                AVB_HASHTREE_DESCRIPTOR_FLAGS_DO_NOT_USE_AB) == 0 &&
1160ab608f80SJason Zhu               avb_strlen(ab_suffix) != 0) {
1161ab608f80SJason Zhu             avb_error("Cannot use A/B with a persistent root digest.\n");
1162ab608f80SJason Zhu             ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;
1163ab608f80SJason Zhu             goto out;
1164ab608f80SJason Zhu           }
1165ab608f80SJason Zhu           if (hashtree_desc.partition_name_len >= AVB_PART_NAME_MAX_SIZE) {
1166ab608f80SJason Zhu             avb_error("Partition name does not fit.\n");
1167ab608f80SJason Zhu             ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;
1168ab608f80SJason Zhu             goto out;
1169ab608f80SJason Zhu           }
1170ab608f80SJason Zhu           avb_memcpy(
1171ab608f80SJason Zhu               part_name, desc_partition_name, hashtree_desc.partition_name_len);
1172ab608f80SJason Zhu           part_name[hashtree_desc.partition_name_len] = '\0';
1173ab608f80SJason Zhu 
1174ab608f80SJason Zhu           /* Determine the expected digest size from the hash algorithm. */
1175ab608f80SJason Zhu           if (avb_strcmp((const char*)hashtree_desc.hash_algorithm, "sha1") ==
1176ab608f80SJason Zhu               0) {
1177ab608f80SJason Zhu             digest_len = AVB_SHA1_DIGEST_SIZE;
1178ab608f80SJason Zhu           } else if (avb_strcmp((const char*)hashtree_desc.hash_algorithm,
1179ab608f80SJason Zhu                                 "sha256") == 0) {
1180ab608f80SJason Zhu             digest_len = AVB_SHA256_DIGEST_SIZE;
1181ab608f80SJason Zhu           } else if (avb_strcmp((const char*)hashtree_desc.hash_algorithm,
1182ab608f80SJason Zhu                                 "sha512") == 0) {
1183ab608f80SJason Zhu             digest_len = AVB_SHA512_DIGEST_SIZE;
1184ab608f80SJason Zhu           } else {
1185ab608f80SJason Zhu             avb_errorv(part_name, ": Unsupported hash algorithm.\n", NULL);
1186ab608f80SJason Zhu             ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;
1187ab608f80SJason Zhu             goto out;
1188ab608f80SJason Zhu           }
1189ab608f80SJason Zhu 
119069fdc596SJason Zhu           ret = read_persistent_digest(ops,
119169fdc596SJason Zhu                                        part_name,
119269fdc596SJason Zhu                                        digest_len,
119369fdc596SJason Zhu                                        NULL /* initial_digest */,
119469fdc596SJason Zhu                                        digest_buf);
1195ab608f80SJason Zhu           if (ret != AVB_SLOT_VERIFY_RESULT_OK) {
1196ab608f80SJason Zhu             goto out;
1197ab608f80SJason Zhu           }
1198ab608f80SJason Zhu 
1199ab608f80SJason Zhu           if (out_additional_cmdline_subst) {
1200ab608f80SJason Zhu             ret =
1201ab608f80SJason Zhu                 avb_add_root_digest_substitution(part_name,
1202ab608f80SJason Zhu                                                  digest_buf,
1203ab608f80SJason Zhu                                                  digest_len,
1204ab608f80SJason Zhu                                                  out_additional_cmdline_subst);
1205ab608f80SJason Zhu             if (ret != AVB_SLOT_VERIFY_RESULT_OK) {
1206ab608f80SJason Zhu               goto out;
1207ab608f80SJason Zhu             }
1208ab608f80SJason Zhu           }
1209ab608f80SJason Zhu         }
1210ab608f80SJason Zhu       } break;
1211ab608f80SJason Zhu 
121237a7bc39SJason Zhu       case AVB_DESCRIPTOR_TAG_PROPERTY:
121337a7bc39SJason Zhu         /* Do nothing. */
121437a7bc39SJason Zhu         break;
121537a7bc39SJason Zhu     }
121637a7bc39SJason Zhu   }
121737a7bc39SJason Zhu 
121869fdc596SJason Zhu   if (rollback_index_location < 0 ||
121969fdc596SJason Zhu       rollback_index_location >= AVB_MAX_NUMBER_OF_ROLLBACK_INDEX_LOCATIONS) {
122037a7bc39SJason Zhu     avb_errorv(
122137a7bc39SJason Zhu         full_partition_name, ": Invalid rollback_index_location.\n", NULL);
122237a7bc39SJason Zhu     ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;
122337a7bc39SJason Zhu     goto out;
122437a7bc39SJason Zhu   }
122537a7bc39SJason Zhu 
122637a7bc39SJason Zhu   slot_data->rollback_indexes[rollback_index_location] =
122737a7bc39SJason Zhu       vbmeta_header.rollback_index;
122837a7bc39SJason Zhu 
122937a7bc39SJason Zhu   if (out_algorithm_type != NULL) {
123037a7bc39SJason Zhu     *out_algorithm_type = (AvbAlgorithmType)vbmeta_header.algorithm_type;
123137a7bc39SJason Zhu   }
123237a7bc39SJason Zhu 
123337a7bc39SJason Zhu out:
123437a7bc39SJason Zhu   /* If |vbmeta_image_data| isn't NULL it means that it adopted
123537a7bc39SJason Zhu    * |vbmeta_buf| so in that case don't free it here.
123637a7bc39SJason Zhu    */
123737a7bc39SJason Zhu   if (vbmeta_image_data == NULL) {
123837a7bc39SJason Zhu     if (vbmeta_buf != NULL) {
123937a7bc39SJason Zhu       avb_free(vbmeta_buf);
124037a7bc39SJason Zhu     }
124137a7bc39SJason Zhu   }
124237a7bc39SJason Zhu   if (descriptors != NULL) {
124337a7bc39SJason Zhu     avb_free(descriptors);
124437a7bc39SJason Zhu   }
124537a7bc39SJason Zhu   return ret;
124637a7bc39SJason Zhu }
124737a7bc39SJason Zhu 
avb_manage_hashtree_error_mode(AvbOps * ops,AvbSlotVerifyFlags flags,AvbSlotVerifyData * data,AvbHashtreeErrorMode * out_hashtree_error_mode)124869fdc596SJason Zhu static AvbIOResult avb_manage_hashtree_error_mode(
124969fdc596SJason Zhu     AvbOps* ops,
125069fdc596SJason Zhu     AvbSlotVerifyFlags flags,
125169fdc596SJason Zhu     AvbSlotVerifyData* data,
125269fdc596SJason Zhu     AvbHashtreeErrorMode* out_hashtree_error_mode) {
125369fdc596SJason Zhu   AvbHashtreeErrorMode ret = AVB_HASHTREE_ERROR_MODE_RESTART;
125469fdc596SJason Zhu   AvbIOResult io_ret = AVB_IO_RESULT_OK;
125569fdc596SJason Zhu   uint8_t vbmeta_digest_sha256[AVB_SHA256_DIGEST_SIZE];
125669fdc596SJason Zhu   uint8_t stored_vbmeta_digest_sha256[AVB_SHA256_DIGEST_SIZE];
125769fdc596SJason Zhu   size_t num_bytes_read;
125869fdc596SJason Zhu 
125969fdc596SJason Zhu   avb_assert(out_hashtree_error_mode != NULL);
126069fdc596SJason Zhu   avb_assert(ops->read_persistent_value != NULL);
126169fdc596SJason Zhu   avb_assert(ops->write_persistent_value != NULL);
126269fdc596SJason Zhu 
126369fdc596SJason Zhu   // If we're rebooting because of dm-verity corruption, make a note of
126469fdc596SJason Zhu   // the vbmeta hash so we can stay in 'eio' mode until things change.
126569fdc596SJason Zhu   if (flags & AVB_SLOT_VERIFY_FLAGS_RESTART_CAUSED_BY_HASHTREE_CORRUPTION) {
126669fdc596SJason Zhu     avb_debug(
126769fdc596SJason Zhu         "Rebooting because of dm-verity corruption - "
126869fdc596SJason Zhu         "recording OS instance and using 'eio' mode.\n");
126969fdc596SJason Zhu     avb_slot_verify_data_calculate_vbmeta_digest(
127069fdc596SJason Zhu         data, AVB_DIGEST_TYPE_SHA256, vbmeta_digest_sha256);
127169fdc596SJason Zhu     io_ret = ops->write_persistent_value(ops,
127269fdc596SJason Zhu                                          AVB_NPV_MANAGED_VERITY_MODE,
127369fdc596SJason Zhu                                          AVB_SHA256_DIGEST_SIZE,
127469fdc596SJason Zhu                                          vbmeta_digest_sha256);
127569fdc596SJason Zhu     if (io_ret != AVB_IO_RESULT_OK) {
127669fdc596SJason Zhu       avb_error("Error writing to " AVB_NPV_MANAGED_VERITY_MODE ".\n");
127769fdc596SJason Zhu       goto out;
127869fdc596SJason Zhu     }
127969fdc596SJason Zhu     ret = AVB_HASHTREE_ERROR_MODE_EIO;
128069fdc596SJason Zhu     io_ret = AVB_IO_RESULT_OK;
128169fdc596SJason Zhu     goto out;
128269fdc596SJason Zhu   }
128369fdc596SJason Zhu 
128469fdc596SJason Zhu   // See if we're in 'eio' mode.
128569fdc596SJason Zhu   io_ret = ops->read_persistent_value(ops,
128669fdc596SJason Zhu                                       AVB_NPV_MANAGED_VERITY_MODE,
128769fdc596SJason Zhu                                       AVB_SHA256_DIGEST_SIZE,
128869fdc596SJason Zhu                                       stored_vbmeta_digest_sha256,
128969fdc596SJason Zhu                                       &num_bytes_read);
129069fdc596SJason Zhu   if (io_ret == AVB_IO_RESULT_ERROR_NO_SUCH_VALUE ||
129169fdc596SJason Zhu       (io_ret == AVB_IO_RESULT_OK && num_bytes_read == 0)) {
129269fdc596SJason Zhu     // This is the usual case ('eio' mode not set).
129369fdc596SJason Zhu     avb_debug("No dm-verity corruption - using in 'restart' mode.\n");
129469fdc596SJason Zhu     ret = AVB_HASHTREE_ERROR_MODE_RESTART;
129569fdc596SJason Zhu     io_ret = AVB_IO_RESULT_OK;
129669fdc596SJason Zhu     goto out;
129769fdc596SJason Zhu   } else if (io_ret != AVB_IO_RESULT_OK) {
129869fdc596SJason Zhu     avb_error("Error reading from " AVB_NPV_MANAGED_VERITY_MODE ".\n");
129969fdc596SJason Zhu     goto out;
130069fdc596SJason Zhu   }
130169fdc596SJason Zhu   if (num_bytes_read != AVB_SHA256_DIGEST_SIZE) {
130269fdc596SJason Zhu     avb_error(
130369fdc596SJason Zhu         "Unexpected number of bytes read from " AVB_NPV_MANAGED_VERITY_MODE
130469fdc596SJason Zhu         ".\n");
130569fdc596SJason Zhu     io_ret = AVB_IO_RESULT_ERROR_IO;
130669fdc596SJason Zhu     goto out;
130769fdc596SJason Zhu   }
130869fdc596SJason Zhu 
130969fdc596SJason Zhu   // OK, so we're currently in 'eio' mode and the vbmeta digest of the OS
131069fdc596SJason Zhu   // that caused this is in |stored_vbmeta_digest_sha256| ... now see if
131169fdc596SJason Zhu   // the OS we're dealing with now is the same.
131269fdc596SJason Zhu   avb_slot_verify_data_calculate_vbmeta_digest(
131369fdc596SJason Zhu       data, AVB_DIGEST_TYPE_SHA256, vbmeta_digest_sha256);
131469fdc596SJason Zhu   if (avb_memcmp(vbmeta_digest_sha256,
131569fdc596SJason Zhu                  stored_vbmeta_digest_sha256,
131669fdc596SJason Zhu                  AVB_SHA256_DIGEST_SIZE) == 0) {
131769fdc596SJason Zhu     // It's the same so we're still in 'eio' mode.
131869fdc596SJason Zhu     avb_debug("Same OS instance detected - staying in 'eio' mode.\n");
131969fdc596SJason Zhu     ret = AVB_HASHTREE_ERROR_MODE_EIO;
132069fdc596SJason Zhu     io_ret = AVB_IO_RESULT_OK;
132169fdc596SJason Zhu   } else {
132269fdc596SJason Zhu     // It did change!
132369fdc596SJason Zhu     avb_debug(
132469fdc596SJason Zhu         "New OS instance detected - changing from 'eio' to 'restart' mode.\n");
132569fdc596SJason Zhu     io_ret =
132669fdc596SJason Zhu         ops->write_persistent_value(ops,
132769fdc596SJason Zhu                                     AVB_NPV_MANAGED_VERITY_MODE,
132869fdc596SJason Zhu                                     0,  // This clears the persistent property.
132969fdc596SJason Zhu                                     vbmeta_digest_sha256);
133069fdc596SJason Zhu     if (io_ret != AVB_IO_RESULT_OK) {
133169fdc596SJason Zhu       avb_error("Error clearing " AVB_NPV_MANAGED_VERITY_MODE ".\n");
133269fdc596SJason Zhu       goto out;
133369fdc596SJason Zhu     }
133469fdc596SJason Zhu     ret = AVB_HASHTREE_ERROR_MODE_RESTART;
133569fdc596SJason Zhu     io_ret = AVB_IO_RESULT_OK;
133669fdc596SJason Zhu   }
133769fdc596SJason Zhu 
133869fdc596SJason Zhu out:
133969fdc596SJason Zhu   *out_hashtree_error_mode = ret;
134069fdc596SJason Zhu   return io_ret;
134169fdc596SJason Zhu }
134269fdc596SJason Zhu 
has_system_partition(AvbOps * ops,const char * ab_suffix)134369fdc596SJason Zhu static bool has_system_partition(AvbOps* ops, const char* ab_suffix) {
134469fdc596SJason Zhu   char part_name[AVB_PART_NAME_MAX_SIZE];
134569fdc596SJason Zhu   char* system_part_name = "system";
134669fdc596SJason Zhu   char guid_buf[37];
134769fdc596SJason Zhu   AvbIOResult io_ret;
134869fdc596SJason Zhu 
134969fdc596SJason Zhu   if (!avb_str_concat(part_name,
135069fdc596SJason Zhu                       sizeof part_name,
135169fdc596SJason Zhu                       system_part_name,
135269fdc596SJason Zhu                       avb_strlen(system_part_name),
135369fdc596SJason Zhu                       ab_suffix,
135469fdc596SJason Zhu                       avb_strlen(ab_suffix))) {
135569fdc596SJason Zhu     avb_error("System partition name and suffix does not fit.\n");
135669fdc596SJason Zhu     return false;
135769fdc596SJason Zhu   }
135869fdc596SJason Zhu 
135969fdc596SJason Zhu   io_ret = ops->get_unique_guid_for_partition(
136069fdc596SJason Zhu       ops, part_name, guid_buf, sizeof guid_buf);
136169fdc596SJason Zhu   if (io_ret == AVB_IO_RESULT_ERROR_NO_SUCH_PARTITION) {
136269fdc596SJason Zhu     avb_debug("No system partition.\n");
136369fdc596SJason Zhu     return false;
136469fdc596SJason Zhu   } else if (io_ret != AVB_IO_RESULT_OK) {
136569fdc596SJason Zhu     avb_error("Error getting unique GUID for system partition.\n");
136669fdc596SJason Zhu     return false;
136769fdc596SJason Zhu   }
136869fdc596SJason Zhu 
136969fdc596SJason Zhu   return true;
137069fdc596SJason Zhu }
137169fdc596SJason Zhu 
avb_slot_verify(AvbOps * ops,const char * const * requested_partitions,const char * ab_suffix,AvbSlotVerifyFlags flags,AvbHashtreeErrorMode hashtree_error_mode,AvbSlotVerifyData ** out_data)137237a7bc39SJason Zhu AvbSlotVerifyResult avb_slot_verify(AvbOps* ops,
137337a7bc39SJason Zhu                                     const char* const* requested_partitions,
137437a7bc39SJason Zhu                                     const char* ab_suffix,
137537a7bc39SJason Zhu                                     AvbSlotVerifyFlags flags,
137637a7bc39SJason Zhu                                     AvbHashtreeErrorMode hashtree_error_mode,
137737a7bc39SJason Zhu                                     AvbSlotVerifyData** out_data) {
137869fdc596SJason Zhu   AvbSlotVerifyResult ret = 0;
137937a7bc39SJason Zhu   AvbSlotVerifyData* slot_data = NULL;
138037a7bc39SJason Zhu   AvbAlgorithmType algorithm_type = AVB_ALGORITHM_TYPE_NONE;
138137a7bc39SJason Zhu   bool using_boot_for_vbmeta = false;
138237a7bc39SJason Zhu   AvbVBMetaImageHeader toplevel_vbmeta;
138337a7bc39SJason Zhu   bool allow_verification_error =
138437a7bc39SJason Zhu       (flags & AVB_SLOT_VERIFY_FLAGS_ALLOW_VERIFICATION_ERROR);
1385ab608f80SJason Zhu   AvbCmdlineSubstList* additional_cmdline_subst = NULL;
138637a7bc39SJason Zhu 
138769fdc596SJason Zhu   /* Fail early if we're missing the AvbOps needed for slot verification. */
138837a7bc39SJason Zhu   avb_assert(ops->read_is_device_unlocked != NULL);
138937a7bc39SJason Zhu   avb_assert(ops->read_from_partition != NULL);
139069fdc596SJason Zhu   avb_assert(ops->get_size_of_partition != NULL);
139137a7bc39SJason Zhu   avb_assert(ops->read_rollback_index != NULL);
139237a7bc39SJason Zhu   avb_assert(ops->get_unique_guid_for_partition != NULL);
139337a7bc39SJason Zhu 
139437a7bc39SJason Zhu   if (out_data != NULL) {
139537a7bc39SJason Zhu     *out_data = NULL;
139637a7bc39SJason Zhu   }
139737a7bc39SJason Zhu 
139837a7bc39SJason Zhu   /* Allowing dm-verity errors defeats the purpose of verified boot so
139937a7bc39SJason Zhu    * only allow this if set up to allow verification errors
140037a7bc39SJason Zhu    * (e.g. typically only UNLOCKED mode).
140137a7bc39SJason Zhu    */
140237a7bc39SJason Zhu   if (hashtree_error_mode == AVB_HASHTREE_ERROR_MODE_LOGGING &&
140337a7bc39SJason Zhu       !allow_verification_error) {
140437a7bc39SJason Zhu     ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_ARGUMENT;
140537a7bc39SJason Zhu     goto fail;
140637a7bc39SJason Zhu   }
140737a7bc39SJason Zhu 
140869fdc596SJason Zhu   /* Make sure passed-in AvbOps support persistent values if
140969fdc596SJason Zhu    * asking for libavb to manage verity state.
141069fdc596SJason Zhu    */
141169fdc596SJason Zhu   if (hashtree_error_mode == AVB_HASHTREE_ERROR_MODE_MANAGED_RESTART_AND_EIO) {
141269fdc596SJason Zhu     if (ops->read_persistent_value == NULL ||
141369fdc596SJason Zhu         ops->write_persistent_value == NULL) {
141469fdc596SJason Zhu       avb_error(
141569fdc596SJason Zhu           "Persistent values required for "
141669fdc596SJason Zhu           "AVB_HASHTREE_ERROR_MODE_MANAGED_RESTART_AND_EIO "
141769fdc596SJason Zhu           "but are not implemented in given AvbOps.\n");
141869fdc596SJason Zhu       ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_ARGUMENT;
141969fdc596SJason Zhu       goto fail;
142069fdc596SJason Zhu     }
142169fdc596SJason Zhu   }
142269fdc596SJason Zhu 
142369fdc596SJason Zhu   /* Make sure passed-in AvbOps support verifying public keys and getting
142469fdc596SJason Zhu    * rollback index location if not using a vbmeta partition.
142569fdc596SJason Zhu    */
142669fdc596SJason Zhu   if (flags & AVB_SLOT_VERIFY_FLAGS_NO_VBMETA_PARTITION) {
142769fdc596SJason Zhu     if (ops->validate_public_key_for_partition == NULL) {
142869fdc596SJason Zhu       avb_error(
142969fdc596SJason Zhu           "AVB_SLOT_VERIFY_FLAGS_NO_VBMETA_PARTITION was passed but the "
143069fdc596SJason Zhu           "validate_public_key_for_partition() operation isn't implemented.\n");
143169fdc596SJason Zhu       ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_ARGUMENT;
143269fdc596SJason Zhu       goto fail;
143369fdc596SJason Zhu     }
143469fdc596SJason Zhu   } else {
143569fdc596SJason Zhu     avb_assert(ops->validate_vbmeta_public_key != NULL);
143669fdc596SJason Zhu   }
143769fdc596SJason Zhu 
143837a7bc39SJason Zhu   slot_data = avb_calloc(sizeof(AvbSlotVerifyData));
143937a7bc39SJason Zhu   if (slot_data == NULL) {
144037a7bc39SJason Zhu     ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
144137a7bc39SJason Zhu     goto fail;
144237a7bc39SJason Zhu   }
144337a7bc39SJason Zhu   slot_data->vbmeta_images =
144437a7bc39SJason Zhu       avb_calloc(sizeof(AvbVBMetaData) * MAX_NUMBER_OF_VBMETA_IMAGES);
144537a7bc39SJason Zhu   if (slot_data->vbmeta_images == NULL) {
144637a7bc39SJason Zhu     ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
144737a7bc39SJason Zhu     goto fail;
144837a7bc39SJason Zhu   }
144937a7bc39SJason Zhu   slot_data->loaded_partitions =
145037a7bc39SJason Zhu       avb_calloc(sizeof(AvbPartitionData) * MAX_NUMBER_OF_LOADED_PARTITIONS);
145137a7bc39SJason Zhu   if (slot_data->loaded_partitions == NULL) {
145237a7bc39SJason Zhu     ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
145337a7bc39SJason Zhu     goto fail;
145437a7bc39SJason Zhu   }
145537a7bc39SJason Zhu 
1456ab608f80SJason Zhu   additional_cmdline_subst = avb_new_cmdline_subst_list();
1457ab608f80SJason Zhu   if (additional_cmdline_subst == NULL) {
1458ab608f80SJason Zhu     ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
1459ab608f80SJason Zhu     goto fail;
1460ab608f80SJason Zhu   }
1461ab608f80SJason Zhu 
146269fdc596SJason Zhu   if (flags & AVB_SLOT_VERIFY_FLAGS_NO_VBMETA_PARTITION) {
146369fdc596SJason Zhu     if (requested_partitions == NULL || requested_partitions[0] == NULL) {
146469fdc596SJason Zhu       avb_fatal(
146569fdc596SJason Zhu           "Requested partitions cannot be empty when using "
146669fdc596SJason Zhu           "AVB_SLOT_VERIFY_FLAGS_NO_VBMETA_PARTITION");
146769fdc596SJason Zhu       ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_ARGUMENT;
146869fdc596SJason Zhu       goto fail;
146969fdc596SJason Zhu     }
147069fdc596SJason Zhu 
147169fdc596SJason Zhu     /* No vbmeta partition, go through each of the requested partitions... */
147269fdc596SJason Zhu     for (size_t n = 0; requested_partitions[n] != NULL; n++) {
147337a7bc39SJason Zhu       ret = load_and_verify_vbmeta(ops,
147437a7bc39SJason Zhu                                    requested_partitions,
147537a7bc39SJason Zhu                                    ab_suffix,
147669fdc596SJason Zhu                                    flags,
147769fdc596SJason Zhu                                    allow_verification_error,
147869fdc596SJason Zhu                                    0 /* toplevel_vbmeta_flags */,
147969fdc596SJason Zhu                                    0 /* rollback_index_location */,
148069fdc596SJason Zhu                                    requested_partitions[n],
148169fdc596SJason Zhu                                    avb_strlen(requested_partitions[n]),
148269fdc596SJason Zhu                                    NULL /* expected_public_key */,
148369fdc596SJason Zhu                                    0 /* expected_public_key_length */,
148469fdc596SJason Zhu                                    slot_data,
148569fdc596SJason Zhu                                    &algorithm_type,
148669fdc596SJason Zhu                                    additional_cmdline_subst);
148769fdc596SJason Zhu       if (!allow_verification_error && ret != AVB_SLOT_VERIFY_RESULT_OK) {
148869fdc596SJason Zhu         goto fail;
148969fdc596SJason Zhu       }
149069fdc596SJason Zhu     }
149169fdc596SJason Zhu 
149269fdc596SJason Zhu   } else {
149369fdc596SJason Zhu     /* Usual path, load "vbmeta"... */
149469fdc596SJason Zhu     ret = load_and_verify_vbmeta(ops,
149569fdc596SJason Zhu                                  requested_partitions,
149669fdc596SJason Zhu                                  ab_suffix,
149769fdc596SJason Zhu                                  flags,
149837a7bc39SJason Zhu                                  allow_verification_error,
149937a7bc39SJason Zhu                                  0 /* toplevel_vbmeta_flags */,
150037a7bc39SJason Zhu                                  0 /* rollback_index_location */,
150137a7bc39SJason Zhu                                  "vbmeta",
150237a7bc39SJason Zhu                                  avb_strlen("vbmeta"),
150337a7bc39SJason Zhu                                  NULL /* expected_public_key */,
150437a7bc39SJason Zhu                                  0 /* expected_public_key_length */,
150537a7bc39SJason Zhu                                  slot_data,
1506ab608f80SJason Zhu                                  &algorithm_type,
1507ab608f80SJason Zhu                                  additional_cmdline_subst);
150837a7bc39SJason Zhu     if (!allow_verification_error && ret != AVB_SLOT_VERIFY_RESULT_OK) {
150937a7bc39SJason Zhu       goto fail;
151037a7bc39SJason Zhu     }
151169fdc596SJason Zhu   }
151269fdc596SJason Zhu 
151369fdc596SJason Zhu   if (!result_should_continue(ret)) {
151469fdc596SJason Zhu     goto fail;
151569fdc596SJason Zhu   }
151637a7bc39SJason Zhu 
151737a7bc39SJason Zhu   /* If things check out, mangle the kernel command-line as needed. */
151869fdc596SJason Zhu   if (!(flags & AVB_SLOT_VERIFY_FLAGS_NO_VBMETA_PARTITION)) {
151937a7bc39SJason Zhu     if (avb_strcmp(slot_data->vbmeta_images[0].partition_name, "vbmeta") != 0) {
152037a7bc39SJason Zhu       avb_assert(
152137a7bc39SJason Zhu           avb_strcmp(slot_data->vbmeta_images[0].partition_name, "boot") == 0);
152237a7bc39SJason Zhu       using_boot_for_vbmeta = true;
152337a7bc39SJason Zhu     }
152469fdc596SJason Zhu   }
152537a7bc39SJason Zhu 
152637a7bc39SJason Zhu   /* Byteswap top-level vbmeta header since we'll need it below. */
152737a7bc39SJason Zhu   avb_vbmeta_image_header_to_host_byte_order(
152837a7bc39SJason Zhu       (const AvbVBMetaImageHeader*)slot_data->vbmeta_images[0].vbmeta_data,
152937a7bc39SJason Zhu       &toplevel_vbmeta);
153037a7bc39SJason Zhu 
153137a7bc39SJason Zhu   /* Fill in |ab_suffix| field. */
153237a7bc39SJason Zhu   slot_data->ab_suffix = avb_strdup(ab_suffix);
153337a7bc39SJason Zhu   if (slot_data->ab_suffix == NULL) {
153437a7bc39SJason Zhu     ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
153537a7bc39SJason Zhu     goto fail;
153637a7bc39SJason Zhu   }
153737a7bc39SJason Zhu 
153837a7bc39SJason Zhu   /* If verification is disabled, we are done ... we specifically
153937a7bc39SJason Zhu    * don't want to add any androidboot.* options since verification
154037a7bc39SJason Zhu    * is disabled.
154137a7bc39SJason Zhu    */
154237a7bc39SJason Zhu   if (toplevel_vbmeta.flags & AVB_VBMETA_IMAGE_FLAGS_VERIFICATION_DISABLED) {
154337a7bc39SJason Zhu     /* Since verification is disabled we didn't process any
154437a7bc39SJason Zhu      * descriptors and thus there's no cmdline... so set root= such
154537a7bc39SJason Zhu      * that the system partition is mounted.
154637a7bc39SJason Zhu      */
154737a7bc39SJason Zhu     avb_assert(slot_data->cmdline == NULL);
154869fdc596SJason Zhu     // Devices with dynamic partitions won't have system partition.
154969fdc596SJason Zhu     // Instead, it has a large super partition to accommodate *.img files.
155069fdc596SJason Zhu     // See b/119551429 for details.
155169fdc596SJason Zhu     if (has_system_partition(ops, ab_suffix)) {
155237a7bc39SJason Zhu       slot_data->cmdline =
155337a7bc39SJason Zhu           avb_strdup("root=PARTUUID=$(ANDROID_SYSTEM_PARTUUID)");
155469fdc596SJason Zhu     } else {
155569fdc596SJason Zhu       // The |cmdline| field should be a NUL-terminated string.
155669fdc596SJason Zhu       slot_data->cmdline = avb_strdup("");
155769fdc596SJason Zhu     }
155837a7bc39SJason Zhu     if (slot_data->cmdline == NULL) {
155937a7bc39SJason Zhu       ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
156037a7bc39SJason Zhu       goto fail;
156137a7bc39SJason Zhu     }
156237a7bc39SJason Zhu   } else {
156369fdc596SJason Zhu     /* If requested, manage dm-verity mode... */
156469fdc596SJason Zhu     AvbHashtreeErrorMode resolved_hashtree_error_mode = hashtree_error_mode;
156569fdc596SJason Zhu     if (hashtree_error_mode ==
156669fdc596SJason Zhu         AVB_HASHTREE_ERROR_MODE_MANAGED_RESTART_AND_EIO) {
156769fdc596SJason Zhu       AvbIOResult io_ret;
156869fdc596SJason Zhu       io_ret = avb_manage_hashtree_error_mode(
156969fdc596SJason Zhu           ops, flags, slot_data, &resolved_hashtree_error_mode);
157069fdc596SJason Zhu       if (io_ret != AVB_IO_RESULT_OK) {
157169fdc596SJason Zhu         ret = AVB_SLOT_VERIFY_RESULT_ERROR_IO;
157269fdc596SJason Zhu         if (io_ret == AVB_IO_RESULT_ERROR_OOM) {
157369fdc596SJason Zhu           ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
157469fdc596SJason Zhu         }
157569fdc596SJason Zhu         goto fail;
157669fdc596SJason Zhu       }
157769fdc596SJason Zhu     }
157869fdc596SJason Zhu     slot_data->resolved_hashtree_error_mode = resolved_hashtree_error_mode;
157969fdc596SJason Zhu 
158069fdc596SJason Zhu     /* Add options... */
158169fdc596SJason Zhu     AvbSlotVerifyResult sub_ret;
158269fdc596SJason Zhu     sub_ret = avb_append_options(ops,
158369fdc596SJason Zhu                                  flags,
1584ab608f80SJason Zhu                                  slot_data,
1585ab608f80SJason Zhu                                  &toplevel_vbmeta,
1586ab608f80SJason Zhu                                  algorithm_type,
158769fdc596SJason Zhu                                  hashtree_error_mode,
158869fdc596SJason Zhu                                  resolved_hashtree_error_mode);
158937a7bc39SJason Zhu     if (sub_ret != AVB_SLOT_VERIFY_RESULT_OK) {
159037a7bc39SJason Zhu       ret = sub_ret;
159137a7bc39SJason Zhu       goto fail;
159237a7bc39SJason Zhu     }
159337a7bc39SJason Zhu   }
159437a7bc39SJason Zhu 
159537a7bc39SJason Zhu   /* Substitute $(ANDROID_SYSTEM_PARTUUID) and friends. */
159669fdc596SJason Zhu   if (slot_data->cmdline != NULL && avb_strlen(slot_data->cmdline) != 0) {
159737a7bc39SJason Zhu     char* new_cmdline;
1598ab608f80SJason Zhu     new_cmdline = avb_sub_cmdline(ops,
1599ab608f80SJason Zhu                                   slot_data->cmdline,
1600ab608f80SJason Zhu                                   ab_suffix,
1601ab608f80SJason Zhu                                   using_boot_for_vbmeta,
1602ab608f80SJason Zhu                                   additional_cmdline_subst);
160337a7bc39SJason Zhu     if (new_cmdline != slot_data->cmdline) {
160437a7bc39SJason Zhu       if (new_cmdline == NULL) {
160537a7bc39SJason Zhu         ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
160637a7bc39SJason Zhu         goto fail;
160737a7bc39SJason Zhu       }
160837a7bc39SJason Zhu       avb_free(slot_data->cmdline);
160937a7bc39SJason Zhu       slot_data->cmdline = new_cmdline;
161037a7bc39SJason Zhu     }
161137a7bc39SJason Zhu   }
161237a7bc39SJason Zhu 
161337a7bc39SJason Zhu   if (out_data != NULL) {
161437a7bc39SJason Zhu     *out_data = slot_data;
161537a7bc39SJason Zhu   } else {
161637a7bc39SJason Zhu     avb_slot_verify_data_free(slot_data);
161737a7bc39SJason Zhu   }
161837a7bc39SJason Zhu 
1619ab608f80SJason Zhu   avb_free_cmdline_subst_list(additional_cmdline_subst);
1620ab608f80SJason Zhu   additional_cmdline_subst = NULL;
1621ab608f80SJason Zhu 
162237a7bc39SJason Zhu   if (!allow_verification_error) {
162337a7bc39SJason Zhu     avb_assert(ret == AVB_SLOT_VERIFY_RESULT_OK);
162437a7bc39SJason Zhu   }
162537a7bc39SJason Zhu 
162637a7bc39SJason Zhu   return ret;
162737a7bc39SJason Zhu 
162837a7bc39SJason Zhu fail:
162937a7bc39SJason Zhu   if (slot_data != NULL) {
163037a7bc39SJason Zhu     avb_slot_verify_data_free(slot_data);
163137a7bc39SJason Zhu   }
1632ab608f80SJason Zhu   if (additional_cmdline_subst != NULL) {
1633ab608f80SJason Zhu     avb_free_cmdline_subst_list(additional_cmdline_subst);
1634ab608f80SJason Zhu   }
163537a7bc39SJason Zhu   return ret;
163637a7bc39SJason Zhu }
163737a7bc39SJason Zhu 
avb_slot_verify_data_free(AvbSlotVerifyData * data)163837a7bc39SJason Zhu void avb_slot_verify_data_free(AvbSlotVerifyData* data) {
163937a7bc39SJason Zhu   if (data->ab_suffix != NULL) {
164037a7bc39SJason Zhu     avb_free(data->ab_suffix);
164137a7bc39SJason Zhu   }
164237a7bc39SJason Zhu   if (data->cmdline != NULL) {
164337a7bc39SJason Zhu     avb_free(data->cmdline);
164437a7bc39SJason Zhu   }
164537a7bc39SJason Zhu   if (data->vbmeta_images != NULL) {
164637a7bc39SJason Zhu     size_t n;
164737a7bc39SJason Zhu     for (n = 0; n < data->num_vbmeta_images; n++) {
164837a7bc39SJason Zhu       AvbVBMetaData* vbmeta_image = &data->vbmeta_images[n];
164937a7bc39SJason Zhu       if (vbmeta_image->partition_name != NULL) {
165037a7bc39SJason Zhu         avb_free(vbmeta_image->partition_name);
165137a7bc39SJason Zhu       }
165237a7bc39SJason Zhu       if (vbmeta_image->vbmeta_data != NULL) {
165337a7bc39SJason Zhu         avb_free(vbmeta_image->vbmeta_data);
165437a7bc39SJason Zhu       }
165537a7bc39SJason Zhu     }
165637a7bc39SJason Zhu     avb_free(data->vbmeta_images);
165737a7bc39SJason Zhu   }
165837a7bc39SJason Zhu   if (data->loaded_partitions != NULL) {
165937a7bc39SJason Zhu     size_t n;
166037a7bc39SJason Zhu     for (n = 0; n < data->num_loaded_partitions; n++) {
166137a7bc39SJason Zhu       AvbPartitionData* loaded_partition = &data->loaded_partitions[n];
166237a7bc39SJason Zhu       if (loaded_partition->partition_name != NULL) {
166337a7bc39SJason Zhu         avb_free(loaded_partition->partition_name);
166437a7bc39SJason Zhu       }
166537a7bc39SJason Zhu       if (loaded_partition->data != NULL && !loaded_partition->preloaded) {
166628317110SJoseph Chen         avb_free(loaded_partition->data);
166737a7bc39SJason Zhu       }
166837a7bc39SJason Zhu     }
166937a7bc39SJason Zhu     avb_free(data->loaded_partitions);
167037a7bc39SJason Zhu   }
167137a7bc39SJason Zhu   avb_free(data);
167237a7bc39SJason Zhu }
167337a7bc39SJason Zhu 
avb_slot_verify_result_to_string(AvbSlotVerifyResult result)167437a7bc39SJason Zhu const char* avb_slot_verify_result_to_string(AvbSlotVerifyResult result) {
167537a7bc39SJason Zhu   const char* ret = NULL;
167637a7bc39SJason Zhu 
167737a7bc39SJason Zhu   switch (result) {
167837a7bc39SJason Zhu     case AVB_SLOT_VERIFY_RESULT_OK:
167937a7bc39SJason Zhu       ret = "OK";
168037a7bc39SJason Zhu       break;
168137a7bc39SJason Zhu     case AVB_SLOT_VERIFY_RESULT_ERROR_OOM:
168237a7bc39SJason Zhu       ret = "ERROR_OOM";
168337a7bc39SJason Zhu       break;
168437a7bc39SJason Zhu     case AVB_SLOT_VERIFY_RESULT_ERROR_IO:
168537a7bc39SJason Zhu       ret = "ERROR_IO";
168637a7bc39SJason Zhu       break;
168737a7bc39SJason Zhu     case AVB_SLOT_VERIFY_RESULT_ERROR_VERIFICATION:
168837a7bc39SJason Zhu       ret = "ERROR_VERIFICATION";
168937a7bc39SJason Zhu       break;
169037a7bc39SJason Zhu     case AVB_SLOT_VERIFY_RESULT_ERROR_ROLLBACK_INDEX:
169137a7bc39SJason Zhu       ret = "ERROR_ROLLBACK_INDEX";
169237a7bc39SJason Zhu       break;
169337a7bc39SJason Zhu     case AVB_SLOT_VERIFY_RESULT_ERROR_PUBLIC_KEY_REJECTED:
169437a7bc39SJason Zhu       ret = "ERROR_PUBLIC_KEY_REJECTED";
169537a7bc39SJason Zhu       break;
169637a7bc39SJason Zhu     case AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA:
169737a7bc39SJason Zhu       ret = "ERROR_INVALID_METADATA";
169837a7bc39SJason Zhu       break;
169937a7bc39SJason Zhu     case AVB_SLOT_VERIFY_RESULT_ERROR_UNSUPPORTED_VERSION:
170037a7bc39SJason Zhu       ret = "ERROR_UNSUPPORTED_VERSION";
170137a7bc39SJason Zhu       break;
170237a7bc39SJason Zhu     case AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_ARGUMENT:
170337a7bc39SJason Zhu       ret = "ERROR_INVALID_ARGUMENT";
170437a7bc39SJason Zhu       break;
170537a7bc39SJason Zhu       /* Do not add a 'default:' case here because of -Wswitch. */
170637a7bc39SJason Zhu   }
170737a7bc39SJason Zhu 
170837a7bc39SJason Zhu   if (ret == NULL) {
170937a7bc39SJason Zhu     avb_error("Unknown AvbSlotVerifyResult value.\n");
171037a7bc39SJason Zhu     ret = "(unknown)";
171137a7bc39SJason Zhu   }
171237a7bc39SJason Zhu 
171337a7bc39SJason Zhu   return ret;
171437a7bc39SJason Zhu }
1715ab608f80SJason Zhu 
avb_slot_verify_data_calculate_vbmeta_digest(AvbSlotVerifyData * data,AvbDigestType digest_type,uint8_t * out_digest)1716ab608f80SJason Zhu void avb_slot_verify_data_calculate_vbmeta_digest(AvbSlotVerifyData* data,
1717ab608f80SJason Zhu                                                   AvbDigestType digest_type,
1718ab608f80SJason Zhu                                                   uint8_t* out_digest) {
1719ab608f80SJason Zhu   bool ret = false;
1720ab608f80SJason Zhu   size_t n;
1721ab608f80SJason Zhu 
1722ab608f80SJason Zhu   switch (digest_type) {
1723ab608f80SJason Zhu     case AVB_DIGEST_TYPE_SHA256: {
1724ab608f80SJason Zhu       AvbSHA256Ctx ctx;
17255b0bc491SJoseph Chen 
17265b0bc491SJoseph Chen       ctx.tot_len = 0;
17275b0bc491SJoseph Chen       for (n = 0; n < data->num_vbmeta_images; n++)
17285b0bc491SJoseph Chen         ctx.tot_len += data->vbmeta_images[n].vbmeta_size;
17295b0bc491SJoseph Chen 
1730ab608f80SJason Zhu       avb_sha256_init(&ctx);
1731ab608f80SJason Zhu       for (n = 0; n < data->num_vbmeta_images; n++) {
1732ab608f80SJason Zhu         avb_sha256_update(&ctx,
1733ab608f80SJason Zhu                           data->vbmeta_images[n].vbmeta_data,
1734ab608f80SJason Zhu                           data->vbmeta_images[n].vbmeta_size);
1735ab608f80SJason Zhu       }
1736ab608f80SJason Zhu       avb_memcpy(out_digest, avb_sha256_final(&ctx), AVB_SHA256_DIGEST_SIZE);
1737ab608f80SJason Zhu       ret = true;
1738ab608f80SJason Zhu     } break;
1739ab608f80SJason Zhu 
1740ab608f80SJason Zhu     case AVB_DIGEST_TYPE_SHA512: {
1741ab608f80SJason Zhu       AvbSHA512Ctx ctx;
17425b0bc491SJoseph Chen 
17435b0bc491SJoseph Chen       ctx.tot_len = 0;
17445b0bc491SJoseph Chen       for (n = 0; n < data->num_vbmeta_images; n++)
17455b0bc491SJoseph Chen         ctx.tot_len += data->vbmeta_images[n].vbmeta_size;
17465b0bc491SJoseph Chen 
1747ab608f80SJason Zhu       avb_sha512_init(&ctx);
1748ab608f80SJason Zhu       for (n = 0; n < data->num_vbmeta_images; n++) {
1749ab608f80SJason Zhu         avb_sha512_update(&ctx,
1750ab608f80SJason Zhu                           data->vbmeta_images[n].vbmeta_data,
1751ab608f80SJason Zhu                           data->vbmeta_images[n].vbmeta_size);
1752ab608f80SJason Zhu       }
1753ab608f80SJason Zhu       avb_memcpy(out_digest, avb_sha512_final(&ctx), AVB_SHA512_DIGEST_SIZE);
1754ab608f80SJason Zhu       ret = true;
1755ab608f80SJason Zhu     } break;
1756ab608f80SJason Zhu 
1757ab608f80SJason Zhu       /* Do not add a 'default:' case here because of -Wswitch. */
1758ab608f80SJason Zhu   }
1759ab608f80SJason Zhu 
1760ab608f80SJason Zhu   if (!ret) {
1761ab608f80SJason Zhu     avb_fatal("Unknown digest type");
1762ab608f80SJason Zhu   }
1763ab608f80SJason Zhu }
1764