From patchwork Wed Apr 25 13:18:01 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Igor Opaniuk X-Patchwork-Id: 134310 Delivered-To: patch@linaro.org Received: by 10.46.151.6 with SMTP id r6csp865240lji; Wed, 25 Apr 2018 06:26:03 -0700 (PDT) X-Google-Smtp-Source: AIpwx4+9/2DR+QZgpkidYXUwYOgjNRPQ/7VzdV+2x4AamW1qyBwuPMhg+CPBVm+Y1Iyp86KzpKdP X-Received: by 10.80.238.140 with SMTP id f12mr21802216edr.10.1524662763338; Wed, 25 Apr 2018 06:26:03 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1524662763; cv=none; d=google.com; s=arc-20160816; b=khrL+FjgdxxAx9reX7RfIQJ+QpZoTWVXGC7yuPpU+EbAoZZQkp/HiSftTol/mtk/0U 3nqlP47p/COnsjYIsOd3c0wpj8ykyJTqd0CK14FQEQ0BV97n7mAXyMj+FgPnRH13SADq 0KKQuIpAjCzXxNtPUCwRd00HDvL7HKErhQYkyg/deF9YCC5XGkaDFaT9t0k81r3GtQFl llX1rnyr3Tip1daTMrHWNrrzNifg7T2UhtQGX/r9quQuYPiyWwOhhThONSNyN35dsGZ7 lKhBsPrcNmtLXHDw9/bMsQ9K3g7PiEtRGdi1i737eOnki+0cdcpQ3WHsUEh6/yWnIlGX GbGQ== 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=xT79RFpq1bKT+/aWDYgWD36AN8V5xWy026N1ft224z4=; b=dj0HGfa+nmJolgwfJ4xWd2pInRWnSO6ptO3L69JdZm8d72jUOO88DW7eOprYx/Tb3H YBMHTCLWEYHL5F9Wvnqe40yiYUxZv8njq0nkkDgz2CKbdxxmOG+klobCCeDOd9efdorz vXoUEB3P+5+GGvq+Pb7XgySYBP8EuVg7FyGbhKDKaYWX9peJFdAm4b3PVZtkxmcsTSBT bu1PQ4T0wDyZshxKh4VJjZBbn66A5y8d8HHqWazJNkWPazWBh0IcC/q+N5Uhtflk2Wuz wmSCnola8RE/ftIMd/nxq719ra5HDDiAH1uKwxEvapDwNnVRAU6SCyWR4pBqLZkneaNt ALJg== ARC-Authentication-Results: i=1; mx.google.com; dkim=neutral (body hash did not verify) header.i=@linaro.org header.s=google header.b=N/XJaQdj; 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 m64si1028715ede.196.2018.04.25.06.26.03; Wed, 25 Apr 2018 06:26:03 -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=N/XJaQdj; 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 E2485C21FDC; Wed, 25 Apr 2018 13:24:24 +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=RCVD_IN_MSPIKE_H3, RCVD_IN_MSPIKE_WL, 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 74A6BC2200D; Wed, 25 Apr 2018 13:21:07 +0000 (UTC) Received: by lists.denx.de (Postfix, from userid 105) id E9DA0C21FA0; Wed, 25 Apr 2018 13:18:17 +0000 (UTC) Received: from mail-lf0-f54.google.com (mail-lf0-f54.google.com [209.85.215.54]) by lists.denx.de (Postfix) with ESMTPS id 410EAC21FEA for ; Wed, 25 Apr 2018 13:18:17 +0000 (UTC) Received: by mail-lf0-f54.google.com with SMTP id j193-v6so2409256lfg.6 for ; Wed, 25 Apr 2018 06:18:17 -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=jrj2ADINfVLTgjzzcuAP61ZJvAOrQ1tYS5xSaCQqM/E=; b=N/XJaQdjI0gGuFlmxwRyHvYr57s+UWxgf13kzpJ5EDEqn23MRRvet6JHp5l3rJd82w YWMM4P1wpXVQCugww5/i6Fgl2b5J12IYj6EPVQojNVBvnuKusUIa2V7u7YsEkAEH0dlv EU+bViihA1xMDoRiWoz2mkV0DWDVf5FY5QDRA= 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=jrj2ADINfVLTgjzzcuAP61ZJvAOrQ1tYS5xSaCQqM/E=; b=T/ZkUnTLl7fPnZnt4475GiZz6SvMexDf9HKej3nQFJqcZ2EA0rBcFxrHTeiPQogUFZ zGYI6zN1yIDyh+TqpzksAfcU7w/BX3HQGM+nBdG9kmwkLjTdMiHQVnN8b0v8WoNmQEAE 3etKfyUXw+lz8CfHSRDO8R+N7XyB+yy5JhehH/IxPDa8ZL2yEcx56+USgX5RJ29zZoIP dASsapgOnYGoJHitltLJoUFCx2Z5ZMR3xolAE4b6MuC6i7Kq5GB0oJ7OOsf9AewOrMk+ sNYOdm93Lh+3kLCe22qtnAJS/VtBot3dQ+AtN7AvHxGPpK4KtLSrgCzV8Yr42i01Ds10 L9Aw== X-Gm-Message-State: ALQs6tDFu6Ws8dg2KDhRpTPoa46tkfLbnboYXNACRKnb66rLoEgD03jN 9PeSXuEEFA4XBlTH/b6fNG586pDmTbCXFw== X-Received: by 2002:a19:17d5:: with SMTP id 82-v6mr13869632lfx.83.1524662296217; Wed, 25 Apr 2018 06:18:16 -0700 (PDT) Received: from localhost ([195.238.93.36]) by smtp.gmail.com with ESMTPSA id i62-v6sm1190299lfa.22.2018.04.25.06.18.15 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Wed, 25 Apr 2018 06:18:15 -0700 (PDT) From: Igor Opaniuk To: u-boot@lists.denx.de Date: Wed, 25 Apr 2018 16:18:01 +0300 Message-Id: <1524662285-19617-5-git-send-email-igor.opaniuk@linaro.org> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1524662285-19617-1-git-send-email-igor.opaniuk@linaro.org> References: <1524662285-19617-1-git-send-email-igor.opaniuk@linaro.org> X-Mailman-Approved-At: Wed, 25 Apr 2018 13:20:58 +0000 Cc: trini@konsulko.com, praneeth@ti.com, misael.lopez@ti.com, joakim.bech@linaro.org Subject: [U-Boot] [PATCH 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 | 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); + + 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" + );