u-boot-dfu-20240215

- Fix avb_verify command with SD cards
- Add u-boot-dfu maintainer tree for AB/AVB
- Avb: report verified boot state based on lock state
- Misc avb refactors improve code quality
This commit is contained in:
Tom Rini 2024-02-15 10:26:24 -05:00
commit 9e00b6993f
6 changed files with 180 additions and 110 deletions

View File

@ -62,6 +62,7 @@ M: Igor Opaniuk <igor.opaniuk@gmail.com>
M: Mattijs Korpershoek <mkorpershoek@baylibre.com>
R: Sam Protsenko <semen.protsenko@linaro.org>
S: Maintained
T: git https://source.denx.de/u-boot/custodians/u-boot-dfu.git
F: boot/android_ab.c
F: cmd/ab_select.c
F: doc/android/ab.rst
@ -72,6 +73,7 @@ ANDROID AVB
M: Igor Opaniuk <igor.opaniuk@gmail.com>
M: Mattijs Korpershoek <mkorpershoek@baylibre.com>
S: Maintained
T: git https://source.denx.de/u-boot/custodians/u-boot-dfu.git
F: cmd/avb.c
F: common/avb_verify.c
F: doc/android/avb2.rst

173
cmd/avb.c
View File

@ -1,8 +1,6 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* (C) Copyright 2018, Linaro Limited
*
* SPDX-License-Identifier: GPL-2.0+
*/
#include <avb_verify.h>
@ -13,6 +11,7 @@
#include <mmc.h>
#define AVB_BOOTARGS "avb_bootargs"
static struct AvbOps *avb_ops;
int do_avb_init(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
@ -30,8 +29,10 @@ int do_avb_init(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
avb_ops = avb_ops_alloc(mmc_dev);
if (avb_ops)
return CMD_RET_SUCCESS;
else
printf("Can't allocate AvbOps");
printf("Failed to initialize avb2\n");
printf("Failed to initialize AVB\n");
return CMD_RET_FAILURE;
}
@ -43,10 +44,11 @@ int do_avb_read_part(struct cmd_tbl *cmdtp, int flag, int argc,
s64 offset;
size_t bytes, bytes_read = 0;
void *buffer;
int ret;
if (!avb_ops) {
printf("AVB 2.0 is not initialized, please run 'avb init'\n");
return CMD_RET_USAGE;
printf("AVB is not initialized, please run 'avb init <id>'\n");
return CMD_RET_FAILURE;
}
if (argc != 5)
@ -57,14 +59,15 @@ int do_avb_read_part(struct cmd_tbl *cmdtp, int flag, int argc,
bytes = hextoul(argv[3], NULL);
buffer = (void *)hextoul(argv[4], NULL);
if (avb_ops->read_from_partition(avb_ops, part, offset, bytes,
buffer, &bytes_read) ==
AVB_IO_RESULT_OK) {
ret = avb_ops->read_from_partition(avb_ops, part, offset,
bytes, buffer, &bytes_read);
if (ret == AVB_IO_RESULT_OK) {
printf("Read %zu bytes\n", bytes_read);
return CMD_RET_SUCCESS;
}
printf("Failed to read from partition\n");
printf("Failed to read from partition '%s', err = %d\n",
part, ret);
return CMD_RET_FAILURE;
}
@ -76,10 +79,11 @@ int do_avb_read_part_hex(struct cmd_tbl *cmdtp, int flag, int argc,
s64 offset;
size_t bytes, bytes_read = 0;
char *buffer;
int ret;
if (!avb_ops) {
printf("AVB 2.0 is not initialized, please run 'avb init'\n");
return CMD_RET_USAGE;
printf("AVB is not initialized, please run 'avb init <id>'\n");
return CMD_RET_FAILURE;
}
if (argc != 4)
@ -96,8 +100,9 @@ int do_avb_read_part_hex(struct cmd_tbl *cmdtp, int flag, int argc,
}
memset(buffer, 0, bytes);
if (avb_ops->read_from_partition(avb_ops, part, offset, bytes, buffer,
&bytes_read) == AVB_IO_RESULT_OK) {
ret = avb_ops->read_from_partition(avb_ops, part, offset,
bytes, buffer, &bytes_read);
if (ret == AVB_IO_RESULT_OK) {
printf("Requested %zu, read %zu bytes\n", bytes, bytes_read);
printf("Data: ");
for (int i = 0; i < bytes_read; i++)
@ -109,7 +114,8 @@ int do_avb_read_part_hex(struct cmd_tbl *cmdtp, int flag, int argc,
return CMD_RET_SUCCESS;
}
printf("Failed to read from partition\n");
printf("Failed to read from partition '%s', err = %d\n",
part, ret);
free(buffer);
return CMD_RET_FAILURE;
@ -122,9 +128,10 @@ int do_avb_write_part(struct cmd_tbl *cmdtp, int flag, int argc,
s64 offset;
size_t bytes;
void *buffer;
int ret;
if (!avb_ops) {
printf("AVB 2.0 is not initialized, run 'avb init' first\n");
printf("AVB is not initialized, please run 'avb init <id>'\n");
return CMD_RET_FAILURE;
}
@ -136,13 +143,15 @@ int do_avb_write_part(struct cmd_tbl *cmdtp, int flag, int argc,
bytes = hextoul(argv[3], NULL);
buffer = (void *)hextoul(argv[4], NULL);
if (avb_ops->write_to_partition(avb_ops, part, offset, bytes, buffer) ==
AVB_IO_RESULT_OK) {
ret = avb_ops->write_to_partition(avb_ops, part, offset,
bytes, buffer);
if (ret == AVB_IO_RESULT_OK) {
printf("Wrote %zu bytes\n", bytes);
return CMD_RET_SUCCESS;
}
printf("Failed to write in partition\n");
printf("Failed to write in partition '%s', err = %d\n",
part, ret);
return CMD_RET_FAILURE;
}
@ -152,9 +161,10 @@ int do_avb_read_rb(struct cmd_tbl *cmdtp, int flag, int argc,
{
size_t index;
u64 rb_idx;
int ret;
if (!avb_ops) {
printf("AVB 2.0 is not initialized, run 'avb init' first\n");
printf("AVB is not initialized, please run 'avb init <id>'\n");
return CMD_RET_FAILURE;
}
@ -163,13 +173,14 @@ int do_avb_read_rb(struct cmd_tbl *cmdtp, int flag, int argc,
index = (size_t)hextoul(argv[1], NULL);
if (avb_ops->read_rollback_index(avb_ops, index, &rb_idx) ==
AVB_IO_RESULT_OK) {
ret = avb_ops->read_rollback_index(avb_ops, index, &rb_idx);
if (ret == AVB_IO_RESULT_OK) {
printf("Rollback index: %llx\n", rb_idx);
return CMD_RET_SUCCESS;
}
printf("Failed to read rollback index\n");
printf("Failed to read rollback index id = %zu, err = %d\n",
index, ret);
return CMD_RET_FAILURE;
}
@ -179,9 +190,10 @@ int do_avb_write_rb(struct cmd_tbl *cmdtp, int flag, int argc,
{
size_t index;
u64 rb_idx;
int ret;
if (!avb_ops) {
printf("AVB 2.0 is not initialized, run 'avb init' first\n");
printf("AVB is not initialized, please run 'avb init <id>'\n");
return CMD_RET_FAILURE;
}
@ -191,11 +203,12 @@ int do_avb_write_rb(struct cmd_tbl *cmdtp, int flag, int argc,
index = (size_t)hextoul(argv[1], NULL);
rb_idx = hextoul(argv[2], NULL);
if (avb_ops->write_rollback_index(avb_ops, index, rb_idx) ==
AVB_IO_RESULT_OK)
ret = avb_ops->write_rollback_index(avb_ops, index, rb_idx);
if (ret == AVB_IO_RESULT_OK)
return CMD_RET_SUCCESS;
printf("Failed to write rollback index\n");
printf("Failed to write rollback index id = %zu, err = %d\n",
index, ret);
return CMD_RET_FAILURE;
}
@ -205,9 +218,10 @@ int do_avb_get_uuid(struct cmd_tbl *cmdtp, int flag,
{
const char *part;
char buffer[UUID_STR_LEN + 1];
int ret;
if (!avb_ops) {
printf("AVB 2.0 is not initialized, run 'avb init' first\n");
printf("AVB is not initialized, please run 'avb init <id>'\n");
return CMD_RET_FAILURE;
}
@ -216,14 +230,16 @@ int do_avb_get_uuid(struct cmd_tbl *cmdtp, int flag,
part = argv[1];
if (avb_ops->get_unique_guid_for_partition(avb_ops, part, buffer,
UUID_STR_LEN + 1) ==
AVB_IO_RESULT_OK) {
ret = avb_ops->get_unique_guid_for_partition(avb_ops, part,
buffer,
UUID_STR_LEN + 1);
if (ret == AVB_IO_RESULT_OK) {
printf("'%s' UUID: %s\n", part, buffer);
return CMD_RET_SUCCESS;
}
printf("Failed to read UUID\n");
printf("Failed to read partition '%s' UUID, err = %d\n",
part, ret);
return CMD_RET_FAILURE;
}
@ -234,15 +250,17 @@ int do_avb_verify_part(struct cmd_tbl *cmdtp, int flag,
const char * const requested_partitions[] = {"boot", NULL};
AvbSlotVerifyResult slot_result;
AvbSlotVerifyData *out_data;
enum avb_boot_state boot_state;
char *cmdline;
char *extra_args;
char *slot_suffix = "";
int ret;
bool unlocked = false;
int res = CMD_RET_FAILURE;
if (!avb_ops) {
printf("AVB 2.0 is not initialized, run 'avb init' first\n");
printf("AVB is not initialized, please run 'avb init <id>'\n");
return CMD_RET_FAILURE;
}
@ -255,9 +273,10 @@ int do_avb_verify_part(struct cmd_tbl *cmdtp, int flag,
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");
ret = avb_ops->read_is_device_unlocked(avb_ops, &unlocked);
if (ret != AVB_IO_RESULT_OK) {
printf("Can't determine device lock state, err = %d\n",
ret);
return CMD_RET_FAILURE;
}
@ -269,18 +288,23 @@ int do_avb_verify_part(struct cmd_tbl *cmdtp, int flag,
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
*/
/*
* LOCKED devices with custom root of trust setup is not supported (YELLOW)
*/
if (slot_result == AVB_SLOT_VERIFY_RESULT_OK) {
printf("Verification passed successfully\n");
/* export additional bootargs to AVB_BOOTARGS env var */
/*
* ORANGE state indicates that device may be freely modified.
* Device integrity is left to the user to verify out-of-band.
*/
if (unlocked)
boot_state = AVB_ORANGE;
else
boot_state = AVB_GREEN;
extra_args = avb_set_state(avb_ops, AVB_GREEN);
/* export boot state to AVB_BOOTARGS env var */
extra_args = avb_set_state(avb_ops, boot_state);
if (extra_args)
cmdline = append_cmd_line(out_data->cmdline,
extra_args);
@ -290,30 +314,8 @@ int do_avb_verify_part(struct cmd_tbl *cmdtp, int flag,
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");
} else {
printf("Verification failed, reason: %s\n", str_avb_slot_error(slot_result));
}
if (out_data)
@ -326,9 +328,10 @@ int do_avb_is_unlocked(struct cmd_tbl *cmdtp, int flag,
int argc, char *const argv[])
{
bool unlock;
int ret;
if (!avb_ops) {
printf("AVB not initialized, run 'avb init' first\n");
printf("AVB is not initialized, please run 'avb init <id>'\n");
return CMD_RET_FAILURE;
}
@ -337,13 +340,14 @@ int do_avb_is_unlocked(struct cmd_tbl *cmdtp, int flag,
return CMD_RET_USAGE;
}
if (avb_ops->read_is_device_unlocked(avb_ops, &unlock) ==
AVB_IO_RESULT_OK) {
ret = avb_ops->read_is_device_unlocked(avb_ops, &unlock);
if (ret == AVB_IO_RESULT_OK) {
printf("Unlocked = %d\n", unlock);
return CMD_RET_SUCCESS;
}
printf("Can't determine device lock state.\n");
printf("Can't determine device lock state, err = %d\n",
ret);
return CMD_RET_FAILURE;
}
@ -356,9 +360,10 @@ int do_avb_read_pvalue(struct cmd_tbl *cmdtp, int flag, int argc,
size_t bytes_read;
void *buffer;
char *endp;
int ret;
if (!avb_ops) {
printf("AVB 2.0 is not initialized, run 'avb init' first\n");
printf("AVB is not initialized, please run 'avb init <id>'\n");
return CMD_RET_FAILURE;
}
@ -374,15 +379,16 @@ int do_avb_read_pvalue(struct cmd_tbl *cmdtp, int flag, int argc,
if (!buffer)
return CMD_RET_FAILURE;
if (avb_ops->read_persistent_value(avb_ops, name, bytes, buffer,
&bytes_read) == AVB_IO_RESULT_OK) {
ret = avb_ops->read_persistent_value(avb_ops, name, bytes,
buffer, &bytes_read);
if (ret == AVB_IO_RESULT_OK) {
printf("Read %zu bytes, value = %s\n", bytes_read,
(char *)buffer);
free(buffer);
return CMD_RET_SUCCESS;
}
printf("Failed to read persistent value\n");
printf("Failed to read persistent value, err = %d\n", ret);
free(buffer);
@ -394,9 +400,10 @@ int do_avb_write_pvalue(struct cmd_tbl *cmdtp, int flag, int argc,
{
const char *name;
const char *value;
int ret;
if (!avb_ops) {
printf("AVB 2.0 is not initialized, run 'avb init' first\n");
printf("AVB is not initialized, please run 'avb init <id>'\n");
return CMD_RET_FAILURE;
}
@ -406,14 +413,16 @@ int do_avb_write_pvalue(struct cmd_tbl *cmdtp, int flag, int argc,
name = argv[1];
value = argv[2];
if (avb_ops->write_persistent_value(avb_ops, name, strlen(value) + 1,
(const uint8_t *)value) ==
AVB_IO_RESULT_OK) {
ret = avb_ops->write_persistent_value(avb_ops, name,
strlen(value) + 1,
(const uint8_t *)value);
if (ret == AVB_IO_RESULT_OK) {
printf("Wrote %zu bytes\n", strlen(value) + 1);
return CMD_RET_SUCCESS;
}
printf("Failed to write persistent value\n");
printf("Failed to write persistent value `%s` = `%s`, err = %d\n",
name, value, ret);
return CMD_RET_FAILURE;
}

View File

@ -1,7 +1,6 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* (C) Copyright 2018, Linaro Limited
*
* SPDX-License-Identifier: GPL-2.0+
*/
#include <avb_verify.h>
@ -120,6 +119,55 @@ static const unsigned char avb_root_pub[1032] = {
0xd8, 0x7e,
};
const char *str_avb_io_error(AvbIOResult res)
{
switch (res) {
case AVB_IO_RESULT_OK:
return "Requested operation was successful";
case AVB_IO_RESULT_ERROR_IO:
return "Underlying hardware encountered an I/O error";
case AVB_IO_RESULT_ERROR_OOM:
return "Unable to allocate memory";
case AVB_IO_RESULT_ERROR_NO_SUCH_PARTITION:
return "Requested partition does not exist";
case AVB_IO_RESULT_ERROR_RANGE_OUTSIDE_PARTITION:
return "Bytes requested is outside the range of partition";
case AVB_IO_RESULT_ERROR_NO_SUCH_VALUE:
return "Named persistent value does not exist";
case AVB_IO_RESULT_ERROR_INVALID_VALUE_SIZE:
return "Named persistent value size is not supported";
case AVB_IO_RESULT_ERROR_INSUFFICIENT_SPACE:
return "Buffer is too small for the requested operation";
default:
return "Unknown AVB error";
}
}
const char *str_avb_slot_error(AvbSlotVerifyResult res)
{
switch (res) {
case AVB_SLOT_VERIFY_RESULT_OK:
return "Verification passed successfully";
case AVB_SLOT_VERIFY_RESULT_ERROR_OOM:
return "Allocation of memory failed";
case AVB_SLOT_VERIFY_RESULT_ERROR_IO:
return "I/O error occurred while trying to load data";
case AVB_SLOT_VERIFY_RESULT_ERROR_VERIFICATION:
return "Digest didn't match or signature checks failed";
case AVB_SLOT_VERIFY_RESULT_ERROR_ROLLBACK_INDEX:
return "Rollback index is less than its stored value";
case AVB_SLOT_VERIFY_RESULT_ERROR_PUBLIC_KEY_REJECTED:
return "Public keys are not accepted";
case AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA:
return "Metadata is invalid or inconsistent";
case AVB_SLOT_VERIFY_RESULT_ERROR_UNSUPPORTED_VERSION:
return "Metadata requires a newer version of libavb";
case AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_ARGUMENT:
return "Invalid arguments are used";
default:
return "Unknown AVB slot verification error";
}
}
/**
* ============================================================================
* Boot states support (GREEN, YELLOW, ORANGE, RED) and dm_verity
@ -280,9 +328,9 @@ static unsigned long mmc_read_and_flush(struct mmc_part *part,
* Reading fails on unaligned buffers, so we have to
* use aligned temporary buffer and then copy to destination
*/
if (unaligned) {
printf("Handling unaligned read buffer..\n");
debug("%s: handling unaligned read buffer, addr = 0x%p\n",
__func__, buffer);
tmp_buf = get_sector_buf();
buf_size = get_sector_buf_size();
if (sectors > buf_size / part->info.blksz)
@ -321,7 +369,8 @@ static unsigned long mmc_write(struct mmc_part *part, lbaint_t start,
if (unaligned) {
tmp_buf = get_sector_buf();
buf_size = get_sector_buf_size();
printf("Handling unaligned wrire buffer..\n");
debug("%s: handling unaligned read buffer, addr = 0x%p\n",
__func__, buffer);
if (sectors > buf_size / part->info.blksz)
sectors = buf_size / part->info.blksz;
@ -349,28 +398,35 @@ static struct mmc_part *get_partition(AvbOps *ops, const char *partition)
dev_num = get_boot_device(ops);
part->mmc = find_mmc_device(dev_num);
if (!part->mmc) {
printf("No MMC device at slot %x\n", dev_num);
printf("%s: no MMC device at slot %x\n", __func__, dev_num);
goto err;
}
if (mmc_init(part->mmc)) {
printf("MMC initialization failed\n");
ret = mmc_init(part->mmc);
if (ret) {
printf("%s: MMC initialization failed, err = %d\n",
__func__, ret);
goto err;
}
ret = mmc_switch_part(part->mmc, part_num);
if (ret)
goto err;
if (IS_MMC(part->mmc)) {
ret = mmc_switch_part(part->mmc, part_num);
if (ret) {
printf("%s: MMC part switch failed, err = %d\n",
__func__, ret);
goto err;
}
}
mmc_blk = mmc_get_blk_desc(part->mmc);
if (!mmc_blk) {
printf("Error - failed to obtain block descriptor\n");
printf("%s: failed to obtain block descriptor\n", __func__);
goto err;
}
ret = part_get_info_by_name(mmc_blk, partition, &part->info);
if (ret < 0) {
printf("Can't find partition '%s'\n", partition);
printf("%s: can't find partition '%s'\n", __func__, partition);
goto err;
}
@ -683,7 +739,7 @@ static AvbIOResult read_rollback_index(AvbOps *ops,
{
#ifndef CONFIG_OPTEE_TA_AVB
/* For now we always return 0 as the stored rollback index. */
printf("%s not supported yet\n", __func__);
debug("%s: rollback protection is not implemented\n", __func__);
if (out_rollback_index)
*out_rollback_index = 0;
@ -729,7 +785,7 @@ static AvbIOResult write_rollback_index(AvbOps *ops,
{
#ifndef CONFIG_OPTEE_TA_AVB
/* For now this is a no-op. */
printf("%s not supported yet\n", __func__);
debug("%s: rollback protection is not implemented\n", __func__);
return AVB_IO_RESULT_OK;
#else
@ -765,8 +821,7 @@ static AvbIOResult read_is_device_unlocked(AvbOps *ops, bool *out_is_unlocked)
{
#ifndef CONFIG_OPTEE_TA_AVB
/* For now we always return that the device is unlocked. */
printf("%s not supported yet\n", __func__);
debug("%s: device locking is not implemented\n", __func__);
*out_is_unlocked = true;

View File

@ -38,16 +38,22 @@ AVB 2.0 U-Boot shell commands
Provides CLI interface to invoke AVB 2.0 verification + misc. commands for
different testing purposes::
avb init <dev> - initialize avb 2.0 for <dev>
avb verify - run verification process using hash data from vbmeta structure
avb init <dev> - initialize avb 2 for <dev>
avb read_rb <num> - read rollback index at location <num>
avb write_rb <num> <rb> - write rollback index <rb> to <num>
avb is_unlocked - returns unlock status of the device
avb get_uuid <partname> - read and print uuid of partition <partname>
avb get_uuid <partname> - read and print uuid of partition <part>
avb read_part <partname> <offset> <num> <addr> - read <num> bytes from
partition <partname> to buffer <addr>
partition <partname> to buffer <addr>
avb read_part_hex <partname> <offset> <num> - read <num> bytes from
partition <partname> and print to stdout
avb write_part <partname> <offset> <num> <addr> - write <num> bytes to
<partname> by <offset> using data from <addr>
<partname> by <offset> using data from <addr>
avb read_pvalue <name> <bytes> - read a persistent value <name>
avb write_pvalue <name> <value> - write a persistent value <name>
avb verify [slot_suffix] - run verification process using hash data
from vbmeta structure
[slot_suffix] - _a, _b, etc (if vbmeta partition is slotted)
Partitions tampering (example)
------------------------------

View File

@ -1,8 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0+ */
/*
* (C) Copyright 2018, Linaro Limited
*
* SPDX-License-Identifier: GPL-2.0+
*/
#ifndef _AVB_VERIFY_H
@ -54,7 +52,8 @@ char *avb_set_enforce_verity(const char *cmdline);
char *avb_set_ignore_corruption(const char *cmdline);
char *append_cmd_line(char *cmdline_orig, char *cmdline_new);
const char *str_avb_io_error(AvbIOResult res);
const char *str_avb_slot_error(AvbSlotVerifyResult res);
/**
* ============================================================================
* I/O helper inline functions

View File

@ -1,6 +1,5 @@
# Copyright (c) 2018, Linaro Limited
#
# SPDX-License-Identifier: GPL-2.0+
# Copyright (c) 2018, Linaro Limited
#
# Android Verified Boot 2.0 Test