MA-11362 [Android] Update AVB lib in u-boot
authorLuo Ji <ji.luo@nxp.com>
Mon, 12 Feb 2018 06:11:47 +0000 (14:11 +0800)
committerzhang sanshan <sanshan.zhang@nxp.com>
Fri, 23 Feb 2018 06:04:17 +0000 (14:04 +0800)
This commit did:
1. Sync the AVB lib with external/avb with commit head:
   commit 8a8103513dea5c47037200beabad2a307f09ecc8
   Merge: 2ee8dbe 852858e
   Author: David Zeuthen <zeuthen@google.com>
   Date:   Fri Jun 30 16:08:03 2017 +0000
    Revert "avbtool: Avoid using $(ANDROID_VERITY_MODE) for now."
am: 1b2f7a64e2
am: 852858e2ed
2. Fix build error and implement ops function
   fsl_get_size_of_partition().

Change-Id: I3d1a04c320b8ea89e9fe28124cf866bd62282e78
Signed-off-by: Luo Ji <ji.luo@nxp.com>
13 files changed:
drivers/usb/gadget/f_fastboot.c
include/fsl_avb.h
lib/avb/fsl/fsl_avb.c
lib/avb/libavb/avb_crc32.c
lib/avb/libavb/avb_ops.h
lib/avb/libavb/avb_rsa.c
lib/avb/libavb/avb_slot_verify.c
lib/avb/libavb/avb_slot_verify.h
lib/avb/libavb/avb_sysdeps.h
lib/avb/libavb/avb_vbmeta_image.h
lib/avb/libavb/avb_version.h
lib/avb/libavb_ab/avb_ab_flow.c
lib/avb/libavb_ab/avb_ab_flow.h

index 7fdabf3..f0a1af7 100755 (executable)
@@ -1304,7 +1304,8 @@ static AvbOps fsl_avb_ops = {
        .read_rollback_index = fsl_read_rollback_index_rpmb,
        .write_rollback_index = fsl_write_rollback_index_rpmb,
        .read_is_device_unlocked = fsl_read_is_device_unlocked,
-       .get_unique_guid_for_partition = fsl_get_unique_guid_for_partition
+       .get_unique_guid_for_partition = fsl_get_unique_guid_for_partition,
+       .get_size_of_partition = fsl_get_size_of_partition
 };
 #endif
 
@@ -1555,7 +1556,8 @@ int do_boota(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) {
        bool allow_fail = (lock_status == FASTBOOT_UNLOCK ? true : false);
        avb_metric = get_timer(0);
        /* if in lock state, do avb verify */
-       avb_result = avb_ab_flow_fast(&fsl_avb_ab_ops, requested_partitions, allow_fail, &avb_out_data);
+       avb_result = avb_ab_flow_fast(&fsl_avb_ab_ops, requested_partitions, allow_fail,
+                       AVB_HASHTREE_ERROR_MODE_RESTART_AND_INVALIDATE, &avb_out_data);
        /* get the duration of avb */
        metrics.avb = get_timer(avb_metric);
 
index 56fb2eb..9cf3249 100644 (file)
@@ -139,6 +139,14 @@ AvbIOResult fsl_get_unique_guid_for_partition(AvbOps* ops,
                                              char* guid_buf,
                                              size_t guid_buf_size);
 
+/* Gets the size of a partition with the name in |partition|
+ * (NUL-terminated UTF-8 string). Returns the value in
+ * |out_size_num_bytes|.
+ * Returns AVB_IO_RESULT_OK on success, otherwise an error code.
+ */
+AvbIOResult fsl_get_size_of_partition(AvbOps* ops,
+                                             const char* partition,
+                                            uint64_t* out_size_num_bytes);
 /* check if the fastboot getvar cmd is for query [avb] bootctl's slot var
  * cmd is the fastboot getvar's cmd in
  * return true if it is a bootctl related cmd, false if it's not.
index 567780d..50a6901 100644 (file)
@@ -410,4 +410,23 @@ AvbIOResult fsl_get_unique_guid_for_partition(AvbOps* ops,
 #else
        return AVB_IO_RESULT_ERROR_IO;
 #endif
+
+}
+/* Gets the size of a partition with the name in |partition|
+ * (NUL-terminated UTF-8 string). Returns the value in
+ * |out_size_num_bytes|.
+ * Returns AVB_IO_RESULT_OK on success, otherwise an error code.
+ */
+AvbIOResult fsl_get_size_of_partition(AvbOps* ops,
+               const char* partition,
+               uint64_t* out_size_num_bytes)
+{
+       struct fastboot_ptentry *pte;
+       pte = fastboot_flash_find_ptn(partition);
+       if (!pte) {
+               ERR("no %s partition\n", partition);
+               return AVB_IO_RESULT_ERROR_NO_SUCH_PARTITION;
+       }
+       *out_size_num_bytes = (uint64_t)(pte->length * 512);
+       return AVB_IO_RESULT_OK;
 }
index a6b806d..7d4cb09 100644 (file)
  */
 
 #include "avb_sysdeps.h"
+#include "avb_util.h"
 
 /* Code taken from FreeBSD 8 */
 
-static uint32_t crc32_tab[] = {
+static uint32_t iavb_crc32_tab[] = {
     0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f,
     0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
     0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2,
@@ -98,16 +99,16 @@ static uint32_t crc32_tab[] = {
  * in sys/libkern.h, where it can be inlined.
  */
 
-static uint32_t _crc32(uint32_t crc_in, const uint8_t* buf, int size) {
+static uint32_t iavb_crc32(uint32_t crc_in, const uint8_t* buf, int size) {
   const uint8_t* p = buf;
   uint32_t crc;
 
   crc = crc_in ^ ~0U;
   while (size--)
-    crc = crc32_tab[(crc ^ *p++) & 0xFF] ^ (crc >> 8);
+    crc = iavb_crc32_tab[(crc ^ *p++) & 0xFF] ^ (crc >> 8);
   return crc ^ ~0U;
 }
 
 uint32_t avb_crc32(const uint8_t* buf, size_t size) {
-  return _crc32(0, buf, size);
+  return iavb_crc32(0, buf, size);
 }
index 908c66c..de36b59 100644 (file)
@@ -71,6 +71,10 @@ struct AvbAtxOps;
 
 /* High-level operations/functions/methods that are platform
  * dependent.
+ *
+ * Operations may be added in the future so when implementing it
+ * always make sure to zero out sizeof(AvbOps) bytes of the struct to
+ * ensure that unimplemented operations are set to NULL.
  */
 struct AvbOps {
   /* This pointer can be used by the application/bootloader using
@@ -205,6 +209,16 @@ struct AvbOps {
                                                const char* partition,
                                                char* guid_buf,
                                                size_t guid_buf_size);
+
+  /* Gets the size of a partition with the name in |partition|
+   * (NUL-terminated UTF-8 string). Returns the value in
+   * |out_size_num_bytes|.
+   *
+   * Returns AVB_IO_RESULT_OK on success, otherwise an error code.
+   */
+  AvbIOResult (*get_size_of_partition)(AvbOps* ops,
+                                       const char* partition,
+                                       uint64_t* out_size_num_bytes);
 };
 
 #ifdef __cplusplus
index dcecc16..f4cb322 100644 (file)
 #include "avb_util.h"
 #include "avb_vbmeta_image.h"
 
-typedef struct Key {
+typedef struct IAvbKey {
   unsigned int len; /* Length of n[] in number of uint32_t */
   uint32_t n0inv;   /* -1 / n[0] mod 2^32 */
   uint32_t* n;      /* modulus as array (host-byte order) */
   uint32_t* rr;     /* R^2 as array (host-byte order) */
-} Key;
+} IAvbKey;
 
-Key* parse_key_data(const uint8_t* data, size_t length) {
+static IAvbKey* iavb_parse_key_data(const uint8_t* data, size_t length) {
   AvbRSAPublicKeyHeader h;
-  Key* key = NULL;
+  IAvbKey* key = NULL;
   size_t expected_length;
   unsigned int i;
   const uint8_t* n;
@@ -76,14 +76,14 @@ Key* parse_key_data(const uint8_t* data, size_t length) {
   /* Store n and rr following the key header so we only have to do one
    * allocation.
    */
-  key = (Key*)(avb_malloc(sizeof(Key) + 2 * h.key_num_bits / 8));
+  key = (IAvbKey*)(avb_malloc(sizeof(IAvbKey) + 2 * h.key_num_bits / 8));
   if (key == NULL) {
     goto fail;
   }
 
   key->len = h.key_num_bits / 32;
   key->n0inv = h.n0inv;
-  key->n = (uint32_t*)(key + 1); /* Skip ahead sizeof(Key) bytes. */
+  key->n = (uint32_t*)(key + 1); /* Skip ahead sizeof(IAvbKey) bytes. */
   key->rr = key->n + key->len;
 
   /* Crypto-code below (modpowF4() and friends) expects the key in
@@ -103,12 +103,12 @@ fail:
   return NULL;
 }
 
-void free_parsed_key(Key* key) {
+static void iavb_free_parsed_key(IAvbKey* key) {
   avb_free(key);
 }
 
 /* a[] -= mod */
-static void subM(const Key* key, uint32_t* a) {
+static void subM(const IAvbKey* key, uint32_t* a) {
   int64_t A = 0;
   uint32_t i;
   for (i = 0; i < key->len; ++i) {
@@ -119,7 +119,7 @@ static void subM(const Key* key, uint32_t* a) {
 }
 
 /* return a[] >= mod */
-static int geM(const Key* key, uint32_t* a) {
+static int geM(const IAvbKey* key, uint32_t* a) {
   uint32_t i;
   for (i = key->len; i;) {
     --i;
@@ -134,7 +134,7 @@ static int geM(const Key* key, uint32_t* a) {
 }
 
 /* montgomery c[] += a * b[] / R % mod */
-static void montMulAdd(const Key* key,
+static void montMulAdd(const IAvbKey* key,
                        uint32_t* c,
                        const uint32_t a,
                        const uint32_t* b) {
@@ -159,7 +159,7 @@ static void montMulAdd(const Key* key,
 }
 
 /* montgomery c[] = a[] * b[] / R % mod */
-static void montMul(const Key* key, uint32_t* c, uint32_t* a, uint32_t* b) {
+static void montMul(const IAvbKey* key, uint32_t* c, uint32_t* a, uint32_t* b) {
   uint32_t i;
   for (i = 0; i < key->len; ++i) {
     c[i] = 0;
@@ -172,7 +172,7 @@ static void montMul(const Key* key, uint32_t* c, uint32_t* a, uint32_t* b) {
 /* In-place public exponentiation. (65537}
  * Input and output big-endian byte array in inout.
  */
-static void modpowF4(const Key* key, uint8_t* inout) {
+static void modpowF4(const IAvbKey* key, uint8_t* inout) {
   uint32_t* a = (uint32_t*)avb_malloc(key->len * sizeof(uint32_t));
   uint32_t* aR = (uint32_t*)avb_malloc(key->len * sizeof(uint32_t));
   uint32_t* aaR = (uint32_t*)avb_malloc(key->len * sizeof(uint32_t));
@@ -237,7 +237,7 @@ bool avb_rsa_verify(const uint8_t* key,
                     const uint8_t* padding,
                     size_t padding_num_bytes) {
   uint8_t* buf = NULL;
-  Key* parsed_key = NULL;
+  IAvbKey* parsed_key = NULL;
   bool success = false;
 
   if (key == NULL || sig == NULL || hash == NULL || padding == NULL) {
@@ -245,7 +245,7 @@ bool avb_rsa_verify(const uint8_t* key,
     goto out;
   }
 
-  parsed_key = parse_key_data(key, key_num_bytes);
+  parsed_key = iavb_parse_key_data(key, key_num_bytes);
   if (parsed_key == NULL) {
     avb_error("Error parsing key.\n");
     goto out;
@@ -290,7 +290,7 @@ bool avb_rsa_verify(const uint8_t* key,
 
 out:
   if (parsed_key != NULL) {
-    free_parsed_key(parsed_key);
+    iavb_free_parsed_key(parsed_key);
   }
   if (buf != NULL) {
     avb_free(buf);
index add57c7..369165e 100644 (file)
@@ -58,6 +58,7 @@ static inline bool result_should_continue(AvbSlotVerifyResult result) {
     case AVB_SLOT_VERIFY_RESULT_ERROR_IO:
     case AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA:
     case AVB_SLOT_VERIFY_RESULT_ERROR_UNSUPPORTED_VERSION:
+    case AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_ARGUMENT:
       return false;
 
     case AVB_SLOT_VERIFY_RESULT_OK:
@@ -91,6 +92,7 @@ static AvbSlotVerifyResult load_and_verify_hash_partition(
   uint8_t* digest;
   size_t digest_len;
   const char* found;
+  uint64_t image_size;
 
   if (!avb_hash_descriptor_validate_and_byteswap(
           (const AvbHashDescriptor*)descriptor, &hash_desc)) {
@@ -109,6 +111,17 @@ static AvbSlotVerifyResult load_and_verify_hash_partition(
     goto out;
   }
 
+  /* Don't bother loading or validating unless the partition was
+   * requested in the first place.
+   */
+  found = avb_strv_find_str(requested_partitions,
+                            (const char*)desc_partition_name,
+                            hash_desc.partition_name_len);
+  if (found == NULL) {
+    ret = AVB_SLOT_VERIFY_RESULT_OK;
+    goto out;
+  }
+
   if (!avb_str_concat(part_name,
                       sizeof part_name,
                       (const char*)desc_partition_name,
@@ -120,6 +133,36 @@ static AvbSlotVerifyResult load_and_verify_hash_partition(
     goto out;
   }
 
+  /* If we're allowing verification errors then hash_desc.image_size
+   * may no longer match what's in the partition... so in this case
+   * just load the entire partition.
+   *
+   * For example, this can happen if a developer does 'fastboot flash
+   * boot /path/to/new/and/bigger/boot.img'. We want this to work
+   * since it's such a common workflow.
+   */
+  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);
+    }
+  }
+
   /* If we are going to load bootimage, load it to
    * hdr->kernel_addr - hdr->page_size address directly,
    * so we don't need to copy it again!*/
@@ -152,12 +195,8 @@ static AvbSlotVerifyResult load_and_verify_hash_partition(
     }
   }
 
-  io_ret = ops->read_from_partition(ops,
-                                    part_name,
-                                    0 /* offset */,
-                                    hash_desc.image_size,
-                                    image_buf,
-                                    &part_num_read);
+  io_ret = ops->read_from_partition(
+      ops, part_name, 0 /* offset */, image_size, image_buf, &part_num_read);
   if (io_ret == AVB_IO_RESULT_ERROR_OOM) {
     ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
     goto out;
@@ -166,7 +205,7 @@ static AvbSlotVerifyResult load_and_verify_hash_partition(
     ret = AVB_SLOT_VERIFY_RESULT_ERROR_IO;
     goto out;
   }
-  if (part_num_read != hash_desc.image_size) {
+  if (part_num_read != image_size) {
     avb_errorv(part_name, ": Read fewer than requested bytes.\n", NULL);
     ret = AVB_SLOT_VERIFY_RESULT_ERROR_IO;
     goto out;
@@ -211,25 +250,21 @@ static AvbSlotVerifyResult load_and_verify_hash_partition(
 
 out:
 
-  if (ret == AVB_SLOT_VERIFY_RESULT_OK || result_should_continue(ret)) {
-    /* If this is the requested partition, copy to slot_data. */
-    found = avb_strv_find_str(requested_partitions,
-                              (const char*)desc_partition_name,
-                              hash_desc.partition_name_len);
-    if (found != NULL) {
-      AvbPartitionData* loaded_partition;
-      if (slot_data->num_loaded_partitions == MAX_NUMBER_OF_LOADED_PARTITIONS) {
-        avb_errorv(part_name, ": Too many loaded partitions.\n", NULL);
-        ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
-        goto fail;
-      }
-      loaded_partition =
-          &slot_data->loaded_partitions[slot_data->num_loaded_partitions++];
-      loaded_partition->partition_name = avb_strdup(found);
-      loaded_partition->data_size = hash_desc.image_size;
-      loaded_partition->data = image_buf;
-      image_buf = NULL;
+  /* If it worked and something was loaded, copy to slot_data. */
+  if ((ret == AVB_SLOT_VERIFY_RESULT_OK || result_should_continue(ret)) &&
+      image_buf != NULL) {
+    AvbPartitionData* loaded_partition;
+    if (slot_data->num_loaded_partitions == MAX_NUMBER_OF_LOADED_PARTITIONS) {
+      avb_errorv(part_name, ": Too many loaded partitions.\n", NULL);
+      ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
+      goto fail;
     }
+    loaded_partition =
+        &slot_data->loaded_partitions[slot_data->num_loaded_partitions++];
+    loaded_partition->partition_name = avb_strdup(found);
+    loaded_partition->data_size = image_size;
+    loaded_partition->data = image_buf;
+    image_buf = NULL;
   }
 
 fail:
@@ -239,6 +274,99 @@ fail:
   return ret;
 }
 
+static AvbSlotVerifyResult load_requested_partitions(
+    AvbOps* ops,
+    const char* const* requested_partitions,
+    const char* ab_suffix,
+    AvbSlotVerifyData* slot_data) {
+  AvbSlotVerifyResult ret;
+  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;
+    uint64_t image_size;
+    size_t part_num_read;
+    AvbPartitionData* loaded_partition;
+
+    if (!avb_str_concat(part_name,
+                        sizeof part_name,
+                        requested_partitions[n],
+                        avb_strlen(requested_partitions[n]),
+                        ab_suffix,
+                        avb_strlen(ab_suffix))) {
+      avb_error("Partition name and suffix does not fit.\n");
+      ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;
+      goto out;
+    }
+
+    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);
+
+    image_buf = avb_malloc(image_size);
+    if (image_buf == NULL) {
+      ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
+      goto out;
+    }
+
+    io_ret = ops->read_from_partition(
+        ops, part_name, 0 /* offset */, image_size, image_buf, &part_num_read);
+    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 loading data from partition.\n", NULL);
+      ret = AVB_SLOT_VERIFY_RESULT_ERROR_IO;
+      goto out;
+    }
+    if (part_num_read != image_size) {
+      avb_errorv(part_name, ": Read fewer than requested bytes.\n", NULL);
+      ret = AVB_SLOT_VERIFY_RESULT_ERROR_IO;
+      goto out;
+    }
+
+    /* Move to slot_data. */
+    if (slot_data->num_loaded_partitions == MAX_NUMBER_OF_LOADED_PARTITIONS) {
+      avb_errorv(part_name, ": Too many loaded partitions.\n", NULL);
+      ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
+      goto out;
+    }
+    loaded_partition =
+        &slot_data->loaded_partitions[slot_data->num_loaded_partitions++];
+    loaded_partition->partition_name = avb_strdup(requested_partitions[n]);
+    if (loaded_partition->partition_name == NULL) {
+      ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
+      goto out;
+    }
+    loaded_partition->data_size = image_size;
+    loaded_partition->data = image_buf;
+    image_buf = NULL;
+  }
+
+  ret = AVB_SLOT_VERIFY_RESULT_OK;
+
+out:
+  if (image_buf != NULL) {
+    avb_free(image_buf);
+  }
+  return ret;
+}
+
 static AvbSlotVerifyResult load_and_verify_vbmeta(
     AvbOps* ops,
     const char* const* requested_partitions,
@@ -471,7 +599,7 @@ static AvbSlotVerifyResult load_and_verify_vbmeta(
         }
       }
     } else {
-      bool key_is_trusted = true;
+      bool key_is_trusted = false;
       const uint8_t* pk_metadata = NULL;
       size_t pk_metadata_len = 0;
 
@@ -556,6 +684,27 @@ static AvbSlotVerifyResult load_and_verify_vbmeta(
       vbmeta_header.auxiliary_data_block_size;
   vbmeta_image_data->verify_result = vbmeta_ret;
 
+  /* If verification has been disabled by setting a bit in the image,
+   * we're done... except that we need to load the entirety of the
+   * requested partitions.
+   */
+  if (vbmeta_header.flags & AVB_VBMETA_IMAGE_FLAGS_VERIFICATION_DISABLED) {
+    AvbSlotVerifyResult sub_ret;
+    avb_debugv(
+        full_partition_name, ": VERIFICATION_DISABLED bit is set.\n", NULL);
+    /* If load_requested_partitions() fail it is always a fatal
+     * failure (e.g. ERROR_INVALID_ARGUMENT, ERROR_OOM, etc.) rather
+     * than recoverable (e.g. one where result_should_continue()
+     * returns true) and we want to convey that error.
+     */
+    sub_ret = load_requested_partitions(
+        ops, requested_partitions, ab_suffix, slot_data);
+    if (sub_ret != AVB_SLOT_VERIFY_RESULT_OK) {
+      ret = sub_ret;
+    }
+    goto out;
+  }
+
   /* Now go through all descriptors and take the appropriate action:
    *
    * - hash descriptor: Load data from partition, calculate hash, and
@@ -949,21 +1098,208 @@ static int cmdline_append_hex(AvbSlotVerifyData* slot_data,
   return ret;
 }
 
+static AvbSlotVerifyResult append_options(
+    AvbOps* ops,
+    AvbSlotVerifyData* slot_data,
+    AvbVBMetaImageHeader* toplevel_vbmeta,
+    AvbAlgorithmType algorithm_type,
+    AvbHashtreeErrorMode hashtree_error_mode) {
+  AvbSlotVerifyResult ret;
+  const char* verity_mode = "enforcing";
+  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.avb_version option. */
+  if (!cmdline_append_version(slot_data,
+                              "androidboot.vbmeta.avb_version",
+                              AVB_VERSION_MAJOR,
+                              AVB_VERSION_MINOR)) {
+    ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
+    goto out;
+  }
+
+  /* Set androidboot.avb.device_state to "locked" or "unlocked". */
+  io_ret = ops->read_is_device_unlocked(ops, &is_device_unlocked);
+  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_error("Error getting device state.\n");
+    ret = AVB_SLOT_VERIFY_RESULT_ERROR_IO;
+    goto out;
+  }
+  if (!cmdline_append_option(slot_data,
+                             "androidboot.vbmeta.device_state",
+                             is_device_unlocked ? "unlocked" : "locked")) {
+    ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
+    goto out;
+  }
+
+  /* Set androidboot.vbmeta.{hash_alg, size, digest} - use same hash
+   * function as is used to sign vbmeta.
+   */
+  switch (algorithm_type) {
+    /* Explicit fallthrough. */
+    case AVB_ALGORITHM_TYPE_NONE:
+    case AVB_ALGORITHM_TYPE_SHA256_RSA2048:
+    case AVB_ALGORITHM_TYPE_SHA256_RSA4096:
+    case AVB_ALGORITHM_TYPE_SHA256_RSA8192: {
+      AvbSHA256Ctx ctx;
+      size_t n, total_size = 0;
+      avb_sha256_init(&ctx);
+      for (n = 0; n < slot_data->num_vbmeta_images; n++) {
+        avb_sha256_update(&ctx,
+                          slot_data->vbmeta_images[n].vbmeta_data,
+                          slot_data->vbmeta_images[n].vbmeta_size);
+        total_size += slot_data->vbmeta_images[n].vbmeta_size;
+      }
+      if (!cmdline_append_option(
+              slot_data, "androidboot.vbmeta.hash_alg", "sha256") ||
+          !cmdline_append_uint64_base10(
+              slot_data, "androidboot.vbmeta.size", total_size) ||
+          !cmdline_append_hex(slot_data,
+                              "androidboot.vbmeta.digest",
+                              avb_sha256_final(&ctx),
+                              AVB_SHA256_DIGEST_SIZE)) {
+        ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
+        goto out;
+      }
+    } break;
+    /* Explicit fallthrough. */
+    case AVB_ALGORITHM_TYPE_SHA512_RSA2048:
+    case AVB_ALGORITHM_TYPE_SHA512_RSA4096:
+    case AVB_ALGORITHM_TYPE_SHA512_RSA8192: {
+      AvbSHA512Ctx ctx;
+      size_t n, total_size = 0;
+      avb_sha512_init(&ctx);
+      for (n = 0; n < slot_data->num_vbmeta_images; n++) {
+        avb_sha512_update(&ctx,
+                          slot_data->vbmeta_images[n].vbmeta_data,
+                          slot_data->vbmeta_images[n].vbmeta_size);
+        total_size += slot_data->vbmeta_images[n].vbmeta_size;
+      }
+      if (!cmdline_append_option(
+              slot_data, "androidboot.vbmeta.hash_alg", "sha512") ||
+          !cmdline_append_uint64_base10(
+              slot_data, "androidboot.vbmeta.size", total_size) ||
+          !cmdline_append_hex(slot_data,
+                              "androidboot.vbmeta.digest",
+                              avb_sha512_final(&ctx),
+                              AVB_SHA512_DIGEST_SIZE)) {
+        ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
+        goto out;
+      }
+    } break;
+    case _AVB_ALGORITHM_NUM_TYPES:
+      avb_assert_not_reached();
+      break;
+  }
+
+  /* Set androidboot.veritymode and androidboot.vbmeta.invalidate_on_error */
+  if (toplevel_vbmeta->flags & AVB_VBMETA_IMAGE_FLAGS_HASHTREE_DISABLED) {
+    verity_mode = "disabled";
+  } else {
+    const char* dm_verity_mode = "restart_on_corruption";
+    char* new_ret;
+
+    switch (hashtree_error_mode) {
+      case AVB_HASHTREE_ERROR_MODE_RESTART_AND_INVALIDATE:
+        if (!cmdline_append_option(
+                slot_data, "androidboot.vbmeta.invalidate_on_error", "yes")) {
+          ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
+          goto out;
+        }
+        verity_mode = "enforcing";
+        dm_verity_mode = "restart_on_corruption";
+        break;
+      case AVB_HASHTREE_ERROR_MODE_RESTART:
+        verity_mode = "enforcing";
+        dm_verity_mode = "restart_on_corruption";
+        break;
+      case AVB_HASHTREE_ERROR_MODE_EIO:
+        verity_mode = "eio";
+        /* For now there's no option to specify the EIO mode. So
+         * just use 'ignore_zero_blocks' since that's already set
+         * and dm-verity-target.c supports specifying this multiple
+         * times.
+         */
+        dm_verity_mode = "ignore_zero_blocks";
+        break;
+      case AVB_HASHTREE_ERROR_MODE_LOGGING:
+        verity_mode = "logging";
+        dm_verity_mode = "ignore_corruption";
+        break;
+    }
+    new_ret = avb_replace(
+        slot_data->cmdline, "$(ANDROID_VERITY_MODE)", dm_verity_mode);
+    avb_free(slot_data->cmdline);
+    slot_data->cmdline = new_ret;
+    if (slot_data->cmdline == NULL) {
+      ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
+      goto out;
+    }
+  }
+  if (!cmdline_append_option(
+          slot_data, "androidboot.veritymode", verity_mode)) {
+    ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
+    goto out;
+  }
+
+  ret = AVB_SLOT_VERIFY_RESULT_OK;
+
+out:
+
+  return ret;
+}
+
 AvbSlotVerifyResult avb_slot_verify(AvbOps* ops,
                                     const char* const* requested_partitions,
                                     const char* ab_suffix,
-                                    bool allow_verification_error,
+                                    AvbSlotVerifyFlags flags,
+                                    AvbHashtreeErrorMode hashtree_error_mode,
                                     AvbSlotVerifyData** out_data) {
   AvbSlotVerifyResult ret;
   AvbSlotVerifyData* slot_data = NULL;
   AvbAlgorithmType algorithm_type = AVB_ALGORITHM_TYPE_NONE;
-  AvbIOResult io_ret;
   bool using_boot_for_vbmeta = false;
+  AvbVBMetaImageHeader toplevel_vbmeta;
+  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.
+   */
+  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->read_rollback_index != NULL);
+  avb_assert(ops->get_unique_guid_for_partition != NULL);
+  /* avb_assert(ops->get_size_of_partition != NULL); */
 
   if (out_data != NULL) {
     *out_data = NULL;
   }
 
+  /* Allowing dm-verity errors defeats the purpose of verified boot so
+   * only allow this if set up to allow verification errors
+   * (e.g. typically only UNLOCKED mode).
+   */
+  if (hashtree_error_mode == AVB_HASHTREE_ERROR_MODE_LOGGING &&
+      !allow_verification_error) {
+    ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_ARGUMENT;
+    goto fail;
+  }
+
   slot_data = avb_calloc(sizeof(AvbSlotVerifyData));
   if (slot_data == NULL) {
     ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
@@ -998,14 +1334,19 @@ AvbSlotVerifyResult avb_slot_verify(AvbOps* ops,
     goto fail;
   }
 
-  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;
-  }
-
   /* If things check out, mangle the kernel command-line as needed. */
   if (result_should_continue(ret)) {
+    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);
+
     /* Fill in |ab_suffix| field. */
     slot_data->ab_suffix = avb_strdup(ab_suffix);
     if (slot_data->ab_suffix == NULL) {
@@ -1013,21 +1354,35 @@ AvbSlotVerifyResult avb_slot_verify(AvbOps* ops,
       goto fail;
     }
 
-    /* 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 fail;
-    }
-
-    /* Add androidboot.vbmeta.avb_version option. */
-    if (!cmdline_append_version(slot_data,
-                                "androidboot.vbmeta.avb_version",
-                                AVB_VERSION_MAJOR,
-                                AVB_VERSION_MINOR)) {
-      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 (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);
+      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 append_options() is either an
+       * I/O or OOM error.
+       */
+      AvbSlotVerifyResult sub_ret = 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;
+      }
     }
 
     /* Substitute $(ANDROID_SYSTEM_PARTUUID) and friends. */
@@ -1043,84 +1398,6 @@ AvbSlotVerifyResult avb_slot_verify(AvbOps* ops,
       slot_data->cmdline = new_cmdline;
     }
 
-    /* Set androidboot.avb.device_state to "locked" or "unlocked". */
-    bool is_device_unlocked;
-    io_ret = ops->read_is_device_unlocked(ops, &is_device_unlocked);
-    if (io_ret == AVB_IO_RESULT_ERROR_OOM) {
-      ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
-      goto fail;
-    } else if (io_ret != AVB_IO_RESULT_OK) {
-      avb_error("Error getting device state.\n");
-      ret = AVB_SLOT_VERIFY_RESULT_ERROR_IO;
-      goto fail;
-    }
-    if (!cmdline_append_option(slot_data,
-                               "androidboot.vbmeta.device_state",
-                               is_device_unlocked ? "unlocked" : "locked")) {
-      ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
-      goto fail;
-    }
-
-    /* Set androidboot.vbmeta.{hash_alg, size, digest} - use same hash
-     * function as is used to sign vbmeta.
-     */
-    switch (algorithm_type) {
-      /* Explicit fallthrough. */
-      case AVB_ALGORITHM_TYPE_NONE:
-      case AVB_ALGORITHM_TYPE_SHA256_RSA2048:
-      case AVB_ALGORITHM_TYPE_SHA256_RSA4096:
-      case AVB_ALGORITHM_TYPE_SHA256_RSA8192: {
-        AvbSHA256Ctx ctx;
-        size_t n, total_size = 0;
-        avb_sha256_init(&ctx);
-        for (n = 0; n < slot_data->num_vbmeta_images; n++) {
-          avb_sha256_update(&ctx,
-                            slot_data->vbmeta_images[n].vbmeta_data,
-                            slot_data->vbmeta_images[n].vbmeta_size);
-          total_size += slot_data->vbmeta_images[n].vbmeta_size;
-        }
-        if (!cmdline_append_option(
-                slot_data, "androidboot.vbmeta.hash_alg", "sha256") ||
-            !cmdline_append_uint64_base10(
-                slot_data, "androidboot.vbmeta.size", total_size) ||
-            !cmdline_append_hex(slot_data,
-                                "androidboot.vbmeta.digest",
-                                avb_sha256_final(&ctx),
-                                AVB_SHA256_DIGEST_SIZE)) {
-          ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
-          goto fail;
-        }
-      } break;
-      /* Explicit fallthrough. */
-      case AVB_ALGORITHM_TYPE_SHA512_RSA2048:
-      case AVB_ALGORITHM_TYPE_SHA512_RSA4096:
-      case AVB_ALGORITHM_TYPE_SHA512_RSA8192: {
-        AvbSHA512Ctx ctx;
-        size_t n, total_size = 0;
-        avb_sha512_init(&ctx);
-        for (n = 0; n < slot_data->num_vbmeta_images; n++) {
-          avb_sha512_update(&ctx,
-                            slot_data->vbmeta_images[n].vbmeta_data,
-                            slot_data->vbmeta_images[n].vbmeta_size);
-          total_size += slot_data->vbmeta_images[n].vbmeta_size;
-        }
-        if (!cmdline_append_option(
-                slot_data, "androidboot.vbmeta.hash_alg", "sha512") ||
-            !cmdline_append_uint64_base10(
-                slot_data, "androidboot.vbmeta.size", total_size) ||
-            !cmdline_append_hex(slot_data,
-                                "androidboot.vbmeta.digest",
-                                avb_sha512_final(&ctx),
-                                AVB_SHA512_DIGEST_SIZE)) {
-          ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
-          goto fail;
-        }
-      } break;
-      case _AVB_ALGORITHM_NUM_TYPES:
-        avb_assert_not_reached();
-        break;
-    }
-
     if (out_data != NULL) {
       *out_data = slot_data;
     } else {
@@ -1141,7 +1418,7 @@ fail:
   return ret;
 }
 
-void avb_slot_verify_data_free(AvbSlotVerifyData* data) {
+void avb_slot_verify_data_free_fast(AvbSlotVerifyData* data) {
   if (data->ab_suffix != NULL) {
     avb_free(data->ab_suffix);
   }
@@ -1166,7 +1443,12 @@ void avb_slot_verify_data_free(AvbSlotVerifyData* data) {
     for (n = 0; n < data->num_loaded_partitions; n++) {
       AvbPartitionData* loaded_partition = &data->loaded_partitions[n];
       if (loaded_partition->partition_name != NULL) {
-        avb_free(loaded_partition->partition_name);
+       /* the address of bootimage isn't alloced by malloc, we don't
+        * need to free it. */
+        if (strstr(loaded_partition->partition_name, "boot") != NULL)
+         continue;
+       else
+          avb_free(loaded_partition->partition_name);
       }
       if (loaded_partition->data != NULL) {
         avb_free(loaded_partition->data);
@@ -1176,7 +1458,8 @@ void avb_slot_verify_data_free(AvbSlotVerifyData* data) {
   }
   avb_free(data);
 }
-void avb_slot_verify_data_free_fast(AvbSlotVerifyData* data) {
+
+void avb_slot_verify_data_free(AvbSlotVerifyData* data) {
   if (data->ab_suffix != NULL) {
     avb_free(data->ab_suffix);
   }
@@ -1201,12 +1484,7 @@ void avb_slot_verify_data_free_fast(AvbSlotVerifyData* data) {
     for (n = 0; n < data->num_loaded_partitions; n++) {
       AvbPartitionData* loaded_partition = &data->loaded_partitions[n];
       if (loaded_partition->partition_name != NULL) {
-       /* the address of bootimage isn't alloced by malloc, we don't
-        * need to free it. */
-        if (strstr(loaded_partition->partition_name, "boot") != NULL)
-         continue;
-       else
-          avb_free(loaded_partition->partition_name);
+        avb_free(loaded_partition->partition_name);
       }
       if (loaded_partition->data != NULL) {
         avb_free(loaded_partition->data);
@@ -1245,6 +1523,9 @@ const char* avb_slot_verify_result_to_string(AvbSlotVerifyResult result) {
     case AVB_SLOT_VERIFY_RESULT_ERROR_UNSUPPORTED_VERSION:
       ret = "ERROR_UNSUPPORTED_VERSION";
       break;
+    case AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_ARGUMENT:
+      ret = "ERROR_INVALID_ARGUMENT";
+      break;
       /* Do not add a 'default:' case here because of -Wswitch. */
   }
 
index 0293304..60033cf 100644 (file)
@@ -50,9 +50,61 @@ typedef enum {
   AVB_SLOT_VERIFY_RESULT_ERROR_ROLLBACK_INDEX,
   AVB_SLOT_VERIFY_RESULT_ERROR_PUBLIC_KEY_REJECTED,
   AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA,
-  AVB_SLOT_VERIFY_RESULT_ERROR_UNSUPPORTED_VERSION
+  AVB_SLOT_VERIFY_RESULT_ERROR_UNSUPPORTED_VERSION,
+  AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_ARGUMENT
 } AvbSlotVerifyResult;
 
+/* Various error handling modes for when verification fails using a
+ * hashtree at runtime inside the HLOS.
+ *
+ * AVB_HASHTREE_ERROR_MODE_RESTART_AND_INVALIDATE means that the OS
+ * will invalidate the current slot and restart.
+ *
+ * AVB_HASHTREE_ERROR_MODE_RESTART means that the OS will restart.
+ *
+ * AVB_HASHTREE_ERROR_MODE_EIO means that an EIO error will be
+ * returned to applications.
+ *
+ * AVB_HASHTREE_ERROR_MODE_LOGGING means that errors will be logged
+ * and corrupt data may be returned to applications. This mode should
+ * be used ONLY for diagnostics and debugging. It cannot be used
+ * unless AVB_SLOT_VERIFY_FLAGS_ALLOW_VERIFICATION_ERROR is also
+ * used.
+ */
+typedef enum {
+  AVB_HASHTREE_ERROR_MODE_RESTART_AND_INVALIDATE,
+  AVB_HASHTREE_ERROR_MODE_RESTART,
+  AVB_HASHTREE_ERROR_MODE_EIO,
+  AVB_HASHTREE_ERROR_MODE_LOGGING
+} AvbHashtreeErrorMode;
+
+/* Flags that influence how avb_slot_verify() works.
+ *
+ * If AVB_SLOT_VERIFY_FLAGS_ALLOW_VERIFICATION_ERROR is NOT set then
+ * avb_slot_verify() will bail out as soon as an error is encountered
+ * and |out_data| is set only if AVB_SLOT_VERIFY_RESULT_OK is
+ * returned.
+ *
+ * Otherwise if AVB_SLOT_VERIFY_FLAGS_ALLOW_VERIFICATION_ERROR is set
+ * avb_slot_verify() will continue verification efforts and |out_data|
+ * is also set if AVB_SLOT_VERIFY_RESULT_ERROR_PUBLIC_KEY_REJECTED,
+ * AVB_SLOT_VERIFY_RESULT_ERROR_VERIFICATION, or
+ * AVB_SLOT_VERIFY_RESULT_ERROR_ROLLBACK_INDEX is returned. It is
+ * undefined which error is returned if more than one distinct error
+ * is encountered. It is guaranteed that AVB_SLOT_VERIFY_RESULT_OK is
+ * returned if, and only if, there are no errors. This mode is needed
+ * to boot valid but unverified slots when the device is unlocked.
+ *
+ * Also, if AVB_SLOT_VERIFY_FLAGS_ALLOW_VERIFICATION_ERROR is set the
+ * contents loaded from |requested_partition| will be the contents of
+ * the entire partition instead of just the size specified in the hash
+ * descriptor.
+ */
+typedef enum {
+  AVB_SLOT_VERIFY_FLAGS_NONE = 0,
+  AVB_SLOT_VERIFY_FLAGS_ALLOW_VERIFICATION_ERROR = (1 << 0)
+} AvbSlotVerifyFlags;
+
 /* Get a textual representation of |result|. */
 const char* avb_slot_verify_result_to_string(AvbSlotVerifyResult result);
 
@@ -103,7 +155,10 @@ typedef struct {
  * avb_slot_verify_data_free() function is called.
  *
  * The |ab_suffix| field is the copy of the of |ab_suffix| field
- * passed to avb_slot_verify(). It is the A/B suffix of the slot.
+ * passed to avb_slot_verify(). It is the A/B suffix of the slot. This
+ * value includes the leading underscore - typical values are "" (if
+ * no slots are in use), "_a" (for the first slot), and "_b" (for the
+ * second slot).
  *
  * The VBMeta images that were checked are available in the
  * |vbmeta_images| field. The field |num_vbmeta_images| contains the
@@ -132,10 +187,25 @@ typedef struct {
  * performing proper substitution of the variables
  * $(ANDROID_SYSTEM_PARTUUID), $(ANDROID_BOOT_PARTUUID), and
  * $(ANDROID_VBMETA_PARTUUID) using the
- * get_unique_guid_for_partition() operation in |AvbOps|.
+ * get_unique_guid_for_partition() operation in |AvbOps|. Additionally
+ * $(ANDROID_VERITY_MODE) will be replaced with the proper dm-verity
+ * option depending on the value of |hashtree_error_mode|.
  *
  * Additionally, the |cmdline| field will have the following kernel
- * command-line options set:
+ * command-line options set (unless verification is disabled, see
+ * below):
+ *
+ *   androidboot.veritymode: This is set to 'disabled' if the
+ *   AVB_VBMETA_IMAGE_FLAGS_HASHTREE_DISABLED flag is set in top-level
+ *   vbmeta struct. Otherwise it is set to 'enforcing' if the
+ *   passed-in hashtree error mode is AVB_HASHTREE_ERROR_MODE_RESTART
+ *   or AVB_HASHTREE_ERROR_MODE_RESTART_AND_INVALIDATE, 'eio' if it's
+ *   set to AVB_HASHTREE_ERROR_MODE_EIO, and 'logging' if it's set to
+ *   AVB_HASHTREE_ERROR_MODE_LOGGING.
+ *
+ *   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.
  *
  *   androidboot.vbmeta.device_state: set to "locked" or "unlocked"
  *   depending on the result of the result of AvbOps's
@@ -158,8 +228,20 @@ typedef struct {
  *   necessarily the same version number of the on-disk metadata for
  *   the slot that was verified.
  *
- * Note that androidboot.slot_suffix is not set in |cmdline| - you
- * will have to pass this command-line option yourself.
+ * Note that androidboot.slot_suffix is not set in the |cmdline| field
+ * in |AvbSlotVerifyData| - you will have to set this yourself.
+ *
+ * If the |AVB_VBMETA_IMAGE_FLAGS_VERIFICATION_DISABLED| flag is set
+ * in the top-level vbmeta struct then only the top-level vbmeta
+ * struct is verified and descriptors will not processed. The return
+ * value will be set accordingly (if this flag is set via 'avbctl
+ * disable-verification' then the return value will be
+ * |AVB_SLOT_VERIFY_RESULT_ERROR_VERIFICATION|) and
+ * |AvbSlotVerifyData| is returned. Additionally all partitions in the
+ * |requested_partitions| are loaded and the |cmdline| field is set to
+ * "root=PARTUUID=$(ANDROID_SYSTEM_PARTUUID)" and the GUID for the
+ * appropriate system partition is substituted in. Note that none of
+ * the androidboot.* options mentioned above will be set.
  *
  * This struct may grow in the future without it being considered an
  * ABI break.
@@ -174,23 +256,28 @@ typedef struct {
   uint64_t rollback_indexes[AVB_MAX_NUMBER_OF_ROLLBACK_INDEX_LOCATIONS];
 } AvbSlotVerifyData;
 
+/* Fast version of avb_slot_verify_data_free, this method will not
+ * free bootimage */
+void avb_slot_verify_data_free_fast(AvbSlotVerifyData* data);
 /* Frees a |AvbSlotVerifyData| including all data it points to. */
 void avb_slot_verify_data_free(AvbSlotVerifyData* data);
-void avb_slot_verify_data_free_fast(AvbSlotVerifyData* data);
+
 /* Performs a full verification of the slot identified by |ab_suffix|
- * and load the contents of the partitions whose name is in the
- * NULL-terminated string array |requested_partitions| (each partition
- * must use hash verification). If not using A/B, pass an empty string
- * (e.g. "", not NULL) for |ab_suffix|.
+ * and load and verify the contents of the partitions whose name is in
+ * the NULL-terminated string array |requested_partitions| (each
+ * partition must use hash verification). If not using A/B, pass an
+ * empty string (e.g. "", not NULL) for |ab_suffix|. This parameter
+ * must include the leading underscore, for example "_a" should be
+ * used to refer to the first slot.
  *
  * Typically the |requested_partitions| array only contains a single
  * item for the boot partition, 'boot'.
  *
- * Verification includes loading data from the 'vbmeta', all hash
- * partitions, and possibly other partitions (with |ab_suffix|
- * appended), inspecting rollback indexes, and checking if the public
- * key used to sign the data is acceptable. The functions in |ops|
- * will be used to do this.
+ * Verification includes loading and verifying data from the 'vbmeta',
+ * the requested hash partitions, and possibly other partitions (with
+ * |ab_suffix| appended), inspecting rollback indexes, and checking if
+ * the public key used to sign the data is acceptable. The functions
+ * in |ops| will be used to do this.
  *
  * If |out_data| is not NULL, it will be set to a newly allocated
  * |AvbSlotVerifyData| struct containing all the data needed to
@@ -198,19 +285,18 @@ void avb_slot_verify_data_free_fast(AvbSlotVerifyData* data);
  * avb_slot_verify_data_free() when you are done with it. See below
  * for when this is returned.
  *
- * If |allow_verification_error| is false this function will bail out
- * as soon as an error is encountered and |out_data| is set only if
- * AVB_SLOT_VERIFY_RESULT_OK is returned.
+ * The |flags| parameter is used to influence the semantics of
+ * avb_slot_verify() - for example the
+ * AVB_SLOT_VERIFY_FLAGS_ALLOW_VERIFICATION_ERROR flag can be used to
+ * ignore verification errors which is something needed in the
+ * UNLOCKED state. See the AvbSlotVerifyFlags enumeration for details.
  *
- * Otherwise if |allow_verification_error| is true the function will
- * continue verification efforts and |out_data| is also set if
- * AVB_SLOT_VERIFY_RESULT_ERROR_PUBLIC_KEY_REJECTED,
- * AVB_SLOT_VERIFY_RESULT_ERROR_VERIFICATION, or
- * AVB_SLOT_VERIFY_RESULT_ERROR_ROLLBACK_INDEX is returned. It is
- * undefined which error is returned if more than one distinct error
- * is encountered. It is guaranteed that AVB_SLOT_VERIFY_RESULT_OK is
- * returned if, and only if, there are no errors. This mode is needed
- * to boot valid but unverified slots when the device is unlocked.
+ * 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.
  *
  * Also note that |out_data| is never set if
  * AVB_SLOT_VERIFY_RESULT_ERROR_OOM, AVB_SLOT_VERIFY_RESULT_ERROR_IO,
@@ -243,11 +329,17 @@ void avb_slot_verify_data_free_fast(AvbSlotVerifyData* data);
  * AVB_SLOT_VERIFY_RESULT_ERROR_UNSUPPORTED_VERSION is returned if
  * some of the metadata requires a newer version of libavb than what
  * is in use.
+ *
+ * AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_ARGUMENT is returned if the
+ * caller passed invalid parameters, for example trying to use
+ * AVB_HASHTREE_ERROR_MODE_LOGGING without
+ * AVB_SLOT_VERIFY_FLAGS_ALLOW_VERIFICATION_ERROR.
  */
 AvbSlotVerifyResult avb_slot_verify(AvbOps* ops,
                                     const char* const* requested_partitions,
                                     const char* ab_suffix,
-                                    bool allow_verification_error,
+                                    AvbSlotVerifyFlags flags,
+                                    AvbHashtreeErrorMode hashtree_error_mode,
                                     AvbSlotVerifyData** out_data);
 
 #ifdef __cplusplus
index dfad04f..34556e2 100644 (file)
@@ -38,8 +38,6 @@ extern "C" {
  * like uint8_t, uint64_t, and bool (with |false|, |true| keywords)
  * must be present.
  */
-
-//#define bool int
 #include <common.h>
 
 /* If you don't have gcc or clang, these attribute macros may need to
index 0df7126..d0c9f15 100644 (file)
@@ -52,9 +52,13 @@ extern "C" {
  *
  * AVB_VBMETA_IMAGE_FLAGS_HASHTREE_DISABLED: If this flag is set,
  * hashtree image verification will be disabled.
+ *
+ * AVB_VBMETA_IMAGE_FLAGS_VERIFICATION_DISABLED: If this flag is set,
+ * verification will be disabled and descriptors will not be parsed.
  */
 typedef enum {
-  AVB_VBMETA_IMAGE_FLAGS_HASHTREE_DISABLED = (1 << 0)
+  AVB_VBMETA_IMAGE_FLAGS_HASHTREE_DISABLED = (1 << 0),
+  AVB_VBMETA_IMAGE_FLAGS_VERIFICATION_DISABLED = (1 << 1)
 } AvbVBMetaImageFlags;
 
 /* Binary format for header of the vbmeta image.
@@ -107,8 +111,8 @@ typedef enum {
  * minimum version of libavb required to verify the header and depends
  * on the features (e.g. algorithms, descriptors) used. Note that this
  * may be 1.0 even if generated by an avbtool from 1.4 but where no
- * features introduced after 1.0 has been used. See the VERSIONING AND
- * COMPATIBILITY section in the README file for more details.
+ * features introduced after 1.0 has been used. See the "Versioning
+ * and compatibility" section in the README.md file for more details.
  *
  * All fields are stored in network byte order when serialized. To
  * generate a copy with fields swapped to native byte order, use the
index 7757d09..9d92970 100644 (file)
@@ -52,10 +52,6 @@ extern "C" {
  */
 const char* avb_version_string(void);
 
-/* TODO: remove when there are no more users of AVB_{MAJOR,MINOR}_VERSION. */
-#define AVB_MAJOR_VERSION AVB_VERSION_MAJOR
-#define AVB_MINOR_VERSION AVB_VERSION_MINOR
-
 #ifdef __cplusplus
 }
 #endif
index cba82f8..0ef9255 100644 (file)
@@ -202,21 +202,19 @@ static AvbIOResult save_metadata_if_changed(AvbABOps* ab_ops,
   return AVB_IO_RESULT_OK;
 }
 
-AvbABFlowResult avb_ab_flow_fast(AvbABOps* ab_ops,
+AvbABFlowResult avb_ab_flow(AvbABOps* ab_ops,
                             const char* const* requested_partitions,
-                            bool allow_verification_error,
+                            AvbSlotVerifyFlags flags,
+                            AvbHashtreeErrorMode hashtree_error_mode,
                             AvbSlotVerifyData** out_data) {
   AvbOps* ops = ab_ops->ops;
   AvbSlotVerifyData* slot_data[2] = {NULL, NULL};
   AvbSlotVerifyData* data = NULL;
   AvbABFlowResult ret;
   AvbABData ab_data, ab_data_orig;
-  size_t slot_index_to_boot, n = 0;
+  size_t slot_index_to_boot, n;
   AvbIOResult io_ret;
   bool saw_and_allowed_verification_error = false;
-  size_t target_slot;
-  AvbSlotVerifyResult verify_result;
-  bool set_slot_unbootable = false;
 
   io_ret = load_metadata(ab_ops, &ab_data, &ab_data_orig);
   if (io_ret == AVB_IO_RESULT_ERROR_OOM) {
@@ -227,18 +225,18 @@ AvbABFlowResult avb_ab_flow_fast(AvbABOps* ab_ops,
     goto out;
   }
 
-  slot_index_to_boot = 2;  // Means not 0 or 1
-  target_slot = (ab_data.slots[1].priority > ab_data.slots[0].priority? 1 : 0);
-
+  /* Validate all bootable slots. */
   for (n = 0; n < 2; n++) {
-      if (!slot_is_bootable(&ab_data.slots[target_slot])) {
-        target_slot = (target_slot == 1 ? 0 : 1);
-        continue;
-      }
+    if (slot_is_bootable(&ab_data.slots[n])) {
+      AvbSlotVerifyResult verify_result;
+      bool set_slot_unbootable = false;
 
-      verify_result = avb_slot_verify(ops, requested_partitions, slot_suffixes[target_slot],
-                     allow_verification_error,
-                     &slot_data[target_slot]);
+      verify_result = avb_slot_verify(ops,
+                                      requested_partitions,
+                                      slot_suffixes[n],
+                                      flags,
+                                      hashtree_error_mode,
+                                      &slot_data[n]);
       switch (verify_result) {
         case AVB_SLOT_VERIFY_RESULT_ERROR_OOM:
           ret = AVB_AB_FLOW_RESULT_ERROR_OOM;
@@ -249,13 +247,13 @@ AvbABFlowResult avb_ab_flow_fast(AvbABOps* ab_ops,
           goto out;
 
         case AVB_SLOT_VERIFY_RESULT_OK:
-          slot_index_to_boot = target_slot;
-         n = 2;
           break;
 
         case AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA:
         case AVB_SLOT_VERIFY_RESULT_ERROR_UNSUPPORTED_VERSION:
-          /* Even with |allow_verification_error| these mean game over. */
+          /* Even with AVB_SLOT_VERIFY_FLAGS_ALLOW_VERIFICATION_ERROR
+           * these mean game over.
+           */
           set_slot_unbootable = true;
           break;
 
@@ -263,40 +261,53 @@ AvbABFlowResult avb_ab_flow_fast(AvbABOps* ab_ops,
         case AVB_SLOT_VERIFY_RESULT_ERROR_VERIFICATION:
         case AVB_SLOT_VERIFY_RESULT_ERROR_ROLLBACK_INDEX:
         case AVB_SLOT_VERIFY_RESULT_ERROR_PUBLIC_KEY_REJECTED:
-          if (allow_verification_error) {
+          if (flags & AVB_SLOT_VERIFY_FLAGS_ALLOW_VERIFICATION_ERROR) {
             /* Do nothing since we allow this. */
             avb_debugv("Allowing slot ",
-                       slot_suffixes[target_slot],
+                       slot_suffixes[n],
                        " which verified "
                        "with result ",
                        avb_slot_verify_result_to_string(verify_result),
-                       " because |allow_verification_error| is true.\n",
+                       " because "
+                       "AVB_SLOT_VERIFY_FLAGS_ALLOW_VERIFICATION_ERROR "
+                       "is set.\n",
                        NULL);
             saw_and_allowed_verification_error = true;
-           slot_index_to_boot = target_slot;
-           n = 2;
           } else {
             set_slot_unbootable = true;
           }
           break;
-        default:
-          break;
+
+        case AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_ARGUMENT:
+          ret = AVB_AB_FLOW_RESULT_ERROR_INVALID_ARGUMENT;
+          goto out;
+          /* Do not add a 'default:' case here because of -Wswitch. */
       }
+
       if (set_slot_unbootable) {
         avb_errorv("Error verifying slot ",
-                   slot_suffixes[target_slot],
+                   slot_suffixes[n],
                    " with result ",
                    avb_slot_verify_result_to_string(verify_result),
                    " - setting unbootable.\n",
                    NULL);
-        slot_set_unbootable(&ab_data.slots[target_slot]);
-       set_slot_unbootable = false;
+        slot_set_unbootable(&ab_data.slots[n]);
       }
-      /* switch to another slot */
-      target_slot = (target_slot == 1 ? 0 : 1);
+    }
   }
 
-  if (slot_index_to_boot == 2) {
+  if (slot_is_bootable(&ab_data.slots[0]) &&
+      slot_is_bootable(&ab_data.slots[1])) {
+    if (ab_data.slots[1].priority > ab_data.slots[0].priority) {
+      slot_index_to_boot = 1;
+    } else {
+      slot_index_to_boot = 0;
+    }
+  } else if (slot_is_bootable(&ab_data.slots[0])) {
+    slot_index_to_boot = 0;
+  } else if (slot_is_bootable(&ab_data.slots[1])) {
+    slot_index_to_boot = 1;
+  } else {
     /* No bootable slots! */
     avb_error("No bootable slots found.\n");
     ret = AVB_AB_FLOW_RESULT_ERROR_NO_BOOTABLE_SLOTS;
@@ -352,7 +363,7 @@ AvbABFlowResult avb_ab_flow_fast(AvbABOps* ab_ops,
   data = slot_data[slot_index_to_boot];
   slot_data[slot_index_to_boot] = NULL;
   if (saw_and_allowed_verification_error) {
-    avb_assert(allow_verification_error);
+    avb_assert(flags & AVB_SLOT_VERIFY_FLAGS_ALLOW_VERIFICATION_ERROR);
     ret = AVB_AB_FLOW_RESULT_OK_WITH_VERIFICATION_ERROR;
   } else {
     ret = AVB_AB_FLOW_RESULT_OK;
@@ -388,18 +399,17 @@ out:
     *out_data = data;
   } else {
     if (data != NULL) {
-      /* the address of bootimage isn't alloced by malloc,
-       * we should not free it. */
-      avb_slot_verify_data_free_fast(data);
+      avb_slot_verify_data_free(data);
     }
   }
 
   return ret;
 }
 
-AvbABFlowResult avb_ab_flow(AvbABOps* ab_ops,
+AvbABFlowResult avb_ab_flow_fast(AvbABOps* ab_ops,
                             const char* const* requested_partitions,
-                            bool allow_verification_error,
+                            AvbSlotVerifyFlags flags,
+                            AvbHashtreeErrorMode hashtree_error_mode,
                             AvbSlotVerifyData** out_data) {
   AvbOps* ops = ab_ops->ops;
   AvbSlotVerifyData* slot_data[2] = {NULL, NULL};
@@ -409,6 +419,9 @@ AvbABFlowResult avb_ab_flow(AvbABOps* ab_ops,
   size_t slot_index_to_boot, n;
   AvbIOResult io_ret;
   bool saw_and_allowed_verification_error = false;
+  size_t target_slot;
+  AvbSlotVerifyResult verify_result;
+  bool set_slot_unbootable = false;
 
   io_ret = load_metadata(ab_ops, &ab_data, &ab_data_orig);
   if (io_ret == AVB_IO_RESULT_ERROR_OOM) {
@@ -419,79 +432,86 @@ AvbABFlowResult avb_ab_flow(AvbABOps* ab_ops,
     goto out;
   }
 
-  /* Validate all bootable slots. */
-  for (n = 0; n < 2; n++) {
-    if (slot_is_bootable(&ab_data.slots[n])) {
-      AvbSlotVerifyResult verify_result;
-      bool set_slot_unbootable = false;
+  slot_index_to_boot = 2;  // Means not 0 or 1
+  target_slot = (ab_data.slots[1].priority > ab_data.slots[0].priority? 1 : 0);
 
-      verify_result = avb_slot_verify(ops,
+  for (n = 0; n < 2; n++) {
+    if (!slot_is_bootable(&ab_data.slots[target_slot])) {
+      target_slot = (target_slot == 1 ? 0 : 1);
+      continue;
+    }
+    verify_result = avb_slot_verify(ops,
                                       requested_partitions,
-                                      slot_suffixes[n],
-                                      allow_verification_error,
-                                      &slot_data[n]);
-      switch (verify_result) {
-        case AVB_SLOT_VERIFY_RESULT_ERROR_OOM:
-          ret = AVB_AB_FLOW_RESULT_ERROR_OOM;
-          goto out;
-
-        case AVB_SLOT_VERIFY_RESULT_ERROR_IO:
-          ret = AVB_AB_FLOW_RESULT_ERROR_IO;
-          goto out;
+                                      slot_suffixes[target_slot],
+                                      flags,
+                                      hashtree_error_mode,
+                                      &slot_data[target_slot]);
+    switch (verify_result) {
+      case AVB_SLOT_VERIFY_RESULT_ERROR_OOM:
+        ret = AVB_AB_FLOW_RESULT_ERROR_OOM;
+        goto out;
 
-        case AVB_SLOT_VERIFY_RESULT_OK:
-          break;
+      case AVB_SLOT_VERIFY_RESULT_ERROR_IO:
+        ret = AVB_AB_FLOW_RESULT_ERROR_IO;
+        goto out;
 
-        case AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA:
-        case AVB_SLOT_VERIFY_RESULT_ERROR_UNSUPPORTED_VERSION:
-          /* Even with |allow_verification_error| these mean game over. */
+      case AVB_SLOT_VERIFY_RESULT_OK:
+       slot_index_to_boot = target_slot;
+       n = 2;
+        break;
+
+      case AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA:
+      case AVB_SLOT_VERIFY_RESULT_ERROR_UNSUPPORTED_VERSION:
+          /* Even with AVB_SLOT_VERIFY_FLAGS_ALLOW_VERIFICATION_ERROR
+           * these mean game over.
+           */
+        set_slot_unbootable = true;
+        break;
+
+      /* explicit fallthrough. */
+      case AVB_SLOT_VERIFY_RESULT_ERROR_VERIFICATION:
+      case AVB_SLOT_VERIFY_RESULT_ERROR_ROLLBACK_INDEX:
+      case AVB_SLOT_VERIFY_RESULT_ERROR_PUBLIC_KEY_REJECTED:
+        if (flags & AVB_SLOT_VERIFY_FLAGS_ALLOW_VERIFICATION_ERROR) {
+          /* Do nothing since we allow this. */
+          avb_debugv("Allowing slot ",
+                     slot_suffixes[target_slot],
+                     " which verified "
+                     "with result ",
+                     avb_slot_verify_result_to_string(verify_result),
+                     " because "
+                     "AVB_SLOT_VERIFY_FLAGS_ALLOW_VERIFICATION_ERROR "
+                     "is set.\n",
+                     NULL);
+          saw_and_allowed_verification_error = true;
+         slot_index_to_boot = target_slot;
+         n = 2;
+        } else {
           set_slot_unbootable = true;
-          break;
+        }
+        break;
 
-        /* explicit fallthrough. */
-        case AVB_SLOT_VERIFY_RESULT_ERROR_VERIFICATION:
-        case AVB_SLOT_VERIFY_RESULT_ERROR_ROLLBACK_INDEX:
-        case AVB_SLOT_VERIFY_RESULT_ERROR_PUBLIC_KEY_REJECTED:
-          if (allow_verification_error) {
-            /* Do nothing since we allow this. */
-            avb_debugv("Allowing slot ",
-                       slot_suffixes[n],
-                       " which verified "
-                       "with result ",
-                       avb_slot_verify_result_to_string(verify_result),
-                       " because |allow_verification_error| is true.\n",
-                       NULL);
-            saw_and_allowed_verification_error = true;
-          } else {
-            set_slot_unbootable = true;
-          }
-          break;
-      }
+      case AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_ARGUMENT:
+        ret = AVB_AB_FLOW_RESULT_ERROR_INVALID_ARGUMENT;
+        goto out;
+        /* Do not add a 'default:' case here because of -Wswitch. */
+    }
 
-      if (set_slot_unbootable) {
-        avb_errorv("Error verifying slot ",
-                   slot_suffixes[n],
-                   " with result ",
-                   avb_slot_verify_result_to_string(verify_result),
-                   " - setting unbootable.\n",
-                   NULL);
-        slot_set_unbootable(&ab_data.slots[n]);
-      }
+    if (set_slot_unbootable) {
+      avb_errorv("Error verifying slot ",
+                 slot_suffixes[target_slot],
+                 " with result ",
+                 avb_slot_verify_result_to_string(verify_result),
+                 " - setting unbootable.\n",
+                 NULL);
+      slot_set_unbootable(&ab_data.slots[target_slot]);
+      set_slot_unbootable = false;
     }
+    /* switch to another slot */
+    target_slot = (target_slot == 1 ? 0 : 1);
   }
 
-  if (slot_is_bootable(&ab_data.slots[0]) &&
-      slot_is_bootable(&ab_data.slots[1])) {
-    if (ab_data.slots[1].priority > ab_data.slots[0].priority) {
-      slot_index_to_boot = 1;
-    } else {
-      slot_index_to_boot = 0;
-    }
-  } else if (slot_is_bootable(&ab_data.slots[0])) {
-    slot_index_to_boot = 0;
-  } else if (slot_is_bootable(&ab_data.slots[1])) {
-    slot_index_to_boot = 1;
-  } else {
+  if (slot_index_to_boot == 2) {
     /* No bootable slots! */
     avb_error("No bootable slots found.\n");
     ret = AVB_AB_FLOW_RESULT_ERROR_NO_BOOTABLE_SLOTS;
@@ -547,7 +567,7 @@ AvbABFlowResult avb_ab_flow(AvbABOps* ab_ops,
   data = slot_data[slot_index_to_boot];
   slot_data[slot_index_to_boot] = NULL;
   if (saw_and_allowed_verification_error) {
-    avb_assert(allow_verification_error);
+    avb_assert(flags & AVB_SLOT_VERIFY_FLAGS_ALLOW_VERIFICATION_ERROR);
     ret = AVB_AB_FLOW_RESULT_OK_WITH_VERIFICATION_ERROR;
   } else {
     ret = AVB_AB_FLOW_RESULT_OK;
@@ -583,7 +603,9 @@ out:
     *out_data = data;
   } else {
     if (data != NULL) {
-      avb_slot_verify_data_free(data);
+      /* the address of bootimage isn't alloced by malloc,
+       * we should not free it. */
+      avb_slot_verify_data_free_fast(data);
     }
   }
 
@@ -699,6 +721,10 @@ const char* avb_ab_flow_result_to_string(AvbABFlowResult result) {
     case AVB_AB_FLOW_RESULT_ERROR_NO_BOOTABLE_SLOTS:
       ret = "ERROR_NO_BOOTABLE_SLOTS";
       break;
+
+    case AVB_AB_FLOW_RESULT_ERROR_INVALID_ARGUMENT:
+      ret = "ERROR_INVALID_ARGUMENT";
+      break;
       /* Do not add a 'default:' case here because of -Wswitch. */
   }
 
index 54920a6..e6e06c8 100644 (file)
@@ -140,7 +140,8 @@ typedef enum {
   AVB_AB_FLOW_RESULT_OK_WITH_VERIFICATION_ERROR,
   AVB_AB_FLOW_RESULT_ERROR_OOM,
   AVB_AB_FLOW_RESULT_ERROR_IO,
-  AVB_AB_FLOW_RESULT_ERROR_NO_BOOTABLE_SLOTS
+  AVB_AB_FLOW_RESULT_ERROR_NO_BOOTABLE_SLOTS,
+  AVB_AB_FLOW_RESULT_ERROR_INVALID_ARGUMENT
 } AvbABFlowResult;
 
 /* Get a textual representation of |result|. */
@@ -156,9 +157,9 @@ const char* avb_ab_flow_result_to_string(AvbABFlowResult result);
  *
  * 2. All bootable slots listed in the A/B metadata are verified using
  * avb_slot_verify(). If a slot is invalid or if it fails verification
- * (and |allow_verification_error| is false, see below), it will be
- * marked as unbootable in the A/B metadata and the metadata will be
- * saved to disk before returning.
+ * (and AVB_SLOT_VERIFY_FLAGS_ALLOW_VERIFICATION_ERROR is not set, see
+ * below), it will be marked as unbootable in the A/B metadata and the
+ * metadata will be saved to disk before returning.
  *
  * 3. If there are no bootable slots, the value
  * AVB_AB_FLOW_RESULT_ERROR_NO_BOOTABLE_SLOTS is returned.
@@ -180,25 +181,26 @@ const char* avb_ab_flow_result_to_string(AvbABFlowResult result);
  * |requested_partitions| array only contains a single item for the
  * boot partition, 'boot'.
  *
- * If the device is unlocked (and _only_ if it's unlocked), true
- * should be passed in the |allow_verification_error| parameter. This
- * will allow considering slots as verified even when
- * avb_slot_verify() returns
+ * If the device is unlocked (and _only_ if it's unlocked), the
+ * AVB_SLOT_VERIFY_FLAGS_ALLOW_VERIFICATION_ERROR flag should be set
+ * in the |flags| parameter. This will allow considering slots as
+ * verified even when avb_slot_verify() returns
  * AVB_SLOT_VERIFY_RESULT_ERROR_PUBLIC_KEY_REJECTED,
  * AVB_SLOT_VERIFY_RESULT_ERROR_VERIFICATION, or
  * AVB_SLOT_VERIFY_RESULT_ERROR_ROLLBACK_INDEX for the slot in
  * question.
  *
- * Note that androidboot.slot_suffix is not set in the |cmdline| field
- * in |AvbSlotVerifyData| - you will have to pass this command-line
- * option yourself.
+ * Note that neither androidboot.slot_suffix nor androidboot.slot are
+ * set in the |cmdline| field in |AvbSlotVerifyData| - you will have
+ * to pass these yourself.
  *
  * If a slot was selected and it verified then AVB_AB_FLOW_RESULT_OK
  * is returned.
  *
  * If a slot was selected but it didn't verify then
  * AVB_AB_FLOW_RESULT_OK_WITH_VERIFICATION_ERROR is returned. This can
- * only happen when |allow_verification_error| is true.
+ * only happen when the AVB_SLOT_VERIFY_FLAGS_ALLOW_VERIFICATION_ERROR
+ * flag is set.
  *
  * If an I/O operation - such as loading/saving metadata or checking
  * rollback indexes - fail, the value AVB_AB_FLOW_RESULT_ERROR_IO is
@@ -207,17 +209,24 @@ const char* avb_ab_flow_result_to_string(AvbABFlowResult result);
  * If memory allocation fails, AVB_AB_FLOW_RESULT_ERROR_OOM is
  * returned.
  *
+ * If invalid arguments are passed,
+ * AVB_AB_FLOW_RESULT_ERROR_INVALID_ARGUMENT is returned. For example
+ * this can happen if using AVB_HASHTREE_ERROR_MODE_LOGGING without
+ * AVB_SLOT_VERIFY_FLAGS_ALLOW_VERIFICATION_ERROR.
+ *
  * Reasonable behavior for handling AVB_AB_FLOW_RESULT_ERROR_NO_BOOTABLE_SLOTS
  * is to initiate device repair (which is device-dependent).
  */
 AvbABFlowResult avb_ab_flow(AvbABOps* ab_ops,
                             const char* const* requested_partitions,
-                            bool allow_verification_error,
+                            AvbSlotVerifyFlags flags,
+                            AvbHashtreeErrorMode hashtree_error_mode,
                             AvbSlotVerifyData** out_data);
 
 AvbABFlowResult avb_ab_flow_fast(AvbABOps* ab_ops,
                             const char* const* requested_partitions,
-                            bool allow_verification_error,
+                            AvbSlotVerifyFlags flags,
+                            AvbHashtreeErrorMode hashtree_error_mode,
                             AvbSlotVerifyData** out_data);
 
 /* Marks the slot with the given slot number as active. Returns