diff options
Diffstat (limited to 'cmd')
-rw-r--r-- | cmd/Kconfig | 16 | ||||
-rw-r--r-- | cmd/Makefile | 3 | ||||
-rw-r--r-- | cmd/avb.c | 372 | ||||
-rw-r--r-- | cmd/booti.c | 2 | ||||
-rw-r--r-- | cmd/iotrace.c | 43 | ||||
-rw-r--r-- | cmd/mmc.c | 2 |
6 files changed, 433 insertions, 5 deletions
diff --git a/cmd/Kconfig b/cmd/Kconfig index 1eb55e5250..45c83359ad 100644 --- a/cmd/Kconfig +++ b/cmd/Kconfig @@ -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 diff --git a/cmd/Makefile b/cmd/Makefile index e0088df33b..13cf7bf6c2 100644 --- a/cmd/Makefile +++ b/cmd/Makefile @@ -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 index 0000000000..f045a0c64c --- /dev/null +++ b/cmd/avb.c @@ -0,0 +1,372 @@ + +/* + * (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; + char *cmdline; + char *extra_args; + + 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: + /* Until we don't have support of changing unlock states, we + * assume that we are by default in locked state. + * So in this case we can boot only when verification is + * successful; we also supply in cmdline GREEN boot state + */ + printf("Verification passed successfully\n"); + + /* export additional bootargs to AVB_BOOTARGS env var */ + + extra_args = avb_set_state(avb_ops, AVB_GREEN); + if (extra_args) + cmdline = append_cmd_line(out_data->cmdline, + extra_args); + else + cmdline = out_data->cmdline; + + env_set(AVB_BOOTARGS, 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" + ); diff --git a/cmd/booti.c b/cmd/booti.c index 45fbb99b68..04353b68ec 100644 --- a/cmd/booti.c +++ b/cmd/booti.c @@ -37,7 +37,7 @@ static int booti_start(cmd_tbl_t *cmdtp, int flag, int argc, debug("* kernel: cmdline image address = 0x%08lx\n", ld); } - ret = booti_setup(ld, &relocated_addr, &image_size); + ret = booti_setup(ld, &relocated_addr, &image_size, false); if (ret != 0) return 1; diff --git a/cmd/iotrace.c b/cmd/iotrace.c index 601b8c8e32..fa6c68b198 100644 --- a/cmd/iotrace.c +++ b/cmd/iotrace.c @@ -9,12 +9,13 @@ static void do_print_stats(void) { - ulong start, size, offset, count; + ulong start, size, needed_size, offset, count; printf("iotrace is %sabled\n", iotrace_get_enabled() ? "en" : "dis"); - iotrace_get_buffer(&start, &size, &offset, &count); + iotrace_get_buffer(&start, &size, &needed_size, &offset, &count); printf("Start: %08lx\n", start); - printf("Size: %08lx\n", size); + printf("Actual Size: %08lx\n", size); + printf("Needed Size: %08lx\n", needed_size); iotrace_get_region(&start, &size); printf("Region: %08lx\n", start); printf("Size: %08lx\n", size); @@ -24,6 +25,36 @@ static void do_print_stats(void) printf("CRC32: %08lx\n", (ulong)iotrace_get_checksum()); } +static void do_print_trace(void) +{ + ulong start, size, needed_size, offset, count; + + struct iotrace_record *cur_record; + + iotrace_get_buffer(&start, &size, &needed_size, &offset, &count); + + if (!start || !size || !count) + return; + + printf("Timestamp Value Address\n"); + + cur_record = (struct iotrace_record *)start; + for (int i = 0; i < count; i++) { + if (cur_record->flags & IOT_WRITE) + printf("%08llu: 0x%08lx --> 0x%08llx\n", + cur_record->timestamp, + cur_record->value, + (unsigned long long)cur_record->addr); + else + printf("%08llu: 0x%08lx <-- 0x%08llx\n", + cur_record->timestamp, + cur_record->value, + (unsigned long long)cur_record->addr); + + cur_record++; + } +} + static int do_set_buffer(int argc, char * const argv[]) { ulong addr = 0, size = 0; @@ -76,6 +107,9 @@ int do_iotrace(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) case 's': do_print_stats(); break; + case 'd': + do_print_trace(); + break; default: return CMD_RET_USAGE; } @@ -90,5 +124,6 @@ U_BOOT_CMD( "iotrace buffer <address> <size> - set iotrace buffer\n" "iotrace limit <address> <size> - set iotrace region limit\n" "iotrace pause - pause tracing\n" - "iotrace resume - resume tracing" + "iotrace resume - resume tracing\n" + "iotrace dump - dump iotrace buffer" ); @@ -935,6 +935,7 @@ U_BOOT_CMD( "mmc part - lists available partition on current mmc device\n" "mmc dev [dev] [part] - show or set current mmc device [partition]\n" "mmc list - lists available devices\n" +#if CONFIG_IS_ENABLED(MMC_HW_PARTITIONING) "mmc hwpartition [args...] - does hardware partitioning\n" " arguments (sizes in 512-byte blocks):\n" " [user [enh start cnt] [wrrel {on|off}]] - sets user data area attributes\n" @@ -942,6 +943,7 @@ U_BOOT_CMD( " [check|set|complete] - mode, complete set partitioning completed\n" " WARNING: Partitioning is a write-once setting once it is set to complete.\n" " Power cycling is required to initialize partitions after set to complete.\n" +#endif #ifdef CONFIG_SUPPORT_EMMC_BOOT "mmc bootbus dev boot_bus_width reset_boot_bus_width boot_mode\n" " - Set the BOOT_BUS_WIDTH field of the specified device\n" |