From patchwork Sun Jun 3 18:56:39 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Igor Opaniuk X-Patchwork-Id: 137607 Delivered-To: patch@linaro.org Received: by 2002:a2e:970d:0:0:0:0:0 with SMTP id r13-v6csp659486lji; Sun, 3 Jun 2018 12:00:29 -0700 (PDT) X-Google-Smtp-Source: ADUXVKJ07uB9sVNSxbo012PxnjAKFI7a40UKgn+x5xpr/1J+Y72eYTuGRbKhCjRrLjCTJHlFgqOH X-Received: by 2002:a50:aa5d:: with SMTP id p29-v6mr3721268edc.233.1528052429483; Sun, 03 Jun 2018 12:00:29 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1528052429; cv=none; d=google.com; s=arc-20160816; b=L27gD5gHILU9uC3tROwh0tNJWQPOyPQI2oU0eaEGqmEM6UU1KCgGIV4LFCivfkknPJ ze2tehqfaOEYafogwnW2dy3TztBbg0RldfJEhMq27ioC3dq6pUjaQ4muaX0oWKR92k7j wvTk1rAgCwS1vkCZXBTf1ZpUxdrpLIRd4Er1wYpqRqumwSFMpnRGMUNYR5MZtXRKnbKm ZSFOvEWa8lJ4cJojhx2jd2uZoMh2GX6Wwyx69xzyc4sIhCALbf1h/X3AaS/ST8uqHeeh VGjxAUvA+7z0CCQquxOkQyzgmROs93y+wW7bQWBVnNDJsdu2bILdPhyXa4vbcdQ7pBbc kScQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=sender:errors-to:content-transfer-encoding:mime-version :list-subscribe:list-help:list-post:list-archive:list-unsubscribe :list-id:precedence:subject:cc:references:in-reply-to:message-id :date:to:from:dkim-signature:arc-authentication-results; bh=t+PWlaaEq3VpcuJMj0v4Q27HzsFlxm9AIqDuG7jbAO8=; b=XCcFCnZ5KEmTdX8KrErS75BPywjNwWXDdGo6g8d32iRZVHK21N9uBqCIKoMqlHTBlx eWiR5T1p+ePt6Cl1FCpuKZxZzeWf5rvMkN9Avn+v4Iyw0zTwhXIKkJJF20KeGh1/Sw/y 3OUanQzmyflQtFFuc1s/UgRRrNr19Lb57OPba5a+OKTvQn3MSziVkM+JpfusoAN4NHMt yrXJUmZq4WgBw3xYzfVYUr47paMNGWGHto5nh4YjZi3sQndETaLz/613uv/qaT0rsXs6 wvfFK2LX2kzlXYd87dIni2SV5eUJl8Vhc4VjbmEqccIWtVcSa/7A4ijGKx3+WoX//UJ3 c0CA== ARC-Authentication-Results: i=1; mx.google.com; dkim=neutral (body hash did not verify) header.i=@linaro.org header.s=google header.b=SyOUVjHa; spf=pass (google.com: best guess record for domain of u-boot-bounces@lists.denx.de designates 81.169.180.215 as permitted sender) smtp.mailfrom=u-boot-bounces@lists.denx.de; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=linaro.org Return-Path: Received: from lists.denx.de (dione.denx.de. [81.169.180.215]) by mx.google.com with ESMTP id a3-v6si3241371ede.111.2018.06.03.12.00.29; Sun, 03 Jun 2018 12:00:29 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of u-boot-bounces@lists.denx.de designates 81.169.180.215 as permitted sender) client-ip=81.169.180.215; Authentication-Results: mx.google.com; dkim=neutral (body hash did not verify) header.i=@linaro.org header.s=google header.b=SyOUVjHa; spf=pass (google.com: best guess record for domain of u-boot-bounces@lists.denx.de designates 81.169.180.215 as permitted sender) smtp.mailfrom=u-boot-bounces@lists.denx.de; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=linaro.org Received: by lists.denx.de (Postfix, from userid 105) id 202F3C21D4A; Sun, 3 Jun 2018 18:58:34 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on lists.denx.de X-Spam-Level: X-Spam-Status: No, score=0.0 required=5.0 tests=T_DKIM_INVALID autolearn=unavailable autolearn_force=no version=3.4.0 Received: from lists.denx.de (localhost [IPv6:::1]) by lists.denx.de (Postfix) with ESMTP id 76A1AC21DA1; Sun, 3 Jun 2018 18:57:04 +0000 (UTC) Received: by lists.denx.de (Postfix, from userid 105) id 68012C21E18; Sun, 3 Jun 2018 18:56:59 +0000 (UTC) Received: from mail-lf0-f52.google.com (mail-lf0-f52.google.com [209.85.215.52]) by lists.denx.de (Postfix) with ESMTPS id ABDAEC21DFF for ; Sun, 3 Jun 2018 18:56:58 +0000 (UTC) Received: by mail-lf0-f52.google.com with SMTP id u4-v6so21853851lff.3 for ; Sun, 03 Jun 2018 11:56:58 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=BD2eLS83cjtOXcudczqRUcXz752syENFkNhZovfOx3Y=; b=SyOUVjHaNMYEM3h11gCgq64amTG7Ef9PkvVRhGy1Q+pLKS/kKF7cQj/vVEx0/XGndr S2Oi3asBbXqsVnZx2RUKsFVCgNZnJiveisILSeSvCnjiR/vqMfUohI1Bv5fnf9nht31o D+9kscIhAAzxIirFUuTT+XPn9wbbfsZMzvnP0= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=BD2eLS83cjtOXcudczqRUcXz752syENFkNhZovfOx3Y=; b=jCKUdNfkqPWy6n2PfZKQnfeWLiB0ngGRq2Hk56Gp49wofXfTcbEq8s296SPAipLLBn WQa1dJvyHOzia9o5RCCpaI7VA1JEEyt4p68Q3U30S1Y5HwMwpvGNGH4dy9SmB4BKfbOn 6W79PajmyDP3Dqu1pK/Kwb9kNPqtgAjaVVObN8gLwn6cqqBlRCwdaOAtcS4ykDl1aXZk HBy0oE3sKfqifSSS1jkUKi00+7a+sXSYOJ5IK7votLj4XuzZn3JYfcRvIwr1qSSelLh8 vsS57Tf2vaIy9JzgK5sKn5cdMh06jPoFmN25/cqkHzNVSwABRwIs2ite3w4CNC0sNGPX q6hw== X-Gm-Message-State: ALKqPwccnNgzzPylB0YJNye5WYeA/+W15tndjgNbnrCkrcFJp4/HIqGQ LxQtKlz4Q+pzSUv1ZfDtic0ZD4otpsoMRA== X-Received: by 2002:a2e:8951:: with SMTP id b17-v6mr7435941ljk.111.1528052217807; Sun, 03 Jun 2018 11:56:57 -0700 (PDT) Received: from localhost (host-176-36-145-117.la.net.ua. [176.36.145.117]) by smtp.gmail.com with ESMTPSA id 81-v6sm2161132lfu.16.2018.06.03.11.56.56 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Sun, 03 Jun 2018 11:56:57 -0700 (PDT) From: Igor Opaniuk To: u-boot@lists.denx.de Date: Sun, 3 Jun 2018 21:56:39 +0300 Message-Id: <1528052203-29689-5-git-send-email-igor.opaniuk@linaro.org> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1528052203-29689-1-git-send-email-igor.opaniuk@linaro.org> References: <1528052203-29689-1-git-send-email-igor.opaniuk@linaro.org> Cc: trini@konsulko.com, praneeth@ti.com, misael.lopez@ti.com, erosca@de.adit-jv.com, joakim.bech@linaro.org Subject: [U-Boot] [PATCH v2 4/8] cmd: avb2.0: avb command for performing verification X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.18 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: u-boot-bounces@lists.denx.de Sender: "U-Boot" 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 | 16 +++ cmd/Makefile | 3 + cmd/avb.c | 357 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 376 insertions(+) create mode 100644 cmd/avb.c diff --git a/cmd/Kconfig b/cmd/Kconfig index bc1d2f3..fa1f2b5 100644 --- a/cmd/Kconfig +++ b/cmd/Kconfig @@ -1675,6 +1675,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 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..dd389cd --- /dev/null +++ b/cmd/avb.c @@ -0,0 +1,357 @@ + +/* + * (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); + + 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 - 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" + );