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;