cmd: avb2.0: avb command for performing verification
authorIgor Opaniuk <igor.opaniuk@linaro.org>
Sun, 3 Jun 2018 18:56:39 +0000 (21:56 +0300)
committerTom Rini <trini@konsulko.com>
Mon, 18 Jun 2018 17:55:13 +0000 (13:55 -0400)
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 <igor.opaniuk@linaro.org>
cmd/Kconfig
cmd/Makefile
cmd/avb.c [new file with mode: 0644]

index 1eb55e52508eb5350dae2fdbc203bd77670f0f51..45c83359add828a60dd8e6f69f9b4abb39a2e44d 100644 (file)
@@ -1754,6 +1754,22 @@ 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
+       default n
+       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
index e0088df33bd1be1763870102682d2fc920a0173c..13cf7bf6c205d43a42214f4d44bde4205c661386 100644 (file)
@@ -155,6 +155,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 (file)
index 0000000..dd389cd
--- /dev/null
+++ b/cmd/avb.c
@@ -0,0 +1,357 @@
+
+/*
+ * (C) Copyright 2018, Linaro Limited
+ *
+ * SPDX-License-Identifier:    GPL-2.0+
+ */
+
+#include <avb_verify.h>
+#include <command.h>
+#include <image.h>
+#include <malloc.h>
+#include <mmc.h>
+
+#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);
+
+       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,
+                               AVB_HASHTREE_ERROR_MODE_RESTART_AND_INVALIDATE,
+                               &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 <dev> - initialize avb2 for <dev>\n"
+       "avb read_rb <num> - read rollback index at location <num>\n"
+       "avb write_rb <num> <rb> - write rollback index <rb> to <num>\n"
+       "avb is_unlocked - returns unlock status of the device\n"
+       "avb get_uuid <partname> - read and print uuid of partition <part>\n"
+       "avb read_part <partname> <offset> <num> <addr> - read <num> bytes from\n"
+       "    partition <partname> to buffer <addr>\n"
+       "avb read_part_hex <partname> <offset> <num> - read <num> bytes from\n"
+       "    partition <partname> and print to stdout\n"
+       "avb write_part <partname> <offset> <num> <addr> - write <num> bytes to\n"
+       "    <partname> by <offset> using data from <addr>\n"
+       "avb verify - run verification process using hash data\n"
+       "    from vbmeta structure\n"
+       );