From mboxrd@z Thu Jan 1 00:00:00 1970 From: Sam Protsenko Date: Wed, 2 May 2018 21:52:09 +0300 Subject: [U-Boot] [PATCH 4/8] cmd: avb2.0: avb command for performing verification In-Reply-To: <1524662285-19617-5-git-send-email-igor.opaniuk@linaro.org> References: <1524662285-19617-1-git-send-email-igor.opaniuk@linaro.org> <1524662285-19617-5-git-send-email-igor.opaniuk@linaro.org> Message-ID: List-Id: MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit To: u-boot@lists.denx.de On 25 April 2018 at 16:18, Igor Opaniuk wrote: > Enable a "avb" command to execute Android Verified > Boot 2.0 operations. It includes such subcommands: > avb init - initialize avb2 subsystem > avb read_rb - read rollback index > avb write_rb - write rollback index > avb is_unlocked - check device lock state > avb get_uuid - read and print uuid of a partition > avb read_part - read data from partition > avb read_part_hex - read data from partition and output to stdout > avb write_part - write data to partition > avb verify - run full verification chain > > Signed-off-by: Igor Opaniuk > --- > cmd/Kconfig | 15 +++ > cmd/Makefile | 3 + > cmd/avb.c | 351 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ > 3 files changed, 369 insertions(+) > create mode 100644 cmd/avb.c > > diff --git a/cmd/Kconfig b/cmd/Kconfig > index bc1d2f3..96695ff 100644 > --- a/cmd/Kconfig > +++ b/cmd/Kconfig > @@ -1675,6 +1675,21 @@ config CMD_TRACE > for analsys (e.g. using bootchart). See doc/README.trace for full > details. > > +config CMD_AVB > + bool "avb - Android Verified Boot 2.0 operations" > + depends on LIBAVB_AB > + help > + Enables a "avb" command to perform verification of partitions using > + Android Verified Boot 2.0 functionality. It includes such subcommands: > + avb init - initialize avb2 subsystem > + avb read_rb - read rollback index > + avb write_rb - write rollback index > + avb is_unlocked - check device lock state > + avb get_uuid - read and print uuid of a partition > + avb read_part - read data from partition > + avb read_part_hex - read data from partition and output to stdout > + avb write_part - write data to partition > + avb verify - run full verification chain > endmenu > > config CMD_UBI > diff --git a/cmd/Makefile b/cmd/Makefile > index c4269ac..bbf6c2a 100644 > --- a/cmd/Makefile > +++ b/cmd/Makefile > @@ -151,6 +151,9 @@ obj-$(CONFIG_CMD_REGULATOR) += regulator.o > > obj-$(CONFIG_CMD_BLOB) += blob.o > > +# Android Verified Boot 2.0 > +obj-$(CONFIG_CMD_AVB) += avb.o > + > obj-$(CONFIG_X86) += x86/ > endif # !CONFIG_SPL_BUILD > > diff --git a/cmd/avb.c b/cmd/avb.c > new file mode 100644 > index 0000000..d040906 > --- /dev/null > +++ b/cmd/avb.c > @@ -0,0 +1,351 @@ > + > +/* > + * (C) Copyright 2018, Linaro Limited > + * > + * SPDX-License-Identifier: GPL-2.0+ > + */ > + > +#include > +#include > +#include > +#include > +#include > + > +#define AVB_BOOTARGS "avb_bootargs" > +static struct AvbOps *avb_ops; > + > +static const char * const requested_partitions[] = {"boot", > + "system", > + "vendor", > + NULL}; > + > +int do_avb_init(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) > +{ > + unsigned long mmc_dev; > + > + if (argc != 2) > + return CMD_RET_USAGE; > + > + mmc_dev = simple_strtoul(argv[1], NULL, 16); > + > + if (avb_ops) > + avb_ops_free(avb_ops); > + > + avb_ops = avb_ops_alloc(mmc_dev); > + if (avb_ops) > + return CMD_RET_SUCCESS; > + > + return CMD_RET_FAILURE; > +} > + > +int do_avb_read_part(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) > +{ > + const char *part; > + s64 offset; > + size_t bytes, bytes_read = 0; > + void *buffer; > + > + if (!avb_ops) { > + printf("AVB 2.0 is not initialized, please run 'avb init'\n"); > + return CMD_RET_USAGE; > + } > + > + if (argc != 5) > + return CMD_RET_USAGE; > + > + part = argv[1]; > + offset = simple_strtoul(argv[2], NULL, 16); > + bytes = simple_strtoul(argv[3], NULL, 16); > + buffer = (void *)simple_strtoul(argv[4], NULL, 16); + Simon Glass AFAIU, to make it possible to run this command on "sandbox", you should use map_sysmem() and friends. > + > + if (avb_ops->read_from_partition(avb_ops, part, offset, bytes, > + buffer, &bytes_read) == > + AVB_IO_RESULT_OK) { > + printf("Read %zu bytes\n", bytes_read); > + return CMD_RET_SUCCESS; > + } > + > + return CMD_RET_FAILURE; > +} > + > +int do_avb_read_part_hex(cmd_tbl_t *cmdtp, int flag, int argc, > + char *const argv[]) > +{ > + const char *part; > + s64 offset; > + size_t bytes, bytes_read = 0; > + char *buffer; > + > + if (!avb_ops) { > + printf("AVB 2.0 is not initialized, please run 'avb init'\n"); > + return CMD_RET_USAGE; > + } > + > + if (argc != 4) > + return CMD_RET_USAGE; > + > + part = argv[1]; > + offset = simple_strtoul(argv[2], NULL, 16); > + bytes = simple_strtoul(argv[3], NULL, 16); > + > + buffer = malloc(bytes); > + if (!buffer) { > + printf("Failed to tlb_allocate buffer for data\n"); > + return CMD_RET_FAILURE; > + } > + memset(buffer, 0, bytes); > + > + if (avb_ops->read_from_partition(avb_ops, part, offset, bytes, buffer, > + &bytes_read) == AVB_IO_RESULT_OK) { > + printf("Requested %zu, read %zu bytes\n", bytes, bytes_read); > + printf("Data: "); > + for (int i = 0; i < bytes_read; i++) > + printf("%02X", buffer[i]); > + > + printf("\n"); > + > + free(buffer); > + return CMD_RET_SUCCESS; > + } > + > + free(buffer); > + return CMD_RET_FAILURE; > +} > + > +int do_avb_write_part(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) > +{ > + const char *part; > + s64 offset; > + size_t bytes; > + void *buffer; > + > + if (!avb_ops) { > + printf("AVB 2.0 is not initialized, run 'avb init' first\n"); > + return CMD_RET_FAILURE; > + } > + > + if (argc != 5) > + return CMD_RET_USAGE; > + > + part = argv[1]; > + offset = simple_strtoul(argv[2], NULL, 16); > + bytes = simple_strtoul(argv[3], NULL, 16); > + buffer = (void *)simple_strtoul(argv[4], NULL, 16); > + > + if (avb_ops->write_to_partition(avb_ops, part, offset, bytes, buffer) == > + AVB_IO_RESULT_OK) { > + printf("Wrote %zu bytes\n", bytes); > + return CMD_RET_SUCCESS; > + } > + > + return CMD_RET_FAILURE; > +} > + > +int do_avb_read_rb(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) > +{ > + size_t index; > + u64 rb_idx; > + > + if (!avb_ops) { > + printf("AVB 2.0 is not initialized, run 'avb init' first\n"); > + return CMD_RET_FAILURE; > + } > + > + if (argc != 2) > + return CMD_RET_USAGE; > + > + index = (size_t)simple_strtoul(argv[1], NULL, 16); > + > + if (avb_ops->read_rollback_index(avb_ops, index, &rb_idx) == > + AVB_IO_RESULT_OK) { > + printf("Rollback index: %llu\n", rb_idx); > + return CMD_RET_SUCCESS; > + } > + return CMD_RET_FAILURE; > +} > + > +int do_avb_write_rb(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) > +{ > + size_t index; > + u64 rb_idx; > + > + if (!avb_ops) { > + printf("AVB 2.0 is not initialized, run 'avb init' first\n"); > + return CMD_RET_FAILURE; > + } > + > + if (argc != 3) > + return CMD_RET_USAGE; > + > + index = (size_t)simple_strtoul(argv[1], NULL, 16); > + rb_idx = simple_strtoul(argv[2], NULL, 16); > + > + if (avb_ops->write_rollback_index(avb_ops, index, rb_idx) == > + AVB_IO_RESULT_OK) > + return CMD_RET_SUCCESS; > + > + return CMD_RET_FAILURE; > +} > + > +int do_avb_get_uuid(cmd_tbl_t *cmdtp, int flag, > + int argc, char * const argv[]) > +{ > + const char *part; > + char buffer[UUID_STR_LEN + 1]; > + > + if (!avb_ops) { > + printf("AVB 2.0 is not initialized, run 'avb init' first\n"); > + return CMD_RET_FAILURE; > + } > + > + if (argc != 2) > + return CMD_RET_USAGE; > + > + part = argv[1]; > + > + if (avb_ops->get_unique_guid_for_partition(avb_ops, part, buffer, > + UUID_STR_LEN + 1) == > + AVB_IO_RESULT_OK) { > + printf("'%s' UUID: %s\n", part, buffer); > + return CMD_RET_SUCCESS; > + } > + > + return CMD_RET_FAILURE; > +} > + > +int do_avb_verify_part(cmd_tbl_t *cmdtp, int flag, > + int argc, char *const argv[]) > +{ > + AvbSlotVerifyResult slot_result; > + AvbSlotVerifyData *out_data; > + > + bool unlocked = false; > + int res = CMD_RET_FAILURE; > + > + if (!avb_ops) { > + printf("AVB 2.0 is not initialized, run 'avb init' first\n"); > + return CMD_RET_FAILURE; > + } > + > + if (argc != 1) > + return CMD_RET_USAGE; > + > + printf("## Android Verified Boot 2.0 version %s\n", > + avb_version_string()); > + > + if (avb_ops->read_is_device_unlocked(avb_ops, &unlocked) != > + AVB_IO_RESULT_OK) { > + printf("Can't determine device lock state.\n"); > + return CMD_RET_FAILURE; > + } > + > + slot_result = avb_slot_verify(avb_ops, requested_partitions, > + "", unlocked, &out_data); > + switch (slot_result) { > + case AVB_SLOT_VERIFY_RESULT_OK: > + printf("Verification passed successfully\n"); > + > + /* export additional bootargs to AVB_BOOTARGS env var */ > + env_set(AVB_BOOTARGS, out_data->cmdline); > + > + res = CMD_RET_SUCCESS; > + break; > + case AVB_SLOT_VERIFY_RESULT_ERROR_VERIFICATION: > + printf("Verification failed\n"); > + break; > + case AVB_SLOT_VERIFY_RESULT_ERROR_IO: > + printf("I/O error occurred during verification\n"); > + break; > + case AVB_SLOT_VERIFY_RESULT_ERROR_OOM: > + printf("OOM error occurred during verification\n"); > + break; > + case AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA: > + printf("Corrupted dm-verity metadata detected\n"); > + break; > + case AVB_SLOT_VERIFY_RESULT_ERROR_UNSUPPORTED_VERSION: > + printf("Unsupported version avbtool was used\n"); > + break; > + case AVB_SLOT_VERIFY_RESULT_ERROR_ROLLBACK_INDEX: > + printf("Checking rollback index failed\n"); > + break; > + case AVB_SLOT_VERIFY_RESULT_ERROR_PUBLIC_KEY_REJECTED: > + printf("Public key was rejected\n"); > + break; > + default: > + printf("Unknown error occurred\n"); > + } > + > + return res; > +} > + > +int do_avb_is_unlocked(cmd_tbl_t *cmdtp, int flag, > + int argc, char * const argv[]) > +{ > + bool unlock; > + > + if (!avb_ops) { > + printf("AVB not initialized, run 'avb init' first\n"); > + return CMD_RET_FAILURE; > + } > + > + if (argc != 1) { > + printf("--%s(-1)\n", __func__); > + return CMD_RET_USAGE; > + } > + > + if (avb_ops->read_is_device_unlocked(avb_ops, &unlock) == > + AVB_IO_RESULT_OK) { > + printf("Unlocked = %d\n", unlock); > + return CMD_RET_SUCCESS; > + } > + > + return CMD_RET_FAILURE; > +} > + > +static cmd_tbl_t cmd_avb[] = { > + U_BOOT_CMD_MKENT(init, 2, 0, do_avb_init, "", ""), > + U_BOOT_CMD_MKENT(read_rb, 2, 0, do_avb_read_rb, "", ""), > + U_BOOT_CMD_MKENT(write_rb, 3, 0, do_avb_write_rb, "", ""), > + U_BOOT_CMD_MKENT(is_unlocked, 1, 0, do_avb_is_unlocked, "", ""), > + U_BOOT_CMD_MKENT(get_uuid, 2, 0, do_avb_get_uuid, "", ""), > + U_BOOT_CMD_MKENT(read_part, 5, 0, do_avb_read_part, "", ""), > + U_BOOT_CMD_MKENT(read_part_hex, 4, 0, do_avb_read_part_hex, "", ""), > + U_BOOT_CMD_MKENT(write_part, 5, 0, do_avb_write_part, "", ""), > + U_BOOT_CMD_MKENT(verify, 1, 0, do_avb_verify_part, "", ""), > +}; > + > +static int do_avb(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) > +{ > + cmd_tbl_t *cp; > + > + cp = find_cmd_tbl(argv[1], cmd_avb, ARRAY_SIZE(cmd_avb)); > + > + argc--; > + argv++; > + > + if (!cp || argc > cp->maxargs) > + return CMD_RET_USAGE; > + > + if (flag == CMD_FLAG_REPEAT) > + return CMD_RET_FAILURE; > + > + return cp->cmd(cmdtp, flag, argc, argv); > +} > + > +U_BOOT_CMD( > + avb, 29, 0, do_avb, > + "Provides commands for testing Android Verified Boot 2.0 functionality", > + "init - initialize avb2 for \n" > + "avb read_rb - read rollback index at location \n" > + "avb write_rb - write rollback index to \n" > + "avb is_unlocked - returns unlock status of the device\n" > + "avb get_uuid - read and print uuid of partition \n" > + "avb read_part - read bytes from\n" > + " partition to buffer \n" > + "avb read_part_hex - read bytes from\n" > + " partition and print to stdout\n" > + "avb write_part - write bytes to\n" > + " by using data from \n" > + "avb verify - run verification process using hash data\n" > + " from vbmeta structure\n" > + ); > -- > 2.7.4 >