Merge 47604339566cdc065ee777814ccb6ad9b99989a6 on remote branch

Change-Id: I1c7bbb8822790b38b307af7fcc3fe79b724865b0
diff --git a/platform/msm_shared/avb/VerifiedBoot.c b/platform/msm_shared/avb/VerifiedBoot.c
index a322e5d..5e74a5a 100644
--- a/platform/msm_shared/avb/VerifiedBoot.c
+++ b/platform/msm_shared/avb/VerifiedBoot.c
@@ -473,6 +473,8 @@
 
 	if((!Info->multi_slot_boot || target_dynamic_partition_supported())
 			&& Info->bootinto_recovery) {
+    if(!Info->multi_slot_boot)
+        VerifyFlags = VerifyFlags | AVB_SLOT_VERIFY_FLAGS_NO_VBMETA_PARTITION;
 		AddRequestedPartition(RequestedPartitionAll, IMG_RECOVERY);
 		NumRequestedPartition += 1;
 		/* Add dtbo validation if target supports dtbo image generation and
diff --git a/platform/msm_shared/avb/libavb/avb_ops.c b/platform/msm_shared/avb/libavb/avb_ops.c
index 914af3c..5f9e711 100644
--- a/platform/msm_shared/avb/libavb/avb_ops.c
+++ b/platform/msm_shared/avb/libavb/avb_ops.c
@@ -402,6 +402,65 @@
 	return AVB_IO_RESULT_OK;
 }
 
+AvbIOResult
+AvbValidatePartitionPublicKey(AvbOps *Ops, const char* Partition,
+                           const uint8_t *PublicKeyData, size_t PublicKeyLength,
+                           const uint8_t *PublicKeyMetadata, size_t PublicKeyMetadataLength,
+                           bool *OutIsTrusted, uint32_t* OutRollbackIndexLocation)
+{
+	UINT8 *UserKeyBuffer = NULL;
+	UINT32 UserKeyLength = 0;
+	EFI_STATUS Status = EFI_SUCCESS;
+	AvbOpsUserData *UserData = NULL;
+
+	dprintf(DEBUG, "ValidatePartitionPublicKey PublicKeyLength %d, "
+	                      "PublicKeyMetadataLength %d\n",
+		   PublicKeyLength, PublicKeyMetadataLength);
+
+	if (OutIsTrusted == NULL || PublicKeyData == NULL) {
+		dprintf(ERROR, "Invalid parameters\n");
+		return AVB_IO_RESULT_ERROR_IO;
+	}
+
+	Status = get_userkey(&UserKeyBuffer, &UserKeyLength);
+	if (Status != EFI_SUCCESS) {
+		dprintf(ERROR, "get_userkey failed!, %d\n", Status);
+		return AVB_IO_RESULT_ERROR_IO;
+	}
+
+	UserData = (AvbOpsUserData *)Ops->user_data;
+	UserData->IsUserKey = FALSE;
+
+	if (PublicKeyLength == UserKeyLength &&
+			memcmp (PublicKeyData, UserKeyBuffer, PublicKeyLength) == 0) {
+		*OutIsTrusted = true;
+		UserData->IsUserKey = TRUE;
+	} else if (PublicKeyLength == ARRAY_SIZE(OEMPublicKey) &&
+			   memcmp(PublicKeyData, OEMPublicKey, PublicKeyLength) == 0) {
+		*OutIsTrusted = true;
+	} else {
+		*OutIsTrusted = false;
+		memset (UserData->PublicKey, ARRAY_SIZE (UserData->PublicKey), 0);
+		UserData->PublicKeyLen = 0;
+	}
+
+	if (*OutIsTrusted == true) {
+		if (PublicKeyLength > ARRAY_SIZE (UserData->PublicKey)) {
+			dprintf(ERROR, "ValidatePartitionPublicKey: "
+				"public key length too large %d\n",
+			PublicKeyLength);
+			return AVB_IO_RESULT_ERROR_OOM;
+        }
+        memcpy (UserData->PublicKey, PublicKeyData, PublicKeyLength);
+        UserData->PublicKeyLen = PublicKeyLength;
+    }
+
+	*OutRollbackIndexLocation = 1; // Recovery rollback index
+	dprintf(DEBUG,
+		   "ValidatePartitionPublicKey OutIsTrusted %d, UserKey %d\n",
+		   *OutIsTrusted, UserData->IsUserKey);
+    return AVB_IO_RESULT_OK;
+}
 
 AvbIOResult AvbReadRollbackIndex(AvbOps *Ops, size_t RollbackIndexLocation,
                                  uint64_t *OutRollbackIndex)
@@ -570,6 +629,7 @@
 	Ops->read_from_partition = AvbReadFromPartition;
 	Ops->write_to_partition = AvbWriteToPartition;
 	Ops->validate_vbmeta_public_key = AvbValidateVbmetaPublicKey;
+	Ops->validate_public_key_for_partition = AvbValidatePartitionPublicKey;
 	Ops->read_rollback_index = AvbReadRollbackIndex;
 	Ops->write_rollback_index = AvbWriteRollbackIndex;
 	Ops->read_is_device_unlocked = AvbReadIsDeviceUnlocked;
diff --git a/platform/msm_shared/avb/libavb/avb_ops.h b/platform/msm_shared/avb/libavb/avb_ops.h
index a74e1c0..88127ba 100644
--- a/platform/msm_shared/avb/libavb/avb_ops.h
+++ b/platform/msm_shared/avb/libavb/avb_ops.h
@@ -161,6 +161,9 @@
    *
    * 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,
@@ -229,6 +232,26 @@
   AvbIOResult (*get_size_of_partition)(AvbOps* ops,
                                        const char* partition,
                                        uint64_t* out_size_num_bytes);
+
+  /* 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);
+
 };
 
 typedef struct {
diff --git a/platform/msm_shared/avb/libavb/avb_slot_verify.c b/platform/msm_shared/avb/libavb/avb_slot_verify.c
index 4561cdd..4e7c8f3 100644
--- a/platform/msm_shared/avb/libavb/avb_slot_verify.c
+++ b/platform/msm_shared/avb/libavb/avb_slot_verify.c
@@ -22,6 +22,34 @@
  * SOFTWARE.
  */
 
+/* Copyright (c) 2017,2020, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * * Redistributions of source code must retain the above copyright
+ *  notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ *  with the distribution.
+ *   * Neither the name of The Linux Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
 #include "avb_slot_verify.h"
 #include "avb_chain_partition_descriptor.h"
 #include "avb_footer.h"
@@ -342,6 +370,7 @@
     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,
@@ -378,7 +407,12 @@
    * rollback_index_location to determine whether we're the main
    * vbmeta struct.
    */
-  is_main_vbmeta = (rollback_index_location == 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>').
@@ -490,6 +524,7 @@
       ret = load_and_verify_vbmeta(ops,
                                    requested_partitions,
                                    ab_suffix,
+                                   flags,
                                    allow_verification_error,
                                    0 /* toplevel_vbmeta_flags */,
                                    0 /* rollback_index_location */,
@@ -566,6 +601,8 @@
     }
   }
 
+  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) {
@@ -593,9 +630,27 @@
         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;
@@ -620,7 +675,7 @@
 
   /* 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;
@@ -645,7 +700,7 @@
   if (!allow_verification_error) {
     if (stored_rollback_index < vbmeta_header.rollback_index) {
       io_ret = ops->write_rollback_index(
-          ops, rollback_index_location, vbmeta_header.rollback_index);
+          ops, rollback_index_location_to_use, vbmeta_header.rollback_index);
       if (io_ret != AVB_IO_RESULT_OK) {
         avb_errorv(full_partition_name,
                    ": Error storing rollback index for location.\n",
@@ -660,7 +715,9 @@
   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);
@@ -787,6 +844,7 @@
         sub_ret = load_and_verify_vbmeta(ops,
                                          requested_partitions,
                                          ab_suffix,
+                                         flags,
                                          allow_verification_error,
                                          toplevel_vbmeta_flags,
                                          chain_desc.rollback_index_location,
@@ -889,14 +947,15 @@
     }
   }
 
-  if (rollback_index_location >= AVB_MAX_NUMBER_OF_ROLLBACK_INDEX_LOCATIONS) {
+  if (rollback_index_location_to_use >=
+            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;
     goto out;
   }
 
-  slot_data->rollback_indexes[rollback_index_location] =
+  slot_data->rollback_indexes[rollback_index_location_to_use] =
       vbmeta_header.rollback_index;
 
   if (out_algorithm_type != NULL) {
@@ -984,6 +1043,16 @@
     }
   }
 
+  /* 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;
+    }
+  }
+
   return ret;
 
 fail:
@@ -1108,6 +1177,7 @@
 
 static AvbSlotVerifyResult append_options(
     AvbOps* ops,
+    AvbSlotVerifyFlags flags,
     AvbSlotVerifyData* slot_data,
     AvbVBMetaImageHeader* toplevel_vbmeta,
     AvbAlgorithmType algorithm_type,
@@ -1117,12 +1187,17 @@
   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. */
@@ -1341,10 +1416,9 @@
   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);
-  /* avb_assert(ops->get_size_of_partition != NULL); */
+  avb_assert(ops->validate_public_key_for_partition != NULL);
 
   if (out_data != NULL) {
     *out_data = NULL;
@@ -1360,6 +1434,21 @@
     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;
@@ -1378,30 +1467,66 @@
     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);
-  if (!allow_verification_error && ret != AVB_SLOT_VERIFY_RESULT_OK) {
-    goto fail;
+  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);
+      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);
+    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,
@@ -1443,6 +1568,7 @@
        * I/O or OOM error.
        */
       AvbSlotVerifyResult sub_ret = append_options(ops,
+                                                   flags,
                                                    slot_data,
                                                    &toplevel_vbmeta,
                                                    algorithm_type,
@@ -1471,7 +1597,6 @@
     } else {
       avb_slot_verify_data_free(slot_data);
     }
-  }
 
   if (!allow_verification_error) {
     avb_assert(ret == AVB_SLOT_VERIFY_RESULT_OK);
diff --git a/platform/msm_shared/avb/libavb/avb_slot_verify.h b/platform/msm_shared/avb/libavb/avb_slot_verify.h
index d8de8fb..6315804 100644
--- a/platform/msm_shared/avb/libavb/avb_slot_verify.h
+++ b/platform/msm_shared/avb/libavb/avb_slot_verify.h
@@ -99,10 +99,21 @@
  * contents loaded from |requested_partition| will be the contents of
  * the entire partition instead of just the size specified in the hash
  * descriptor.
+ *
+ * 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|. */
@@ -218,7 +229,9 @@
  *   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