release-request-7bfcab52-d1c0-4256-9d6b-5b5092bc78ca-for-git_oc-mr1-release-4133428 snap-temp-L95800000077479875

Change-Id: Ia5ad2fd2ddb28b0d1bcecbce5e7623fe4e9c8997
diff --git a/Android.bp b/Android.bp
index 3e14003..48480d1 100644
--- a/Android.bp
+++ b/Android.bp
@@ -114,6 +114,7 @@
         "libavb_ab/avb_ab_flow.c",
         "libavb_user/avb_ops_user.c",
         "libavb_user/avb_user_verity.c",
+        "libavb_user/avb_user_verification.c",
     ],
 }
 
diff --git a/libavb/avb_slot_verify.c b/libavb/avb_slot_verify.c
index 7ba4075..f7b74a6 100644
--- a/libavb/avb_slot_verify.c
+++ b/libavb/avb_slot_verify.c
@@ -244,6 +244,99 @@
   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,
@@ -561,6 +654,27 @@
       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
@@ -954,6 +1068,168 @@
   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;
+  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;
+    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,
@@ -963,10 +1239,8 @@
   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;
-  const char* verity_mode;
   bool allow_verification_error =
       (flags & AVB_SLOT_VERIFY_FLAGS_ALLOW_VERIFICATION_ERROR);
 
@@ -1050,21 +1324,35 @@
       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. */
@@ -1080,133 +1368,6 @@
       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;
-    }
-
-    /* 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;
-      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 fail;
-          }
-          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) {
-        goto fail;
-      }
-    }
-    if (!cmdline_append_option(
-            slot_data, "androidboot.veritymode", verity_mode)) {
-      ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
-      goto fail;
-    }
-
     if (out_data != NULL) {
       *out_data = slot_data;
     } else {
diff --git a/libavb/avb_slot_verify.h b/libavb/avb_slot_verify.h
index 8794b98..d8de8fb 100644
--- a/libavb/avb_slot_verify.h
+++ b/libavb/avb_slot_verify.h
@@ -192,7 +192,8 @@
  * 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
@@ -227,14 +228,20 @@
  *   necessarily the same version number of the on-disk metadata for
  *   the slot that was verified.
  *
- * Note that neither androidboot.slot_suffix nor androidboot.slot are
- * set in the |cmdline| field in |AvbSlotVerifyData| - you will have
- * to pass these yourself.
+ * Note that androidboot.slot_suffix is not set in the |cmdline| field
+ * in |AvbSlotVerifyData| - you will have to set this yourself.
  *
- * Also note that androidboot.veritymode is set by libavb and since
- * AVB only supports 'enforcing' and 'disabled' values, the boot
- * loader is relieved of managing any state related to dm-verity or
- * setting this cmdline parameter.
+ * 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.
diff --git a/libavb/avb_vbmeta_image.h b/libavb/avb_vbmeta_image.h
index 90c3a54..d0c9f15 100644
--- a/libavb/avb_vbmeta_image.h
+++ b/libavb/avb_vbmeta_image.h
@@ -52,9 +52,13 @@
  *
  * 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.
diff --git a/libavb_ab/avb_ab_flow.c b/libavb_ab/avb_ab_flow.c
index e0661fa..bf6eab1 100644
--- a/libavb_ab/avb_ab_flow.c
+++ b/libavb_ab/avb_ab_flow.c
@@ -515,6 +515,7 @@
     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;
diff --git a/libavb_user/avb_user_verification.c b/libavb_user/avb_user_verification.c
new file mode 100644
index 0000000..f572128
--- /dev/null
+++ b/libavb_user/avb_user_verification.c
@@ -0,0 +1,214 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "avb_user_verification.h"
+
+/* Maximum allow length (in bytes) of a partition name, including
+ * ab_suffix.
+ */
+#define AVB_PART_NAME_MAX_SIZE 32
+
+/* Loads the toplevel AvbVBMetaImageHeader from the slot denoted by
+ * |ab_suffix| into |vbmeta_image|. No validation, verification, or
+ * byteswapping is performed.
+ *
+ * If successful, |true| is returned and the partition it was loaded
+ * from is returned in |out_partition_name| and the offset on said
+ * partition is returned in |out_vbmeta_offset|.
+ */
+static bool load_top_level_vbmeta_header(
+    AvbOps* ops,
+    const char* ab_suffix,
+    uint8_t vbmeta_image[AVB_VBMETA_IMAGE_HEADER_SIZE],
+    char out_partition_name[AVB_PART_NAME_MAX_SIZE],
+    uint64_t* out_vbmeta_offset) {
+  uint64_t vbmeta_offset = 0;
+  size_t num_read;
+  bool ret = false;
+  AvbIOResult io_res;
+
+  /* Construct full partition name. */
+  if (!avb_str_concat(out_partition_name,
+                      AVB_PART_NAME_MAX_SIZE,
+                      "vbmeta",
+                      6,
+                      ab_suffix,
+                      avb_strlen(ab_suffix))) {
+    avb_error("Partition name and suffix does not fit.\n");
+    goto out;
+  }
+
+  /* Only read the header, not the entire struct. */
+  io_res = ops->read_from_partition(ops,
+                                    out_partition_name,
+                                    vbmeta_offset,
+                                    AVB_VBMETA_IMAGE_HEADER_SIZE,
+                                    vbmeta_image,
+                                    &num_read);
+  if (io_res == AVB_IO_RESULT_ERROR_NO_SUCH_PARTITION) {
+    AvbFooter footer;
+
+    /* Try looking for the vbmeta struct in 'boot' via the footer. */
+    if (!avb_str_concat(out_partition_name,
+                        AVB_PART_NAME_MAX_SIZE,
+                        "boot",
+                        4,
+                        ab_suffix,
+                        avb_strlen(ab_suffix))) {
+      avb_error("Partition name and suffix does not fit.\n");
+      goto out;
+    }
+    io_res = ops->read_from_partition(ops,
+                                      out_partition_name,
+                                      -AVB_FOOTER_SIZE,
+                                      AVB_FOOTER_SIZE,
+                                      &footer,
+                                      &num_read);
+    if (io_res != AVB_IO_RESULT_OK) {
+      avb_errorv("Error loading footer from partition '",
+                 out_partition_name,
+                 "'\n",
+                 NULL);
+      goto out;
+    }
+
+    if (avb_memcmp(footer.magic, AVB_FOOTER_MAGIC, AVB_FOOTER_MAGIC_LEN) != 0) {
+      avb_errorv("Data from '",
+                 out_partition_name,
+                 "' does not look like a vbmeta footer.\n",
+                 NULL);
+      goto out;
+    }
+
+    vbmeta_offset = avb_be64toh(footer.vbmeta_offset);
+    io_res = ops->read_from_partition(ops,
+                                      out_partition_name,
+                                      vbmeta_offset,
+                                      AVB_VBMETA_IMAGE_HEADER_SIZE,
+                                      vbmeta_image,
+                                      &num_read);
+  }
+
+  if (io_res != AVB_IO_RESULT_OK) {
+    avb_errorv(
+        "Error loading from partition '", out_partition_name, "'\n", NULL);
+    goto out;
+  }
+
+  if (out_vbmeta_offset != NULL) {
+    *out_vbmeta_offset = vbmeta_offset;
+  }
+
+  ret = true;
+
+out:
+  return ret;
+}
+
+bool avb_user_verification_get(AvbOps* ops,
+                               const char* ab_suffix,
+                               bool* out_verification_enabled) {
+  uint8_t vbmeta_image[AVB_VBMETA_IMAGE_HEADER_SIZE]; /* 256 bytes. */
+  char partition_name[AVB_PART_NAME_MAX_SIZE];        /* 32 bytes. */
+  AvbVBMetaImageHeader* header;
+  uint32_t flags;
+  bool ret = false;
+
+  if (!load_top_level_vbmeta_header(
+          ops, ab_suffix, vbmeta_image, partition_name, NULL)) {
+    goto out;
+  }
+
+  if (avb_memcmp(vbmeta_image, AVB_MAGIC, AVB_MAGIC_LEN) != 0) {
+    avb_errorv("Data from '",
+               partition_name,
+               "' does not look like a vbmeta header.\n",
+               NULL);
+    goto out;
+  }
+
+  /* Set/clear the VERIFICATION_DISABLED bit, as requested. */
+  header = (AvbVBMetaImageHeader*)vbmeta_image;
+  flags = avb_be32toh(header->flags);
+
+  if (out_verification_enabled != NULL) {
+    *out_verification_enabled =
+        !(flags & AVB_VBMETA_IMAGE_FLAGS_VERIFICATION_DISABLED);
+  }
+
+  ret = true;
+
+out:
+  return ret;
+}
+
+bool avb_user_verification_set(AvbOps* ops,
+                               const char* ab_suffix,
+                               bool enable_verification) {
+  uint8_t vbmeta_image[AVB_VBMETA_IMAGE_HEADER_SIZE]; /* 256 bytes. */
+  char partition_name[AVB_PART_NAME_MAX_SIZE];        /* 32 bytes. */
+  uint64_t vbmeta_offset;
+  AvbIOResult io_res;
+  AvbVBMetaImageHeader* header;
+  uint32_t flags;
+  bool ret = false;
+
+  if (!load_top_level_vbmeta_header(
+          ops, ab_suffix, vbmeta_image, partition_name, &vbmeta_offset)) {
+    goto out;
+  }
+
+  if (avb_memcmp(vbmeta_image, AVB_MAGIC, AVB_MAGIC_LEN) != 0) {
+    avb_errorv("Data from '",
+               partition_name,
+               "' does not look like a vbmeta header.\n",
+               NULL);
+    goto out;
+  }
+
+  /* Set/clear the VERIFICATION_DISABLED bit, as requested. */
+  header = (AvbVBMetaImageHeader*)vbmeta_image;
+  flags = avb_be32toh(header->flags);
+  flags &= ~AVB_VBMETA_IMAGE_FLAGS_VERIFICATION_DISABLED;
+  if (!enable_verification) {
+    flags |= AVB_VBMETA_IMAGE_FLAGS_VERIFICATION_DISABLED;
+  }
+  header->flags = avb_htobe32(flags);
+
+  /* Write the header. */
+  io_res = ops->write_to_partition(ops,
+                                   partition_name,
+                                   vbmeta_offset,
+                                   AVB_VBMETA_IMAGE_HEADER_SIZE,
+                                   vbmeta_image);
+  if (io_res != AVB_IO_RESULT_OK) {
+    avb_errorv("Error writing to partition '", partition_name, "'\n", NULL);
+    goto out;
+  }
+
+  ret = true;
+
+out:
+  return ret;
+}
diff --git a/libavb_user/avb_user_verification.h b/libavb_user/avb_user_verification.h
new file mode 100644
index 0000000..7a33c8d
--- /dev/null
+++ b/libavb_user/avb_user_verification.h
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef AVB_USER_VERIFICATION_H_
+#define AVB_USER_VERIFICATION_H_
+
+#include <libavb/libavb.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Function to enable or disable verification for an entire slot. The
+ * passed in |ops| should be obtained via avb_ops_user_new(). The
+ * |ab_suffix| parameter should specify the slot to modify including
+ * the leading underscore (e.g. "_a" or "_b"). The
+ * |enable_verification| parameter should be set to |true| to enable
+ * dm-verification and |false| to disable.
+ *
+ * Returns |true| if the operation succeeded, otherwise |false|.
+ */
+bool avb_user_verification_set(AvbOps* ops,
+                               const char* ab_suffix,
+                               bool enable_verification);
+
+/* Gets whether verification is enabled for an entire slot. The passed
+ * in |ops| should be obtained via avb_ops_user_new(). The |ab_suffix|
+ * parameter should specify the slot to query including the leading
+ * underscore (e.g. "_a" or "_b"). The result is returned in the
+ * |out_verification_enabled| parameter.
+ *
+ * Returns |true| if the operation succeeded, otherwise |false|.
+ */
+bool avb_user_verification_get(AvbOps* ops,
+                               const char* ab_suffix,
+                               bool* out_verification_enabled);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* AVB_USER_VERIFICATION_H_ */
diff --git a/libavb_user/avb_user_verity.c b/libavb_user/avb_user_verity.c
index 8098909..ecf0043 100644
--- a/libavb_user/avb_user_verity.c
+++ b/libavb_user/avb_user_verity.c
@@ -37,7 +37,7 @@
  * from is returned in |out_partition_name| and the offset on said
  * partition is returned in |out_vbmeta_offset|.
  */
-bool load_top_level_vbmeta_header(
+static bool load_top_level_vbmeta_header(
     AvbOps* ops,
     const char* ab_suffix,
     uint8_t vbmeta_image[AVB_VBMETA_IMAGE_HEADER_SIZE],
diff --git a/libavb_user/libavb_user.h b/libavb_user/libavb_user.h
index b9d10ab..a8b8c55 100644
--- a/libavb_user/libavb_user.h
+++ b/libavb_user/libavb_user.h
@@ -34,6 +34,7 @@
 
 #define AVB_INSIDE_LIBAVB_USER_H
 #include "avb_ops_user.h"
+#include "avb_user_verification.h"
 #include "avb_user_verity.h"
 #undef AVB_INSIDE_LIBAVB_USER_H
 
diff --git a/test/avb_slot_verify_unittest.cc b/test/avb_slot_verify_unittest.cc
index 8348bf2..88b87f4 100644
--- a/test/avb_slot_verify_unittest.cc
+++ b/test/avb_slot_verify_unittest.cc
@@ -46,6 +46,7 @@
 
   void CmdlineWithHashtreeVerification(bool hashtree_verification_on);
   void CmdlineWithChainedHashtreeVerification(bool hashtree_verification_on);
+  void VerificationDisabled(bool use_avbctl);
 
   FakeAvbOps ops_;
 };
@@ -1677,6 +1678,154 @@
   CmdlineWithChainedHashtreeVerification(true);
 }
 
+void AvbSlotVerifyTest::VerificationDisabled(bool use_avbctl) {
+  const size_t boot_part_size = 32 * 1024 * 1024;
+  const size_t dtbo_part_size = 4 * 1024 * 1024;
+  const size_t rootfs_size = 1028 * 1024;
+  const size_t partition_size = 1536 * 1024;
+
+  // Generate boot_a.img and dtbo_a.img since avb_slot_verify() will
+  // attempt to load them upon encountering the VERIFICATION_DISABLED
+  // flag.
+  base::FilePath boot_path = GenerateImage("boot_a.img", boot_part_size);
+  const size_t DTBO_DATA_OFFSET = 42;
+  base::FilePath dtbo_path =
+      GenerateImage("dtbo_a.img", dtbo_part_size, DTBO_DATA_OFFSET);
+
+  // Generate a 1028 KiB file with known content.
+  std::vector<uint8_t> rootfs;
+  rootfs.resize(rootfs_size);
+  for (size_t n = 0; n < rootfs_size; n++)
+    rootfs[n] = uint8_t(n);
+  base::FilePath rootfs_path = testdir_.Append("rootfs.bin");
+  EXPECT_EQ(rootfs_size,
+            static_cast<const size_t>(
+                base::WriteFile(rootfs_path,
+                                reinterpret_cast<const char*>(rootfs.data()),
+                                rootfs.size())));
+
+  EXPECT_COMMAND(0,
+                 "./avbtool add_hashtree_footer --salt d00df00d --image %s "
+                 "--partition_size %d --partition_name foobar "
+                 "--algorithm SHA256_RSA2048 "
+                 "--key test/data/testkey_rsa2048.pem "
+                 "--internal_release_string \"\" "
+                 "--do_not_generate_fec",
+                 rootfs_path.value().c_str(),
+                 (int)partition_size);
+
+  // Check that we correctly generate dm-verity kernel cmdline
+  // snippets, if requested.
+  GenerateVBMetaImage(
+      "vbmeta_a.img",
+      "SHA256_RSA2048",
+      4,
+      base::FilePath("test/data/testkey_rsa2048.pem"),
+      base::StringPrintf(
+          "--setup_rootfs_from_kernel %s "
+          "--kernel_cmdline should_be_in_both=1 "
+          "--algorithm SHA256_RSA2048 "
+          "--flags %d "
+          "--internal_release_string \"\"",
+          rootfs_path.value().c_str(),
+          use_avbctl ? 0 : AVB_VBMETA_IMAGE_FLAGS_VERIFICATION_DISABLED));
+
+  EXPECT_EQ(
+      base::StringPrintf(
+          "Minimum libavb version:   1.0\n"
+          "Header Block:             256 bytes\n"
+          "Authentication Block:     320 bytes\n"
+          "Auxiliary Block:          960 bytes\n"
+          "Algorithm:                SHA256_RSA2048\n"
+          "Rollback Index:           4\n"
+          "Flags:                    %d\n"
+          "Release String:           ''\n"
+          "Descriptors:\n"
+          "    Kernel Cmdline descriptor:\n"
+          "      Flags:                 1\n"
+          "      Kernel Cmdline:        'dm=\"1 vroot none ro 1,0 2056 verity "
+          "1 PARTUUID=$(ANDROID_SYSTEM_PARTUUID) "
+          "PARTUUID=$(ANDROID_SYSTEM_PARTUUID) 4096 4096 257 257 sha1 "
+          "e811611467dcd6e8dc4324e45f706c2bdd51db67 d00df00d 2 "
+          "$(ANDROID_VERITY_MODE) ignore_zero_blocks\" root=/dev/dm-0'\n"
+          "    Kernel Cmdline descriptor:\n"
+          "      Flags:                 2\n"
+          "      Kernel Cmdline:        "
+          "'root=PARTUUID=$(ANDROID_SYSTEM_PARTUUID)'\n"
+          "    Kernel Cmdline descriptor:\n"
+          "      Flags:                 0\n"
+          "      Kernel Cmdline:        'should_be_in_both=1'\n",
+          use_avbctl ? 0 : AVB_VBMETA_IMAGE_FLAGS_VERIFICATION_DISABLED),
+      InfoImage(vbmeta_image_path_));
+
+  ops_.set_expected_public_key(
+      PublicKeyAVB(base::FilePath("test/data/testkey_rsa2048.pem")));
+
+  // Manually set the flag the same way 'avbctl disable-verification'
+  // would do it.
+  if (use_avbctl) {
+    uint32_t flags_data;
+    flags_data = avb_htobe32(AVB_VBMETA_IMAGE_FLAGS_VERIFICATION_DISABLED);
+    EXPECT_EQ(AVB_IO_RESULT_OK,
+              ops_.avb_ops()->write_to_partition(
+                  ops_.avb_ops(),
+                  "vbmeta_a",
+                  offsetof(AvbVBMetaImageHeader, flags),
+                  sizeof flags_data,
+                  &flags_data));
+  }
+
+  // Check that avb_slot_verify() doesn't return any of the
+  // descriptors and instead return a kernel command-line with
+  // root=PARTUUID=<whatever_for_system_a> and none of the
+  // androidboot.vbmeta.* options are set. Also ensure all the
+  // requested partitions are loaded.
+  //
+  // Also if we modified via avbctl we should expect
+  // ERROR_VERIFICATION instead of OK.
+  //
+  AvbSlotVerifyResult expected_result = AVB_SLOT_VERIFY_RESULT_OK;
+  if (use_avbctl) {
+    expected_result = AVB_SLOT_VERIFY_RESULT_ERROR_VERIFICATION;
+  }
+  AvbSlotVerifyData* slot_data = NULL;
+  const char* requested_partitions[] = {"boot", "dtbo", NULL};
+  EXPECT_EQ(expected_result,
+            avb_slot_verify(ops_.avb_ops(),
+                            requested_partitions,
+                            "_a",
+                            AVB_SLOT_VERIFY_FLAGS_ALLOW_VERIFICATION_ERROR,
+                            AVB_HASHTREE_ERROR_MODE_RESTART_AND_INVALIDATE,
+                            &slot_data));
+  EXPECT_NE(nullptr, slot_data);
+  EXPECT_EQ("root=PARTUUID=1234-fake-guid-for:system_a",
+            std::string(slot_data->cmdline));
+  // Also make sure that it actually loads the boot and dtbo partitions.
+  EXPECT_EQ(size_t(2), slot_data->num_loaded_partitions);
+  EXPECT_EQ("boot",
+            std::string(slot_data->loaded_partitions[0].partition_name));
+  EXPECT_EQ(boot_part_size, slot_data->loaded_partitions[0].data_size);
+  for (size_t n = 0; n < boot_part_size; n++) {
+    EXPECT_EQ(uint8_t(n), slot_data->loaded_partitions[0].data[n]);
+  }
+  EXPECT_EQ("dtbo",
+            std::string(slot_data->loaded_partitions[1].partition_name));
+  EXPECT_EQ(dtbo_part_size, slot_data->loaded_partitions[1].data_size);
+  for (size_t n = 0; n < dtbo_part_size; n++) {
+    EXPECT_EQ(uint8_t(n + DTBO_DATA_OFFSET),
+              slot_data->loaded_partitions[1].data[n]);
+  }
+  avb_slot_verify_data_free(slot_data);
+}
+
+TEST_F(AvbSlotVerifyTest, VerificationDisabledUnmodified) {
+  VerificationDisabled(false);  // use_avbctl
+}
+
+TEST_F(AvbSlotVerifyTest, VerificationDisabledModified) {
+  VerificationDisabled(true);  // use_avbctl
+}
+
 // In the event that there's no vbmeta partition, we treat the vbmeta
 // struct from 'boot' as the top-level partition. Check that this
 // works.
diff --git a/tools/avbctl/avbctl.cc b/tools/avbctl/avbctl.cc
index 9d83f0b..d0922b3 100644
--- a/tools/avbctl/avbctl.cc
+++ b/tools/avbctl/avbctl.cc
@@ -41,10 +41,17 @@
           "  %s COMMAND\n"
           "\n"
           "Commands:\n"
-          "  %s get-verity        - Prints whether verity is enabled in "
+          "  %s get-verity           - Prints whether verity is enabled in "
           "current slot.\n"
-          "  %s disable-verity    - Disable verity in current slot.\n"
-          "  %s enable-verity     - Enable verity in current slot.\n",
+          "  %s disable-verity       - Disable verity in current slot.\n"
+          "  %s enable-verity        - Enable verity in current slot.\n"
+          "  %s get-verification     - Prints whether verification is enabled "
+          "in current slot.\n"
+          "  %s disable-verification - Disable verification in current slot.\n"
+          "  %s enable-verification  - Enable verification in current slot.\n",
+          argv[0],
+          argv[0],
+          argv[0],
           argv[0],
           argv[0],
           argv[0],
@@ -52,6 +59,71 @@
           argv[0]);
 }
 
+/* Function to enable and disable verification. The |ops| parameter
+ * should be an |AvbOps| from libavb_user.
+ */
+int do_set_verification(AvbOps* ops,
+                        const std::string& ab_suffix,
+                        bool enable_verification) {
+  bool verification_enabled;
+
+  if (!avb_user_verification_get(
+          ops, ab_suffix.c_str(), &verification_enabled)) {
+    fprintf(stderr, "Error getting whether verification is enabled.\n");
+    return EX_SOFTWARE;
+  }
+
+  if ((verification_enabled && enable_verification) ||
+      (!verification_enabled && !enable_verification)) {
+    fprintf(stdout,
+            "verification is already %s",
+            verification_enabled ? "enabled" : "disabled");
+    if (ab_suffix != "") {
+      fprintf(stdout, " on slot with suffix %s", ab_suffix.c_str());
+    }
+    fprintf(stdout, ".\n");
+    return EX_OK;
+  }
+
+  if (!avb_user_verification_set(ops, ab_suffix.c_str(), enable_verification)) {
+    fprintf(stderr, "Error setting verification.\n");
+    return EX_SOFTWARE;
+  }
+
+  fprintf(stdout,
+          "Successfully %s verification",
+          enable_verification ? "enabled" : "disabled");
+  if (ab_suffix != "") {
+    fprintf(stdout, " on slot with suffix %s", ab_suffix.c_str());
+  }
+  fprintf(stdout, ". Reboot the device for changes to take effect.\n");
+
+  return EX_OK;
+}
+
+/* Function to query if verification. The |ops| parameter should be an
+ * |AvbOps| from libavb_user.
+ */
+int do_get_verification(AvbOps* ops, const std::string& ab_suffix) {
+  bool verification_enabled;
+
+  if (!avb_user_verification_get(
+          ops, ab_suffix.c_str(), &verification_enabled)) {
+    fprintf(stderr, "Error getting whether verification is enabled.\n");
+    return EX_SOFTWARE;
+  }
+
+  fprintf(stdout,
+          "verification is %s",
+          verification_enabled ? "enabled" : "disabled");
+  if (ab_suffix != "") {
+    fprintf(stdout, " on slot with suffix %s", ab_suffix.c_str());
+  }
+  fprintf(stdout, ".\n");
+
+  return EX_OK;
+}
+
 /* Function to enable and disable dm-verity. The |ops| parameter
  * should be an |AvbOps| from libavb_user.
  */
@@ -158,6 +230,12 @@
     ret = do_set_verity(ops, ab_suffix, true);
   } else if (strcmp(argv[1], "get-verity") == 0) {
     ret = do_get_verity(ops, ab_suffix);
+  } else if (strcmp(argv[1], "disable-verification") == 0) {
+    ret = do_set_verification(ops, ab_suffix, false);
+  } else if (strcmp(argv[1], "enable-verification") == 0) {
+    ret = do_set_verification(ops, ab_suffix, true);
+  } else if (strcmp(argv[1], "get-verification") == 0) {
+    ret = do_get_verification(ops, ab_suffix);
   } else {
     usage(stderr, argc, argv);
     ret = EX_USAGE;