libavb: Support vbmeta blobs in beginning of partition.

If we don't find a AvbFooter when resolving a chain descriptor, also
check if there's a vbmeta struct in the beginning. If there is, use
it.

This is to support the use-case where a single vbmeta_<orgname>
partition can hold metadata for several other partitions which may not
be easily readable by the bootloader (e.g. they are "logical"
partitions using a proprietary partitioning format). For example, this
supports the following setup

vbmeta         # chain desc for vbmeta_google
vbmeta_google  # hash desc for boot, dtbo and hashtree desc for system, vendor
boot
dtbo
super          # container for system and vendor logical partitions
system         # logical partition (not readable by bootloader)
vendor         # logical partition (not readable by bootloader)

where vbmeta_google has the vbmeta struct in the beginning just as if
it were the main vbmeta partition.

Additional change: Previously it was optional to support the
get_size_of_partition() operation. Starting with this commit, this
operation is mandatory and must be implemented such that
AVB_IO_RESULT_ERROR_NO_SUCH_PARTITION is returned for partitions that
don't exist.

Also introduce a new 'extract_vbmeta_image' sub-command to avbtool
that can be used to extract the vbmeta blob from a footer.

Change-Id: I157537f36f77c768283c0745794cf9be93089c35
diff --git a/platform/msm_shared/avb/libavb/avb_ops.h b/platform/msm_shared/avb/libavb/avb_ops.h
index 4899b95..a74e1c0 100644
--- a/platform/msm_shared/avb/libavb/avb_ops.h
+++ b/platform/msm_shared/avb/libavb/avb_ops.h
@@ -221,6 +221,9 @@
    * (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,
diff --git a/platform/msm_shared/avb/libavb/avb_slot_verify.c b/platform/msm_shared/avb/libavb/avb_slot_verify.c
index 60d4a5f..d83c87b 100644
--- a/platform/msm_shared/avb/libavb/avb_slot_verify.c
+++ b/platform/msm_shared/avb/libavb/avb_slot_verify.c
@@ -138,13 +138,6 @@
    */
   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;
@@ -155,7 +148,6 @@
         goto out;
       }
       avb_debugv(part_name, ": Loading entire partition.\n", NULL);
-    }
   }
 
   if (!strncmp(part_name, "boot", strlen("boot"))) {
@@ -272,12 +264,6 @@
   uint8_t* image_buf = NULL;
   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[PART_NAME_MAX_SIZE];
     AvbIOResult io_ret;
@@ -399,7 +385,7 @@
     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,
@@ -411,18 +397,17 @@
     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).
    */
+
+
+  vbmeta_offset = 0;
+  vbmeta_size = VBMETA_MAX_SIZE;
   if (is_vbmeta_partition) {
-    vbmeta_offset = 0;
-    vbmeta_size = VBMETA_MAX_SIZE;
     io_ret = ops->read_from_partition(ops,
                                     partition_name,
                                     vbmeta_offset,
@@ -456,20 +441,18 @@
 
     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;
+      avb_errorv(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;
+      }
     }
 
-    /* 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;
-    }
-    vbmeta_offset = footer.vbmeta_offset;
-    vbmeta_size = footer.vbmeta_size;
     vbmeta_buf = avb_malloc(vbmeta_size); // for chain partitions
     if (vbmeta_buf == NULL) {
         ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
@@ -1299,13 +1282,10 @@
   bool allow_verification_error =
       (flags & AVB_SLOT_VERIFY_FLAGS_ALLOW_VERIFICATION_ERROR);
 
-  /* 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->get_size_of_partition != NULL);
   avb_assert(ops->validate_vbmeta_public_key != NULL);
   avb_assert(ops->read_rollback_index != NULL);
   avb_assert(ops->get_unique_guid_for_partition != NULL);