All of lore.kernel.org
 help / color / mirror / Atom feed
* [U-Boot] [PATCH 1/2] libavb: Update libavb to current AOSP master
@ 2019-08-15 20:04 Sam Protsenko
  2019-08-15 20:04 ` [U-Boot] [PATCH 2/2] libavb: Fix build warnings after updating the lib Sam Protsenko
                   ` (3 more replies)
  0 siblings, 4 replies; 15+ messages in thread
From: Sam Protsenko @ 2019-08-15 20:04 UTC (permalink / raw)
  To: u-boot

Update libavb to commit 5fbb42a189aa in AOSP/master, because new version
has support for super partition [1], which we need for implementing
Android dynamic partitions. All changes from previous patches for libavb
in U-Boot are accounted for in this commit:
  - commit ecc6f6bea6a2 ("libavb: Handle wrong hashtree_error_mode in
                          avb_append_options()")
  - commit 897a1d947e7e ("libavb: Update SPDX tag style")
  - commit d8f9d2af96b3 ("avb2.0: add Android Verified Boot 2.0 library")

Tested on X15:

    ## Android Verified Boot 2.0 version 1.1.0
    read_is_device_unlocked not supported yet
    read_rollback_index not supported yet
    read_is_device_unlocked not supported yet
    Verification passed successfully
    AVB verification OK.

Unit test passes:

    $ ./test/py/test.py --bd sandbox --build -k test_avb

      test/py/tests/test_android/test_avb.py ss..s.

[1] https://android.googlesource.com/platform/external/avb/+/49936b4c0109411fdd38bd4ba3a32a01c40439a9

Signed-off-by: Sam Protsenko <semen.protsenko@linaro.org>
---
 lib/libavb/avb_cmdline.c       |  52 ++-
 lib/libavb/avb_cmdline.h       |   4 +-
 lib/libavb/avb_descriptor.c    |  11 +-
 lib/libavb/avb_ops.h           |  41 ++-
 lib/libavb/avb_sha.h           |  12 +-
 lib/libavb/avb_sha256.c        |  36 +-
 lib/libavb/avb_sha512.c        |  22 +-
 lib/libavb/avb_slot_verify.c   | 652 +++++++++++++++++++++++++--------
 lib/libavb/avb_slot_verify.h   |  59 ++-
 lib/libavb/avb_sysdeps.h       |   8 +
 lib/libavb/avb_sysdeps_posix.c |  16 +-
 lib/libavb/avb_vbmeta_image.c  |  11 +-
 12 files changed, 710 insertions(+), 214 deletions(-)

diff --git a/lib/libavb/avb_cmdline.c b/lib/libavb/avb_cmdline.c
index d246699272..cb5b98e423 100644
--- a/lib/libavb/avb_cmdline.c
+++ b/lib/libavb/avb_cmdline.c
@@ -39,6 +39,14 @@ char* avb_sub_cmdline(AvbOps* ops,
     char part_name[AVB_PART_NAME_MAX_SIZE];
     char guid_buf[37];
 
+    /* Don't attempt to query the partition guid unless its search string is
+     * present in the command line. Note: the original cmdline is used here,
+     * not the replaced one. See b/116010959.
+     */
+    if (avb_strstr(cmdline, replace_str[n]) == NULL) {
+      continue;
+    }
+
     if (!avb_str_concat(part_name,
                         sizeof part_name,
                         part_name_str[n],
@@ -70,7 +78,15 @@ char* avb_sub_cmdline(AvbOps* ops,
     }
   }
 
-  avb_assert(ret != NULL);
+  /* It's possible there is no _PARTUUID for replacement above.
+   * Duplicate cmdline to ret for additional substitutions below.
+   */
+  if (ret == NULL) {
+    ret = avb_strdup(cmdline);
+    if (ret == NULL) {
+      goto fail;
+    }
+  }
 
   /* Replace any additional substitutions. */
   if (additional_substitutions != NULL) {
@@ -198,21 +214,27 @@ static int cmdline_append_hex(AvbSlotVerifyData* slot_data,
 
 AvbSlotVerifyResult avb_append_options(
     AvbOps* ops,
+    AvbSlotVerifyFlags flags,
     AvbSlotVerifyData* slot_data,
     AvbVBMetaImageHeader* toplevel_vbmeta,
     AvbAlgorithmType algorithm_type,
-    AvbHashtreeErrorMode hashtree_error_mode) {
+    AvbHashtreeErrorMode hashtree_error_mode,
+    AvbHashtreeErrorMode resolved_hashtree_error_mode) {
   AvbSlotVerifyResult ret;
   const char* verity_mode;
   bool is_device_unlocked;
   AvbIOResult io_ret;
 
-  /* Add androidboot.vbmeta.device option. */
-  if (!cmdline_append_option(slot_data,
-                             "androidboot.vbmeta.device",
-                             "PARTUUID=$(ANDROID_VBMETA_PARTUUID)")) {
-    ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
-    goto out;
+  /* Add androidboot.vbmeta.device option... except if not using a vbmeta
+   * partition since it doesn't make sense in that case.
+   */
+  if (!(flags & AVB_SLOT_VERIFY_FLAGS_NO_VBMETA_PARTITION)) {
+    if (!cmdline_append_option(slot_data,
+                               "androidboot.vbmeta.device",
+                               "PARTUUID=$(ANDROID_VBMETA_PARTUUID)")) {
+      ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
+      goto out;
+    }
   }
 
   /* Add androidboot.vbmeta.avb_version option. */
@@ -304,7 +326,7 @@ AvbSlotVerifyResult avb_append_options(
     const char* dm_verity_mode;
     char* new_ret;
 
-    switch (hashtree_error_mode) {
+    switch (resolved_hashtree_error_mode) {
       case AVB_HASHTREE_ERROR_MODE_RESTART_AND_INVALIDATE:
         if (!cmdline_append_option(
                 slot_data, "androidboot.vbmeta.invalidate_on_error", "yes")) {
@@ -331,6 +353,11 @@ AvbSlotVerifyResult avb_append_options(
         verity_mode = "logging";
         dm_verity_mode = "ignore_corruption";
         break;
+      case AVB_HASHTREE_ERROR_MODE_MANAGED_RESTART_AND_EIO:
+        // Should never get here because MANAGED_RESTART_AND_EIO is
+        // remapped by avb_manage_hashtree_error_mode().
+        avb_assert_not_reached();
+        break;
       default:
         ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_ARGUMENT;
         goto out;
@@ -349,6 +376,13 @@ AvbSlotVerifyResult avb_append_options(
     ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
     goto out;
   }
+  if (hashtree_error_mode == AVB_HASHTREE_ERROR_MODE_MANAGED_RESTART_AND_EIO) {
+    if (!cmdline_append_option(
+            slot_data, "androidboot.veritymode.managed", "yes")) {
+      ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
+      goto out;
+    }
+  }
 
   ret = AVB_SLOT_VERIFY_RESULT_OK;
 
diff --git a/lib/libavb/avb_cmdline.h b/lib/libavb/avb_cmdline.h
index 9af3a99994..96539d84bd 100644
--- a/lib/libavb/avb_cmdline.h
+++ b/lib/libavb/avb_cmdline.h
@@ -43,10 +43,12 @@ char* avb_sub_cmdline(AvbOps* ops,
 
 AvbSlotVerifyResult avb_append_options(
     AvbOps* ops,
+    AvbSlotVerifyFlags flags,
     AvbSlotVerifyData* slot_data,
     AvbVBMetaImageHeader* toplevel_vbmeta,
     AvbAlgorithmType algorithm_type,
-    AvbHashtreeErrorMode hashtree_error_mode);
+    AvbHashtreeErrorMode hashtree_error_mode,
+    AvbHashtreeErrorMode resolved_hashtree_error_mode);
 
 /* Allocates and initializes a new command line substitution list. Free with
  * |avb_free_cmdline_subst_list|.
diff --git a/lib/libavb/avb_descriptor.c b/lib/libavb/avb_descriptor.c
index fb0b305f2c..9f03b9777a 100644
--- a/lib/libavb/avb_descriptor.c
+++ b/lib/libavb/avb_descriptor.c
@@ -72,7 +72,11 @@ bool avb_descriptor_foreach(const uint8_t* image_data,
     const AvbDescriptor* dh = (const AvbDescriptor*)p;
     avb_assert_aligned(dh);
     uint64_t nb_following = avb_be64toh(dh->num_bytes_following);
-    uint64_t nb_total = sizeof(AvbDescriptor) + nb_following;
+    uint64_t nb_total = 0;
+    if (!avb_safe_add(&nb_total, sizeof(AvbDescriptor), nb_following)) {
+      avb_error("Invalid descriptor length.\n");
+      goto out;
+    }
 
     if ((nb_total & 7) != 0) {
       avb_error("Invalid descriptor length.\n");
@@ -88,7 +92,10 @@ bool avb_descriptor_foreach(const uint8_t* image_data,
       goto out;
     }
 
-    p += nb_total;
+    if (!avb_safe_add_to((uint64_t*)(&p), nb_total)) {
+      avb_error("Invalid descriptor length.\n");
+      goto out;
+    }
   }
 
   ret = true;
diff --git a/lib/libavb/avb_ops.h b/lib/libavb/avb_ops.h
index 8bbdc7c31b..6a5c589da8 100644
--- a/lib/libavb/avb_ops.h
+++ b/lib/libavb/avb_ops.h
@@ -18,6 +18,7 @@ extern "C" {
 
 /* Well-known names of named persistent values. */
 #define AVB_NPV_PERSISTENT_DIGEST_PREFIX "avb.persistent_digest."
+#define AVB_NPV_MANAGED_VERITY_MODE "avb.managed_verity_mode"
 
 /* Return codes used for I/O operations.
  *
@@ -171,6 +172,10 @@ struct AvbOps {
    *
    * If AVB_IO_RESULT_OK is returned then |out_is_trusted| is set -
    * true if trusted or false if untrusted.
+   *
+   * NOTE: If AVB_SLOT_VERIFY_FLAGS_NO_VBMETA_PARTITION is passed to
+   * avb_slot_verify() then this operation is never used. Instead, the
+   * validate_public_key_for_partition() operation is used
    */
   AvbIOResult (*validate_vbmeta_public_key)(AvbOps* ops,
                                             const uint8_t* public_key_data,
@@ -231,6 +236,9 @@ struct AvbOps {
    * (NUL-terminated UTF-8 string). Returns the value in
    * |out_size_num_bytes|.
    *
+   * If the partition doesn't exist the AVB_IO_RESULT_ERROR_NO_SUCH_PARTITION
+   * error code should be returned.
+   *
    * Returns AVB_IO_RESULT_OK on success, otherwise an error code.
    */
   AvbIOResult (*get_size_of_partition)(AvbOps* ops,
@@ -253,9 +261,10 @@ struct AvbOps {
    * AVB_IO_RESULT_ERROR_NO_SUCH_VALUE. If |buffer_size| is smaller than the
    * size of the stored value, returns AVB_IO_RESULT_ERROR_INSUFFICIENT_SPACE.
    *
-   * This operation is currently only used to support persistent digests. If a
-   * device does not use persistent digests this function pointer can be set to
-   * NULL.
+   * This operation is currently only used to support persistent digests or the
+   * AVB_HASHTREE_ERROR_MODE_MANAGED_RESTART_AND_EIO hashtree error mode. If a
+   * device does not use one of these features this function pointer can be set
+   * to NULL.
    */
   AvbIOResult (*read_persistent_value)(AvbOps* ops,
                                        const char* name,
@@ -275,14 +284,34 @@ struct AvbOps {
    * AVB_IO_RESULT_ERROR_NO_SUCH_VALUE. If the |value_size| is not supported,
    * returns AVB_IO_RESULT_ERROR_INVALID_VALUE_SIZE.
    *
-   * This operation is currently only used to support persistent digests. If a
-   * device does not use persistent digests this function pointer can be set to
-   * NULL.
+   * This operation is currently only used to support persistent digests or the
+   * AVB_HASHTREE_ERROR_MODE_MANAGED_RESTART_AND_EIO hashtree error mode. If a
+   * device does not use one of these features this function pointer can be set
+   * to NULL.
    */
   AvbIOResult (*write_persistent_value)(AvbOps* ops,
                                         const char* name,
                                         size_t value_size,
                                         const uint8_t* value);
+
+  /* Like validate_vbmeta_public_key() but for when the flag
+   * AVB_SLOT_VERIFY_FLAGS_NO_VBMETA_PARTITION is being used. The name of the
+   * partition to get the public key for is passed in |partition_name|.
+   *
+   * Also returns the rollback index location to use for the partition, in
+   * |out_rollback_index_location|.
+   *
+   * Returns AVB_IO_RESULT_OK on success, otherwise an error code.
+   */
+  AvbIOResult (*validate_public_key_for_partition)(
+      AvbOps* ops,
+      const char* partition,
+      const uint8_t* public_key_data,
+      size_t public_key_length,
+      const uint8_t* public_key_metadata,
+      size_t public_key_metadata_length,
+      bool* out_is_trusted,
+      uint32_t* out_rollback_index_location);
 };
 
 #ifdef __cplusplus
diff --git a/lib/libavb/avb_sha.h b/lib/libavb/avb_sha.h
index 365aaadc2f..f5d02e09f2 100644
--- a/lib/libavb/avb_sha.h
+++ b/lib/libavb/avb_sha.h
@@ -31,8 +31,8 @@ extern "C" {
 /* Data structure used for SHA-256. */
 typedef struct {
   uint32_t h[8];
-  uint32_t tot_len;
-  uint32_t len;
+  uint64_t tot_len;
+  size_t len;
   uint8_t block[2 * AVB_SHA256_BLOCK_SIZE];
   uint8_t buf[AVB_SHA256_DIGEST_SIZE]; /* Used for storing the final digest. */
 } AvbSHA256Ctx;
@@ -40,8 +40,8 @@ typedef struct {
 /* Data structure used for SHA-512. */
 typedef struct {
   uint64_t h[8];
-  uint32_t tot_len;
-  uint32_t len;
+  uint64_t tot_len;
+  size_t len;
   uint8_t block[2 * AVB_SHA512_BLOCK_SIZE];
   uint8_t buf[AVB_SHA512_DIGEST_SIZE]; /* Used for storing the final digest. */
 } AvbSHA512Ctx;
@@ -50,7 +50,7 @@ typedef struct {
 void avb_sha256_init(AvbSHA256Ctx* ctx);
 
 /* Updates the SHA-256 context with |len| bytes from |data|. */
-void avb_sha256_update(AvbSHA256Ctx* ctx, const uint8_t* data, uint32_t len);
+void avb_sha256_update(AvbSHA256Ctx* ctx, const uint8_t* data, size_t len);
 
 /* Returns the SHA-256 digest. */
 uint8_t* avb_sha256_final(AvbSHA256Ctx* ctx) AVB_ATTR_WARN_UNUSED_RESULT;
@@ -59,7 +59,7 @@ uint8_t* avb_sha256_final(AvbSHA256Ctx* ctx) AVB_ATTR_WARN_UNUSED_RESULT;
 void avb_sha512_init(AvbSHA512Ctx* ctx);
 
 /* Updates the SHA-512 context with |len| bytes from |data|. */
-void avb_sha512_update(AvbSHA512Ctx* ctx, const uint8_t* data, uint32_t len);
+void avb_sha512_update(AvbSHA512Ctx* ctx, const uint8_t* data, size_t len);
 
 /* Returns the SHA-512 digest. */
 uint8_t* avb_sha512_final(AvbSHA512Ctx* ctx) AVB_ATTR_WARN_UNUSED_RESULT;
diff --git a/lib/libavb/avb_sha256.c b/lib/libavb/avb_sha256.c
index d24c7015f6..86ecca57b7 100644
--- a/lib/libavb/avb_sha256.c
+++ b/lib/libavb/avb_sha256.c
@@ -29,6 +29,18 @@
     *((str) + 0) = (uint8_t)((x) >> 24); \
   }
 
+#define UNPACK64(x, str)                         \
+  {                                              \
+    *((str) + 7) = (uint8_t)x;                   \
+    *((str) + 6) = (uint8_t)((uint64_t)x >> 8);  \
+    *((str) + 5) = (uint8_t)((uint64_t)x >> 16); \
+    *((str) + 4) = (uint8_t)((uint64_t)x >> 24); \
+    *((str) + 3) = (uint8_t)((uint64_t)x >> 32); \
+    *((str) + 2) = (uint8_t)((uint64_t)x >> 40); \
+    *((str) + 1) = (uint8_t)((uint64_t)x >> 48); \
+    *((str) + 0) = (uint8_t)((uint64_t)x >> 56); \
+  }
+
 #define PACK32(str, x)                                                    \
   {                                                                       \
     *(x) = ((uint32_t) * ((str) + 3)) | ((uint32_t) * ((str) + 2) << 8) | \
@@ -96,18 +108,18 @@ void avb_sha256_init(AvbSHA256Ctx* ctx) {
 
 static void SHA256_transform(AvbSHA256Ctx* ctx,
                              const uint8_t* message,
-                             unsigned int block_nb) {
+                             size_t block_nb) {
   uint32_t w[64];
   uint32_t wv[8];
   uint32_t t1, t2;
   const unsigned char* sub_block;
-  int i;
+  size_t i;
 
 #ifndef UNROLL_LOOPS
-  int j;
+  size_t j;
 #endif
 
-  for (i = 0; i < (int)block_nb; i++) {
+  for (i = 0; i < block_nb; i++) {
     sub_block = message + (i << 6);
 
 #ifndef UNROLL_LOOPS
@@ -293,9 +305,9 @@ static void SHA256_transform(AvbSHA256Ctx* ctx,
   }
 }
 
-void avb_sha256_update(AvbSHA256Ctx* ctx, const uint8_t* data, uint32_t len) {
-  unsigned int block_nb;
-  unsigned int new_len, rem_len, tmp_len;
+void avb_sha256_update(AvbSHA256Ctx* ctx, const uint8_t* data, size_t len) {
+  size_t block_nb;
+  size_t new_len, rem_len, tmp_len;
   const uint8_t* shifted_data;
 
   tmp_len = AVB_SHA256_BLOCK_SIZE - ctx->len;
@@ -325,11 +337,11 @@ void avb_sha256_update(AvbSHA256Ctx* ctx, const uint8_t* data, uint32_t len) {
 }
 
 uint8_t* avb_sha256_final(AvbSHA256Ctx* ctx) {
-  unsigned int block_nb;
-  unsigned int pm_len;
-  unsigned int len_b;
+  size_t block_nb;
+  size_t pm_len;
+  uint64_t len_b;
 #ifndef UNROLL_LOOPS
-  int i;
+  size_t i;
 #endif
 
   block_nb =
@@ -340,7 +352,7 @@ uint8_t* avb_sha256_final(AvbSHA256Ctx* ctx) {
 
   avb_memset(ctx->block + ctx->len, 0, pm_len - ctx->len);
   ctx->block[ctx->len] = 0x80;
-  UNPACK32(len_b, ctx->block + pm_len - 4);
+  UNPACK64(len_b, ctx->block + pm_len - 8);
 
   SHA256_transform(ctx, ctx->block, block_nb);
 
diff --git a/lib/libavb/avb_sha512.c b/lib/libavb/avb_sha512.c
index a5e7297aa7..b19054fc74 100644
--- a/lib/libavb/avb_sha512.c
+++ b/lib/libavb/avb_sha512.c
@@ -127,14 +127,14 @@ void avb_sha512_init(AvbSHA512Ctx* ctx) {
 
 static void SHA512_transform(AvbSHA512Ctx* ctx,
                              const uint8_t* message,
-                             unsigned int block_nb) {
+                             size_t block_nb) {
   uint64_t w[80];
   uint64_t wv[8];
   uint64_t t1, t2;
   const uint8_t* sub_block;
-  int i, j;
+  size_t i, j;
 
-  for (i = 0; i < (int)block_nb; i++) {
+  for (i = 0; i < block_nb; i++) {
     sub_block = message + (i << 7);
 
 #ifdef UNROLL_LOOPS_SHA512
@@ -291,9 +291,9 @@ static void SHA512_transform(AvbSHA512Ctx* ctx,
   }
 }
 
-void avb_sha512_update(AvbSHA512Ctx* ctx, const uint8_t* data, uint32_t len) {
-  unsigned int block_nb;
-  unsigned int new_len, rem_len, tmp_len;
+void avb_sha512_update(AvbSHA512Ctx* ctx, const uint8_t* data, size_t len) {
+  size_t block_nb;
+  size_t new_len, rem_len, tmp_len;
   const uint8_t* shifted_data;
 
   tmp_len = AVB_SHA512_BLOCK_SIZE - ctx->len;
@@ -323,12 +323,12 @@ void avb_sha512_update(AvbSHA512Ctx* ctx, const uint8_t* data, uint32_t len) {
 }
 
 uint8_t* avb_sha512_final(AvbSHA512Ctx* ctx) {
-  unsigned int block_nb;
-  unsigned int pm_len;
-  unsigned int len_b;
+  size_t block_nb;
+  size_t pm_len;
+  uint64_t len_b;
 
 #ifndef UNROLL_LOOPS_SHA512
-  int i;
+  size_t i;
 #endif
 
   block_nb =
@@ -339,7 +339,7 @@ uint8_t* avb_sha512_final(AvbSHA512Ctx* ctx) {
 
   avb_memset(ctx->block + ctx->len, 0, pm_len - ctx->len);
   ctx->block[ctx->len] = 0x80;
-  UNPACK32(len_b, ctx->block + pm_len - 4);
+  UNPACK64(len_b, ctx->block + pm_len - 8);
 
   SHA512_transform(ctx, ctx->block, block_nb);
 
diff --git a/lib/libavb/avb_slot_verify.c b/lib/libavb/avb_slot_verify.c
index a941850d93..5d400b38aa 100644
--- a/lib/libavb/avb_slot_verify.c
+++ b/lib/libavb/avb_slot_verify.c
@@ -24,6 +24,14 @@
 /* Maximum size of a vbmeta image - 64 KiB. */
 #define VBMETA_MAX_SIZE (64 * 1024)
 
+static AvbSlotVerifyResult 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);
+
 /* Helper function to see if we should continue with verification in
  * allow_verification_error=true mode if something goes wrong. See the
  * comments for the avb_slot_verify() function for more information.
@@ -114,9 +122,26 @@ static AvbSlotVerifyResult load_full_partition(AvbOps* ops,
   return AVB_SLOT_VERIFY_RESULT_OK;
 }
 
+/* Reads a persistent digest stored as a named persistent value corresponding to
+ * the given |part_name|. The value is returned in |out_digest| which must point
+ * to |expected_digest_size| bytes. If there is no digest stored for |part_name|
+ * it can be initialized by providing a non-NULL |initial_digest| of length
+ * |expected_digest_size|. This automatic initialization will only occur if the
+ * device is currently locked. The |initial_digest| may be NULL.
+ *
+ * Returns AVB_SLOT_VERIFY_RESULT_OK on success, otherwise returns an
+ * AVB_SLOT_VERIFY_RESULT_ERROR_* error code.
+ *
+ * If the value does not exist, is not supported, or is not populated, and
+ * |initial_digest| is NULL, returns
+ * AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA. If |expected_digest_size| does
+ * not match the stored digest size, also returns
+ * AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA.
+ */
 static AvbSlotVerifyResult read_persistent_digest(AvbOps* ops,
                                                   const char* part_name,
                                                   size_t expected_digest_size,
+                                                  const uint8_t* initial_digest,
                                                   uint8_t* out_digest) {
   char* persistent_value_name = NULL;
   AvbIOResult io_ret = AVB_IO_RESULT_OK;
@@ -131,30 +156,106 @@ static AvbSlotVerifyResult read_persistent_digest(AvbOps* ops,
   if (persistent_value_name == NULL) {
     return AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
   }
+
   io_ret = ops->read_persistent_value(ops,
                                       persistent_value_name,
                                       expected_digest_size,
                                       out_digest,
                                       &stored_digest_size);
+
+  // If no such named persistent value exists and an initial digest value was
+  // given, initialize the named persistent value with the given digest. If
+  // initialized successfully, this will recurse into this function but with a
+  // NULL initial_digest.
+  if (io_ret == AVB_IO_RESULT_ERROR_NO_SUCH_VALUE && initial_digest) {
+    AvbSlotVerifyResult ret =
+        initialize_persistent_digest(ops,
+                                     part_name,
+                                     persistent_value_name,
+                                     expected_digest_size,
+                                     initial_digest,
+                                     out_digest);
+    avb_free(persistent_value_name);
+    return ret;
+  }
   avb_free(persistent_value_name);
+
   if (io_ret == AVB_IO_RESULT_ERROR_OOM) {
     return AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
   } else if (io_ret == AVB_IO_RESULT_ERROR_NO_SUCH_VALUE) {
+    // Treat a missing persistent value as a verification error, which is
+    // ignoreable, rather than a metadata error which is not.
     avb_errorv(part_name, ": Persistent digest does not exist.\n", NULL);
-    return AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;
+    return AVB_SLOT_VERIFY_RESULT_ERROR_VERIFICATION;
   } else if (io_ret == AVB_IO_RESULT_ERROR_INVALID_VALUE_SIZE ||
-             io_ret == AVB_IO_RESULT_ERROR_INSUFFICIENT_SPACE ||
-             expected_digest_size != stored_digest_size) {
+             io_ret == AVB_IO_RESULT_ERROR_INSUFFICIENT_SPACE) {
     avb_errorv(
         part_name, ": Persistent digest is not of expected size.\n", NULL);
     return AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;
   } else if (io_ret != AVB_IO_RESULT_OK) {
     avb_errorv(part_name, ": Error reading persistent digest.\n", NULL);
     return AVB_SLOT_VERIFY_RESULT_ERROR_IO;
+  } else if (expected_digest_size != stored_digest_size) {
+    avb_errorv(
+        part_name, ": Persistent digest is not of expected size.\n", NULL);
+    return AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;
   }
   return AVB_SLOT_VERIFY_RESULT_OK;
 }
 
+static AvbSlotVerifyResult 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) {
+  AvbSlotVerifyResult ret;
+  AvbIOResult io_ret = AVB_IO_RESULT_OK;
+  bool is_device_unlocked = true;
+
+  io_ret = ops->read_is_device_unlocked(ops, &is_device_unlocked);
+  if (io_ret == AVB_IO_RESULT_ERROR_OOM) {
+    return AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
+  } else if (io_ret != AVB_IO_RESULT_OK) {
+    avb_error("Error getting device lock state.\n");
+    return AVB_SLOT_VERIFY_RESULT_ERROR_IO;
+  }
+
+  if (is_device_unlocked) {
+    avb_debugv(part_name,
+               ": Digest does not exist, device unlocked so not initializing "
+               "digest.\n",
+               NULL);
+    return AVB_SLOT_VERIFY_RESULT_ERROR_VERIFICATION;
+  }
+
+  // Device locked; initialize digest with given initial value.
+  avb_debugv(part_name,
+             ": Digest does not exist, initializing persistent digest.\n",
+             NULL);
+  io_ret = ops->write_persistent_value(
+      ops, persistent_value_name, digest_size, initial_digest);
+  if (io_ret == AVB_IO_RESULT_ERROR_OOM) {
+    return AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
+  } else if (io_ret != AVB_IO_RESULT_OK) {
+    avb_errorv(part_name, ": Error initializing persistent digest.\n", NULL);
+    return AVB_SLOT_VERIFY_RESULT_ERROR_IO;
+  }
+
+  // To ensure that the digest value was written successfully - and avoid a
+  // scenario where the digest is simply 'initialized' on every verify - recurse
+  // into read_persistent_digest to read back the written value. The NULL
+  // initial_digest ensures that this will not recurse again.
+  ret = read_persistent_digest(ops, part_name, digest_size, NULL, out_digest);
+  if (ret != AVB_SLOT_VERIFY_RESULT_OK) {
+    avb_errorv(part_name,
+               ": Reading back initialized persistent digest failed!\n",
+               NULL);
+  }
+  return ret;
+}
+
 static AvbSlotVerifyResult load_and_verify_hash_partition(
     AvbOps* ops,
     const char* const* requested_partitions,
@@ -248,24 +349,16 @@ static AvbSlotVerifyResult load_and_verify_hash_partition(
    */
   image_size = hash_desc.image_size;
   if (allow_verification_error) {
-    if (ops->get_size_of_partition == NULL) {
-      avb_errorv(part_name,
-                 ": The get_size_of_partition() operation is "
-                 "not implemented so we may not load the entire partition. "
-                 "Please implement.",
-                 NULL);
-    } else {
-      io_ret = ops->get_size_of_partition(ops, part_name, &image_size);
-      if (io_ret == AVB_IO_RESULT_ERROR_OOM) {
-        ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
-        goto out;
-      } else if (io_ret != AVB_IO_RESULT_OK) {
-        avb_errorv(part_name, ": Error determining partition size.\n", NULL);
-        ret = AVB_SLOT_VERIFY_RESULT_ERROR_IO;
-        goto out;
-      }
-      avb_debugv(part_name, ": Loading entire partition.\n", NULL);
+    io_ret = ops->get_size_of_partition(ops, part_name, &image_size);
+    if (io_ret == AVB_IO_RESULT_ERROR_OOM) {
+      ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
+      goto out;
+    } else if (io_ret != AVB_IO_RESULT_OK) {
+      avb_errorv(part_name, ": Error determining partition size.\n", NULL);
+      ret = AVB_SLOT_VERIFY_RESULT_ERROR_IO;
+      goto out;
     }
+    avb_debugv(part_name, ": Loading entire partition.\n", NULL);
   }
 
   ret = load_full_partition(
@@ -273,19 +366,27 @@ static AvbSlotVerifyResult load_and_verify_hash_partition(
   if (ret != AVB_SLOT_VERIFY_RESULT_OK) {
     goto out;
   }
-
+  // Although only one of the type might be used, we have to defined the
+  // structure here so that they would live outside the 'if/else' scope to be
+  // used later.
+  AvbSHA256Ctx sha256_ctx;
+  AvbSHA512Ctx sha512_ctx;
+  size_t image_size_to_hash = hash_desc.image_size;
+  // If we allow verification error and the whole partition is smaller than
+  // image size in hash descriptor, we just hash the whole partition.
+  if (image_size_to_hash > image_size) {
+    image_size_to_hash = image_size;
+  }
   if (avb_strcmp((const char*)hash_desc.hash_algorithm, "sha256") == 0) {
-    AvbSHA256Ctx sha256_ctx;
     avb_sha256_init(&sha256_ctx);
     avb_sha256_update(&sha256_ctx, desc_salt, hash_desc.salt_len);
-    avb_sha256_update(&sha256_ctx, image_buf, hash_desc.image_size);
+    avb_sha256_update(&sha256_ctx, image_buf, image_size_to_hash);
     digest = avb_sha256_final(&sha256_ctx);
     digest_len = AVB_SHA256_DIGEST_SIZE;
   } else if (avb_strcmp((const char*)hash_desc.hash_algorithm, "sha512") == 0) {
-    AvbSHA512Ctx sha512_ctx;
     avb_sha512_init(&sha512_ctx);
     avb_sha512_update(&sha512_ctx, desc_salt, hash_desc.salt_len);
-    avb_sha512_update(&sha512_ctx, image_buf, hash_desc.image_size);
+    avb_sha512_update(&sha512_ctx, image_buf, image_size_to_hash);
     digest = avb_sha512_final(&sha512_ctx);
     digest_len = AVB_SHA512_DIGEST_SIZE;
   } else {
@@ -295,18 +396,21 @@ static AvbSlotVerifyResult load_and_verify_hash_partition(
   }
 
   if (hash_desc.digest_len == 0) {
-    // Expect a match to a persistent digest.
+    /* Expect a match to a persistent digest. */
     avb_debugv(part_name, ": No digest, using persistent digest.\n", NULL);
     expected_digest_len = digest_len;
     expected_digest = expected_digest_buf;
     avb_assert(expected_digest_len <= sizeof(expected_digest_buf));
-    ret =
-        read_persistent_digest(ops, part_name, digest_len, expected_digest_buf);
+    /* Pass |digest| as the |initial_digest| so devices not yet initialized get
+     * initialized to the current partition digest.
+     */
+    ret = read_persistent_digest(
+        ops, part_name, digest_len, digest, expected_digest_buf);
     if (ret != AVB_SLOT_VERIFY_RESULT_OK) {
       goto out;
     }
   } else {
-    // Expect a match to the digest in the descriptor.
+    /* Expect a match to the digest in the descriptor. */
     expected_digest_len = hash_desc.digest_len;
     expected_digest = desc_digest;
   }
@@ -365,12 +469,6 @@ static AvbSlotVerifyResult load_requested_partitions(
   bool image_preloaded = false;
   size_t n;
 
-  if (ops->get_size_of_partition == NULL) {
-    avb_error("get_size_of_partition() not implemented.\n");
-    ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_ARGUMENT;
-    goto out;
-  }
-
   for (n = 0; requested_partitions[n] != NULL; n++) {
     char part_name[AVB_PART_NAME_MAX_SIZE];
     AvbIOResult io_ret;
@@ -441,6 +539,7 @@ static AvbSlotVerifyResult 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,
@@ -467,7 +566,7 @@ static AvbSlotVerifyResult load_and_verify_vbmeta(
   size_t num_descriptors;
   size_t n;
   bool is_main_vbmeta;
-  bool is_vbmeta_partition;
+  bool look_for_vbmeta_footer;
   AvbVBMetaData* vbmeta_image_data = NULL;
 
   ret = AVB_SLOT_VERIFY_RESULT_OK;
@@ -478,8 +577,20 @@ static AvbSlotVerifyResult load_and_verify_vbmeta(
    * rollback_index_location to determine whether we're the main
    * vbmeta struct.
    */
-  is_main_vbmeta = (rollback_index_location == 0);
-  is_vbmeta_partition = (avb_strcmp(partition_name, "vbmeta") == 0);
+  is_main_vbmeta = false;
+  if (rollback_index_location == 0) {
+    if ((flags & AVB_SLOT_VERIFY_FLAGS_NO_VBMETA_PARTITION) == 0) {
+      is_main_vbmeta = true;
+    }
+  }
+
+  /* Don't use footers for vbmeta partitions ('vbmeta' or
+   * 'vbmeta_<partition_name>').
+   */
+  look_for_vbmeta_footer = true;
+  if (avb_strncmp(partition_name, "vbmeta", avb_strlen("vbmeta")) == 0) {
+    look_for_vbmeta_footer = false;
+  }
 
   if (!avb_validate_utf8((const uint8_t*)partition_name, partition_name_len)) {
     avb_error("Partition name is not valid UTF-8.\n");
@@ -487,7 +598,7 @@ static AvbSlotVerifyResult load_and_verify_vbmeta(
     goto out;
   }
 
-  /* Construct full partition name. */
+  /* Construct full partition name e.g. system_a. */
   if (!avb_str_concat(full_partition_name,
                       sizeof full_partition_name,
                       partition_name,
@@ -499,19 +610,15 @@ static AvbSlotVerifyResult load_and_verify_vbmeta(
     goto out;
   }
 
-  avb_debugv("Loading vbmeta struct from partition '",
-             full_partition_name,
-             "'.\n",
-             NULL);
-
-  /* If we're loading from the main vbmeta partition, the vbmeta
-   * struct is in the beginning. Otherwise we have to locate it via a
-   * footer.
+  /* If we're loading from the main vbmeta partition, the vbmeta struct is in
+   * the beginning. Otherwise we may have to locate it via a footer... if no
+   * footer is found, we look in the beginning to support e.g. vbmeta_<org>
+   * partitions holding data for e.g. super partitions (b/80195851 for
+   * rationale).
    */
-  if (is_vbmeta_partition) {
-    vbmeta_offset = 0;
-    vbmeta_size = VBMETA_MAX_SIZE;
-  } else {
+  vbmeta_offset = 0;
+  vbmeta_size = VBMETA_MAX_SIZE;
+  if (look_for_vbmeta_footer) {
     uint8_t footer_buf[AVB_FOOTER_SIZE];
     size_t footer_num_read;
     AvbFooter footer;
@@ -534,21 +641,17 @@ static AvbSlotVerifyResult load_and_verify_vbmeta(
 
     if (!avb_footer_validate_and_byteswap((const AvbFooter*)footer_buf,
                                           &footer)) {
-      avb_errorv(full_partition_name, ": Error validating footer.\n", NULL);
-      ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;
-      goto out;
-    }
-
-    /* Basic footer sanity check since the data is untrusted. */
-    if (footer.vbmeta_size > VBMETA_MAX_SIZE) {
-      avb_errorv(
-          full_partition_name, ": Invalid vbmeta size in footer.\n", NULL);
-      ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;
-      goto out;
+      avb_debugv(full_partition_name, ": No footer detected.\n", NULL);
+    } else {
+      /* Basic footer sanity check since the data is untrusted. */
+      if (footer.vbmeta_size > VBMETA_MAX_SIZE) {
+        avb_errorv(
+            full_partition_name, ": Invalid vbmeta size in footer.\n", NULL);
+      } else {
+        vbmeta_offset = footer.vbmeta_offset;
+        vbmeta_size = footer.vbmeta_size;
+      }
     }
-
-    vbmeta_offset = footer.vbmeta_offset;
-    vbmeta_size = footer.vbmeta_size;
   }
 
   vbmeta_buf = avb_malloc(vbmeta_size);
@@ -557,6 +660,18 @@ static AvbSlotVerifyResult load_and_verify_vbmeta(
     goto out;
   }
 
+  if (vbmeta_offset != 0) {
+    avb_debugv("Loading vbmeta struct in footer from partition '",
+               full_partition_name,
+               "'.\n",
+               NULL);
+  } else {
+    avb_debugv("Loading vbmeta struct from partition '",
+               full_partition_name,
+               "'.\n",
+               NULL);
+  }
+
   io_ret = ops->read_from_partition(ops,
                                     full_partition_name,
                                     vbmeta_offset,
@@ -571,13 +686,14 @@ static AvbSlotVerifyResult load_and_verify_vbmeta(
      * go try to get it from the boot partition instead.
      */
     if (is_main_vbmeta && io_ret == AVB_IO_RESULT_ERROR_NO_SUCH_PARTITION &&
-        is_vbmeta_partition) {
+        !look_for_vbmeta_footer) {
       avb_debugv(full_partition_name,
                  ": No such partition. Trying 'boot' instead.\n",
                  NULL);
       ret = load_and_verify_vbmeta(ops,
                                    requested_partitions,
                                    ab_suffix,
+                                   flags,
                                    allow_verification_error,
                                    0 /* toplevel_vbmeta_flags */,
                                    0 /* rollback_index_location */,
@@ -655,6 +771,8 @@ static AvbSlotVerifyResult load_and_verify_vbmeta(
     }
   }
 
+  uint32_t rollback_index_location_to_use = rollback_index_location;
+
   /* Check if key used to make signature matches what is expected. */
   if (pk_data != NULL) {
     if (expected_public_key != NULL) {
@@ -682,9 +800,27 @@ static AvbSlotVerifyResult load_and_verify_vbmeta(
         pk_metadata_len = vbmeta_header.public_key_metadata_size;
       }
 
-      avb_assert(is_main_vbmeta);
-      io_ret = ops->validate_vbmeta_public_key(
-          ops, pk_data, pk_len, pk_metadata, pk_metadata_len, &key_is_trusted);
+      // If we're not using a vbmeta partition, need to use another AvbOps...
+      if (flags & AVB_SLOT_VERIFY_FLAGS_NO_VBMETA_PARTITION) {
+        io_ret = ops->validate_public_key_for_partition(
+            ops,
+            full_partition_name,
+            pk_data,
+            pk_len,
+            pk_metadata,
+            pk_metadata_len,
+            &key_is_trusted,
+            &rollback_index_location_to_use);
+      } else {
+        avb_assert(is_main_vbmeta);
+        io_ret = ops->validate_vbmeta_public_key(ops,
+                                                 pk_data,
+                                                 pk_len,
+                                                 pk_metadata,
+                                                 pk_metadata_len,
+                                                 &key_is_trusted);
+      }
+
       if (io_ret == AVB_IO_RESULT_ERROR_OOM) {
         ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
         goto out;
@@ -709,7 +845,7 @@ static AvbSlotVerifyResult load_and_verify_vbmeta(
 
   /* Check rollback index. */
   io_ret = ops->read_rollback_index(
-      ops, rollback_index_location, &stored_rollback_index);
+      ops, rollback_index_location_to_use, &stored_rollback_index);
   if (io_ret == AVB_IO_RESULT_ERROR_OOM) {
     ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
     goto out;
@@ -735,7 +871,9 @@ static AvbSlotVerifyResult load_and_verify_vbmeta(
   if (is_main_vbmeta) {
     avb_assert(slot_data->num_vbmeta_images == 0);
   } else {
-    avb_assert(slot_data->num_vbmeta_images > 0);
+    if (!(flags & AVB_SLOT_VERIFY_FLAGS_NO_VBMETA_PARTITION)) {
+      avb_assert(slot_data->num_vbmeta_images > 0);
+    }
   }
   if (slot_data->num_vbmeta_images == MAX_NUMBER_OF_VBMETA_IMAGES) {
     avb_errorv(full_partition_name, ": Too many vbmeta images.\n", NULL);
@@ -859,6 +997,7 @@ static AvbSlotVerifyResult load_and_verify_vbmeta(
             load_and_verify_vbmeta(ops,
                                    requested_partitions,
                                    ab_suffix,
+                                   flags,
                                    allow_verification_error,
                                    toplevel_vbmeta_flags,
                                    chain_desc.rollback_index_location,
@@ -1019,7 +1158,11 @@ static AvbSlotVerifyResult load_and_verify_vbmeta(
             goto out;
           }
 
-          ret = read_persistent_digest(ops, part_name, digest_len, digest_buf);
+          ret = read_persistent_digest(ops,
+                                       part_name,
+                                       digest_len,
+                                       NULL /* initial_digest */,
+                                       digest_buf);
           if (ret != AVB_SLOT_VERIFY_RESULT_OK) {
             goto out;
           }
@@ -1043,7 +1186,8 @@ static AvbSlotVerifyResult load_and_verify_vbmeta(
     }
   }
 
-  if (rollback_index_location >= AVB_MAX_NUMBER_OF_ROLLBACK_INDEX_LOCATIONS) {
+  if (rollback_index_location < 0 ||
+      rollback_index_location >= AVB_MAX_NUMBER_OF_ROLLBACK_INDEX_LOCATIONS) {
     avb_errorv(
         full_partition_name, ": Invalid rollback_index_location.\n", NULL);
     ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;
@@ -1072,6 +1216,130 @@ out:
   return ret;
 }
 
+static AvbIOResult avb_manage_hashtree_error_mode(
+    AvbOps* ops,
+    AvbSlotVerifyFlags flags,
+    AvbSlotVerifyData* data,
+    AvbHashtreeErrorMode* out_hashtree_error_mode) {
+  AvbHashtreeErrorMode ret = AVB_HASHTREE_ERROR_MODE_RESTART;
+  AvbIOResult io_ret = AVB_IO_RESULT_OK;
+  uint8_t vbmeta_digest_sha256[AVB_SHA256_DIGEST_SIZE];
+  uint8_t stored_vbmeta_digest_sha256[AVB_SHA256_DIGEST_SIZE];
+  size_t num_bytes_read;
+
+  avb_assert(out_hashtree_error_mode != NULL);
+  avb_assert(ops->read_persistent_value != NULL);
+  avb_assert(ops->write_persistent_value != NULL);
+
+  // If we're rebooting because of dm-verity corruption, make a note of
+  // the vbmeta hash so we can stay in 'eio' mode until things change.
+  if (flags & AVB_SLOT_VERIFY_FLAGS_RESTART_CAUSED_BY_HASHTREE_CORRUPTION) {
+    avb_debug(
+        "Rebooting because of dm-verity corruption - "
+        "recording OS instance and using 'eio' mode.\n");
+    avb_slot_verify_data_calculate_vbmeta_digest(
+        data, AVB_DIGEST_TYPE_SHA256, vbmeta_digest_sha256);
+    io_ret = ops->write_persistent_value(ops,
+                                         AVB_NPV_MANAGED_VERITY_MODE,
+                                         AVB_SHA256_DIGEST_SIZE,
+                                         vbmeta_digest_sha256);
+    if (io_ret != AVB_IO_RESULT_OK) {
+      avb_error("Error writing to " AVB_NPV_MANAGED_VERITY_MODE ".\n");
+      goto out;
+    }
+    ret = AVB_HASHTREE_ERROR_MODE_EIO;
+    io_ret = AVB_IO_RESULT_OK;
+    goto out;
+  }
+
+  // See if we're in 'eio' mode.
+  io_ret = ops->read_persistent_value(ops,
+                                      AVB_NPV_MANAGED_VERITY_MODE,
+                                      AVB_SHA256_DIGEST_SIZE,
+                                      stored_vbmeta_digest_sha256,
+                                      &num_bytes_read);
+  if (io_ret == AVB_IO_RESULT_ERROR_NO_SUCH_VALUE ||
+      (io_ret == AVB_IO_RESULT_OK && num_bytes_read == 0)) {
+    // This is the usual case ('eio' mode not set).
+    avb_debug("No dm-verity corruption - using in 'restart' mode.\n");
+    ret = AVB_HASHTREE_ERROR_MODE_RESTART;
+    io_ret = AVB_IO_RESULT_OK;
+    goto out;
+  } else if (io_ret != AVB_IO_RESULT_OK) {
+    avb_error("Error reading from " AVB_NPV_MANAGED_VERITY_MODE ".\n");
+    goto out;
+  }
+  if (num_bytes_read != AVB_SHA256_DIGEST_SIZE) {
+    avb_error(
+        "Unexpected number of bytes read from " AVB_NPV_MANAGED_VERITY_MODE
+        ".\n");
+    io_ret = AVB_IO_RESULT_ERROR_IO;
+    goto out;
+  }
+
+  // OK, so we're currently in 'eio' mode and the vbmeta digest of the OS
+  // that caused this is in |stored_vbmeta_digest_sha256| ... now see if
+  // the OS we're dealing with now is the same.
+  avb_slot_verify_data_calculate_vbmeta_digest(
+      data, AVB_DIGEST_TYPE_SHA256, vbmeta_digest_sha256);
+  if (avb_memcmp(vbmeta_digest_sha256,
+                 stored_vbmeta_digest_sha256,
+                 AVB_SHA256_DIGEST_SIZE) == 0) {
+    // It's the same so we're still in 'eio' mode.
+    avb_debug("Same OS instance detected - staying in 'eio' mode.\n");
+    ret = AVB_HASHTREE_ERROR_MODE_EIO;
+    io_ret = AVB_IO_RESULT_OK;
+  } else {
+    // It did change!
+    avb_debug(
+        "New OS instance detected - changing from 'eio' to 'restart' mode.\n");
+    io_ret =
+        ops->write_persistent_value(ops,
+                                    AVB_NPV_MANAGED_VERITY_MODE,
+                                    0,  // This clears the persistent property.
+                                    vbmeta_digest_sha256);
+    if (io_ret != AVB_IO_RESULT_OK) {
+      avb_error("Error clearing " AVB_NPV_MANAGED_VERITY_MODE ".\n");
+      goto out;
+    }
+    ret = AVB_HASHTREE_ERROR_MODE_RESTART;
+    io_ret = AVB_IO_RESULT_OK;
+  }
+
+out:
+  *out_hashtree_error_mode = ret;
+  return io_ret;
+}
+
+static bool has_system_partition(AvbOps* ops, const char* ab_suffix) {
+  char part_name[AVB_PART_NAME_MAX_SIZE];
+  char* system_part_name = "system";
+  char guid_buf[37];
+  AvbIOResult io_ret;
+
+  if (!avb_str_concat(part_name,
+                      sizeof part_name,
+                      system_part_name,
+                      avb_strlen(system_part_name),
+                      ab_suffix,
+                      avb_strlen(ab_suffix))) {
+    avb_error("System partition name and suffix does not fit.\n");
+    return false;
+  }
+
+  io_ret = ops->get_unique_guid_for_partition(
+      ops, part_name, guid_buf, sizeof guid_buf);
+  if (io_ret == AVB_IO_RESULT_ERROR_NO_SUCH_PARTITION) {
+    avb_debug("No system partition.\n");
+    return false;
+  } else if (io_ret != AVB_IO_RESULT_OK) {
+    avb_error("Error getting unique GUID for system partition.\n");
+    return false;
+  }
+
+  return true;
+}
+
 AvbSlotVerifyResult avb_slot_verify(AvbOps* ops,
                                     const char* const* requested_partitions,
                                     const char* ab_suffix,
@@ -1087,14 +1355,10 @@ AvbSlotVerifyResult avb_slot_verify(AvbOps* ops,
       (flags & AVB_SLOT_VERIFY_FLAGS_ALLOW_VERIFICATION_ERROR);
   AvbCmdlineSubstList* additional_cmdline_subst = NULL;
 
-  /* Fail early if we're missing the AvbOps needed for slot verification.
-   *
-   * For now, handle get_size_of_partition() not being implemented. In
-   * a later release we may change that.
-   */
+  /* Fail early if we're missing the AvbOps needed for slot verification. */
   avb_assert(ops->read_is_device_unlocked != NULL);
   avb_assert(ops->read_from_partition != NULL);
-  avb_assert(ops->validate_vbmeta_public_key != NULL);
+  avb_assert(ops->get_size_of_partition != NULL);
   avb_assert(ops->read_rollback_index != NULL);
   avb_assert(ops->get_unique_guid_for_partition != NULL);
 
@@ -1112,6 +1376,36 @@ AvbSlotVerifyResult avb_slot_verify(AvbOps* ops,
     goto fail;
   }
 
+  /* Make sure passed-in AvbOps support persistent values if
+   * asking for libavb to manage verity state.
+   */
+  if (hashtree_error_mode == AVB_HASHTREE_ERROR_MODE_MANAGED_RESTART_AND_EIO) {
+    if (ops->read_persistent_value == NULL ||
+        ops->write_persistent_value == NULL) {
+      avb_error(
+          "Persistent values required for "
+          "AVB_HASHTREE_ERROR_MODE_MANAGED_RESTART_AND_EIO "
+          "but are not implemented in given AvbOps.\n");
+      ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_ARGUMENT;
+      goto fail;
+    }
+  }
+
+  /* Make sure passed-in AvbOps support verifying public keys and getting
+   * rollback index location if not using a vbmeta partition.
+   */
+  if (flags & AVB_SLOT_VERIFY_FLAGS_NO_VBMETA_PARTITION) {
+    if (ops->validate_public_key_for_partition == NULL) {
+      avb_error(
+          "AVB_SLOT_VERIFY_FLAGS_NO_VBMETA_PARTITION was passed but the "
+          "validate_public_key_for_partition() operation isn't implemented.\n");
+      ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_ARGUMENT;
+      goto fail;
+    }
+  } else {
+    avb_assert(ops->validate_vbmeta_public_key != NULL);
+  }
+
   slot_data = avb_calloc(sizeof(AvbSlotVerifyData));
   if (slot_data == NULL) {
     ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
@@ -1136,99 +1430,163 @@ AvbSlotVerifyResult avb_slot_verify(AvbOps* ops,
     goto fail;
   }
 
-  ret = load_and_verify_vbmeta(ops,
-                               requested_partitions,
-                               ab_suffix,
-                               allow_verification_error,
-                               0 /* toplevel_vbmeta_flags */,
-                               0 /* rollback_index_location */,
-                               "vbmeta",
-                               avb_strlen("vbmeta"),
-                               NULL /* expected_public_key */,
-                               0 /* expected_public_key_length */,
-                               slot_data,
-                               &algorithm_type,
-                               additional_cmdline_subst);
-  if (!allow_verification_error && ret != AVB_SLOT_VERIFY_RESULT_OK) {
+  if (flags & AVB_SLOT_VERIFY_FLAGS_NO_VBMETA_PARTITION) {
+    if (requested_partitions == NULL || requested_partitions[0] == NULL) {
+      avb_fatal(
+          "Requested partitions cannot be empty when using "
+          "AVB_SLOT_VERIFY_FLAGS_NO_VBMETA_PARTITION");
+      ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_ARGUMENT;
+      goto fail;
+    }
+
+    /* No vbmeta partition, go through each of the requested partitions... */
+    for (size_t n = 0; requested_partitions[n] != NULL; n++) {
+      ret = load_and_verify_vbmeta(ops,
+                                   requested_partitions,
+                                   ab_suffix,
+                                   flags,
+                                   allow_verification_error,
+                                   0 /* toplevel_vbmeta_flags */,
+                                   0 /* rollback_index_location */,
+                                   requested_partitions[n],
+                                   avb_strlen(requested_partitions[n]),
+                                   NULL /* expected_public_key */,
+                                   0 /* expected_public_key_length */,
+                                   slot_data,
+                                   &algorithm_type,
+                                   additional_cmdline_subst);
+      if (!allow_verification_error && ret != AVB_SLOT_VERIFY_RESULT_OK) {
+        goto fail;
+      }
+    }
+
+  } else {
+    /* Usual path, load "vbmeta"... */
+    ret = load_and_verify_vbmeta(ops,
+                                 requested_partitions,
+                                 ab_suffix,
+                                 flags,
+                                 allow_verification_error,
+                                 0 /* toplevel_vbmeta_flags */,
+                                 0 /* rollback_index_location */,
+                                 "vbmeta",
+                                 avb_strlen("vbmeta"),
+                                 NULL /* expected_public_key */,
+                                 0 /* expected_public_key_length */,
+                                 slot_data,
+                                 &algorithm_type,
+                                 additional_cmdline_subst);
+    if (!allow_verification_error && ret != AVB_SLOT_VERIFY_RESULT_OK) {
+      goto fail;
+    }
+  }
+
+  if (!result_should_continue(ret)) {
     goto fail;
   }
 
   /* If things check out, mangle the kernel command-line as needed. */
-  if (result_should_continue(ret)) {
+  if (!(flags & AVB_SLOT_VERIFY_FLAGS_NO_VBMETA_PARTITION)) {
     if (avb_strcmp(slot_data->vbmeta_images[0].partition_name, "vbmeta") != 0) {
       avb_assert(
           avb_strcmp(slot_data->vbmeta_images[0].partition_name, "boot") == 0);
       using_boot_for_vbmeta = true;
     }
+  }
 
-    /* Byteswap top-level vbmeta header since we'll need it below. */
-    avb_vbmeta_image_header_to_host_byte_order(
-        (const AvbVBMetaImageHeader*)slot_data->vbmeta_images[0].vbmeta_data,
-        &toplevel_vbmeta);
+  /* Byteswap top-level vbmeta header since we'll need it below. */
+  avb_vbmeta_image_header_to_host_byte_order(
+      (const AvbVBMetaImageHeader*)slot_data->vbmeta_images[0].vbmeta_data,
+      &toplevel_vbmeta);
 
-    /* Fill in |ab_suffix| field. */
-    slot_data->ab_suffix = avb_strdup(ab_suffix);
-    if (slot_data->ab_suffix == NULL) {
-      ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
-      goto fail;
-    }
+  /* Fill in |ab_suffix| field. */
+  slot_data->ab_suffix = avb_strdup(ab_suffix);
+  if (slot_data->ab_suffix == NULL) {
+    ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
+    goto fail;
+  }
 
-    /* If verification is disabled, we are done ... we specifically
-     * don't want to add any androidboot.* options since verification
-     * is disabled.
+  /* If verification is disabled, we are done ... we specifically
+   * don't want to add any androidboot.* options since verification
+   * is disabled.
+   */
+  if (toplevel_vbmeta.flags & AVB_VBMETA_IMAGE_FLAGS_VERIFICATION_DISABLED) {
+    /* Since verification is disabled we didn't process any
+     * descriptors and thus there's no cmdline... so set root= such
+     * that the system partition is mounted.
      */
-    if (toplevel_vbmeta.flags & AVB_VBMETA_IMAGE_FLAGS_VERIFICATION_DISABLED) {
-      /* Since verification is disabled we didn't process any
-       * descriptors and thus there's no cmdline... so set root= such
-       * that the system partition is mounted.
-       */
-      avb_assert(slot_data->cmdline == NULL);
+    avb_assert(slot_data->cmdline == NULL);
+    // Devices with dynamic partitions won't have system partition.
+    // Instead, it has a large super partition to accommodate *.img files.
+    // See b/119551429 for details.
+    if (has_system_partition(ops, ab_suffix)) {
       slot_data->cmdline =
           avb_strdup("root=PARTUUID=$(ANDROID_SYSTEM_PARTUUID)");
-      if (slot_data->cmdline == NULL) {
-        ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
-        goto fail;
-      }
     } else {
-      /* Add options - any failure in avb_append_options() is either an
-       * I/O or OOM error.
-       */
-      AvbSlotVerifyResult sub_ret = avb_append_options(ops,
-                                                       slot_data,
-                                                       &toplevel_vbmeta,
-                                                       algorithm_type,
-                                                       hashtree_error_mode);
-      if (sub_ret != AVB_SLOT_VERIFY_RESULT_OK) {
-        ret = sub_ret;
-        goto fail;
-      }
+      // The |cmdline| field should be a NUL-terminated string.
+      slot_data->cmdline = avb_strdup("");
     }
-
-    /* Substitute $(ANDROID_SYSTEM_PARTUUID) and friends. */
-    if (slot_data->cmdline != NULL) {
-      char* new_cmdline;
-      new_cmdline = avb_sub_cmdline(ops,
-                                    slot_data->cmdline,
-                                    ab_suffix,
-                                    using_boot_for_vbmeta,
-                                    additional_cmdline_subst);
-      if (new_cmdline != slot_data->cmdline) {
-        if (new_cmdline == NULL) {
+    if (slot_data->cmdline == NULL) {
+      ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
+      goto fail;
+    }
+  } else {
+    /* If requested, manage dm-verity mode... */
+    AvbHashtreeErrorMode resolved_hashtree_error_mode = hashtree_error_mode;
+    if (hashtree_error_mode ==
+        AVB_HASHTREE_ERROR_MODE_MANAGED_RESTART_AND_EIO) {
+      AvbIOResult io_ret;
+      io_ret = avb_manage_hashtree_error_mode(
+          ops, flags, slot_data, &resolved_hashtree_error_mode);
+      if (io_ret != AVB_IO_RESULT_OK) {
+        ret = AVB_SLOT_VERIFY_RESULT_ERROR_IO;
+        if (io_ret == AVB_IO_RESULT_ERROR_OOM) {
           ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
-          goto fail;
         }
-        avb_free(slot_data->cmdline);
-        slot_data->cmdline = new_cmdline;
+        goto fail;
       }
     }
+    slot_data->resolved_hashtree_error_mode = resolved_hashtree_error_mode;
 
-    if (out_data != NULL) {
-      *out_data = slot_data;
-    } else {
-      avb_slot_verify_data_free(slot_data);
+    /* Add options... */
+    AvbSlotVerifyResult sub_ret;
+    sub_ret = avb_append_options(ops,
+                                 flags,
+                                 slot_data,
+                                 &toplevel_vbmeta,
+                                 algorithm_type,
+                                 hashtree_error_mode,
+                                 resolved_hashtree_error_mode);
+    if (sub_ret != AVB_SLOT_VERIFY_RESULT_OK) {
+      ret = sub_ret;
+      goto fail;
+    }
+  }
+
+  /* Substitute $(ANDROID_SYSTEM_PARTUUID) and friends. */
+  if (slot_data->cmdline != NULL && avb_strlen(slot_data->cmdline) != 0) {
+    char* new_cmdline;
+    new_cmdline = avb_sub_cmdline(ops,
+                                  slot_data->cmdline,
+                                  ab_suffix,
+                                  using_boot_for_vbmeta,
+                                  additional_cmdline_subst);
+    if (new_cmdline != slot_data->cmdline) {
+      if (new_cmdline == NULL) {
+        ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
+        goto fail;
+      }
+      avb_free(slot_data->cmdline);
+      slot_data->cmdline = new_cmdline;
     }
   }
 
+  if (out_data != NULL) {
+    *out_data = slot_data;
+  } else {
+    avb_slot_verify_data_free(slot_data);
+  }
+
   avb_free_cmdline_subst_list(additional_cmdline_subst);
   additional_cmdline_subst = NULL;
 
diff --git a/lib/libavb/avb_slot_verify.h b/lib/libavb/avb_slot_verify.h
index 73fd70d4ce..8d0fa53693 100644
--- a/lib/libavb/avb_slot_verify.h
+++ b/lib/libavb/avb_slot_verify.h
@@ -51,12 +51,25 @@ typedef enum {
  * be used ONLY for diagnostics and debugging. It cannot be used
  * unless AVB_SLOT_VERIFY_FLAGS_ALLOW_VERIFICATION_ERROR is also
  * used.
+ *
+ * AVB_HASHTREE_ERROR_MODE_MANAGED_RESTART_AND_EIO means that either
+ * AVB_HASHTREE_ERROR_MODE_RESTART or AVB_HASHTREE_ERROR_MODE_EIO is used
+ * depending on state. This mode implements a state machine whereby
+ * AVB_HASHTREE_ERROR_MODE_RESTART is used by default and when
+ * AVB_SLOT_VERIFY_FLAGS_RESTART_CAUSED_BY_HASHTREE_CORRUPTION is passed the
+ * mode transitions to AVB_HASHTREE_ERROR_MODE_EIO. When a new OS has been
+ * detected the device transitions back to the AVB_HASHTREE_ERROR_MODE_RESTART
+ * mode. To do this persistent storage is needed - specifically this means that
+ * the passed in AvbOps will need to have the read_persistent_value() and
+ * write_persistent_value() operations implemented. The name of the persistent
+ * value used is "avb.managed_verity_mode" and 32 bytes of storage is needed.
  */
 typedef enum {
   AVB_HASHTREE_ERROR_MODE_RESTART_AND_INVALIDATE,
   AVB_HASHTREE_ERROR_MODE_RESTART,
   AVB_HASHTREE_ERROR_MODE_EIO,
-  AVB_HASHTREE_ERROR_MODE_LOGGING
+  AVB_HASHTREE_ERROR_MODE_LOGGING,
+  AVB_HASHTREE_ERROR_MODE_MANAGED_RESTART_AND_EIO
 } AvbHashtreeErrorMode;
 
 /* Flags that influence how avb_slot_verify() works.
@@ -80,10 +93,26 @@ typedef enum {
  * contents loaded from |requested_partition| will be the contents of
  * the entire partition instead of just the size specified in the hash
  * descriptor.
+ *
+ * The AVB_SLOT_VERIFY_FLAGS_RESTART_CAUSED_BY_HASHTREE_CORRUPTION flag
+ * should be set if using AVB_HASHTREE_ERROR_MODE_MANAGED_RESTART_AND_EIO
+ * and the reason the boot loader is running is because the device
+ * was restarted by the dm-verity driver.
+ *
+ * If the AVB_SLOT_VERIFY_FLAGS_NO_VBMETA_PARTITION flag is set then
+ * data won't be loaded from the "vbmeta" partition and the
+ * |validate_vbmeta_public_key| operation is never called. Instead, the
+ * vbmeta structs in |requested_partitions| are loaded and processed and the
+ * |validate_public_key_for_partition| operation is called for each of these
+ * vbmeta structs. This flag is useful when booting into recovery on a device
+ * not using A/B - see section "Booting into recovery" in README.md for
+ * more information.
  */
 typedef enum {
   AVB_SLOT_VERIFY_FLAGS_NONE = 0,
-  AVB_SLOT_VERIFY_FLAGS_ALLOW_VERIFICATION_ERROR = (1 << 0)
+  AVB_SLOT_VERIFY_FLAGS_ALLOW_VERIFICATION_ERROR = (1 << 0),
+  AVB_SLOT_VERIFY_FLAGS_RESTART_CAUSED_BY_HASHTREE_CORRUPTION = (1 << 1),
+  AVB_SLOT_VERIFY_FLAGS_NO_VBMETA_PARTITION = (1 << 2),
 } AvbSlotVerifyFlags;
 
 /* Get a textual representation of |result|. */
@@ -188,6 +217,10 @@ typedef struct {
  *   set to AVB_HASHTREE_ERROR_MODE_EIO, and 'logging' if it's set to
  *   AVB_HASHTREE_ERROR_MODE_LOGGING.
  *
+ *   androidboot.veritymode.managed: This is set to 'yes' only
+ *   if hashtree validation isn't disabled and the passed-in hashtree
+ *   error mode is AVB_HASHTREE_ERROR_MODE_MANAGED_RESTART_AND_EIO.
+ *
  *   androidboot.vbmeta.invalidate_on_error: This is set to 'yes' only
  *   if hashtree validation isn't disabled and the passed-in hashtree
  *   error mode is AVB_HASHTREE_ERROR_MODE_RESTART_AND_INVALIDATE.
@@ -203,7 +236,9 @@ typedef struct {
  *   PARTUUID=$(ANDROID_VBMETA_PARTUUID) before substitution so it
  *   will end up pointing to the vbmeta partition for the verified
  *   slot. If there is no vbmeta partition it will point to the boot
- *   partition of the verified slot.
+ *   partition of the verified slot. If the flag
+ *   AVB_SLOT_VERIFY_FLAGS_NO_VBMETA_PARTITION is used, this is not
+ *   set.
  *
  *   androidboot.vbmeta.avb_version: This is set to the decimal value
  *   of AVB_VERSION_MAJOR followed by a dot followed by the decimal
@@ -228,6 +263,15 @@ typedef struct {
  * appropriate system partition is substituted in. Note that none of
  * the androidboot.* options mentioned above will be set.
  *
+ * The |resolved_hashtree_error_mode| is the the value of the passed
+ * avb_slot_verify()'s |hashtree_error_mode| parameter except that it never has
+ * the value AVB_HASHTREE_ERROR_MODE_MANAGED_RESTART_AND_EIO. If this value was
+ * passed in, then the restart/eio state machine is used resulting in
+ * |resolved_hashtree_error_mode| being set to either
+ * AVB_HASHTREE_ERROR_MODE_RESTART or AVB_HASHTREE_ERROR_MODE_EIO.  If set to
+ * AVB_HASHTREE_ERROR_MODE_EIO the boot loader should present a RED warning
+ * screen for the user to click through before continuing to boot.
+ *
  * This struct may grow in the future without it being considered an
  * ABI break.
  */
@@ -239,6 +283,7 @@ typedef struct {
   size_t num_loaded_partitions;
   char* cmdline;
   uint64_t rollback_indexes[AVB_MAX_NUMBER_OF_ROLLBACK_INDEX_LOCATIONS];
+  AvbHashtreeErrorMode resolved_hashtree_error_mode;
 } AvbSlotVerifyData;
 
 /* Calculates a digest of all vbmeta images in |data| using
@@ -282,12 +327,8 @@ void avb_slot_verify_data_free(AvbSlotVerifyData* data);
  * ignore verification errors which is something needed in the
  * UNLOCKED state. See the AvbSlotVerifyFlags enumeration for details.
  *
- * The |hashtree_error_mode| parameter should be set to the desired
- * error handling mode when hashtree validation fails inside the
- * HLOS. This value isn't used by libavb per se - it is forwarded to
- * the HLOS through the androidboot.veritymode and
- * androidboot.vbmeta.invalidate_on_error cmdline parameters. See the
- * AvbHashtreeErrorMode enumeration for details.
+ * The |hashtree_error_mode| parameter should be set to the desired error
+ * handling mode. See the AvbHashtreeErrorMode enumeration for details.
  *
  * Also note that |out_data| is never set if
  * AVB_SLOT_VERIFY_RESULT_ERROR_OOM, AVB_SLOT_VERIFY_RESULT_ERROR_IO,
diff --git a/lib/libavb/avb_sysdeps.h b/lib/libavb/avb_sysdeps.h
index f032de4a2e..f52428cc62 100644
--- a/lib/libavb/avb_sysdeps.h
+++ b/lib/libavb/avb_sysdeps.h
@@ -53,6 +53,14 @@ int avb_memcmp(const void* src1,
  */
 int avb_strcmp(const char* s1, const char* s2);
 
+/* Compare |n| bytes in two strings.
+ *
+ * Return an integer less than, equal to, or greater than zero if the
+ * first |n| bytes of |s1| is found, respectively, to be less than,
+ * to match, or be greater than the first |n| bytes of |s2|.
+ */
+int avb_strncmp(const char* s1, const char* s2, size_t n);
+
 /* Copy |n| bytes from |src| to |dest|. */
 void* avb_memcpy(void* dest, const void* src, size_t n);
 
diff --git a/lib/libavb/avb_sysdeps_posix.c b/lib/libavb/avb_sysdeps_posix.c
index e9addc1c87..4ccf41e428 100644
--- a/lib/libavb/avb_sysdeps_posix.c
+++ b/lib/libavb/avb_sysdeps_posix.c
@@ -24,14 +24,12 @@ int avb_strcmp(const char* s1, const char* s2) {
   return strcmp(s1, s2);
 }
 
-size_t avb_strlen(const char* str) {
-  return strlen(str);
+int avb_strncmp(const char* s1, const char* s2, size_t n) {
+  return strncmp(s1, s2, n);
 }
 
-uint32_t avb_div_by_10(uint64_t* dividend) {
-  uint32_t rem = (uint32_t)(*dividend % 10);
-  *dividend /= 10;
-  return rem;
+size_t avb_strlen(const char* str) {
+  return strlen(str);
 }
 
 void avb_abort(void) {
@@ -60,3 +58,9 @@ void* avb_malloc_(size_t size) {
 void avb_free(void* ptr) {
   free(ptr);
 }
+
+uint32_t avb_div_by_10(uint64_t* dividend) {
+  uint32_t rem = (uint32_t)(*dividend % 10);
+  *dividend /= 10;
+  return rem;
+}
diff --git a/lib/libavb/avb_vbmeta_image.c b/lib/libavb/avb_vbmeta_image.c
index a7e2322b9e..384f5ac19e 100644
--- a/lib/libavb/avb_vbmeta_image.c
+++ b/lib/libavb/avb_vbmeta_image.c
@@ -35,17 +35,18 @@ AvbVBMetaVerifyResult avb_vbmeta_image_verify(
     *out_public_key_length = 0;
   }
 
+  /* Before we byteswap or compare Magic, ensure length is long enough. */
+  if (length < sizeof(AvbVBMetaImageHeader)) {
+    avb_error("Length is smaller than header.\n");
+    goto out;
+  }
+
   /* Ensure magic is correct. */
   if (avb_safe_memcmp(data, AVB_MAGIC, AVB_MAGIC_LEN) != 0) {
     avb_error("Magic is incorrect.\n");
     goto out;
   }
 
-  /* Before we byteswap, ensure length is long enough. */
-  if (length < sizeof(AvbVBMetaImageHeader)) {
-    avb_error("Length is smaller than header.\n");
-    goto out;
-  }
   avb_vbmeta_image_header_to_host_byte_order((const AvbVBMetaImageHeader*)data,
                                              &h);
 
-- 
2.23.0.rc1

^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [U-Boot] [PATCH 2/2] libavb: Fix build warnings after updating the lib
  2019-08-15 20:04 [U-Boot] [PATCH 1/2] libavb: Update libavb to current AOSP master Sam Protsenko
@ 2019-08-15 20:04 ` Sam Protsenko
  2019-08-16 13:35   ` Eugeniu Rosca
  2019-11-01 13:29   ` Tom Rini
  2019-08-16 10:36 ` [U-Boot] [PATCH 1/2] libavb: Update libavb to current AOSP master Eugeniu Rosca
                   ` (2 subsequent siblings)
  3 siblings, 2 replies; 15+ messages in thread
From: Sam Protsenko @ 2019-08-15 20:04 UTC (permalink / raw)
  To: u-boot

After updating libavb to most recent version from AOSP/master, two new
warnings appear:

Warning #1:

    lib/libavb/avb_cmdline.c: In function 'avb_append_options':
    lib/libavb/avb_cmdline.c:365:15: warning: 'dm_verity_mode' may be
                                     used uninitialized in this function
                                     [-Wmaybe-uninitialized]
         new_ret = avb_replace(
                   ^~~~~~~~~~~~
             slot_data->cmdline, "$(ANDROID_VERITY_MODE)", dm_verity_mode);
             ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    lib/libavb/avb_cmdline.c:374:8: warning: 'verity_mode' may be used
                                    uninitialized in this function
                                    [-Wmaybe-uninitialized]
       if (!cmdline_append_option(
            ^~~~~~~~~~~~~~~~~~~~~~
               slot_data, "androidboot.veritymode", verity_mode)) {
               ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Warning #2:

    lib/libavb/avb_slot_verify.c: In function 'avb_slot_verify':
    lib/libavb/avb_slot_verify.c:1349:23: warning: 'ret' may be used
                                          uninitialized in this function
                                          [-Wmaybe-uninitialized]
       AvbSlotVerifyResult ret;
                           ^~~

Fix those by providing default return values to affected functions.

Signed-off-by: Sam Protsenko <semen.protsenko@linaro.org>
---
 lib/libavb/avb_cmdline.c     | 3 ++-
 lib/libavb/avb_slot_verify.c | 2 +-
 2 files changed, 3 insertions(+), 2 deletions(-)

diff --git a/lib/libavb/avb_cmdline.c b/lib/libavb/avb_cmdline.c
index cb5b98e423..684c512bb9 100644
--- a/lib/libavb/avb_cmdline.c
+++ b/lib/libavb/avb_cmdline.c
@@ -357,7 +357,8 @@ AvbSlotVerifyResult avb_append_options(
         // Should never get here because MANAGED_RESTART_AND_EIO is
         // remapped by avb_manage_hashtree_error_mode().
         avb_assert_not_reached();
-        break;
+        ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_ARGUMENT;
+        goto out;
       default:
         ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_ARGUMENT;
         goto out;
diff --git a/lib/libavb/avb_slot_verify.c b/lib/libavb/avb_slot_verify.c
index 5d400b38aa..c0defdf9c9 100644
--- a/lib/libavb/avb_slot_verify.c
+++ b/lib/libavb/avb_slot_verify.c
@@ -1346,7 +1346,7 @@ AvbSlotVerifyResult avb_slot_verify(AvbOps* ops,
                                     AvbSlotVerifyFlags flags,
                                     AvbHashtreeErrorMode hashtree_error_mode,
                                     AvbSlotVerifyData** out_data) {
-  AvbSlotVerifyResult ret;
+  AvbSlotVerifyResult ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_ARGUMENT;
   AvbSlotVerifyData* slot_data = NULL;
   AvbAlgorithmType algorithm_type = AVB_ALGORITHM_TYPE_NONE;
   bool using_boot_for_vbmeta = false;
-- 
2.23.0.rc1

^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [U-Boot] [PATCH 1/2] libavb: Update libavb to current AOSP master
  2019-08-15 20:04 [U-Boot] [PATCH 1/2] libavb: Update libavb to current AOSP master Sam Protsenko
  2019-08-15 20:04 ` [U-Boot] [PATCH 2/2] libavb: Fix build warnings after updating the lib Sam Protsenko
@ 2019-08-16 10:36 ` Eugeniu Rosca
  2019-08-16 10:59   ` Sam Protsenko
  2019-10-16  9:32 ` Igor Opaniuk
  2019-11-01 13:29 ` Tom Rini
  3 siblings, 1 reply; 15+ messages in thread
From: Eugeniu Rosca @ 2019-08-16 10:36 UTC (permalink / raw)
  To: u-boot

Hi Sam,

On Thu, Aug 15, 2019 at 11:04:02PM +0300, Sam Protsenko wrote:
> Update libavb to commit 5fbb42a189aa in AOSP/master, because new version
> has support for super partition [1], which we need for implementing
> Android dynamic partitions. All changes from previous patches for libavb
> in U-Boot are accounted for in this commit:
>   - commit ecc6f6bea6a2 ("libavb: Handle wrong hashtree_error_mode in
>                           avb_append_options()")
>   - commit 897a1d947e7e ("libavb: Update SPDX tag style")
>   - commit d8f9d2af96b3 ("avb2.0: add Android Verified Boot 2.0 library")
> 
> Tested on X15:
> 
>     ## Android Verified Boot 2.0 version 1.1.0
>     read_is_device_unlocked not supported yet
>     read_rollback_index not supported yet
>     read_is_device_unlocked not supported yet
>     Verification passed successfully
>     AVB verification OK.
> 
> Unit test passes:
> 
>     $ ./test/py/test.py --bd sandbox --build -k test_avb
> 
>       test/py/tests/test_android/test_avb.py ss..s.
> 
> [1] https://android.googlesource.com/platform/external/avb/+/49936b4c0109411fdd38bd4ba3a32a01c40439a9
> 
> Signed-off-by: Sam Protsenko <semen.protsenko@linaro.org>

Thanks for the efforts. I get the same result, except the following
minor difference [*]. The diff is minor and non-functional, but I
think it's worth staying closer to AOSP.

I will post my Reviewed-by signature, once this is addressed. TIA.

[*] diff --git a/lib/libavb/avb_sysdeps_posix.c b/lib/libavb/avb_sysdeps_posix.c
index 4ccf41e42834..74a37a949496 100644
--- a/lib/libavb/avb_sysdeps_posix.c
+++ b/lib/libavb/avb_sysdeps_posix.c
@@ -32,6 +32,12 @@ size_t avb_strlen(const char* str) {
   return strlen(str);
 }
 
+uint32_t avb_div_by_10(uint64_t* dividend) {
+  uint32_t rem = (uint32_t)(*dividend % 10);
+  *dividend /= 10;
+  return rem;
+}
+
 void avb_abort(void) {
   hang();
 }
@@ -58,9 +64,3 @@ void* avb_malloc_(size_t size) {
 void avb_free(void* ptr) {
   free(ptr);
 }
-
-uint32_t avb_div_by_10(uint64_t* dividend) {
-  uint32_t rem = (uint32_t)(*dividend % 10);
-  *dividend /= 10;
-  return rem;
-}

-- 
Best Regards,
Eugeniu.

^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [U-Boot] [PATCH 1/2] libavb: Update libavb to current AOSP master
  2019-08-16 10:36 ` [U-Boot] [PATCH 1/2] libavb: Update libavb to current AOSP master Eugeniu Rosca
@ 2019-08-16 10:59   ` Sam Protsenko
  2019-08-16 11:06     ` Eugeniu Rosca
  0 siblings, 1 reply; 15+ messages in thread
From: Sam Protsenko @ 2019-08-16 10:59 UTC (permalink / raw)
  To: u-boot

Hi Eugeniu,

On Fri, Aug 16, 2019 at 1:36 PM Eugeniu Rosca <erosca@de.adit-jv.com> wrote:
>
> Hi Sam,
>
> On Thu, Aug 15, 2019 at 11:04:02PM +0300, Sam Protsenko wrote:
> > Update libavb to commit 5fbb42a189aa in AOSP/master, because new version
> > has support for super partition [1], which we need for implementing
> > Android dynamic partitions. All changes from previous patches for libavb
> > in U-Boot are accounted for in this commit:
> >   - commit ecc6f6bea6a2 ("libavb: Handle wrong hashtree_error_mode in
> >                           avb_append_options()")
> >   - commit 897a1d947e7e ("libavb: Update SPDX tag style")
> >   - commit d8f9d2af96b3 ("avb2.0: add Android Verified Boot 2.0 library")
> >
> > Tested on X15:
> >
> >     ## Android Verified Boot 2.0 version 1.1.0
> >     read_is_device_unlocked not supported yet
> >     read_rollback_index not supported yet
> >     read_is_device_unlocked not supported yet
> >     Verification passed successfully
> >     AVB verification OK.
> >
> > Unit test passes:
> >
> >     $ ./test/py/test.py --bd sandbox --build -k test_avb
> >
> >       test/py/tests/test_android/test_avb.py ss..s.
> >
> > [1] https://android.googlesource.com/platform/external/avb/+/49936b4c0109411fdd38bd4ba3a32a01c40439a9
> >
> > Signed-off-by: Sam Protsenko <semen.protsenko@linaro.org>
>
> Thanks for the efforts. I get the same result, except the following
> minor difference [*]. The diff is minor and non-functional, but I
> think it's worth staying closer to AOSP.
>

I've used most recent commit on master branch of external/avb project
of AOSP, and I can see that avb_div_by_10() is sitting in the end of
file: [1]. Not sure why you have different result... Are you looking
to different branch/commit perhaps?

[1] https://android.googlesource.com/platform/external/avb/+/5fbb42a189aabb9a0bb5c3a8df89c9baf828a0d1/libavb/avb_sysdeps_posix.c#84

> I will post my Reviewed-by signature, once this is addressed. TIA.
>
> [*] diff --git a/lib/libavb/avb_sysdeps_posix.c b/lib/libavb/avb_sysdeps_posix.c
> index 4ccf41e42834..74a37a949496 100644
> --- a/lib/libavb/avb_sysdeps_posix.c
> +++ b/lib/libavb/avb_sysdeps_posix.c
> @@ -32,6 +32,12 @@ size_t avb_strlen(const char* str) {
>    return strlen(str);
>  }
>
> +uint32_t avb_div_by_10(uint64_t* dividend) {
> +  uint32_t rem = (uint32_t)(*dividend % 10);
> +  *dividend /= 10;
> +  return rem;
> +}
> +
>  void avb_abort(void) {
>    hang();
>  }
> @@ -58,9 +64,3 @@ void* avb_malloc_(size_t size) {
>  void avb_free(void* ptr) {
>    free(ptr);
>  }
> -
> -uint32_t avb_div_by_10(uint64_t* dividend) {
> -  uint32_t rem = (uint32_t)(*dividend % 10);
> -  *dividend /= 10;
> -  return rem;
> -}
>
> --
> Best Regards,
> Eugeniu.

^ permalink raw reply	[flat|nested] 15+ messages in thread

* [U-Boot] [PATCH 1/2] libavb: Update libavb to current AOSP master
  2019-08-16 10:59   ` Sam Protsenko
@ 2019-08-16 11:06     ` Eugeniu Rosca
  0 siblings, 0 replies; 15+ messages in thread
From: Eugeniu Rosca @ 2019-08-16 11:06 UTC (permalink / raw)
  To: u-boot

On Fri, Aug 16, 2019 at 01:59:20PM +0300, Sam Protsenko wrote:
[..]
> On Fri, Aug 16, 2019 at 1:36 PM Eugeniu Rosca <erosca@de.adit-jv.com> wrote:
> > Thanks for the efforts. I get the same result, except the following
> > minor difference [*]. The diff is minor and non-functional, but I
> > think it's worth staying closer to AOSP.
> 
> I've used most recent commit on master branch of external/avb project
> of AOSP, and I can see that avb_div_by_10() is sitting in the end of
> file: [1]. Not sure why you have different result... Are you looking
> to different branch/commit perhaps?
> 
> [1] https://android.googlesource.com/platform/external/avb/+/5fbb42a189aabb9a0bb5c3a8df89c9baf828a0d1/libavb/avb_sysdeps_posix.c#84

Small amendment. Since I effectively cherry picked the AOSP commits from
AVB into U-Boot (as described in [2]), my result left the avb_div_by_10()
function *in place* (as none of the imported AOSP commits does any
change to this function). That led to the mismatch between our results.

IOW what this patch appears to do *in addition* to importing the list of
AOSP commits mentioned in [2] is repositioning the avb_div_by_10() such
that it matches the AOSP. I obviously have no concerns about that.

[2] https://patchwork.ozlabs.org/patch/1144801/#2235834

Having said that:

Reviewed-by: Eugeniu Rosca <rosca.eugeniu@gmail.com>

Thanks!

-- 
Best Regards,
Eugeniu.

^ permalink raw reply	[flat|nested] 15+ messages in thread

* [U-Boot] [PATCH 2/2] libavb: Fix build warnings after updating the lib
  2019-08-15 20:04 ` [U-Boot] [PATCH 2/2] libavb: Fix build warnings after updating the lib Sam Protsenko
@ 2019-08-16 13:35   ` Eugeniu Rosca
  2019-08-16 15:46     ` David Zeuthen
  2019-11-01 13:29   ` Tom Rini
  1 sibling, 1 reply; 15+ messages in thread
From: Eugeniu Rosca @ 2019-08-16 13:35 UTC (permalink / raw)
  To: u-boot

Hi Sam,

CC: LIBAVB people (w.r.t. libavb fixes in U-Boot)

I can reproduce the compiler warnings myself and I confirm they are
fixed with this patch. More comments below.

On Thu, Aug 15, 2019 at 11:04:03PM +0300, Sam Protsenko wrote:
> After updating libavb to most recent version from AOSP/master, two new
> warnings appear:
> 
> Warning #1:
> 
>     lib/libavb/avb_cmdline.c: In function 'avb_append_options':
>     lib/libavb/avb_cmdline.c:365:15: warning: 'dm_verity_mode' may be
>                                      used uninitialized in this function
>                                      [-Wmaybe-uninitialized]
>          new_ret = avb_replace(
>                    ^~~~~~~~~~~~
>              slot_data->cmdline, "$(ANDROID_VERITY_MODE)", dm_verity_mode);
>              ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
>     lib/libavb/avb_cmdline.c:374:8: warning: 'verity_mode' may be used
>                                     uninitialized in this function
>                                     [-Wmaybe-uninitialized]
>        if (!cmdline_append_option(
>             ^~~~~~~~~~~~~~~~~~~~~~
>                slot_data, "androidboot.veritymode", verity_mode)) {
>                ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> 
> Warning #2:
> 
>     lib/libavb/avb_slot_verify.c: In function 'avb_slot_verify':
>     lib/libavb/avb_slot_verify.c:1349:23: warning: 'ret' may be used
>                                           uninitialized in this function
>                                           [-Wmaybe-uninitialized]
>        AvbSlotVerifyResult ret;
>                            ^~~

FWIW, few of Linux commits do word-wrapping of ASCII/console dumps for
the sake of improved readability and git grepping. Recent checkpatch
versions don't warn on that.

> 
> Fix those by providing default return values to affected functions.
> 
> Signed-off-by: Sam Protsenko <semen.protsenko@linaro.org>
> ---
>  lib/libavb/avb_cmdline.c     | 3 ++-
>  lib/libavb/avb_slot_verify.c | 2 +-
>  2 files changed, 3 insertions(+), 2 deletions(-)
> 
> diff --git a/lib/libavb/avb_cmdline.c b/lib/libavb/avb_cmdline.c
> index cb5b98e423..684c512bb9 100644
> --- a/lib/libavb/avb_cmdline.c
> +++ b/lib/libavb/avb_cmdline.c
> @@ -357,7 +357,8 @@ AvbSlotVerifyResult avb_append_options(
>          // Should never get here because MANAGED_RESTART_AND_EIO is
>          // remapped by avb_manage_hashtree_error_mode().
>          avb_assert_not_reached();
> -        break;
> +        ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_ARGUMENT;
> +        goto out;

With AVB_ENABLE_DEBUG enabled, PVS-Studio reports:
lib/libavb/avb_cmdline.c	360	warn	V779 Unreachable code detected. It is possible that an error is present.

How about replacing the 'break' statement with a 'fallthrough' comment?
It shuts down the warning w/o changing the functionality.

>        default:
>          ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_ARGUMENT;
>          goto out;
> diff --git a/lib/libavb/avb_slot_verify.c b/lib/libavb/avb_slot_verify.c
> index 5d400b38aa..c0defdf9c9 100644
> --- a/lib/libavb/avb_slot_verify.c
> +++ b/lib/libavb/avb_slot_verify.c
> @@ -1346,7 +1346,7 @@ AvbSlotVerifyResult avb_slot_verify(AvbOps* ops,
>                                      AvbSlotVerifyFlags flags,
>                                      AvbHashtreeErrorMode hashtree_error_mode,
>                                      AvbSlotVerifyData** out_data) {
> -  AvbSlotVerifyResult ret;
> +  AvbSlotVerifyResult ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_ARGUMENT;

What should we do with these out-of-tree libavb fixes? IMHO they are not
specific to U-Boot and should be upstream-able. IMHO it is not healthy
to accumulate too many of them, since this will make future libavb sync
more painful.

-- 
Best Regards,
Eugeniu.

^ permalink raw reply	[flat|nested] 15+ messages in thread

* [U-Boot] [PATCH 2/2] libavb: Fix build warnings after updating the lib
  2019-08-16 13:35   ` Eugeniu Rosca
@ 2019-08-16 15:46     ` David Zeuthen
  2019-08-19  8:28       ` Eugeniu Rosca
  0 siblings, 1 reply; 15+ messages in thread
From: David Zeuthen @ 2019-08-16 15:46 UTC (permalink / raw)
  To: u-boot

Hi,

As for upstreaming libavb patches, I'd be interested in landing them
upstream... makes it easier for anyone.

Our upstream is AOSP and we use gerrit for code-review:
https://android-review.googlesource.com/q/project:platform%252Fexternal%252Favb

Here's a guide to contributing:
https://source.android.com/setup/contribute/submit-patches ... hope it's
not too painful to use the AOSP process!

Thanks,
David



On Fri, Aug 16, 2019 at 9:35 AM Eugeniu Rosca <erosca@de.adit-jv.com> wrote:

> Hi Sam,
>
> CC: LIBAVB people (w.r.t. libavb fixes in U-Boot)
>
> I can reproduce the compiler warnings myself and I confirm they are
> fixed with this patch. More comments below.
>
> On Thu, Aug 15, 2019 at 11:04:03PM +0300, Sam Protsenko wrote:
> > After updating libavb to most recent version from AOSP/master, two new
> > warnings appear:
> >
> > Warning #1:
> >
> >     lib/libavb/avb_cmdline.c: In function 'avb_append_options':
> >     lib/libavb/avb_cmdline.c:365:15: warning: 'dm_verity_mode' may be
> >                                      used uninitialized in this function
> >                                      [-Wmaybe-uninitialized]
> >          new_ret = avb_replace(
> >                    ^~~~~~~~~~~~
> >              slot_data->cmdline, "$(ANDROID_VERITY_MODE)",
> dm_verity_mode);
> >
> ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> >     lib/libavb/avb_cmdline.c:374:8: warning: 'verity_mode' may be used
> >                                     uninitialized in this function
> >                                     [-Wmaybe-uninitialized]
> >        if (!cmdline_append_option(
> >             ^~~~~~~~~~~~~~~~~~~~~~
> >                slot_data, "androidboot.veritymode", verity_mode)) {
> >                ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> >
> > Warning #2:
> >
> >     lib/libavb/avb_slot_verify.c: In function 'avb_slot_verify':
> >     lib/libavb/avb_slot_verify.c:1349:23: warning: 'ret' may be used
> >                                           uninitialized in this function
> >                                           [-Wmaybe-uninitialized]
> >        AvbSlotVerifyResult ret;
> >                            ^~~
>
> FWIW, few of Linux commits do word-wrapping of ASCII/console dumps for
> the sake of improved readability and git grepping. Recent checkpatch
> versions don't warn on that.
>
> >
> > Fix those by providing default return values to affected functions.
> >
> > Signed-off-by: Sam Protsenko <semen.protsenko@linaro.org>
> > ---
> >  lib/libavb/avb_cmdline.c     | 3 ++-
> >  lib/libavb/avb_slot_verify.c | 2 +-
> >  2 files changed, 3 insertions(+), 2 deletions(-)
> >
> > diff --git a/lib/libavb/avb_cmdline.c b/lib/libavb/avb_cmdline.c
> > index cb5b98e423..684c512bb9 100644
> > --- a/lib/libavb/avb_cmdline.c
> > +++ b/lib/libavb/avb_cmdline.c
> > @@ -357,7 +357,8 @@ AvbSlotVerifyResult avb_append_options(
> >          // Should never get here because MANAGED_RESTART_AND_EIO is
> >          // remapped by avb_manage_hashtree_error_mode().
> >          avb_assert_not_reached();
> > -        break;
> > +        ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_ARGUMENT;
> > +        goto out;
>
> With AVB_ENABLE_DEBUG enabled, PVS-Studio reports:
> lib/libavb/avb_cmdline.c        360     warn    V779 Unreachable code
> detected. It is possible that an error is present.
>
> How about replacing the 'break' statement with a 'fallthrough' comment?
> It shuts down the warning w/o changing the functionality.
>
> >        default:
> >          ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_ARGUMENT;
> >          goto out;
> > diff --git a/lib/libavb/avb_slot_verify.c b/lib/libavb/avb_slot_verify.c
> > index 5d400b38aa..c0defdf9c9 100644
> > --- a/lib/libavb/avb_slot_verify.c
> > +++ b/lib/libavb/avb_slot_verify.c
> > @@ -1346,7 +1346,7 @@ AvbSlotVerifyResult avb_slot_verify(AvbOps* ops,
> >                                      AvbSlotVerifyFlags flags,
> >                                      AvbHashtreeErrorMode
> hashtree_error_mode,
> >                                      AvbSlotVerifyData** out_data) {
> > -  AvbSlotVerifyResult ret;
> > +  AvbSlotVerifyResult ret =
> AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_ARGUMENT;
>
> What should we do with these out-of-tree libavb fixes? IMHO they are not
> specific to U-Boot and should be upstream-able. IMHO it is not healthy
> to accumulate too many of them, since this will make future libavb sync
> more painful.
>
> --
> Best Regards,
> Eugeniu.
>


-- 

David Zeuthen |  zeuthen at google.com |
 Google
| Android Hardware-Backed Security

^ permalink raw reply	[flat|nested] 15+ messages in thread

* [U-Boot] [PATCH 2/2] libavb: Fix build warnings after updating the lib
  2019-08-16 15:46     ` David Zeuthen
@ 2019-08-19  8:28       ` Eugeniu Rosca
  2019-08-19  9:40         ` Igor Opaniuk
  2019-08-19 15:59         ` Tom Rini
  0 siblings, 2 replies; 15+ messages in thread
From: Eugeniu Rosca @ 2019-08-19  8:28 UTC (permalink / raw)
  To: u-boot

Hi all,

On Fri, Aug 16, 2019 at 11:46:03AM -0400, David Zeuthen wrote:
>    Hi,
>    As for upstreaming libavb patches, I'd be interested in landing them
>    upstream... makes it easier for anyone.
>    Our upstream is AOSP and we use gerrit for
>    code-review: https://android-review.googlesource.com/q/project:platform%252Fexternal%252Favb
>    Here's a guide to
>    contributing: https://source.android.com/setup/contribute/submit-patches ...
>    hope it's not too painful to use the AOSP process!
>    Thanks,
>    David

David, thanks for being open about discussing/accepting the fixes.

U-Boot folks,

What's your opinion w.r.t. the right/best order between accepting
the libavb fixes locally in U-Boot and pushing them to upstream?
Which should come first? I suppose they can be first applied internally
and replaced later on if they get reworked/optimized during upstreaming.

-- 
Best Regards,
Eugeniu.

^ permalink raw reply	[flat|nested] 15+ messages in thread

* [U-Boot] [PATCH 2/2] libavb: Fix build warnings after updating the lib
  2019-08-19  8:28       ` Eugeniu Rosca
@ 2019-08-19  9:40         ` Igor Opaniuk
  2019-08-19  9:50           ` Igor Opaniuk
  2019-08-20  2:33           ` Bowgo Tsai
  2019-08-19 15:59         ` Tom Rini
  1 sibling, 2 replies; 15+ messages in thread
From: Igor Opaniuk @ 2019-08-19  9:40 UTC (permalink / raw)
  To: u-boot

Hi Eugeniu,

On Mon, Aug 19, 2019 at 11:28 AM Eugeniu Rosca <erosca@de.adit-jv.com> wrote:
>
> Hi all,
>
> On Fri, Aug 16, 2019 at 11:46:03AM -0400, David Zeuthen wrote:
> >    Hi,
> >    As for upstreaming libavb patches, I'd be interested in landing them
> >    upstream... makes it easier for anyone.
> >    Our upstream is AOSP and we use gerrit for
> >    code-review: https://android-review.googlesource.com/q/project:platform%252Fexternal%252Favb
> >    Here's a guide to
> >    contributing: https://source.android.com/setup/contribute/submit-patches ...
> >    hope it's not too painful to use the AOSP process!
> >    Thanks,
> >    David
>
> David, thanks for being open about discussing/accepting the fixes.
>
> U-Boot folks,
>
> What's your opinion w.r.t. the right/best order between accepting
> the libavb fixes locally in U-Boot and pushing them to upstream?
> Which should come first? I suppose they can be first applied internally
> and replaced later on if they get reworked/optimized during upstreaming.
>
> --
> Best Regards,
> Eugeniu.

IMHO, the best approach here is to upstream fixes to AOSP libavb first,
only then port stuff to U-boot.

Nevertheless, taking into account the amount of time needed
(sometimes it can take months, or even years, Sam has good
stories about that) to get something applied to AOSP, I would suggest
to proceed internally with commits like this ASAP, but somehow (extended
commit message for each "libavb sync" patch with the list of patches out of
AOSP tree; or introduce "doc/android/libavb-porting.txt", where we can
provide all details about list of commits from AOSP + out-of-tree commits,
how-to do porting etc; other ideas?) keep track of changes that are not
up-streamed to AOSP yet.

Ideally we have to achieve 1:1 mapping (with the only difference - SPDX tags),
of [1] in lib/libavb/, otherwise we will fight with constant code
divergence (obviously).

[1] https://android.googlesource.com/platform/external/avb/+/<revision>/libavb

--
Best regards - Freundliche Grüsse - Meilleures salutations

Igor Opaniuk

mailto: igor.opaniuk at gmail.com
skype: igor.opanyuk
+380 (93) 836 40 67
http://ua.linkedin.com/in/iopaniuk

^ permalink raw reply	[flat|nested] 15+ messages in thread

* [U-Boot] [PATCH 2/2] libavb: Fix build warnings after updating the lib
  2019-08-19  9:40         ` Igor Opaniuk
@ 2019-08-19  9:50           ` Igor Opaniuk
  2019-08-20  2:33           ` Bowgo Tsai
  1 sibling, 0 replies; 15+ messages in thread
From: Igor Opaniuk @ 2019-08-19  9:50 UTC (permalink / raw)
  To: u-boot

On Mon, Aug 19, 2019 at 12:40 PM Igor Opaniuk <igor.opaniuk@gmail.com> wrote:
>
> Hi Eugeniu,
>
> On Mon, Aug 19, 2019 at 11:28 AM Eugeniu Rosca <erosca@de.adit-jv.com> wrote:
> >
> > Hi all,
> >
> > On Fri, Aug 16, 2019 at 11:46:03AM -0400, David Zeuthen wrote:
> > >    Hi,
> > >    As for upstreaming libavb patches, I'd be interested in landing them
> > >    upstream... makes it easier for anyone.
> > >    Our upstream is AOSP and we use gerrit for
> > >    code-review: https://android-review.googlesource.com/q/project:platform%252Fexternal%252Favb
> > >    Here's a guide to
> > >    contributing: https://source.android.com/setup/contribute/submit-patches ...
> > >    hope it's not too painful to use the AOSP process!
> > >    Thanks,
> > >    David
> >
> > David, thanks for being open about discussing/accepting the fixes.
> >
> > U-Boot folks,
> >
> > What's your opinion w.r.t. the right/best order between accepting
> > the libavb fixes locally in U-Boot and pushing them to upstream?
> > Which should come first? I suppose they can be first applied internally
> > and replaced later on if they get reworked/optimized during upstreaming.
> >
> > --
> > Best Regards,
> > Eugeniu.
>
> IMHO, the best approach here is to upstream fixes to AOSP libavb first,
> only then port stuff to U-boot.
>
> Nevertheless, taking into account the amount of time needed
> (sometimes it can take months, or even years, Sam has good
> stories about that) to get something applied to AOSP, I would suggest
> to proceed internally with commits like this ASAP, but somehow (extended
> commit message for each "libavb sync" patch with the list of patches out of
> AOSP tree; or introduce "doc/android/libavb-porting.txt", where we can
> provide all details about list of commits from AOSP + out-of-tree commits,
> how-to do porting etc; other ideas?) keep track of changes that are not
> up-streamed to AOSP yet.
>
> Ideally we have to achieve 1:1 mapping (with the only difference - SPDX tags),

And avb_sysdeps_posix.c (implementation of avb_abort() and list of includes).
You see, I'm already missing some of introduced changes on top of
"vanilla" libavb.

> of [1] in lib/libavb/, otherwise we will fight with constant code
> divergence (obviously).
>
> [1] https://android.googlesource.com/platform/external/avb/+/<revision>/libavb
>
> --
> Best regards - Freundliche Grüsse - Meilleures salutations
>
> Igor Opaniuk
>
> mailto: igor.opaniuk at gmail.com
> skype: igor.opanyuk
> +380 (93) 836 40 67
> http://ua.linkedin.com/in/iopaniuk



-- 
Best regards - Freundliche Grüsse - Meilleures salutations

Igor Opaniuk

mailto: igor.opaniuk at gmail.com
skype: igor.opanyuk
+380 (93) 836 40 67
http://ua.linkedin.com/in/iopaniuk

^ permalink raw reply	[flat|nested] 15+ messages in thread

* [U-Boot] [PATCH 2/2] libavb: Fix build warnings after updating the lib
  2019-08-19  8:28       ` Eugeniu Rosca
  2019-08-19  9:40         ` Igor Opaniuk
@ 2019-08-19 15:59         ` Tom Rini
  1 sibling, 0 replies; 15+ messages in thread
From: Tom Rini @ 2019-08-19 15:59 UTC (permalink / raw)
  To: u-boot

On Mon, Aug 19, 2019 at 10:28:41AM +0200, Eugeniu Rosca wrote:
> Hi all,
> 
> On Fri, Aug 16, 2019 at 11:46:03AM -0400, David Zeuthen wrote:
> >    Hi,
> >    As for upstreaming libavb patches, I'd be interested in landing them
> >    upstream... makes it easier for anyone.
> >    Our upstream is AOSP and we use gerrit for
> >    code-review: https://android-review.googlesource.com/q/project:platform%252Fexternal%252Favb
> >    Here's a guide to
> >    contributing: https://source.android.com/setup/contribute/submit-patches ...
> >    hope it's not too painful to use the AOSP process!
> >    Thanks,
> >    David
> 
> David, thanks for being open about discussing/accepting the fixes.
> 
> U-Boot folks,
> 
> What's your opinion w.r.t. the right/best order between accepting
> the libavb fixes locally in U-Boot and pushing them to upstream?
> Which should come first? I suppose they can be first applied internally
> and replaced later on if they get reworked/optimized during upstreaming.

I think we certainly need to submit the changes upstream first, and then
keep our changes in-sync with any feedback we get from upstream.  This
is just like how we handle DTS changes too.

-- 
Tom
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 819 bytes
Desc: not available
URL: <http://lists.denx.de/pipermail/u-boot/attachments/20190819/4d73da90/attachment.sig>

^ permalink raw reply	[flat|nested] 15+ messages in thread

* [U-Boot] [PATCH 2/2] libavb: Fix build warnings after updating the lib
  2019-08-19  9:40         ` Igor Opaniuk
  2019-08-19  9:50           ` Igor Opaniuk
@ 2019-08-20  2:33           ` Bowgo Tsai
  1 sibling, 0 replies; 15+ messages in thread
From: Bowgo Tsai @ 2019-08-20  2:33 UTC (permalink / raw)
  To: u-boot

Hi,

Just to re: > taking into account the amount of time needed
(sometimes it can take months, or even years, Sam has good
stories about that) to get something applied to AOSP

This probably needs to be discussed case by case, as there are ~750 project
<https://android.googlesource.com/platform/manifest/+/refs/heads/master/default.xml>s
on AOSP now. For large changes, it might be helpful to start by a buganizer
or e-mail thread, to reach a consensus with individual owners.

For small changes (e.g., fix some code health issue), the review should be
just a few days or a few weeks.


On Mon, Aug 19, 2019 at 5:40 PM Igor Opaniuk <igor.opaniuk@gmail.com> wrote:

> Hi Eugeniu,
>
> On Mon, Aug 19, 2019 at 11:28 AM Eugeniu Rosca <erosca@de.adit-jv.com>
> wrote:
> >
> > Hi all,
> >
> > On Fri, Aug 16, 2019 at 11:46:03AM -0400, David Zeuthen wrote:
> > >    Hi,
> > >    As for upstreaming libavb patches, I'd be interested in landing them
> > >    upstream... makes it easier for anyone.
> > >    Our upstream is AOSP and we use gerrit for
> > >    code-review:
> https://android-review.googlesource.com/q/project:platform%252Fexternal%252Favb
> > >    Here's a guide to
> > >    contributing:
> https://source.android.com/setup/contribute/submit-patches ...
> > >    hope it's not too painful to use the AOSP process!
> > >    Thanks,
> > >    David
> >
> > David, thanks for being open about discussing/accepting the fixes.
> >
> > U-Boot folks,
> >
> > What's your opinion w.r.t. the right/best order between accepting
> > the libavb fixes locally in U-Boot and pushing them to upstream?
> > Which should come first? I suppose they can be first applied internally
> > and replaced later on if they get reworked/optimized during upstreaming.
> >
> > --
> > Best Regards,
> > Eugeniu.
>
> IMHO, the best approach here is to upstream fixes to AOSP libavb first,
> only then port stuff to U-boot.
>
> Nevertheless, taking into account the amount of time needed
> (sometimes it can take months, or even years, Sam has good
> stories about that) to get something applied to AOSP, I would suggest
> to proceed internally with commits like this ASAP, but somehow (extended
> commit message for each "libavb sync" patch with the list of patches out of
> AOSP tree; or introduce "doc/android/libavb-porting.txt", where we can
> provide all details about list of commits from AOSP + out-of-tree commits,
> how-to do porting etc; other ideas?) keep track of changes that are not
> up-streamed to AOSP yet.
>
> Ideally we have to achieve 1:1 mapping (with the only difference - SPDX
> tags),
> of [1] in lib/libavb/, otherwise we will fight with constant code
> divergence (obviously).
>
> [1] https://android.googlesource.com/platform/external/avb/+/
> <revision>/libavb
>
> --
> Best regards - Freundliche Grüsse - Meilleures salutations
>
> Igor Opaniuk
>
> mailto: igor.opaniuk at gmail.com
> skype: igor.opanyuk
> +380 (93) 836 40 67
> http://ua.linkedin.com/in/iopaniuk
>


-- 

Bowgo Tsai |  Engineer |  bowgotsai at google.com |  +886 (2) 8729-6364
<%2B886287296364>

^ permalink raw reply	[flat|nested] 15+ messages in thread

* [U-Boot] [PATCH 1/2] libavb: Update libavb to current AOSP master
  2019-08-15 20:04 [U-Boot] [PATCH 1/2] libavb: Update libavb to current AOSP master Sam Protsenko
  2019-08-15 20:04 ` [U-Boot] [PATCH 2/2] libavb: Fix build warnings after updating the lib Sam Protsenko
  2019-08-16 10:36 ` [U-Boot] [PATCH 1/2] libavb: Update libavb to current AOSP master Eugeniu Rosca
@ 2019-10-16  9:32 ` Igor Opaniuk
  2019-11-01 13:29 ` Tom Rini
  3 siblings, 0 replies; 15+ messages in thread
From: Igor Opaniuk @ 2019-10-16  9:32 UTC (permalink / raw)
  To: u-boot

Hi Sam,

On Thu, Aug 15, 2019 at 11:04 PM Sam Protsenko
<semen.protsenko@linaro.org> wrote:
>
> Update libavb to commit 5fbb42a189aa in AOSP/master, because new version
> has support for super partition [1], which we need for implementing
> Android dynamic partitions. All changes from previous patches for libavb
> in U-Boot are accounted for in this commit:
>   - commit ecc6f6bea6a2 ("libavb: Handle wrong hashtree_error_mode in
>                           avb_append_options()")
>   - commit 897a1d947e7e ("libavb: Update SPDX tag style")
>   - commit d8f9d2af96b3 ("avb2.0: add Android Verified Boot 2.0 library")
>
> Tested on X15:
>
>     ## Android Verified Boot 2.0 version 1.1.0
>     read_is_device_unlocked not supported yet
>     read_rollback_index not supported yet
>     read_is_device_unlocked not supported yet
>     Verification passed successfully
>     AVB verification OK.
>
> Unit test passes:
>
>     $ ./test/py/test.py --bd sandbox --build -k test_avb
>
>       test/py/tests/test_android/test_avb.py ss..s.
>
> [1] https://android.googlesource.com/platform/external/avb/+/49936b4c0109411fdd38bd4ba3a32a01c40439a9
>
> Signed-off-by: Sam Protsenko <semen.protsenko@linaro.org>
> ---
>  lib/libavb/avb_cmdline.c       |  52 ++-
>  lib/libavb/avb_cmdline.h       |   4 +-
>  lib/libavb/avb_descriptor.c    |  11 +-
>  lib/libavb/avb_ops.h           |  41 ++-
>  lib/libavb/avb_sha.h           |  12 +-
>  lib/libavb/avb_sha256.c        |  36 +-
>  lib/libavb/avb_sha512.c        |  22 +-
>  lib/libavb/avb_slot_verify.c   | 652 +++++++++++++++++++++++++--------
>  lib/libavb/avb_slot_verify.h   |  59 ++-
>  lib/libavb/avb_sysdeps.h       |   8 +
>  lib/libavb/avb_sysdeps_posix.c |  16 +-
>  lib/libavb/avb_vbmeta_image.c  |  11 +-
>  12 files changed, 710 insertions(+), 214 deletions(-)
>
> diff --git a/lib/libavb/avb_cmdline.c b/lib/libavb/avb_cmdline.c
> index d246699272..cb5b98e423 100644
> --- a/lib/libavb/avb_cmdline.c
> +++ b/lib/libavb/avb_cmdline.c
> @@ -39,6 +39,14 @@ char* avb_sub_cmdline(AvbOps* ops,
>      char part_name[AVB_PART_NAME_MAX_SIZE];
>      char guid_buf[37];
>
> +    /* Don't attempt to query the partition guid unless its search string is
> +     * present in the command line. Note: the original cmdline is used here,
> +     * not the replaced one. See b/116010959.
> +     */
> +    if (avb_strstr(cmdline, replace_str[n]) == NULL) {
> +      continue;
> +    }
> +
>      if (!avb_str_concat(part_name,
>                          sizeof part_name,
>                          part_name_str[n],
> @@ -70,7 +78,15 @@ char* avb_sub_cmdline(AvbOps* ops,
>      }
>    }
>
> -  avb_assert(ret != NULL);
> +  /* It's possible there is no _PARTUUID for replacement above.
> +   * Duplicate cmdline to ret for additional substitutions below.
> +   */
> +  if (ret == NULL) {
> +    ret = avb_strdup(cmdline);
> +    if (ret == NULL) {
> +      goto fail;
> +    }
> +  }
>
>    /* Replace any additional substitutions. */
>    if (additional_substitutions != NULL) {
> @@ -198,21 +214,27 @@ static int cmdline_append_hex(AvbSlotVerifyData* slot_data,
>
>  AvbSlotVerifyResult avb_append_options(
>      AvbOps* ops,
> +    AvbSlotVerifyFlags flags,
>      AvbSlotVerifyData* slot_data,
>      AvbVBMetaImageHeader* toplevel_vbmeta,
>      AvbAlgorithmType algorithm_type,
> -    AvbHashtreeErrorMode hashtree_error_mode) {
> +    AvbHashtreeErrorMode hashtree_error_mode,
> +    AvbHashtreeErrorMode resolved_hashtree_error_mode) {
>    AvbSlotVerifyResult ret;
>    const char* verity_mode;
>    bool is_device_unlocked;
>    AvbIOResult io_ret;
>
> -  /* Add androidboot.vbmeta.device option. */
> -  if (!cmdline_append_option(slot_data,
> -                             "androidboot.vbmeta.device",
> -                             "PARTUUID=$(ANDROID_VBMETA_PARTUUID)")) {
> -    ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
> -    goto out;
> +  /* Add androidboot.vbmeta.device option... except if not using a vbmeta
> +   * partition since it doesn't make sense in that case.
> +   */
> +  if (!(flags & AVB_SLOT_VERIFY_FLAGS_NO_VBMETA_PARTITION)) {
> +    if (!cmdline_append_option(slot_data,
> +                               "androidboot.vbmeta.device",
> +                               "PARTUUID=$(ANDROID_VBMETA_PARTUUID)")) {
> +      ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
> +      goto out;
> +    }
>    }
>
>    /* Add androidboot.vbmeta.avb_version option. */
> @@ -304,7 +326,7 @@ AvbSlotVerifyResult avb_append_options(
>      const char* dm_verity_mode;
>      char* new_ret;
>
> -    switch (hashtree_error_mode) {
> +    switch (resolved_hashtree_error_mode) {
>        case AVB_HASHTREE_ERROR_MODE_RESTART_AND_INVALIDATE:
>          if (!cmdline_append_option(
>                  slot_data, "androidboot.vbmeta.invalidate_on_error", "yes")) {
> @@ -331,6 +353,11 @@ AvbSlotVerifyResult avb_append_options(
>          verity_mode = "logging";
>          dm_verity_mode = "ignore_corruption";
>          break;
> +      case AVB_HASHTREE_ERROR_MODE_MANAGED_RESTART_AND_EIO:
> +        // Should never get here because MANAGED_RESTART_AND_EIO is
> +        // remapped by avb_manage_hashtree_error_mode().
> +        avb_assert_not_reached();
> +        break;
>        default:
>          ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_ARGUMENT;
>          goto out;
> @@ -349,6 +376,13 @@ AvbSlotVerifyResult avb_append_options(
>      ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
>      goto out;
>    }
> +  if (hashtree_error_mode == AVB_HASHTREE_ERROR_MODE_MANAGED_RESTART_AND_EIO) {
> +    if (!cmdline_append_option(
> +            slot_data, "androidboot.veritymode.managed", "yes")) {
> +      ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
> +      goto out;
> +    }
> +  }
>
>    ret = AVB_SLOT_VERIFY_RESULT_OK;
>
> diff --git a/lib/libavb/avb_cmdline.h b/lib/libavb/avb_cmdline.h
> index 9af3a99994..96539d84bd 100644
> --- a/lib/libavb/avb_cmdline.h
> +++ b/lib/libavb/avb_cmdline.h
> @@ -43,10 +43,12 @@ char* avb_sub_cmdline(AvbOps* ops,
>
>  AvbSlotVerifyResult avb_append_options(
>      AvbOps* ops,
> +    AvbSlotVerifyFlags flags,
>      AvbSlotVerifyData* slot_data,
>      AvbVBMetaImageHeader* toplevel_vbmeta,
>      AvbAlgorithmType algorithm_type,
> -    AvbHashtreeErrorMode hashtree_error_mode);
> +    AvbHashtreeErrorMode hashtree_error_mode,
> +    AvbHashtreeErrorMode resolved_hashtree_error_mode);
>
>  /* Allocates and initializes a new command line substitution list. Free with
>   * |avb_free_cmdline_subst_list|.
> diff --git a/lib/libavb/avb_descriptor.c b/lib/libavb/avb_descriptor.c
> index fb0b305f2c..9f03b9777a 100644
> --- a/lib/libavb/avb_descriptor.c
> +++ b/lib/libavb/avb_descriptor.c
> @@ -72,7 +72,11 @@ bool avb_descriptor_foreach(const uint8_t* image_data,
>      const AvbDescriptor* dh = (const AvbDescriptor*)p;
>      avb_assert_aligned(dh);
>      uint64_t nb_following = avb_be64toh(dh->num_bytes_following);
> -    uint64_t nb_total = sizeof(AvbDescriptor) + nb_following;
> +    uint64_t nb_total = 0;
> +    if (!avb_safe_add(&nb_total, sizeof(AvbDescriptor), nb_following)) {
> +      avb_error("Invalid descriptor length.\n");
> +      goto out;
> +    }
>
>      if ((nb_total & 7) != 0) {
>        avb_error("Invalid descriptor length.\n");
> @@ -88,7 +92,10 @@ bool avb_descriptor_foreach(const uint8_t* image_data,
>        goto out;
>      }
>
> -    p += nb_total;
> +    if (!avb_safe_add_to((uint64_t*)(&p), nb_total)) {
> +      avb_error("Invalid descriptor length.\n");
> +      goto out;
> +    }
>    }
>
>    ret = true;
> diff --git a/lib/libavb/avb_ops.h b/lib/libavb/avb_ops.h
> index 8bbdc7c31b..6a5c589da8 100644
> --- a/lib/libavb/avb_ops.h
> +++ b/lib/libavb/avb_ops.h
> @@ -18,6 +18,7 @@ extern "C" {
>
>  /* Well-known names of named persistent values. */
>  #define AVB_NPV_PERSISTENT_DIGEST_PREFIX "avb.persistent_digest."
> +#define AVB_NPV_MANAGED_VERITY_MODE "avb.managed_verity_mode"
>
>  /* Return codes used for I/O operations.
>   *
> @@ -171,6 +172,10 @@ struct AvbOps {
>     *
>     * If AVB_IO_RESULT_OK is returned then |out_is_trusted| is set -
>     * true if trusted or false if untrusted.
> +   *
> +   * NOTE: If AVB_SLOT_VERIFY_FLAGS_NO_VBMETA_PARTITION is passed to
> +   * avb_slot_verify() then this operation is never used. Instead, the
> +   * validate_public_key_for_partition() operation is used
>     */
>    AvbIOResult (*validate_vbmeta_public_key)(AvbOps* ops,
>                                              const uint8_t* public_key_data,
> @@ -231,6 +236,9 @@ struct AvbOps {
>     * (NUL-terminated UTF-8 string). Returns the value in
>     * |out_size_num_bytes|.
>     *
> +   * If the partition doesn't exist the AVB_IO_RESULT_ERROR_NO_SUCH_PARTITION
> +   * error code should be returned.
> +   *
>     * Returns AVB_IO_RESULT_OK on success, otherwise an error code.
>     */
>    AvbIOResult (*get_size_of_partition)(AvbOps* ops,
> @@ -253,9 +261,10 @@ struct AvbOps {
>     * AVB_IO_RESULT_ERROR_NO_SUCH_VALUE. If |buffer_size| is smaller than the
>     * size of the stored value, returns AVB_IO_RESULT_ERROR_INSUFFICIENT_SPACE.
>     *
> -   * This operation is currently only used to support persistent digests. If a
> -   * device does not use persistent digests this function pointer can be set to
> -   * NULL.
> +   * This operation is currently only used to support persistent digests or the
> +   * AVB_HASHTREE_ERROR_MODE_MANAGED_RESTART_AND_EIO hashtree error mode. If a
> +   * device does not use one of these features this function pointer can be set
> +   * to NULL.
>     */
>    AvbIOResult (*read_persistent_value)(AvbOps* ops,
>                                         const char* name,
> @@ -275,14 +284,34 @@ struct AvbOps {
>     * AVB_IO_RESULT_ERROR_NO_SUCH_VALUE. If the |value_size| is not supported,
>     * returns AVB_IO_RESULT_ERROR_INVALID_VALUE_SIZE.
>     *
> -   * This operation is currently only used to support persistent digests. If a
> -   * device does not use persistent digests this function pointer can be set to
> -   * NULL.
> +   * This operation is currently only used to support persistent digests or the
> +   * AVB_HASHTREE_ERROR_MODE_MANAGED_RESTART_AND_EIO hashtree error mode. If a
> +   * device does not use one of these features this function pointer can be set
> +   * to NULL.
>     */
>    AvbIOResult (*write_persistent_value)(AvbOps* ops,
>                                          const char* name,
>                                          size_t value_size,
>                                          const uint8_t* value);
> +
> +  /* Like validate_vbmeta_public_key() but for when the flag
> +   * AVB_SLOT_VERIFY_FLAGS_NO_VBMETA_PARTITION is being used. The name of the
> +   * partition to get the public key for is passed in |partition_name|.
> +   *
> +   * Also returns the rollback index location to use for the partition, in
> +   * |out_rollback_index_location|.
> +   *
> +   * Returns AVB_IO_RESULT_OK on success, otherwise an error code.
> +   */
> +  AvbIOResult (*validate_public_key_for_partition)(
> +      AvbOps* ops,
> +      const char* partition,
> +      const uint8_t* public_key_data,
> +      size_t public_key_length,
> +      const uint8_t* public_key_metadata,
> +      size_t public_key_metadata_length,
> +      bool* out_is_trusted,
> +      uint32_t* out_rollback_index_location);
>  };
>
>  #ifdef __cplusplus
> diff --git a/lib/libavb/avb_sha.h b/lib/libavb/avb_sha.h
> index 365aaadc2f..f5d02e09f2 100644
> --- a/lib/libavb/avb_sha.h
> +++ b/lib/libavb/avb_sha.h
> @@ -31,8 +31,8 @@ extern "C" {
>  /* Data structure used for SHA-256. */
>  typedef struct {
>    uint32_t h[8];
> -  uint32_t tot_len;
> -  uint32_t len;
> +  uint64_t tot_len;
> +  size_t len;
>    uint8_t block[2 * AVB_SHA256_BLOCK_SIZE];
>    uint8_t buf[AVB_SHA256_DIGEST_SIZE]; /* Used for storing the final digest. */
>  } AvbSHA256Ctx;
> @@ -40,8 +40,8 @@ typedef struct {
>  /* Data structure used for SHA-512. */
>  typedef struct {
>    uint64_t h[8];
> -  uint32_t tot_len;
> -  uint32_t len;
> +  uint64_t tot_len;
> +  size_t len;
>    uint8_t block[2 * AVB_SHA512_BLOCK_SIZE];
>    uint8_t buf[AVB_SHA512_DIGEST_SIZE]; /* Used for storing the final digest. */
>  } AvbSHA512Ctx;
> @@ -50,7 +50,7 @@ typedef struct {
>  void avb_sha256_init(AvbSHA256Ctx* ctx);
>
>  /* Updates the SHA-256 context with |len| bytes from |data|. */
> -void avb_sha256_update(AvbSHA256Ctx* ctx, const uint8_t* data, uint32_t len);
> +void avb_sha256_update(AvbSHA256Ctx* ctx, const uint8_t* data, size_t len);
>
>  /* Returns the SHA-256 digest. */
>  uint8_t* avb_sha256_final(AvbSHA256Ctx* ctx) AVB_ATTR_WARN_UNUSED_RESULT;
> @@ -59,7 +59,7 @@ uint8_t* avb_sha256_final(AvbSHA256Ctx* ctx) AVB_ATTR_WARN_UNUSED_RESULT;
>  void avb_sha512_init(AvbSHA512Ctx* ctx);
>
>  /* Updates the SHA-512 context with |len| bytes from |data|. */
> -void avb_sha512_update(AvbSHA512Ctx* ctx, const uint8_t* data, uint32_t len);
> +void avb_sha512_update(AvbSHA512Ctx* ctx, const uint8_t* data, size_t len);
>
>  /* Returns the SHA-512 digest. */
>  uint8_t* avb_sha512_final(AvbSHA512Ctx* ctx) AVB_ATTR_WARN_UNUSED_RESULT;
> diff --git a/lib/libavb/avb_sha256.c b/lib/libavb/avb_sha256.c
> index d24c7015f6..86ecca57b7 100644
> --- a/lib/libavb/avb_sha256.c
> +++ b/lib/libavb/avb_sha256.c
> @@ -29,6 +29,18 @@
>      *((str) + 0) = (uint8_t)((x) >> 24); \
>    }
>
> +#define UNPACK64(x, str)                         \
> +  {                                              \
> +    *((str) + 7) = (uint8_t)x;                   \
> +    *((str) + 6) = (uint8_t)((uint64_t)x >> 8);  \
> +    *((str) + 5) = (uint8_t)((uint64_t)x >> 16); \
> +    *((str) + 4) = (uint8_t)((uint64_t)x >> 24); \
> +    *((str) + 3) = (uint8_t)((uint64_t)x >> 32); \
> +    *((str) + 2) = (uint8_t)((uint64_t)x >> 40); \
> +    *((str) + 1) = (uint8_t)((uint64_t)x >> 48); \
> +    *((str) + 0) = (uint8_t)((uint64_t)x >> 56); \
> +  }
> +
>  #define PACK32(str, x)                                                    \
>    {                                                                       \
>      *(x) = ((uint32_t) * ((str) + 3)) | ((uint32_t) * ((str) + 2) << 8) | \
> @@ -96,18 +108,18 @@ void avb_sha256_init(AvbSHA256Ctx* ctx) {
>
>  static void SHA256_transform(AvbSHA256Ctx* ctx,
>                               const uint8_t* message,
> -                             unsigned int block_nb) {
> +                             size_t block_nb) {
>    uint32_t w[64];
>    uint32_t wv[8];
>    uint32_t t1, t2;
>    const unsigned char* sub_block;
> -  int i;
> +  size_t i;
>
>  #ifndef UNROLL_LOOPS
> -  int j;
> +  size_t j;
>  #endif
>
> -  for (i = 0; i < (int)block_nb; i++) {
> +  for (i = 0; i < block_nb; i++) {
>      sub_block = message + (i << 6);
>
>  #ifndef UNROLL_LOOPS
> @@ -293,9 +305,9 @@ static void SHA256_transform(AvbSHA256Ctx* ctx,
>    }
>  }
>
> -void avb_sha256_update(AvbSHA256Ctx* ctx, const uint8_t* data, uint32_t len) {
> -  unsigned int block_nb;
> -  unsigned int new_len, rem_len, tmp_len;
> +void avb_sha256_update(AvbSHA256Ctx* ctx, const uint8_t* data, size_t len) {
> +  size_t block_nb;
> +  size_t new_len, rem_len, tmp_len;
>    const uint8_t* shifted_data;
>
>    tmp_len = AVB_SHA256_BLOCK_SIZE - ctx->len;
> @@ -325,11 +337,11 @@ void avb_sha256_update(AvbSHA256Ctx* ctx, const uint8_t* data, uint32_t len) {
>  }
>
>  uint8_t* avb_sha256_final(AvbSHA256Ctx* ctx) {
> -  unsigned int block_nb;
> -  unsigned int pm_len;
> -  unsigned int len_b;
> +  size_t block_nb;
> +  size_t pm_len;
> +  uint64_t len_b;
>  #ifndef UNROLL_LOOPS
> -  int i;
> +  size_t i;
>  #endif
>
>    block_nb =
> @@ -340,7 +352,7 @@ uint8_t* avb_sha256_final(AvbSHA256Ctx* ctx) {
>
>    avb_memset(ctx->block + ctx->len, 0, pm_len - ctx->len);
>    ctx->block[ctx->len] = 0x80;
> -  UNPACK32(len_b, ctx->block + pm_len - 4);
> +  UNPACK64(len_b, ctx->block + pm_len - 8);
>
>    SHA256_transform(ctx, ctx->block, block_nb);
>
> diff --git a/lib/libavb/avb_sha512.c b/lib/libavb/avb_sha512.c
> index a5e7297aa7..b19054fc74 100644
> --- a/lib/libavb/avb_sha512.c
> +++ b/lib/libavb/avb_sha512.c
> @@ -127,14 +127,14 @@ void avb_sha512_init(AvbSHA512Ctx* ctx) {
>
>  static void SHA512_transform(AvbSHA512Ctx* ctx,
>                               const uint8_t* message,
> -                             unsigned int block_nb) {
> +                             size_t block_nb) {
>    uint64_t w[80];
>    uint64_t wv[8];
>    uint64_t t1, t2;
>    const uint8_t* sub_block;
> -  int i, j;
> +  size_t i, j;
>
> -  for (i = 0; i < (int)block_nb; i++) {
> +  for (i = 0; i < block_nb; i++) {
>      sub_block = message + (i << 7);
>
>  #ifdef UNROLL_LOOPS_SHA512
> @@ -291,9 +291,9 @@ static void SHA512_transform(AvbSHA512Ctx* ctx,
>    }
>  }
>
> -void avb_sha512_update(AvbSHA512Ctx* ctx, const uint8_t* data, uint32_t len) {
> -  unsigned int block_nb;
> -  unsigned int new_len, rem_len, tmp_len;
> +void avb_sha512_update(AvbSHA512Ctx* ctx, const uint8_t* data, size_t len) {
> +  size_t block_nb;
> +  size_t new_len, rem_len, tmp_len;
>    const uint8_t* shifted_data;
>
>    tmp_len = AVB_SHA512_BLOCK_SIZE - ctx->len;
> @@ -323,12 +323,12 @@ void avb_sha512_update(AvbSHA512Ctx* ctx, const uint8_t* data, uint32_t len) {
>  }
>
>  uint8_t* avb_sha512_final(AvbSHA512Ctx* ctx) {
> -  unsigned int block_nb;
> -  unsigned int pm_len;
> -  unsigned int len_b;
> +  size_t block_nb;
> +  size_t pm_len;
> +  uint64_t len_b;
>
>  #ifndef UNROLL_LOOPS_SHA512
> -  int i;
> +  size_t i;
>  #endif
>
>    block_nb =
> @@ -339,7 +339,7 @@ uint8_t* avb_sha512_final(AvbSHA512Ctx* ctx) {
>
>    avb_memset(ctx->block + ctx->len, 0, pm_len - ctx->len);
>    ctx->block[ctx->len] = 0x80;
> -  UNPACK32(len_b, ctx->block + pm_len - 4);
> +  UNPACK64(len_b, ctx->block + pm_len - 8);
>
>    SHA512_transform(ctx, ctx->block, block_nb);
>
> diff --git a/lib/libavb/avb_slot_verify.c b/lib/libavb/avb_slot_verify.c
> index a941850d93..5d400b38aa 100644
> --- a/lib/libavb/avb_slot_verify.c
> +++ b/lib/libavb/avb_slot_verify.c
> @@ -24,6 +24,14 @@
>  /* Maximum size of a vbmeta image - 64 KiB. */
>  #define VBMETA_MAX_SIZE (64 * 1024)
>
> +static AvbSlotVerifyResult 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);
> +
>  /* Helper function to see if we should continue with verification in
>   * allow_verification_error=true mode if something goes wrong. See the
>   * comments for the avb_slot_verify() function for more information.
> @@ -114,9 +122,26 @@ static AvbSlotVerifyResult load_full_partition(AvbOps* ops,
>    return AVB_SLOT_VERIFY_RESULT_OK;
>  }
>
> +/* Reads a persistent digest stored as a named persistent value corresponding to
> + * the given |part_name|. The value is returned in |out_digest| which must point
> + * to |expected_digest_size| bytes. If there is no digest stored for |part_name|
> + * it can be initialized by providing a non-NULL |initial_digest| of length
> + * |expected_digest_size|. This automatic initialization will only occur if the
> + * device is currently locked. The |initial_digest| may be NULL.
> + *
> + * Returns AVB_SLOT_VERIFY_RESULT_OK on success, otherwise returns an
> + * AVB_SLOT_VERIFY_RESULT_ERROR_* error code.
> + *
> + * If the value does not exist, is not supported, or is not populated, and
> + * |initial_digest| is NULL, returns
> + * AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA. If |expected_digest_size| does
> + * not match the stored digest size, also returns
> + * AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA.
> + */
>  static AvbSlotVerifyResult read_persistent_digest(AvbOps* ops,
>                                                    const char* part_name,
>                                                    size_t expected_digest_size,
> +                                                  const uint8_t* initial_digest,
>                                                    uint8_t* out_digest) {
>    char* persistent_value_name = NULL;
>    AvbIOResult io_ret = AVB_IO_RESULT_OK;
> @@ -131,30 +156,106 @@ static AvbSlotVerifyResult read_persistent_digest(AvbOps* ops,
>    if (persistent_value_name == NULL) {
>      return AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
>    }
> +
>    io_ret = ops->read_persistent_value(ops,
>                                        persistent_value_name,
>                                        expected_digest_size,
>                                        out_digest,
>                                        &stored_digest_size);
> +
> +  // If no such named persistent value exists and an initial digest value was
> +  // given, initialize the named persistent value with the given digest. If
> +  // initialized successfully, this will recurse into this function but with a
> +  // NULL initial_digest.
> +  if (io_ret == AVB_IO_RESULT_ERROR_NO_SUCH_VALUE && initial_digest) {
> +    AvbSlotVerifyResult ret =
> +        initialize_persistent_digest(ops,
> +                                     part_name,
> +                                     persistent_value_name,
> +                                     expected_digest_size,
> +                                     initial_digest,
> +                                     out_digest);
> +    avb_free(persistent_value_name);
> +    return ret;
> +  }
>    avb_free(persistent_value_name);
> +
>    if (io_ret == AVB_IO_RESULT_ERROR_OOM) {
>      return AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
>    } else if (io_ret == AVB_IO_RESULT_ERROR_NO_SUCH_VALUE) {
> +    // Treat a missing persistent value as a verification error, which is
> +    // ignoreable, rather than a metadata error which is not.
>      avb_errorv(part_name, ": Persistent digest does not exist.\n", NULL);
> -    return AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;
> +    return AVB_SLOT_VERIFY_RESULT_ERROR_VERIFICATION;
>    } else if (io_ret == AVB_IO_RESULT_ERROR_INVALID_VALUE_SIZE ||
> -             io_ret == AVB_IO_RESULT_ERROR_INSUFFICIENT_SPACE ||
> -             expected_digest_size != stored_digest_size) {
> +             io_ret == AVB_IO_RESULT_ERROR_INSUFFICIENT_SPACE) {
>      avb_errorv(
>          part_name, ": Persistent digest is not of expected size.\n", NULL);
>      return AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;
>    } else if (io_ret != AVB_IO_RESULT_OK) {
>      avb_errorv(part_name, ": Error reading persistent digest.\n", NULL);
>      return AVB_SLOT_VERIFY_RESULT_ERROR_IO;
> +  } else if (expected_digest_size != stored_digest_size) {
> +    avb_errorv(
> +        part_name, ": Persistent digest is not of expected size.\n", NULL);
> +    return AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;
>    }
>    return AVB_SLOT_VERIFY_RESULT_OK;
>  }
>
> +static AvbSlotVerifyResult 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) {
> +  AvbSlotVerifyResult ret;
> +  AvbIOResult io_ret = AVB_IO_RESULT_OK;
> +  bool is_device_unlocked = true;
> +
> +  io_ret = ops->read_is_device_unlocked(ops, &is_device_unlocked);
> +  if (io_ret == AVB_IO_RESULT_ERROR_OOM) {
> +    return AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
> +  } else if (io_ret != AVB_IO_RESULT_OK) {
> +    avb_error("Error getting device lock state.\n");
> +    return AVB_SLOT_VERIFY_RESULT_ERROR_IO;
> +  }
> +
> +  if (is_device_unlocked) {
> +    avb_debugv(part_name,
> +               ": Digest does not exist, device unlocked so not initializing "
> +               "digest.\n",
> +               NULL);
> +    return AVB_SLOT_VERIFY_RESULT_ERROR_VERIFICATION;
> +  }
> +
> +  // Device locked; initialize digest with given initial value.
> +  avb_debugv(part_name,
> +             ": Digest does not exist, initializing persistent digest.\n",
> +             NULL);
> +  io_ret = ops->write_persistent_value(
> +      ops, persistent_value_name, digest_size, initial_digest);
> +  if (io_ret == AVB_IO_RESULT_ERROR_OOM) {
> +    return AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
> +  } else if (io_ret != AVB_IO_RESULT_OK) {
> +    avb_errorv(part_name, ": Error initializing persistent digest.\n", NULL);
> +    return AVB_SLOT_VERIFY_RESULT_ERROR_IO;
> +  }
> +
> +  // To ensure that the digest value was written successfully - and avoid a
> +  // scenario where the digest is simply 'initialized' on every verify - recurse
> +  // into read_persistent_digest to read back the written value. The NULL
> +  // initial_digest ensures that this will not recurse again.
> +  ret = read_persistent_digest(ops, part_name, digest_size, NULL, out_digest);
> +  if (ret != AVB_SLOT_VERIFY_RESULT_OK) {
> +    avb_errorv(part_name,
> +               ": Reading back initialized persistent digest failed!\n",
> +               NULL);
> +  }
> +  return ret;
> +}
> +
>  static AvbSlotVerifyResult load_and_verify_hash_partition(
>      AvbOps* ops,
>      const char* const* requested_partitions,
> @@ -248,24 +349,16 @@ static AvbSlotVerifyResult load_and_verify_hash_partition(
>     */
>    image_size = hash_desc.image_size;
>    if (allow_verification_error) {
> -    if (ops->get_size_of_partition == NULL) {
> -      avb_errorv(part_name,
> -                 ": The get_size_of_partition() operation is "
> -                 "not implemented so we may not load the entire partition. "
> -                 "Please implement.",
> -                 NULL);
> -    } else {
> -      io_ret = ops->get_size_of_partition(ops, part_name, &image_size);
> -      if (io_ret == AVB_IO_RESULT_ERROR_OOM) {
> -        ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
> -        goto out;
> -      } else if (io_ret != AVB_IO_RESULT_OK) {
> -        avb_errorv(part_name, ": Error determining partition size.\n", NULL);
> -        ret = AVB_SLOT_VERIFY_RESULT_ERROR_IO;
> -        goto out;
> -      }
> -      avb_debugv(part_name, ": Loading entire partition.\n", NULL);
> +    io_ret = ops->get_size_of_partition(ops, part_name, &image_size);
> +    if (io_ret == AVB_IO_RESULT_ERROR_OOM) {
> +      ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
> +      goto out;
> +    } else if (io_ret != AVB_IO_RESULT_OK) {
> +      avb_errorv(part_name, ": Error determining partition size.\n", NULL);
> +      ret = AVB_SLOT_VERIFY_RESULT_ERROR_IO;
> +      goto out;
>      }
> +    avb_debugv(part_name, ": Loading entire partition.\n", NULL);
>    }
>
>    ret = load_full_partition(
> @@ -273,19 +366,27 @@ static AvbSlotVerifyResult load_and_verify_hash_partition(
>    if (ret != AVB_SLOT_VERIFY_RESULT_OK) {
>      goto out;
>    }
> -
> +  // Although only one of the type might be used, we have to defined the
> +  // structure here so that they would live outside the 'if/else' scope to be
> +  // used later.
> +  AvbSHA256Ctx sha256_ctx;
> +  AvbSHA512Ctx sha512_ctx;
> +  size_t image_size_to_hash = hash_desc.image_size;
> +  // If we allow verification error and the whole partition is smaller than
> +  // image size in hash descriptor, we just hash the whole partition.
> +  if (image_size_to_hash > image_size) {
> +    image_size_to_hash = image_size;
> +  }
>    if (avb_strcmp((const char*)hash_desc.hash_algorithm, "sha256") == 0) {
> -    AvbSHA256Ctx sha256_ctx;
>      avb_sha256_init(&sha256_ctx);
>      avb_sha256_update(&sha256_ctx, desc_salt, hash_desc.salt_len);
> -    avb_sha256_update(&sha256_ctx, image_buf, hash_desc.image_size);
> +    avb_sha256_update(&sha256_ctx, image_buf, image_size_to_hash);
>      digest = avb_sha256_final(&sha256_ctx);
>      digest_len = AVB_SHA256_DIGEST_SIZE;
>    } else if (avb_strcmp((const char*)hash_desc.hash_algorithm, "sha512") == 0) {
> -    AvbSHA512Ctx sha512_ctx;
>      avb_sha512_init(&sha512_ctx);
>      avb_sha512_update(&sha512_ctx, desc_salt, hash_desc.salt_len);
> -    avb_sha512_update(&sha512_ctx, image_buf, hash_desc.image_size);
> +    avb_sha512_update(&sha512_ctx, image_buf, image_size_to_hash);
>      digest = avb_sha512_final(&sha512_ctx);
>      digest_len = AVB_SHA512_DIGEST_SIZE;
>    } else {
> @@ -295,18 +396,21 @@ static AvbSlotVerifyResult load_and_verify_hash_partition(
>    }
>
>    if (hash_desc.digest_len == 0) {
> -    // Expect a match to a persistent digest.
> +    /* Expect a match to a persistent digest. */
>      avb_debugv(part_name, ": No digest, using persistent digest.\n", NULL);
>      expected_digest_len = digest_len;
>      expected_digest = expected_digest_buf;
>      avb_assert(expected_digest_len <= sizeof(expected_digest_buf));
> -    ret =
> -        read_persistent_digest(ops, part_name, digest_len, expected_digest_buf);
> +    /* Pass |digest| as the |initial_digest| so devices not yet initialized get
> +     * initialized to the current partition digest.
> +     */
> +    ret = read_persistent_digest(
> +        ops, part_name, digest_len, digest, expected_digest_buf);
>      if (ret != AVB_SLOT_VERIFY_RESULT_OK) {
>        goto out;
>      }
>    } else {
> -    // Expect a match to the digest in the descriptor.
> +    /* Expect a match to the digest in the descriptor. */
>      expected_digest_len = hash_desc.digest_len;
>      expected_digest = desc_digest;
>    }
> @@ -365,12 +469,6 @@ static AvbSlotVerifyResult load_requested_partitions(
>    bool image_preloaded = false;
>    size_t n;
>
> -  if (ops->get_size_of_partition == NULL) {
> -    avb_error("get_size_of_partition() not implemented.\n");
> -    ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_ARGUMENT;
> -    goto out;
> -  }
> -
>    for (n = 0; requested_partitions[n] != NULL; n++) {
>      char part_name[AVB_PART_NAME_MAX_SIZE];
>      AvbIOResult io_ret;
> @@ -441,6 +539,7 @@ static AvbSlotVerifyResult 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,
> @@ -467,7 +566,7 @@ static AvbSlotVerifyResult load_and_verify_vbmeta(
>    size_t num_descriptors;
>    size_t n;
>    bool is_main_vbmeta;
> -  bool is_vbmeta_partition;
> +  bool look_for_vbmeta_footer;
>    AvbVBMetaData* vbmeta_image_data = NULL;
>
>    ret = AVB_SLOT_VERIFY_RESULT_OK;
> @@ -478,8 +577,20 @@ static AvbSlotVerifyResult load_and_verify_vbmeta(
>     * rollback_index_location to determine whether we're the main
>     * vbmeta struct.
>     */
> -  is_main_vbmeta = (rollback_index_location == 0);
> -  is_vbmeta_partition = (avb_strcmp(partition_name, "vbmeta") == 0);
> +  is_main_vbmeta = false;
> +  if (rollback_index_location == 0) {
> +    if ((flags & AVB_SLOT_VERIFY_FLAGS_NO_VBMETA_PARTITION) == 0) {
> +      is_main_vbmeta = true;
> +    }
> +  }
> +
> +  /* Don't use footers for vbmeta partitions ('vbmeta' or
> +   * 'vbmeta_<partition_name>').
> +   */
> +  look_for_vbmeta_footer = true;
> +  if (avb_strncmp(partition_name, "vbmeta", avb_strlen("vbmeta")) == 0) {
> +    look_for_vbmeta_footer = false;
> +  }
>
>    if (!avb_validate_utf8((const uint8_t*)partition_name, partition_name_len)) {
>      avb_error("Partition name is not valid UTF-8.\n");
> @@ -487,7 +598,7 @@ static AvbSlotVerifyResult load_and_verify_vbmeta(
>      goto out;
>    }
>
> -  /* Construct full partition name. */
> +  /* Construct full partition name e.g. system_a. */
>    if (!avb_str_concat(full_partition_name,
>                        sizeof full_partition_name,
>                        partition_name,
> @@ -499,19 +610,15 @@ static AvbSlotVerifyResult load_and_verify_vbmeta(
>      goto out;
>    }
>
> -  avb_debugv("Loading vbmeta struct from partition '",
> -             full_partition_name,
> -             "'.\n",
> -             NULL);
> -
> -  /* If we're loading from the main vbmeta partition, the vbmeta
> -   * struct is in the beginning. Otherwise we have to locate it via a
> -   * footer.
> +  /* If we're loading from the main vbmeta partition, the vbmeta struct is in
> +   * the beginning. Otherwise we may have to locate it via a footer... if no
> +   * footer is found, we look in the beginning to support e.g. vbmeta_<org>
> +   * partitions holding data for e.g. super partitions (b/80195851 for
> +   * rationale).
>     */
> -  if (is_vbmeta_partition) {
> -    vbmeta_offset = 0;
> -    vbmeta_size = VBMETA_MAX_SIZE;
> -  } else {
> +  vbmeta_offset = 0;
> +  vbmeta_size = VBMETA_MAX_SIZE;
> +  if (look_for_vbmeta_footer) {
>      uint8_t footer_buf[AVB_FOOTER_SIZE];
>      size_t footer_num_read;
>      AvbFooter footer;
> @@ -534,21 +641,17 @@ static AvbSlotVerifyResult load_and_verify_vbmeta(
>
>      if (!avb_footer_validate_and_byteswap((const AvbFooter*)footer_buf,
>                                            &footer)) {
> -      avb_errorv(full_partition_name, ": Error validating footer.\n", NULL);
> -      ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;
> -      goto out;
> -    }
> -
> -    /* Basic footer sanity check since the data is untrusted. */
> -    if (footer.vbmeta_size > VBMETA_MAX_SIZE) {
> -      avb_errorv(
> -          full_partition_name, ": Invalid vbmeta size in footer.\n", NULL);
> -      ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;
> -      goto out;
> +      avb_debugv(full_partition_name, ": No footer detected.\n", NULL);
> +    } else {
> +      /* Basic footer sanity check since the data is untrusted. */
> +      if (footer.vbmeta_size > VBMETA_MAX_SIZE) {
> +        avb_errorv(
> +            full_partition_name, ": Invalid vbmeta size in footer.\n", NULL);
> +      } else {
> +        vbmeta_offset = footer.vbmeta_offset;
> +        vbmeta_size = footer.vbmeta_size;
> +      }
>      }
> -
> -    vbmeta_offset = footer.vbmeta_offset;
> -    vbmeta_size = footer.vbmeta_size;
>    }
>
>    vbmeta_buf = avb_malloc(vbmeta_size);
> @@ -557,6 +660,18 @@ static AvbSlotVerifyResult load_and_verify_vbmeta(
>      goto out;
>    }
>
> +  if (vbmeta_offset != 0) {
> +    avb_debugv("Loading vbmeta struct in footer from partition '",
> +               full_partition_name,
> +               "'.\n",
> +               NULL);
> +  } else {
> +    avb_debugv("Loading vbmeta struct from partition '",
> +               full_partition_name,
> +               "'.\n",
> +               NULL);
> +  }
> +
>    io_ret = ops->read_from_partition(ops,
>                                      full_partition_name,
>                                      vbmeta_offset,
> @@ -571,13 +686,14 @@ static AvbSlotVerifyResult load_and_verify_vbmeta(
>       * go try to get it from the boot partition instead.
>       */
>      if (is_main_vbmeta && io_ret == AVB_IO_RESULT_ERROR_NO_SUCH_PARTITION &&
> -        is_vbmeta_partition) {
> +        !look_for_vbmeta_footer) {
>        avb_debugv(full_partition_name,
>                   ": No such partition. Trying 'boot' instead.\n",
>                   NULL);
>        ret = load_and_verify_vbmeta(ops,
>                                     requested_partitions,
>                                     ab_suffix,
> +                                   flags,
>                                     allow_verification_error,
>                                     0 /* toplevel_vbmeta_flags */,
>                                     0 /* rollback_index_location */,
> @@ -655,6 +771,8 @@ static AvbSlotVerifyResult load_and_verify_vbmeta(
>      }
>    }
>
> +  uint32_t rollback_index_location_to_use = rollback_index_location;
> +
>    /* Check if key used to make signature matches what is expected. */
>    if (pk_data != NULL) {
>      if (expected_public_key != NULL) {
> @@ -682,9 +800,27 @@ static AvbSlotVerifyResult load_and_verify_vbmeta(
>          pk_metadata_len = vbmeta_header.public_key_metadata_size;
>        }
>
> -      avb_assert(is_main_vbmeta);
> -      io_ret = ops->validate_vbmeta_public_key(
> -          ops, pk_data, pk_len, pk_metadata, pk_metadata_len, &key_is_trusted);
> +      // If we're not using a vbmeta partition, need to use another AvbOps...
> +      if (flags & AVB_SLOT_VERIFY_FLAGS_NO_VBMETA_PARTITION) {
> +        io_ret = ops->validate_public_key_for_partition(
> +            ops,
> +            full_partition_name,
> +            pk_data,
> +            pk_len,
> +            pk_metadata,
> +            pk_metadata_len,
> +            &key_is_trusted,
> +            &rollback_index_location_to_use);
> +      } else {
> +        avb_assert(is_main_vbmeta);
> +        io_ret = ops->validate_vbmeta_public_key(ops,
> +                                                 pk_data,
> +                                                 pk_len,
> +                                                 pk_metadata,
> +                                                 pk_metadata_len,
> +                                                 &key_is_trusted);
> +      }
> +
>        if (io_ret == AVB_IO_RESULT_ERROR_OOM) {
>          ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
>          goto out;
> @@ -709,7 +845,7 @@ static AvbSlotVerifyResult load_and_verify_vbmeta(
>
>    /* Check rollback index. */
>    io_ret = ops->read_rollback_index(
> -      ops, rollback_index_location, &stored_rollback_index);
> +      ops, rollback_index_location_to_use, &stored_rollback_index);
>    if (io_ret == AVB_IO_RESULT_ERROR_OOM) {
>      ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
>      goto out;
> @@ -735,7 +871,9 @@ static AvbSlotVerifyResult load_and_verify_vbmeta(
>    if (is_main_vbmeta) {
>      avb_assert(slot_data->num_vbmeta_images == 0);
>    } else {
> -    avb_assert(slot_data->num_vbmeta_images > 0);
> +    if (!(flags & AVB_SLOT_VERIFY_FLAGS_NO_VBMETA_PARTITION)) {
> +      avb_assert(slot_data->num_vbmeta_images > 0);
> +    }
>    }
>    if (slot_data->num_vbmeta_images == MAX_NUMBER_OF_VBMETA_IMAGES) {
>      avb_errorv(full_partition_name, ": Too many vbmeta images.\n", NULL);
> @@ -859,6 +997,7 @@ static AvbSlotVerifyResult load_and_verify_vbmeta(
>              load_and_verify_vbmeta(ops,
>                                     requested_partitions,
>                                     ab_suffix,
> +                                   flags,
>                                     allow_verification_error,
>                                     toplevel_vbmeta_flags,
>                                     chain_desc.rollback_index_location,
> @@ -1019,7 +1158,11 @@ static AvbSlotVerifyResult load_and_verify_vbmeta(
>              goto out;
>            }
>
> -          ret = read_persistent_digest(ops, part_name, digest_len, digest_buf);
> +          ret = read_persistent_digest(ops,
> +                                       part_name,
> +                                       digest_len,
> +                                       NULL /* initial_digest */,
> +                                       digest_buf);
>            if (ret != AVB_SLOT_VERIFY_RESULT_OK) {
>              goto out;
>            }
> @@ -1043,7 +1186,8 @@ static AvbSlotVerifyResult load_and_verify_vbmeta(
>      }
>    }
>
> -  if (rollback_index_location >= AVB_MAX_NUMBER_OF_ROLLBACK_INDEX_LOCATIONS) {
> +  if (rollback_index_location < 0 ||
> +      rollback_index_location >= AVB_MAX_NUMBER_OF_ROLLBACK_INDEX_LOCATIONS) {
>      avb_errorv(
>          full_partition_name, ": Invalid rollback_index_location.\n", NULL);
>      ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;
> @@ -1072,6 +1216,130 @@ out:
>    return ret;
>  }
>
> +static AvbIOResult avb_manage_hashtree_error_mode(
> +    AvbOps* ops,
> +    AvbSlotVerifyFlags flags,
> +    AvbSlotVerifyData* data,
> +    AvbHashtreeErrorMode* out_hashtree_error_mode) {
> +  AvbHashtreeErrorMode ret = AVB_HASHTREE_ERROR_MODE_RESTART;
> +  AvbIOResult io_ret = AVB_IO_RESULT_OK;
> +  uint8_t vbmeta_digest_sha256[AVB_SHA256_DIGEST_SIZE];
> +  uint8_t stored_vbmeta_digest_sha256[AVB_SHA256_DIGEST_SIZE];
> +  size_t num_bytes_read;
> +
> +  avb_assert(out_hashtree_error_mode != NULL);
> +  avb_assert(ops->read_persistent_value != NULL);
> +  avb_assert(ops->write_persistent_value != NULL);
> +
> +  // If we're rebooting because of dm-verity corruption, make a note of
> +  // the vbmeta hash so we can stay in 'eio' mode until things change.
> +  if (flags & AVB_SLOT_VERIFY_FLAGS_RESTART_CAUSED_BY_HASHTREE_CORRUPTION) {
> +    avb_debug(
> +        "Rebooting because of dm-verity corruption - "
> +        "recording OS instance and using 'eio' mode.\n");
> +    avb_slot_verify_data_calculate_vbmeta_digest(
> +        data, AVB_DIGEST_TYPE_SHA256, vbmeta_digest_sha256);
> +    io_ret = ops->write_persistent_value(ops,
> +                                         AVB_NPV_MANAGED_VERITY_MODE,
> +                                         AVB_SHA256_DIGEST_SIZE,
> +                                         vbmeta_digest_sha256);
> +    if (io_ret != AVB_IO_RESULT_OK) {
> +      avb_error("Error writing to " AVB_NPV_MANAGED_VERITY_MODE ".\n");
> +      goto out;
> +    }
> +    ret = AVB_HASHTREE_ERROR_MODE_EIO;
> +    io_ret = AVB_IO_RESULT_OK;
> +    goto out;
> +  }
> +
> +  // See if we're in 'eio' mode.
> +  io_ret = ops->read_persistent_value(ops,
> +                                      AVB_NPV_MANAGED_VERITY_MODE,
> +                                      AVB_SHA256_DIGEST_SIZE,
> +                                      stored_vbmeta_digest_sha256,
> +                                      &num_bytes_read);
> +  if (io_ret == AVB_IO_RESULT_ERROR_NO_SUCH_VALUE ||
> +      (io_ret == AVB_IO_RESULT_OK && num_bytes_read == 0)) {
> +    // This is the usual case ('eio' mode not set).
> +    avb_debug("No dm-verity corruption - using in 'restart' mode.\n");
> +    ret = AVB_HASHTREE_ERROR_MODE_RESTART;
> +    io_ret = AVB_IO_RESULT_OK;
> +    goto out;
> +  } else if (io_ret != AVB_IO_RESULT_OK) {
> +    avb_error("Error reading from " AVB_NPV_MANAGED_VERITY_MODE ".\n");
> +    goto out;
> +  }
> +  if (num_bytes_read != AVB_SHA256_DIGEST_SIZE) {
> +    avb_error(
> +        "Unexpected number of bytes read from " AVB_NPV_MANAGED_VERITY_MODE
> +        ".\n");
> +    io_ret = AVB_IO_RESULT_ERROR_IO;
> +    goto out;
> +  }
> +
> +  // OK, so we're currently in 'eio' mode and the vbmeta digest of the OS
> +  // that caused this is in |stored_vbmeta_digest_sha256| ... now see if
> +  // the OS we're dealing with now is the same.
> +  avb_slot_verify_data_calculate_vbmeta_digest(
> +      data, AVB_DIGEST_TYPE_SHA256, vbmeta_digest_sha256);
> +  if (avb_memcmp(vbmeta_digest_sha256,
> +                 stored_vbmeta_digest_sha256,
> +                 AVB_SHA256_DIGEST_SIZE) == 0) {
> +    // It's the same so we're still in 'eio' mode.
> +    avb_debug("Same OS instance detected - staying in 'eio' mode.\n");
> +    ret = AVB_HASHTREE_ERROR_MODE_EIO;
> +    io_ret = AVB_IO_RESULT_OK;
> +  } else {
> +    // It did change!
> +    avb_debug(
> +        "New OS instance detected - changing from 'eio' to 'restart' mode.\n");
> +    io_ret =
> +        ops->write_persistent_value(ops,
> +                                    AVB_NPV_MANAGED_VERITY_MODE,
> +                                    0,  // This clears the persistent property.
> +                                    vbmeta_digest_sha256);
> +    if (io_ret != AVB_IO_RESULT_OK) {
> +      avb_error("Error clearing " AVB_NPV_MANAGED_VERITY_MODE ".\n");
> +      goto out;
> +    }
> +    ret = AVB_HASHTREE_ERROR_MODE_RESTART;
> +    io_ret = AVB_IO_RESULT_OK;
> +  }
> +
> +out:
> +  *out_hashtree_error_mode = ret;
> +  return io_ret;
> +}
> +
> +static bool has_system_partition(AvbOps* ops, const char* ab_suffix) {
> +  char part_name[AVB_PART_NAME_MAX_SIZE];
> +  char* system_part_name = "system";
> +  char guid_buf[37];
> +  AvbIOResult io_ret;
> +
> +  if (!avb_str_concat(part_name,
> +                      sizeof part_name,
> +                      system_part_name,
> +                      avb_strlen(system_part_name),
> +                      ab_suffix,
> +                      avb_strlen(ab_suffix))) {
> +    avb_error("System partition name and suffix does not fit.\n");
> +    return false;
> +  }
> +
> +  io_ret = ops->get_unique_guid_for_partition(
> +      ops, part_name, guid_buf, sizeof guid_buf);
> +  if (io_ret == AVB_IO_RESULT_ERROR_NO_SUCH_PARTITION) {
> +    avb_debug("No system partition.\n");
> +    return false;
> +  } else if (io_ret != AVB_IO_RESULT_OK) {
> +    avb_error("Error getting unique GUID for system partition.\n");
> +    return false;
> +  }
> +
> +  return true;
> +}
> +
>  AvbSlotVerifyResult avb_slot_verify(AvbOps* ops,
>                                      const char* const* requested_partitions,
>                                      const char* ab_suffix,
> @@ -1087,14 +1355,10 @@ AvbSlotVerifyResult avb_slot_verify(AvbOps* ops,
>        (flags & AVB_SLOT_VERIFY_FLAGS_ALLOW_VERIFICATION_ERROR);
>    AvbCmdlineSubstList* additional_cmdline_subst = NULL;
>
> -  /* Fail early if we're missing the AvbOps needed for slot verification.
> -   *
> -   * For now, handle get_size_of_partition() not being implemented. In
> -   * a later release we may change that.
> -   */
> +  /* Fail early if we're missing the AvbOps needed for slot verification. */
>    avb_assert(ops->read_is_device_unlocked != NULL);
>    avb_assert(ops->read_from_partition != NULL);
> -  avb_assert(ops->validate_vbmeta_public_key != NULL);
> +  avb_assert(ops->get_size_of_partition != NULL);
>    avb_assert(ops->read_rollback_index != NULL);
>    avb_assert(ops->get_unique_guid_for_partition != NULL);
>
> @@ -1112,6 +1376,36 @@ AvbSlotVerifyResult avb_slot_verify(AvbOps* ops,
>      goto fail;
>    }
>
> +  /* Make sure passed-in AvbOps support persistent values if
> +   * asking for libavb to manage verity state.
> +   */
> +  if (hashtree_error_mode == AVB_HASHTREE_ERROR_MODE_MANAGED_RESTART_AND_EIO) {
> +    if (ops->read_persistent_value == NULL ||
> +        ops->write_persistent_value == NULL) {
> +      avb_error(
> +          "Persistent values required for "
> +          "AVB_HASHTREE_ERROR_MODE_MANAGED_RESTART_AND_EIO "
> +          "but are not implemented in given AvbOps.\n");
> +      ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_ARGUMENT;
> +      goto fail;
> +    }
> +  }
> +
> +  /* Make sure passed-in AvbOps support verifying public keys and getting
> +   * rollback index location if not using a vbmeta partition.
> +   */
> +  if (flags & AVB_SLOT_VERIFY_FLAGS_NO_VBMETA_PARTITION) {
> +    if (ops->validate_public_key_for_partition == NULL) {
> +      avb_error(
> +          "AVB_SLOT_VERIFY_FLAGS_NO_VBMETA_PARTITION was passed but the "
> +          "validate_public_key_for_partition() operation isn't implemented.\n");
> +      ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_ARGUMENT;
> +      goto fail;
> +    }
> +  } else {
> +    avb_assert(ops->validate_vbmeta_public_key != NULL);
> +  }
> +
>    slot_data = avb_calloc(sizeof(AvbSlotVerifyData));
>    if (slot_data == NULL) {
>      ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
> @@ -1136,99 +1430,163 @@ AvbSlotVerifyResult avb_slot_verify(AvbOps* ops,
>      goto fail;
>    }
>
> -  ret = load_and_verify_vbmeta(ops,
> -                               requested_partitions,
> -                               ab_suffix,
> -                               allow_verification_error,
> -                               0 /* toplevel_vbmeta_flags */,
> -                               0 /* rollback_index_location */,
> -                               "vbmeta",
> -                               avb_strlen("vbmeta"),
> -                               NULL /* expected_public_key */,
> -                               0 /* expected_public_key_length */,
> -                               slot_data,
> -                               &algorithm_type,
> -                               additional_cmdline_subst);
> -  if (!allow_verification_error && ret != AVB_SLOT_VERIFY_RESULT_OK) {
> +  if (flags & AVB_SLOT_VERIFY_FLAGS_NO_VBMETA_PARTITION) {
> +    if (requested_partitions == NULL || requested_partitions[0] == NULL) {
> +      avb_fatal(
> +          "Requested partitions cannot be empty when using "
> +          "AVB_SLOT_VERIFY_FLAGS_NO_VBMETA_PARTITION");
> +      ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_ARGUMENT;
> +      goto fail;
> +    }
> +
> +    /* No vbmeta partition, go through each of the requested partitions... */
> +    for (size_t n = 0; requested_partitions[n] != NULL; n++) {
> +      ret = load_and_verify_vbmeta(ops,
> +                                   requested_partitions,
> +                                   ab_suffix,
> +                                   flags,
> +                                   allow_verification_error,
> +                                   0 /* toplevel_vbmeta_flags */,
> +                                   0 /* rollback_index_location */,
> +                                   requested_partitions[n],
> +                                   avb_strlen(requested_partitions[n]),
> +                                   NULL /* expected_public_key */,
> +                                   0 /* expected_public_key_length */,
> +                                   slot_data,
> +                                   &algorithm_type,
> +                                   additional_cmdline_subst);
> +      if (!allow_verification_error && ret != AVB_SLOT_VERIFY_RESULT_OK) {
> +        goto fail;
> +      }
> +    }
> +
> +  } else {
> +    /* Usual path, load "vbmeta"... */
> +    ret = load_and_verify_vbmeta(ops,
> +                                 requested_partitions,
> +                                 ab_suffix,
> +                                 flags,
> +                                 allow_verification_error,
> +                                 0 /* toplevel_vbmeta_flags */,
> +                                 0 /* rollback_index_location */,
> +                                 "vbmeta",
> +                                 avb_strlen("vbmeta"),
> +                                 NULL /* expected_public_key */,
> +                                 0 /* expected_public_key_length */,
> +                                 slot_data,
> +                                 &algorithm_type,
> +                                 additional_cmdline_subst);
> +    if (!allow_verification_error && ret != AVB_SLOT_VERIFY_RESULT_OK) {
> +      goto fail;
> +    }
> +  }
> +
> +  if (!result_should_continue(ret)) {
>      goto fail;
>    }
>
>    /* If things check out, mangle the kernel command-line as needed. */
> -  if (result_should_continue(ret)) {
> +  if (!(flags & AVB_SLOT_VERIFY_FLAGS_NO_VBMETA_PARTITION)) {
>      if (avb_strcmp(slot_data->vbmeta_images[0].partition_name, "vbmeta") != 0) {
>        avb_assert(
>            avb_strcmp(slot_data->vbmeta_images[0].partition_name, "boot") == 0);
>        using_boot_for_vbmeta = true;
>      }
> +  }
>
> -    /* Byteswap top-level vbmeta header since we'll need it below. */
> -    avb_vbmeta_image_header_to_host_byte_order(
> -        (const AvbVBMetaImageHeader*)slot_data->vbmeta_images[0].vbmeta_data,
> -        &toplevel_vbmeta);
> +  /* Byteswap top-level vbmeta header since we'll need it below. */
> +  avb_vbmeta_image_header_to_host_byte_order(
> +      (const AvbVBMetaImageHeader*)slot_data->vbmeta_images[0].vbmeta_data,
> +      &toplevel_vbmeta);
>
> -    /* Fill in |ab_suffix| field. */
> -    slot_data->ab_suffix = avb_strdup(ab_suffix);
> -    if (slot_data->ab_suffix == NULL) {
> -      ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
> -      goto fail;
> -    }
> +  /* Fill in |ab_suffix| field. */
> +  slot_data->ab_suffix = avb_strdup(ab_suffix);
> +  if (slot_data->ab_suffix == NULL) {
> +    ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
> +    goto fail;
> +  }
>
> -    /* If verification is disabled, we are done ... we specifically
> -     * don't want to add any androidboot.* options since verification
> -     * is disabled.
> +  /* If verification is disabled, we are done ... we specifically
> +   * don't want to add any androidboot.* options since verification
> +   * is disabled.
> +   */
> +  if (toplevel_vbmeta.flags & AVB_VBMETA_IMAGE_FLAGS_VERIFICATION_DISABLED) {
> +    /* Since verification is disabled we didn't process any
> +     * descriptors and thus there's no cmdline... so set root= such
> +     * that the system partition is mounted.
>       */
> -    if (toplevel_vbmeta.flags & AVB_VBMETA_IMAGE_FLAGS_VERIFICATION_DISABLED) {
> -      /* Since verification is disabled we didn't process any
> -       * descriptors and thus there's no cmdline... so set root= such
> -       * that the system partition is mounted.
> -       */
> -      avb_assert(slot_data->cmdline == NULL);
> +    avb_assert(slot_data->cmdline == NULL);
> +    // Devices with dynamic partitions won't have system partition.
> +    // Instead, it has a large super partition to accommodate *.img files.
> +    // See b/119551429 for details.
> +    if (has_system_partition(ops, ab_suffix)) {
>        slot_data->cmdline =
>            avb_strdup("root=PARTUUID=$(ANDROID_SYSTEM_PARTUUID)");
> -      if (slot_data->cmdline == NULL) {
> -        ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
> -        goto fail;
> -      }
>      } else {
> -      /* Add options - any failure in avb_append_options() is either an
> -       * I/O or OOM error.
> -       */
> -      AvbSlotVerifyResult sub_ret = avb_append_options(ops,
> -                                                       slot_data,
> -                                                       &toplevel_vbmeta,
> -                                                       algorithm_type,
> -                                                       hashtree_error_mode);
> -      if (sub_ret != AVB_SLOT_VERIFY_RESULT_OK) {
> -        ret = sub_ret;
> -        goto fail;
> -      }
> +      // The |cmdline| field should be a NUL-terminated string.
> +      slot_data->cmdline = avb_strdup("");
>      }
> -
> -    /* Substitute $(ANDROID_SYSTEM_PARTUUID) and friends. */
> -    if (slot_data->cmdline != NULL) {
> -      char* new_cmdline;
> -      new_cmdline = avb_sub_cmdline(ops,
> -                                    slot_data->cmdline,
> -                                    ab_suffix,
> -                                    using_boot_for_vbmeta,
> -                                    additional_cmdline_subst);
> -      if (new_cmdline != slot_data->cmdline) {
> -        if (new_cmdline == NULL) {
> +    if (slot_data->cmdline == NULL) {
> +      ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
> +      goto fail;
> +    }
> +  } else {
> +    /* If requested, manage dm-verity mode... */
> +    AvbHashtreeErrorMode resolved_hashtree_error_mode = hashtree_error_mode;
> +    if (hashtree_error_mode ==
> +        AVB_HASHTREE_ERROR_MODE_MANAGED_RESTART_AND_EIO) {
> +      AvbIOResult io_ret;
> +      io_ret = avb_manage_hashtree_error_mode(
> +          ops, flags, slot_data, &resolved_hashtree_error_mode);
> +      if (io_ret != AVB_IO_RESULT_OK) {
> +        ret = AVB_SLOT_VERIFY_RESULT_ERROR_IO;
> +        if (io_ret == AVB_IO_RESULT_ERROR_OOM) {
>            ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
> -          goto fail;
>          }
> -        avb_free(slot_data->cmdline);
> -        slot_data->cmdline = new_cmdline;
> +        goto fail;
>        }
>      }
> +    slot_data->resolved_hashtree_error_mode = resolved_hashtree_error_mode;
>
> -    if (out_data != NULL) {
> -      *out_data = slot_data;
> -    } else {
> -      avb_slot_verify_data_free(slot_data);
> +    /* Add options... */
> +    AvbSlotVerifyResult sub_ret;
> +    sub_ret = avb_append_options(ops,
> +                                 flags,
> +                                 slot_data,
> +                                 &toplevel_vbmeta,
> +                                 algorithm_type,
> +                                 hashtree_error_mode,
> +                                 resolved_hashtree_error_mode);
> +    if (sub_ret != AVB_SLOT_VERIFY_RESULT_OK) {
> +      ret = sub_ret;
> +      goto fail;
> +    }
> +  }
> +
> +  /* Substitute $(ANDROID_SYSTEM_PARTUUID) and friends. */
> +  if (slot_data->cmdline != NULL && avb_strlen(slot_data->cmdline) != 0) {
> +    char* new_cmdline;
> +    new_cmdline = avb_sub_cmdline(ops,
> +                                  slot_data->cmdline,
> +                                  ab_suffix,
> +                                  using_boot_for_vbmeta,
> +                                  additional_cmdline_subst);
> +    if (new_cmdline != slot_data->cmdline) {
> +      if (new_cmdline == NULL) {
> +        ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
> +        goto fail;
> +      }
> +      avb_free(slot_data->cmdline);
> +      slot_data->cmdline = new_cmdline;
>      }
>    }
>
> +  if (out_data != NULL) {
> +    *out_data = slot_data;
> +  } else {
> +    avb_slot_verify_data_free(slot_data);
> +  }
> +
>    avb_free_cmdline_subst_list(additional_cmdline_subst);
>    additional_cmdline_subst = NULL;
>
> diff --git a/lib/libavb/avb_slot_verify.h b/lib/libavb/avb_slot_verify.h
> index 73fd70d4ce..8d0fa53693 100644
> --- a/lib/libavb/avb_slot_verify.h
> +++ b/lib/libavb/avb_slot_verify.h
> @@ -51,12 +51,25 @@ typedef enum {
>   * be used ONLY for diagnostics and debugging. It cannot be used
>   * unless AVB_SLOT_VERIFY_FLAGS_ALLOW_VERIFICATION_ERROR is also
>   * used.
> + *
> + * AVB_HASHTREE_ERROR_MODE_MANAGED_RESTART_AND_EIO means that either
> + * AVB_HASHTREE_ERROR_MODE_RESTART or AVB_HASHTREE_ERROR_MODE_EIO is used
> + * depending on state. This mode implements a state machine whereby
> + * AVB_HASHTREE_ERROR_MODE_RESTART is used by default and when
> + * AVB_SLOT_VERIFY_FLAGS_RESTART_CAUSED_BY_HASHTREE_CORRUPTION is passed the
> + * mode transitions to AVB_HASHTREE_ERROR_MODE_EIO. When a new OS has been
> + * detected the device transitions back to the AVB_HASHTREE_ERROR_MODE_RESTART
> + * mode. To do this persistent storage is needed - specifically this means that
> + * the passed in AvbOps will need to have the read_persistent_value() and
> + * write_persistent_value() operations implemented. The name of the persistent
> + * value used is "avb.managed_verity_mode" and 32 bytes of storage is needed.
>   */
>  typedef enum {
>    AVB_HASHTREE_ERROR_MODE_RESTART_AND_INVALIDATE,
>    AVB_HASHTREE_ERROR_MODE_RESTART,
>    AVB_HASHTREE_ERROR_MODE_EIO,
> -  AVB_HASHTREE_ERROR_MODE_LOGGING
> +  AVB_HASHTREE_ERROR_MODE_LOGGING,
> +  AVB_HASHTREE_ERROR_MODE_MANAGED_RESTART_AND_EIO
>  } AvbHashtreeErrorMode;
>
>  /* Flags that influence how avb_slot_verify() works.
> @@ -80,10 +93,26 @@ typedef enum {
>   * contents loaded from |requested_partition| will be the contents of
>   * the entire partition instead of just the size specified in the hash
>   * descriptor.
> + *
> + * The AVB_SLOT_VERIFY_FLAGS_RESTART_CAUSED_BY_HASHTREE_CORRUPTION flag
> + * should be set if using AVB_HASHTREE_ERROR_MODE_MANAGED_RESTART_AND_EIO
> + * and the reason the boot loader is running is because the device
> + * was restarted by the dm-verity driver.
> + *
> + * If the AVB_SLOT_VERIFY_FLAGS_NO_VBMETA_PARTITION flag is set then
> + * data won't be loaded from the "vbmeta" partition and the
> + * |validate_vbmeta_public_key| operation is never called. Instead, the
> + * vbmeta structs in |requested_partitions| are loaded and processed and the
> + * |validate_public_key_for_partition| operation is called for each of these
> + * vbmeta structs. This flag is useful when booting into recovery on a device
> + * not using A/B - see section "Booting into recovery" in README.md for
> + * more information.
>   */
>  typedef enum {
>    AVB_SLOT_VERIFY_FLAGS_NONE = 0,
> -  AVB_SLOT_VERIFY_FLAGS_ALLOW_VERIFICATION_ERROR = (1 << 0)
> +  AVB_SLOT_VERIFY_FLAGS_ALLOW_VERIFICATION_ERROR = (1 << 0),
> +  AVB_SLOT_VERIFY_FLAGS_RESTART_CAUSED_BY_HASHTREE_CORRUPTION = (1 << 1),
> +  AVB_SLOT_VERIFY_FLAGS_NO_VBMETA_PARTITION = (1 << 2),
>  } AvbSlotVerifyFlags;
>
>  /* Get a textual representation of |result|. */
> @@ -188,6 +217,10 @@ typedef struct {
>   *   set to AVB_HASHTREE_ERROR_MODE_EIO, and 'logging' if it's set to
>   *   AVB_HASHTREE_ERROR_MODE_LOGGING.
>   *
> + *   androidboot.veritymode.managed: This is set to 'yes' only
> + *   if hashtree validation isn't disabled and the passed-in hashtree
> + *   error mode is AVB_HASHTREE_ERROR_MODE_MANAGED_RESTART_AND_EIO.
> + *
>   *   androidboot.vbmeta.invalidate_on_error: This is set to 'yes' only
>   *   if hashtree validation isn't disabled and the passed-in hashtree
>   *   error mode is AVB_HASHTREE_ERROR_MODE_RESTART_AND_INVALIDATE.
> @@ -203,7 +236,9 @@ typedef struct {
>   *   PARTUUID=$(ANDROID_VBMETA_PARTUUID) before substitution so it
>   *   will end up pointing to the vbmeta partition for the verified
>   *   slot. If there is no vbmeta partition it will point to the boot
> - *   partition of the verified slot.
> + *   partition of the verified slot. If the flag
> + *   AVB_SLOT_VERIFY_FLAGS_NO_VBMETA_PARTITION is used, this is not
> + *   set.
>   *
>   *   androidboot.vbmeta.avb_version: This is set to the decimal value
>   *   of AVB_VERSION_MAJOR followed by a dot followed by the decimal
> @@ -228,6 +263,15 @@ typedef struct {
>   * appropriate system partition is substituted in. Note that none of
>   * the androidboot.* options mentioned above will be set.
>   *
> + * The |resolved_hashtree_error_mode| is the the value of the passed
> + * avb_slot_verify()'s |hashtree_error_mode| parameter except that it never has
> + * the value AVB_HASHTREE_ERROR_MODE_MANAGED_RESTART_AND_EIO. If this value was
> + * passed in, then the restart/eio state machine is used resulting in
> + * |resolved_hashtree_error_mode| being set to either
> + * AVB_HASHTREE_ERROR_MODE_RESTART or AVB_HASHTREE_ERROR_MODE_EIO.  If set to
> + * AVB_HASHTREE_ERROR_MODE_EIO the boot loader should present a RED warning
> + * screen for the user to click through before continuing to boot.
> + *
>   * This struct may grow in the future without it being considered an
>   * ABI break.
>   */
> @@ -239,6 +283,7 @@ typedef struct {
>    size_t num_loaded_partitions;
>    char* cmdline;
>    uint64_t rollback_indexes[AVB_MAX_NUMBER_OF_ROLLBACK_INDEX_LOCATIONS];
> +  AvbHashtreeErrorMode resolved_hashtree_error_mode;
>  } AvbSlotVerifyData;
>
>  /* Calculates a digest of all vbmeta images in |data| using
> @@ -282,12 +327,8 @@ void avb_slot_verify_data_free(AvbSlotVerifyData* data);
>   * ignore verification errors which is something needed in the
>   * UNLOCKED state. See the AvbSlotVerifyFlags enumeration for details.
>   *
> - * The |hashtree_error_mode| parameter should be set to the desired
> - * error handling mode when hashtree validation fails inside the
> - * HLOS. This value isn't used by libavb per se - it is forwarded to
> - * the HLOS through the androidboot.veritymode and
> - * androidboot.vbmeta.invalidate_on_error cmdline parameters. See the
> - * AvbHashtreeErrorMode enumeration for details.
> + * The |hashtree_error_mode| parameter should be set to the desired error
> + * handling mode. See the AvbHashtreeErrorMode enumeration for details.
>   *
>   * Also note that |out_data| is never set if
>   * AVB_SLOT_VERIFY_RESULT_ERROR_OOM, AVB_SLOT_VERIFY_RESULT_ERROR_IO,
> diff --git a/lib/libavb/avb_sysdeps.h b/lib/libavb/avb_sysdeps.h
> index f032de4a2e..f52428cc62 100644
> --- a/lib/libavb/avb_sysdeps.h
> +++ b/lib/libavb/avb_sysdeps.h
> @@ -53,6 +53,14 @@ int avb_memcmp(const void* src1,
>   */
>  int avb_strcmp(const char* s1, const char* s2);
>
> +/* Compare |n| bytes in two strings.
> + *
> + * Return an integer less than, equal to, or greater than zero if the
> + * first |n| bytes of |s1| is found, respectively, to be less than,
> + * to match, or be greater than the first |n| bytes of |s2|.
> + */
> +int avb_strncmp(const char* s1, const char* s2, size_t n);
> +
>  /* Copy |n| bytes from |src| to |dest|. */
>  void* avb_memcpy(void* dest, const void* src, size_t n);
>
> diff --git a/lib/libavb/avb_sysdeps_posix.c b/lib/libavb/avb_sysdeps_posix.c
> index e9addc1c87..4ccf41e428 100644
> --- a/lib/libavb/avb_sysdeps_posix.c
> +++ b/lib/libavb/avb_sysdeps_posix.c
> @@ -24,14 +24,12 @@ int avb_strcmp(const char* s1, const char* s2) {
>    return strcmp(s1, s2);
>  }
>
> -size_t avb_strlen(const char* str) {
> -  return strlen(str);
> +int avb_strncmp(const char* s1, const char* s2, size_t n) {
> +  return strncmp(s1, s2, n);
>  }
>
> -uint32_t avb_div_by_10(uint64_t* dividend) {
> -  uint32_t rem = (uint32_t)(*dividend % 10);
> -  *dividend /= 10;
> -  return rem;
> +size_t avb_strlen(const char* str) {
> +  return strlen(str);
>  }
>
>  void avb_abort(void) {
> @@ -60,3 +58,9 @@ void* avb_malloc_(size_t size) {
>  void avb_free(void* ptr) {
>    free(ptr);
>  }
> +
> +uint32_t avb_div_by_10(uint64_t* dividend) {
> +  uint32_t rem = (uint32_t)(*dividend % 10);
> +  *dividend /= 10;
> +  return rem;
> +}
> diff --git a/lib/libavb/avb_vbmeta_image.c b/lib/libavb/avb_vbmeta_image.c
> index a7e2322b9e..384f5ac19e 100644
> --- a/lib/libavb/avb_vbmeta_image.c
> +++ b/lib/libavb/avb_vbmeta_image.c
> @@ -35,17 +35,18 @@ AvbVBMetaVerifyResult avb_vbmeta_image_verify(
>      *out_public_key_length = 0;
>    }
>
> +  /* Before we byteswap or compare Magic, ensure length is long enough. */
> +  if (length < sizeof(AvbVBMetaImageHeader)) {
> +    avb_error("Length is smaller than header.\n");
> +    goto out;
> +  }
> +
>    /* Ensure magic is correct. */
>    if (avb_safe_memcmp(data, AVB_MAGIC, AVB_MAGIC_LEN) != 0) {
>      avb_error("Magic is incorrect.\n");
>      goto out;
>    }
>
> -  /* Before we byteswap, ensure length is long enough. */
> -  if (length < sizeof(AvbVBMetaImageHeader)) {
> -    avb_error("Length is smaller than header.\n");
> -    goto out;
> -  }
>    avb_vbmeta_image_header_to_host_byte_order((const AvbVBMetaImageHeader*)data,
>                                               &h);
>
> --
> 2.23.0.rc1
>

Acked-by: Igor Opaniuk <igor.opaniuk@gmail.com>

-- 
Best regards - Freundliche Grüsse - Meilleures salutations

Igor Opaniuk

mailto: igor.opaniuk at gmail.com
skype: igor.opanyuk
+380 (93) 836 40 67
http://ua.linkedin.com/in/iopaniuk

^ permalink raw reply	[flat|nested] 15+ messages in thread

* [U-Boot] [PATCH 1/2] libavb: Update libavb to current AOSP master
  2019-08-15 20:04 [U-Boot] [PATCH 1/2] libavb: Update libavb to current AOSP master Sam Protsenko
                   ` (2 preceding siblings ...)
  2019-10-16  9:32 ` Igor Opaniuk
@ 2019-11-01 13:29 ` Tom Rini
  3 siblings, 0 replies; 15+ messages in thread
From: Tom Rini @ 2019-11-01 13:29 UTC (permalink / raw)
  To: u-boot

On Thu, Aug 15, 2019 at 11:04:02PM +0300, Sam Protsenko wrote:

> Update libavb to commit 5fbb42a189aa in AOSP/master, because new version
> has support for super partition [1], which we need for implementing
> Android dynamic partitions. All changes from previous patches for libavb
> in U-Boot are accounted for in this commit:
>   - commit ecc6f6bea6a2 ("libavb: Handle wrong hashtree_error_mode in
>                           avb_append_options()")
>   - commit 897a1d947e7e ("libavb: Update SPDX tag style")
>   - commit d8f9d2af96b3 ("avb2.0: add Android Verified Boot 2.0 library")
> 
> Tested on X15:
> 
>     ## Android Verified Boot 2.0 version 1.1.0
>     read_is_device_unlocked not supported yet
>     read_rollback_index not supported yet
>     read_is_device_unlocked not supported yet
>     Verification passed successfully
>     AVB verification OK.
> 
> Unit test passes:
> 
>     $ ./test/py/test.py --bd sandbox --build -k test_avb
> 
>       test/py/tests/test_android/test_avb.py ss..s.
> 
> [1] https://android.googlesource.com/platform/external/avb/+/49936b4c0109411fdd38bd4ba3a32a01c40439a9
> 
> Signed-off-by: Sam Protsenko <semen.protsenko@linaro.org>
> Reviewed-by: Eugeniu Rosca <rosca.eugeniu@gmail.com>
> Acked-by: Igor Opaniuk <igor.opaniuk@gmail.com>

Applied to u-boot/master, thanks!

-- 
Tom
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 833 bytes
Desc: not available
URL: <http://lists.denx.de/pipermail/u-boot/attachments/20191101/5a3f764a/attachment.sig>

^ permalink raw reply	[flat|nested] 15+ messages in thread

* [U-Boot] [PATCH 2/2] libavb: Fix build warnings after updating the lib
  2019-08-15 20:04 ` [U-Boot] [PATCH 2/2] libavb: Fix build warnings after updating the lib Sam Protsenko
  2019-08-16 13:35   ` Eugeniu Rosca
@ 2019-11-01 13:29   ` Tom Rini
  1 sibling, 0 replies; 15+ messages in thread
From: Tom Rini @ 2019-11-01 13:29 UTC (permalink / raw)
  To: u-boot

On Thu, Aug 15, 2019 at 11:04:03PM +0300, Sam Protsenko wrote:

> After updating libavb to most recent version from AOSP/master, two new
> warnings appear:
> 
> Warning #1:
> 
>     lib/libavb/avb_cmdline.c: In function 'avb_append_options':
>     lib/libavb/avb_cmdline.c:365:15: warning: 'dm_verity_mode' may be
>                                      used uninitialized in this function
>                                      [-Wmaybe-uninitialized]
>          new_ret = avb_replace(
>                    ^~~~~~~~~~~~
>              slot_data->cmdline, "$(ANDROID_VERITY_MODE)", dm_verity_mode);
>              ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
>     lib/libavb/avb_cmdline.c:374:8: warning: 'verity_mode' may be used
>                                     uninitialized in this function
>                                     [-Wmaybe-uninitialized]
>        if (!cmdline_append_option(
>             ^~~~~~~~~~~~~~~~~~~~~~
>                slot_data, "androidboot.veritymode", verity_mode)) {
>                ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> 
> Warning #2:
> 
>     lib/libavb/avb_slot_verify.c: In function 'avb_slot_verify':
>     lib/libavb/avb_slot_verify.c:1349:23: warning: 'ret' may be used
>                                           uninitialized in this function
>                                           [-Wmaybe-uninitialized]
>        AvbSlotVerifyResult ret;
>                            ^~~
> 
> Fix those by providing default return values to affected functions.
> 
> Signed-off-by: Sam Protsenko <semen.protsenko@linaro.org>

Applied to u-boot/master, thanks!

-- 
Tom
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 833 bytes
Desc: not available
URL: <http://lists.denx.de/pipermail/u-boot/attachments/20191101/1fa86699/attachment.sig>

^ permalink raw reply	[flat|nested] 15+ messages in thread

end of thread, other threads:[~2019-11-01 13:29 UTC | newest]

Thread overview: 15+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-08-15 20:04 [U-Boot] [PATCH 1/2] libavb: Update libavb to current AOSP master Sam Protsenko
2019-08-15 20:04 ` [U-Boot] [PATCH 2/2] libavb: Fix build warnings after updating the lib Sam Protsenko
2019-08-16 13:35   ` Eugeniu Rosca
2019-08-16 15:46     ` David Zeuthen
2019-08-19  8:28       ` Eugeniu Rosca
2019-08-19  9:40         ` Igor Opaniuk
2019-08-19  9:50           ` Igor Opaniuk
2019-08-20  2:33           ` Bowgo Tsai
2019-08-19 15:59         ` Tom Rini
2019-11-01 13:29   ` Tom Rini
2019-08-16 10:36 ` [U-Boot] [PATCH 1/2] libavb: Update libavb to current AOSP master Eugeniu Rosca
2019-08-16 10:59   ` Sam Protsenko
2019-08-16 11:06     ` Eugeniu Rosca
2019-10-16  9:32 ` Igor Opaniuk
2019-11-01 13:29 ` Tom Rini

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.