U-Boot
Threads by month
- ----- 2025 -----
- May
- April
- March
- February
- January
- ----- 2024 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2023 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2022 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2021 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2020 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2019 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2018 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2017 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2016 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2015 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2014 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2013 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2012 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2011 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2010 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2009 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2008 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2007 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2006 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2005 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2004 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2003 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2002 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2001 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2000 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
September 2019
- 202 participants
- 675 discussions

[U-Boot] [PATCH] mkimage: Set correct FDT type and ramdisk architecture in FIT auto mode
by Michal Sojka 01 Nov '19
by Michal Sojka 01 Nov '19
01 Nov '19
From: Michal Sojka <michal.sojka(a)cvut.cz>
When running the following command
mkimage -f auto -A arm -O linux -T kernel -C none -a 0x8000 -e 0x8000 \
-d zImage -b zynq-microzed.dtb -i initramfs.cpio image.ub
the type of fdt subimage is the same as of the main kernel image and
the architecture of the initramfs image is not set. Such an image is
refused by U-Boot when booting. This commits sets the mentioned
attributes, allowing to use the "-f auto" mode in this case instead of
writing full .its file.
Following is the diff of mkimage output without and with this commit:
FIT description: Kernel Image image with one or more FDT blobs
Created: Thu Sep 12 23:23:16 2019
Image 0 (kernel-1)
Description:
Created: Thu Sep 12 23:23:16 2019
Type: Kernel Image
Compression: uncompressed
Data Size: 4192744 Bytes = 4094.48 KiB = 4.00 MiB
Architecture: ARM
OS: Linux
Load Address: 0x00008000
Entry Point: 0x00008000
Image 1 (fdt-1)
Description: zynq-microzed
Created: Thu Sep 12 23:23:16 2019
- Type: Kernel Image
+ Type: Flat Device Tree
Compression: uncompressed
Data Size: 9398 Bytes = 9.18 KiB = 0.01 MiB
Architecture: ARM
- OS: Unknown OS
- Load Address: unavailable
- Entry Point: unavailable
Image 2 (ramdisk-1)
Description: unavailable
Created: Thu Sep 12 23:23:16 2019
Type: RAMDisk Image
Compression: Unknown Compression
Data Size: 760672 Bytes = 742.84 KiB = 0.73 MiB
- Architecture: Unknown Architecture
+ Architecture: ARM
OS: Linux
Load Address: unavailable
Entry Point: unavailable
Default Configuration: 'conf-1'
Configuration 0 (conf-1)
Description: zynq-microzed
Kernel: kernel-1
Init Ramdisk: ramdisk-1
FDT: fdt-1
Loadables: kernel-1
Signed-off-by: Michal Sojka <michal.sojka(a)cvut.cz>
---
tools/fit_image.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/tools/fit_image.c b/tools/fit_image.c
index 5aca634b5e..0201cc44d8 100644
--- a/tools/fit_image.c
+++ b/tools/fit_image.c
@@ -229,6 +229,7 @@ static int fit_write_images(struct image_tool_params *params, char *fdt)
for (cont = params->content_head; cont; cont = cont->next) {
if (cont->type != IH_TYPE_FLATDT)
continue;
+ typename = genimg_get_type_short_name(cont->type);
snprintf(str, sizeof(str), "%s-%d", FIT_FDT_PROP, ++upto);
fdt_begin_node(fdt, str);
@@ -253,6 +254,8 @@ static int fit_write_images(struct image_tool_params *params, char *fdt)
fdt_property_string(fdt, FIT_TYPE_PROP, FIT_RAMDISK_PROP);
fdt_property_string(fdt, FIT_OS_PROP,
genimg_get_os_short_name(params->os));
+ fdt_property_string(fdt, FIT_ARCH_PROP,
+ genimg_get_arch_short_name(params->arch));
ret = fdt_property_file(params, fdt, FIT_DATA_PROP,
params->fit_ramdisk);
--
2.23.0
2
1

01 Nov '19
Update libavb to commit 5fbb42a189aa in AOSP/master, because new version
has support for super partition [1], which we need for implementing
Android dynamic partitions. All changes from previous patches for libavb
in U-Boot are accounted for in this commit:
- commit ecc6f6bea6a2 ("libavb: Handle wrong hashtree_error_mode in
avb_append_options()")
- commit 897a1d947e7e ("libavb: Update SPDX tag style")
- commit d8f9d2af96b3 ("avb2.0: add Android Verified Boot 2.0 library")
Tested on X15:
## Android Verified Boot 2.0 version 1.1.0
read_is_device_unlocked not supported yet
read_rollback_index not supported yet
read_is_device_unlocked not supported yet
Verification passed successfully
AVB verification OK.
Unit test passes:
$ ./test/py/test.py --bd sandbox --build -k test_avb
test/py/tests/test_android/test_avb.py ss..s.
[1] https://android.googlesource.com/platform/external/avb/+/49936b4c0109411fdd…
Signed-off-by: Sam Protsenko <semen.protsenko(a)linaro.org>
---
lib/libavb/avb_cmdline.c | 52 ++-
lib/libavb/avb_cmdline.h | 4 +-
lib/libavb/avb_descriptor.c | 11 +-
lib/libavb/avb_ops.h | 41 ++-
lib/libavb/avb_sha.h | 12 +-
lib/libavb/avb_sha256.c | 36 +-
lib/libavb/avb_sha512.c | 22 +-
lib/libavb/avb_slot_verify.c | 652 +++++++++++++++++++++++++--------
lib/libavb/avb_slot_verify.h | 59 ++-
lib/libavb/avb_sysdeps.h | 8 +
lib/libavb/avb_sysdeps_posix.c | 16 +-
lib/libavb/avb_vbmeta_image.c | 11 +-
12 files changed, 710 insertions(+), 214 deletions(-)
diff --git a/lib/libavb/avb_cmdline.c b/lib/libavb/avb_cmdline.c
index d246699272..cb5b98e423 100644
--- a/lib/libavb/avb_cmdline.c
+++ b/lib/libavb/avb_cmdline.c
@@ -39,6 +39,14 @@ char* avb_sub_cmdline(AvbOps* ops,
char part_name[AVB_PART_NAME_MAX_SIZE];
char guid_buf[37];
+ /* Don't attempt to query the partition guid unless its search string is
+ * present in the command line. Note: the original cmdline is used here,
+ * not the replaced one. See b/116010959.
+ */
+ if (avb_strstr(cmdline, replace_str[n]) == NULL) {
+ continue;
+ }
+
if (!avb_str_concat(part_name,
sizeof part_name,
part_name_str[n],
@@ -70,7 +78,15 @@ char* avb_sub_cmdline(AvbOps* ops,
}
}
- avb_assert(ret != NULL);
+ /* It's possible there is no _PARTUUID for replacement above.
+ * Duplicate cmdline to ret for additional substitutions below.
+ */
+ if (ret == NULL) {
+ ret = avb_strdup(cmdline);
+ if (ret == NULL) {
+ goto fail;
+ }
+ }
/* Replace any additional substitutions. */
if (additional_substitutions != NULL) {
@@ -198,21 +214,27 @@ static int cmdline_append_hex(AvbSlotVerifyData* slot_data,
AvbSlotVerifyResult avb_append_options(
AvbOps* ops,
+ AvbSlotVerifyFlags flags,
AvbSlotVerifyData* slot_data,
AvbVBMetaImageHeader* toplevel_vbmeta,
AvbAlgorithmType algorithm_type,
- AvbHashtreeErrorMode hashtree_error_mode) {
+ AvbHashtreeErrorMode hashtree_error_mode,
+ AvbHashtreeErrorMode resolved_hashtree_error_mode) {
AvbSlotVerifyResult ret;
const char* verity_mode;
bool is_device_unlocked;
AvbIOResult io_ret;
- /* Add androidboot.vbmeta.device option. */
- if (!cmdline_append_option(slot_data,
- "androidboot.vbmeta.device",
- "PARTUUID=$(ANDROID_VBMETA_PARTUUID)")) {
- ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
- goto out;
+ /* Add androidboot.vbmeta.device option... except if not using a vbmeta
+ * partition since it doesn't make sense in that case.
+ */
+ if (!(flags & AVB_SLOT_VERIFY_FLAGS_NO_VBMETA_PARTITION)) {
+ if (!cmdline_append_option(slot_data,
+ "androidboot.vbmeta.device",
+ "PARTUUID=$(ANDROID_VBMETA_PARTUUID)")) {
+ ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
+ goto out;
+ }
}
/* Add androidboot.vbmeta.avb_version option. */
@@ -304,7 +326,7 @@ AvbSlotVerifyResult avb_append_options(
const char* dm_verity_mode;
char* new_ret;
- switch (hashtree_error_mode) {
+ switch (resolved_hashtree_error_mode) {
case AVB_HASHTREE_ERROR_MODE_RESTART_AND_INVALIDATE:
if (!cmdline_append_option(
slot_data, "androidboot.vbmeta.invalidate_on_error", "yes")) {
@@ -331,6 +353,11 @@ AvbSlotVerifyResult avb_append_options(
verity_mode = "logging";
dm_verity_mode = "ignore_corruption";
break;
+ case AVB_HASHTREE_ERROR_MODE_MANAGED_RESTART_AND_EIO:
+ // Should never get here because MANAGED_RESTART_AND_EIO is
+ // remapped by avb_manage_hashtree_error_mode().
+ avb_assert_not_reached();
+ break;
default:
ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_ARGUMENT;
goto out;
@@ -349,6 +376,13 @@ AvbSlotVerifyResult avb_append_options(
ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
goto out;
}
+ if (hashtree_error_mode == AVB_HASHTREE_ERROR_MODE_MANAGED_RESTART_AND_EIO) {
+ if (!cmdline_append_option(
+ slot_data, "androidboot.veritymode.managed", "yes")) {
+ ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
+ goto out;
+ }
+ }
ret = AVB_SLOT_VERIFY_RESULT_OK;
diff --git a/lib/libavb/avb_cmdline.h b/lib/libavb/avb_cmdline.h
index 9af3a99994..96539d84bd 100644
--- a/lib/libavb/avb_cmdline.h
+++ b/lib/libavb/avb_cmdline.h
@@ -43,10 +43,12 @@ char* avb_sub_cmdline(AvbOps* ops,
AvbSlotVerifyResult avb_append_options(
AvbOps* ops,
+ AvbSlotVerifyFlags flags,
AvbSlotVerifyData* slot_data,
AvbVBMetaImageHeader* toplevel_vbmeta,
AvbAlgorithmType algorithm_type,
- AvbHashtreeErrorMode hashtree_error_mode);
+ AvbHashtreeErrorMode hashtree_error_mode,
+ AvbHashtreeErrorMode resolved_hashtree_error_mode);
/* Allocates and initializes a new command line substitution list. Free with
* |avb_free_cmdline_subst_list|.
diff --git a/lib/libavb/avb_descriptor.c b/lib/libavb/avb_descriptor.c
index fb0b305f2c..9f03b9777a 100644
--- a/lib/libavb/avb_descriptor.c
+++ b/lib/libavb/avb_descriptor.c
@@ -72,7 +72,11 @@ bool avb_descriptor_foreach(const uint8_t* image_data,
const AvbDescriptor* dh = (const AvbDescriptor*)p;
avb_assert_aligned(dh);
uint64_t nb_following = avb_be64toh(dh->num_bytes_following);
- uint64_t nb_total = sizeof(AvbDescriptor) + nb_following;
+ uint64_t nb_total = 0;
+ if (!avb_safe_add(&nb_total, sizeof(AvbDescriptor), nb_following)) {
+ avb_error("Invalid descriptor length.\n");
+ goto out;
+ }
if ((nb_total & 7) != 0) {
avb_error("Invalid descriptor length.\n");
@@ -88,7 +92,10 @@ bool avb_descriptor_foreach(const uint8_t* image_data,
goto out;
}
- p += nb_total;
+ if (!avb_safe_add_to((uint64_t*)(&p), nb_total)) {
+ avb_error("Invalid descriptor length.\n");
+ goto out;
+ }
}
ret = true;
diff --git a/lib/libavb/avb_ops.h b/lib/libavb/avb_ops.h
index 8bbdc7c31b..6a5c589da8 100644
--- a/lib/libavb/avb_ops.h
+++ b/lib/libavb/avb_ops.h
@@ -18,6 +18,7 @@ extern "C" {
/* Well-known names of named persistent values. */
#define AVB_NPV_PERSISTENT_DIGEST_PREFIX "avb.persistent_digest."
+#define AVB_NPV_MANAGED_VERITY_MODE "avb.managed_verity_mode"
/* Return codes used for I/O operations.
*
@@ -171,6 +172,10 @@ struct AvbOps {
*
* If AVB_IO_RESULT_OK is returned then |out_is_trusted| is set -
* true if trusted or false if untrusted.
+ *
+ * NOTE: If AVB_SLOT_VERIFY_FLAGS_NO_VBMETA_PARTITION is passed to
+ * avb_slot_verify() then this operation is never used. Instead, the
+ * validate_public_key_for_partition() operation is used
*/
AvbIOResult (*validate_vbmeta_public_key)(AvbOps* ops,
const uint8_t* public_key_data,
@@ -231,6 +236,9 @@ struct AvbOps {
* (NUL-terminated UTF-8 string). Returns the value in
* |out_size_num_bytes|.
*
+ * If the partition doesn't exist the AVB_IO_RESULT_ERROR_NO_SUCH_PARTITION
+ * error code should be returned.
+ *
* Returns AVB_IO_RESULT_OK on success, otherwise an error code.
*/
AvbIOResult (*get_size_of_partition)(AvbOps* ops,
@@ -253,9 +261,10 @@ struct AvbOps {
* AVB_IO_RESULT_ERROR_NO_SUCH_VALUE. If |buffer_size| is smaller than the
* size of the stored value, returns AVB_IO_RESULT_ERROR_INSUFFICIENT_SPACE.
*
- * This operation is currently only used to support persistent digests. If a
- * device does not use persistent digests this function pointer can be set to
- * NULL.
+ * This operation is currently only used to support persistent digests or the
+ * AVB_HASHTREE_ERROR_MODE_MANAGED_RESTART_AND_EIO hashtree error mode. If a
+ * device does not use one of these features this function pointer can be set
+ * to NULL.
*/
AvbIOResult (*read_persistent_value)(AvbOps* ops,
const char* name,
@@ -275,14 +284,34 @@ struct AvbOps {
* AVB_IO_RESULT_ERROR_NO_SUCH_VALUE. If the |value_size| is not supported,
* returns AVB_IO_RESULT_ERROR_INVALID_VALUE_SIZE.
*
- * This operation is currently only used to support persistent digests. If a
- * device does not use persistent digests this function pointer can be set to
- * NULL.
+ * This operation is currently only used to support persistent digests or the
+ * AVB_HASHTREE_ERROR_MODE_MANAGED_RESTART_AND_EIO hashtree error mode. If a
+ * device does not use one of these features this function pointer can be set
+ * to NULL.
*/
AvbIOResult (*write_persistent_value)(AvbOps* ops,
const char* name,
size_t value_size,
const uint8_t* value);
+
+ /* Like validate_vbmeta_public_key() but for when the flag
+ * AVB_SLOT_VERIFY_FLAGS_NO_VBMETA_PARTITION is being used. The name of the
+ * partition to get the public key for is passed in |partition_name|.
+ *
+ * Also returns the rollback index location to use for the partition, in
+ * |out_rollback_index_location|.
+ *
+ * Returns AVB_IO_RESULT_OK on success, otherwise an error code.
+ */
+ AvbIOResult (*validate_public_key_for_partition)(
+ AvbOps* ops,
+ const char* partition,
+ const uint8_t* public_key_data,
+ size_t public_key_length,
+ const uint8_t* public_key_metadata,
+ size_t public_key_metadata_length,
+ bool* out_is_trusted,
+ uint32_t* out_rollback_index_location);
};
#ifdef __cplusplus
diff --git a/lib/libavb/avb_sha.h b/lib/libavb/avb_sha.h
index 365aaadc2f..f5d02e09f2 100644
--- a/lib/libavb/avb_sha.h
+++ b/lib/libavb/avb_sha.h
@@ -31,8 +31,8 @@ extern "C" {
/* Data structure used for SHA-256. */
typedef struct {
uint32_t h[8];
- uint32_t tot_len;
- uint32_t len;
+ uint64_t tot_len;
+ size_t len;
uint8_t block[2 * AVB_SHA256_BLOCK_SIZE];
uint8_t buf[AVB_SHA256_DIGEST_SIZE]; /* Used for storing the final digest. */
} AvbSHA256Ctx;
@@ -40,8 +40,8 @@ typedef struct {
/* Data structure used for SHA-512. */
typedef struct {
uint64_t h[8];
- uint32_t tot_len;
- uint32_t len;
+ uint64_t tot_len;
+ size_t len;
uint8_t block[2 * AVB_SHA512_BLOCK_SIZE];
uint8_t buf[AVB_SHA512_DIGEST_SIZE]; /* Used for storing the final digest. */
} AvbSHA512Ctx;
@@ -50,7 +50,7 @@ typedef struct {
void avb_sha256_init(AvbSHA256Ctx* ctx);
/* Updates the SHA-256 context with |len| bytes from |data|. */
-void avb_sha256_update(AvbSHA256Ctx* ctx, const uint8_t* data, uint32_t len);
+void avb_sha256_update(AvbSHA256Ctx* ctx, const uint8_t* data, size_t len);
/* Returns the SHA-256 digest. */
uint8_t* avb_sha256_final(AvbSHA256Ctx* ctx) AVB_ATTR_WARN_UNUSED_RESULT;
@@ -59,7 +59,7 @@ uint8_t* avb_sha256_final(AvbSHA256Ctx* ctx) AVB_ATTR_WARN_UNUSED_RESULT;
void avb_sha512_init(AvbSHA512Ctx* ctx);
/* Updates the SHA-512 context with |len| bytes from |data|. */
-void avb_sha512_update(AvbSHA512Ctx* ctx, const uint8_t* data, uint32_t len);
+void avb_sha512_update(AvbSHA512Ctx* ctx, const uint8_t* data, size_t len);
/* Returns the SHA-512 digest. */
uint8_t* avb_sha512_final(AvbSHA512Ctx* ctx) AVB_ATTR_WARN_UNUSED_RESULT;
diff --git a/lib/libavb/avb_sha256.c b/lib/libavb/avb_sha256.c
index d24c7015f6..86ecca57b7 100644
--- a/lib/libavb/avb_sha256.c
+++ b/lib/libavb/avb_sha256.c
@@ -29,6 +29,18 @@
*((str) + 0) = (uint8_t)((x) >> 24); \
}
+#define UNPACK64(x, str) \
+ { \
+ *((str) + 7) = (uint8_t)x; \
+ *((str) + 6) = (uint8_t)((uint64_t)x >> 8); \
+ *((str) + 5) = (uint8_t)((uint64_t)x >> 16); \
+ *((str) + 4) = (uint8_t)((uint64_t)x >> 24); \
+ *((str) + 3) = (uint8_t)((uint64_t)x >> 32); \
+ *((str) + 2) = (uint8_t)((uint64_t)x >> 40); \
+ *((str) + 1) = (uint8_t)((uint64_t)x >> 48); \
+ *((str) + 0) = (uint8_t)((uint64_t)x >> 56); \
+ }
+
#define PACK32(str, x) \
{ \
*(x) = ((uint32_t) * ((str) + 3)) | ((uint32_t) * ((str) + 2) << 8) | \
@@ -96,18 +108,18 @@ void avb_sha256_init(AvbSHA256Ctx* ctx) {
static void SHA256_transform(AvbSHA256Ctx* ctx,
const uint8_t* message,
- unsigned int block_nb) {
+ size_t block_nb) {
uint32_t w[64];
uint32_t wv[8];
uint32_t t1, t2;
const unsigned char* sub_block;
- int i;
+ size_t i;
#ifndef UNROLL_LOOPS
- int j;
+ size_t j;
#endif
- for (i = 0; i < (int)block_nb; i++) {
+ for (i = 0; i < block_nb; i++) {
sub_block = message + (i << 6);
#ifndef UNROLL_LOOPS
@@ -293,9 +305,9 @@ static void SHA256_transform(AvbSHA256Ctx* ctx,
}
}
-void avb_sha256_update(AvbSHA256Ctx* ctx, const uint8_t* data, uint32_t len) {
- unsigned int block_nb;
- unsigned int new_len, rem_len, tmp_len;
+void avb_sha256_update(AvbSHA256Ctx* ctx, const uint8_t* data, size_t len) {
+ size_t block_nb;
+ size_t new_len, rem_len, tmp_len;
const uint8_t* shifted_data;
tmp_len = AVB_SHA256_BLOCK_SIZE - ctx->len;
@@ -325,11 +337,11 @@ void avb_sha256_update(AvbSHA256Ctx* ctx, const uint8_t* data, uint32_t len) {
}
uint8_t* avb_sha256_final(AvbSHA256Ctx* ctx) {
- unsigned int block_nb;
- unsigned int pm_len;
- unsigned int len_b;
+ size_t block_nb;
+ size_t pm_len;
+ uint64_t len_b;
#ifndef UNROLL_LOOPS
- int i;
+ size_t i;
#endif
block_nb =
@@ -340,7 +352,7 @@ uint8_t* avb_sha256_final(AvbSHA256Ctx* ctx) {
avb_memset(ctx->block + ctx->len, 0, pm_len - ctx->len);
ctx->block[ctx->len] = 0x80;
- UNPACK32(len_b, ctx->block + pm_len - 4);
+ UNPACK64(len_b, ctx->block + pm_len - 8);
SHA256_transform(ctx, ctx->block, block_nb);
diff --git a/lib/libavb/avb_sha512.c b/lib/libavb/avb_sha512.c
index a5e7297aa7..b19054fc74 100644
--- a/lib/libavb/avb_sha512.c
+++ b/lib/libavb/avb_sha512.c
@@ -127,14 +127,14 @@ void avb_sha512_init(AvbSHA512Ctx* ctx) {
static void SHA512_transform(AvbSHA512Ctx* ctx,
const uint8_t* message,
- unsigned int block_nb) {
+ size_t block_nb) {
uint64_t w[80];
uint64_t wv[8];
uint64_t t1, t2;
const uint8_t* sub_block;
- int i, j;
+ size_t i, j;
- for (i = 0; i < (int)block_nb; i++) {
+ for (i = 0; i < block_nb; i++) {
sub_block = message + (i << 7);
#ifdef UNROLL_LOOPS_SHA512
@@ -291,9 +291,9 @@ static void SHA512_transform(AvbSHA512Ctx* ctx,
}
}
-void avb_sha512_update(AvbSHA512Ctx* ctx, const uint8_t* data, uint32_t len) {
- unsigned int block_nb;
- unsigned int new_len, rem_len, tmp_len;
+void avb_sha512_update(AvbSHA512Ctx* ctx, const uint8_t* data, size_t len) {
+ size_t block_nb;
+ size_t new_len, rem_len, tmp_len;
const uint8_t* shifted_data;
tmp_len = AVB_SHA512_BLOCK_SIZE - ctx->len;
@@ -323,12 +323,12 @@ void avb_sha512_update(AvbSHA512Ctx* ctx, const uint8_t* data, uint32_t len) {
}
uint8_t* avb_sha512_final(AvbSHA512Ctx* ctx) {
- unsigned int block_nb;
- unsigned int pm_len;
- unsigned int len_b;
+ size_t block_nb;
+ size_t pm_len;
+ uint64_t len_b;
#ifndef UNROLL_LOOPS_SHA512
- int i;
+ size_t i;
#endif
block_nb =
@@ -339,7 +339,7 @@ uint8_t* avb_sha512_final(AvbSHA512Ctx* ctx) {
avb_memset(ctx->block + ctx->len, 0, pm_len - ctx->len);
ctx->block[ctx->len] = 0x80;
- UNPACK32(len_b, ctx->block + pm_len - 4);
+ UNPACK64(len_b, ctx->block + pm_len - 8);
SHA512_transform(ctx, ctx->block, block_nb);
diff --git a/lib/libavb/avb_slot_verify.c b/lib/libavb/avb_slot_verify.c
index a941850d93..5d400b38aa 100644
--- a/lib/libavb/avb_slot_verify.c
+++ b/lib/libavb/avb_slot_verify.c
@@ -24,6 +24,14 @@
/* Maximum size of a vbmeta image - 64 KiB. */
#define VBMETA_MAX_SIZE (64 * 1024)
+static AvbSlotVerifyResult initialize_persistent_digest(
+ AvbOps* ops,
+ const char* part_name,
+ const char* persistent_value_name,
+ size_t digest_size,
+ const uint8_t* initial_digest,
+ uint8_t* out_digest);
+
/* Helper function to see if we should continue with verification in
* allow_verification_error=true mode if something goes wrong. See the
* comments for the avb_slot_verify() function for more information.
@@ -114,9 +122,26 @@ static AvbSlotVerifyResult load_full_partition(AvbOps* ops,
return AVB_SLOT_VERIFY_RESULT_OK;
}
+/* Reads a persistent digest stored as a named persistent value corresponding to
+ * the given |part_name|. The value is returned in |out_digest| which must point
+ * to |expected_digest_size| bytes. If there is no digest stored for |part_name|
+ * it can be initialized by providing a non-NULL |initial_digest| of length
+ * |expected_digest_size|. This automatic initialization will only occur if the
+ * device is currently locked. The |initial_digest| may be NULL.
+ *
+ * Returns AVB_SLOT_VERIFY_RESULT_OK on success, otherwise returns an
+ * AVB_SLOT_VERIFY_RESULT_ERROR_* error code.
+ *
+ * If the value does not exist, is not supported, or is not populated, and
+ * |initial_digest| is NULL, returns
+ * AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA. If |expected_digest_size| does
+ * not match the stored digest size, also returns
+ * AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA.
+ */
static AvbSlotVerifyResult read_persistent_digest(AvbOps* ops,
const char* part_name,
size_t expected_digest_size,
+ const uint8_t* initial_digest,
uint8_t* out_digest) {
char* persistent_value_name = NULL;
AvbIOResult io_ret = AVB_IO_RESULT_OK;
@@ -131,30 +156,106 @@ static AvbSlotVerifyResult read_persistent_digest(AvbOps* ops,
if (persistent_value_name == NULL) {
return AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
}
+
io_ret = ops->read_persistent_value(ops,
persistent_value_name,
expected_digest_size,
out_digest,
&stored_digest_size);
+
+ // If no such named persistent value exists and an initial digest value was
+ // given, initialize the named persistent value with the given digest. If
+ // initialized successfully, this will recurse into this function but with a
+ // NULL initial_digest.
+ if (io_ret == AVB_IO_RESULT_ERROR_NO_SUCH_VALUE && initial_digest) {
+ AvbSlotVerifyResult ret =
+ initialize_persistent_digest(ops,
+ part_name,
+ persistent_value_name,
+ expected_digest_size,
+ initial_digest,
+ out_digest);
+ avb_free(persistent_value_name);
+ return ret;
+ }
avb_free(persistent_value_name);
+
if (io_ret == AVB_IO_RESULT_ERROR_OOM) {
return AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
} else if (io_ret == AVB_IO_RESULT_ERROR_NO_SUCH_VALUE) {
+ // Treat a missing persistent value as a verification error, which is
+ // ignoreable, rather than a metadata error which is not.
avb_errorv(part_name, ": Persistent digest does not exist.\n", NULL);
- return AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;
+ return AVB_SLOT_VERIFY_RESULT_ERROR_VERIFICATION;
} else if (io_ret == AVB_IO_RESULT_ERROR_INVALID_VALUE_SIZE ||
- io_ret == AVB_IO_RESULT_ERROR_INSUFFICIENT_SPACE ||
- expected_digest_size != stored_digest_size) {
+ io_ret == AVB_IO_RESULT_ERROR_INSUFFICIENT_SPACE) {
avb_errorv(
part_name, ": Persistent digest is not of expected size.\n", NULL);
return AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;
} else if (io_ret != AVB_IO_RESULT_OK) {
avb_errorv(part_name, ": Error reading persistent digest.\n", NULL);
return AVB_SLOT_VERIFY_RESULT_ERROR_IO;
+ } else if (expected_digest_size != stored_digest_size) {
+ avb_errorv(
+ part_name, ": Persistent digest is not of expected size.\n", NULL);
+ return AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;
}
return AVB_SLOT_VERIFY_RESULT_OK;
}
+static AvbSlotVerifyResult initialize_persistent_digest(
+ AvbOps* ops,
+ const char* part_name,
+ const char* persistent_value_name,
+ size_t digest_size,
+ const uint8_t* initial_digest,
+ uint8_t* out_digest) {
+ AvbSlotVerifyResult ret;
+ AvbIOResult io_ret = AVB_IO_RESULT_OK;
+ bool is_device_unlocked = true;
+
+ io_ret = ops->read_is_device_unlocked(ops, &is_device_unlocked);
+ if (io_ret == AVB_IO_RESULT_ERROR_OOM) {
+ return AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
+ } else if (io_ret != AVB_IO_RESULT_OK) {
+ avb_error("Error getting device lock state.\n");
+ return AVB_SLOT_VERIFY_RESULT_ERROR_IO;
+ }
+
+ if (is_device_unlocked) {
+ avb_debugv(part_name,
+ ": Digest does not exist, device unlocked so not initializing "
+ "digest.\n",
+ NULL);
+ return AVB_SLOT_VERIFY_RESULT_ERROR_VERIFICATION;
+ }
+
+ // Device locked; initialize digest with given initial value.
+ avb_debugv(part_name,
+ ": Digest does not exist, initializing persistent digest.\n",
+ NULL);
+ io_ret = ops->write_persistent_value(
+ ops, persistent_value_name, digest_size, initial_digest);
+ if (io_ret == AVB_IO_RESULT_ERROR_OOM) {
+ return AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
+ } else if (io_ret != AVB_IO_RESULT_OK) {
+ avb_errorv(part_name, ": Error initializing persistent digest.\n", NULL);
+ return AVB_SLOT_VERIFY_RESULT_ERROR_IO;
+ }
+
+ // To ensure that the digest value was written successfully - and avoid a
+ // scenario where the digest is simply 'initialized' on every verify - recurse
+ // into read_persistent_digest to read back the written value. The NULL
+ // initial_digest ensures that this will not recurse again.
+ ret = read_persistent_digest(ops, part_name, digest_size, NULL, out_digest);
+ if (ret != AVB_SLOT_VERIFY_RESULT_OK) {
+ avb_errorv(part_name,
+ ": Reading back initialized persistent digest failed!\n",
+ NULL);
+ }
+ return ret;
+}
+
static AvbSlotVerifyResult load_and_verify_hash_partition(
AvbOps* ops,
const char* const* requested_partitions,
@@ -248,24 +349,16 @@ static AvbSlotVerifyResult load_and_verify_hash_partition(
*/
image_size = hash_desc.image_size;
if (allow_verification_error) {
- if (ops->get_size_of_partition == NULL) {
- avb_errorv(part_name,
- ": The get_size_of_partition() operation is "
- "not implemented so we may not load the entire partition. "
- "Please implement.",
- NULL);
- } else {
- io_ret = ops->get_size_of_partition(ops, part_name, &image_size);
- if (io_ret == AVB_IO_RESULT_ERROR_OOM) {
- ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
- goto out;
- } else if (io_ret != AVB_IO_RESULT_OK) {
- avb_errorv(part_name, ": Error determining partition size.\n", NULL);
- ret = AVB_SLOT_VERIFY_RESULT_ERROR_IO;
- goto out;
- }
- avb_debugv(part_name, ": Loading entire partition.\n", NULL);
+ io_ret = ops->get_size_of_partition(ops, part_name, &image_size);
+ if (io_ret == AVB_IO_RESULT_ERROR_OOM) {
+ ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
+ goto out;
+ } else if (io_ret != AVB_IO_RESULT_OK) {
+ avb_errorv(part_name, ": Error determining partition size.\n", NULL);
+ ret = AVB_SLOT_VERIFY_RESULT_ERROR_IO;
+ goto out;
}
+ avb_debugv(part_name, ": Loading entire partition.\n", NULL);
}
ret = load_full_partition(
@@ -273,19 +366,27 @@ static AvbSlotVerifyResult load_and_verify_hash_partition(
if (ret != AVB_SLOT_VERIFY_RESULT_OK) {
goto out;
}
-
+ // Although only one of the type might be used, we have to defined the
+ // structure here so that they would live outside the 'if/else' scope to be
+ // used later.
+ AvbSHA256Ctx sha256_ctx;
+ AvbSHA512Ctx sha512_ctx;
+ size_t image_size_to_hash = hash_desc.image_size;
+ // If we allow verification error and the whole partition is smaller than
+ // image size in hash descriptor, we just hash the whole partition.
+ if (image_size_to_hash > image_size) {
+ image_size_to_hash = image_size;
+ }
if (avb_strcmp((const char*)hash_desc.hash_algorithm, "sha256") == 0) {
- AvbSHA256Ctx sha256_ctx;
avb_sha256_init(&sha256_ctx);
avb_sha256_update(&sha256_ctx, desc_salt, hash_desc.salt_len);
- avb_sha256_update(&sha256_ctx, image_buf, hash_desc.image_size);
+ avb_sha256_update(&sha256_ctx, image_buf, image_size_to_hash);
digest = avb_sha256_final(&sha256_ctx);
digest_len = AVB_SHA256_DIGEST_SIZE;
} else if (avb_strcmp((const char*)hash_desc.hash_algorithm, "sha512") == 0) {
- AvbSHA512Ctx sha512_ctx;
avb_sha512_init(&sha512_ctx);
avb_sha512_update(&sha512_ctx, desc_salt, hash_desc.salt_len);
- avb_sha512_update(&sha512_ctx, image_buf, hash_desc.image_size);
+ avb_sha512_update(&sha512_ctx, image_buf, image_size_to_hash);
digest = avb_sha512_final(&sha512_ctx);
digest_len = AVB_SHA512_DIGEST_SIZE;
} else {
@@ -295,18 +396,21 @@ static AvbSlotVerifyResult load_and_verify_hash_partition(
}
if (hash_desc.digest_len == 0) {
- // Expect a match to a persistent digest.
+ /* Expect a match to a persistent digest. */
avb_debugv(part_name, ": No digest, using persistent digest.\n", NULL);
expected_digest_len = digest_len;
expected_digest = expected_digest_buf;
avb_assert(expected_digest_len <= sizeof(expected_digest_buf));
- ret =
- read_persistent_digest(ops, part_name, digest_len, expected_digest_buf);
+ /* Pass |digest| as the |initial_digest| so devices not yet initialized get
+ * initialized to the current partition digest.
+ */
+ ret = read_persistent_digest(
+ ops, part_name, digest_len, digest, expected_digest_buf);
if (ret != AVB_SLOT_VERIFY_RESULT_OK) {
goto out;
}
} else {
- // Expect a match to the digest in the descriptor.
+ /* Expect a match to the digest in the descriptor. */
expected_digest_len = hash_desc.digest_len;
expected_digest = desc_digest;
}
@@ -365,12 +469,6 @@ static AvbSlotVerifyResult load_requested_partitions(
bool image_preloaded = false;
size_t n;
- if (ops->get_size_of_partition == NULL) {
- avb_error("get_size_of_partition() not implemented.\n");
- ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_ARGUMENT;
- goto out;
- }
-
for (n = 0; requested_partitions[n] != NULL; n++) {
char part_name[AVB_PART_NAME_MAX_SIZE];
AvbIOResult io_ret;
@@ -441,6 +539,7 @@ static AvbSlotVerifyResult load_and_verify_vbmeta(
AvbOps* ops,
const char* const* requested_partitions,
const char* ab_suffix,
+ AvbSlotVerifyFlags flags,
bool allow_verification_error,
AvbVBMetaImageFlags toplevel_vbmeta_flags,
int rollback_index_location,
@@ -467,7 +566,7 @@ static AvbSlotVerifyResult load_and_verify_vbmeta(
size_t num_descriptors;
size_t n;
bool is_main_vbmeta;
- bool is_vbmeta_partition;
+ bool look_for_vbmeta_footer;
AvbVBMetaData* vbmeta_image_data = NULL;
ret = AVB_SLOT_VERIFY_RESULT_OK;
@@ -478,8 +577,20 @@ static AvbSlotVerifyResult load_and_verify_vbmeta(
* rollback_index_location to determine whether we're the main
* vbmeta struct.
*/
- is_main_vbmeta = (rollback_index_location == 0);
- is_vbmeta_partition = (avb_strcmp(partition_name, "vbmeta") == 0);
+ is_main_vbmeta = false;
+ if (rollback_index_location == 0) {
+ if ((flags & AVB_SLOT_VERIFY_FLAGS_NO_VBMETA_PARTITION) == 0) {
+ is_main_vbmeta = true;
+ }
+ }
+
+ /* Don't use footers for vbmeta partitions ('vbmeta' or
+ * 'vbmeta_<partition_name>').
+ */
+ look_for_vbmeta_footer = true;
+ if (avb_strncmp(partition_name, "vbmeta", avb_strlen("vbmeta")) == 0) {
+ look_for_vbmeta_footer = false;
+ }
if (!avb_validate_utf8((const uint8_t*)partition_name, partition_name_len)) {
avb_error("Partition name is not valid UTF-8.\n");
@@ -487,7 +598,7 @@ static AvbSlotVerifyResult load_and_verify_vbmeta(
goto out;
}
- /* Construct full partition name. */
+ /* Construct full partition name e.g. system_a. */
if (!avb_str_concat(full_partition_name,
sizeof full_partition_name,
partition_name,
@@ -499,19 +610,15 @@ static AvbSlotVerifyResult load_and_verify_vbmeta(
goto out;
}
- avb_debugv("Loading vbmeta struct from partition '",
- full_partition_name,
- "'.\n",
- NULL);
-
- /* If we're loading from the main vbmeta partition, the vbmeta
- * struct is in the beginning. Otherwise we have to locate it via a
- * footer.
+ /* If we're loading from the main vbmeta partition, the vbmeta struct is in
+ * the beginning. Otherwise we may have to locate it via a footer... if no
+ * footer is found, we look in the beginning to support e.g. vbmeta_<org>
+ * partitions holding data for e.g. super partitions (b/80195851 for
+ * rationale).
*/
- if (is_vbmeta_partition) {
- vbmeta_offset = 0;
- vbmeta_size = VBMETA_MAX_SIZE;
- } else {
+ vbmeta_offset = 0;
+ vbmeta_size = VBMETA_MAX_SIZE;
+ if (look_for_vbmeta_footer) {
uint8_t footer_buf[AVB_FOOTER_SIZE];
size_t footer_num_read;
AvbFooter footer;
@@ -534,21 +641,17 @@ static AvbSlotVerifyResult load_and_verify_vbmeta(
if (!avb_footer_validate_and_byteswap((const AvbFooter*)footer_buf,
&footer)) {
- avb_errorv(full_partition_name, ": Error validating footer.\n", NULL);
- ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;
- goto out;
- }
-
- /* Basic footer sanity check since the data is untrusted. */
- if (footer.vbmeta_size > VBMETA_MAX_SIZE) {
- avb_errorv(
- full_partition_name, ": Invalid vbmeta size in footer.\n", NULL);
- ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;
- goto out;
+ avb_debugv(full_partition_name, ": No footer detected.\n", NULL);
+ } else {
+ /* Basic footer sanity check since the data is untrusted. */
+ if (footer.vbmeta_size > VBMETA_MAX_SIZE) {
+ avb_errorv(
+ full_partition_name, ": Invalid vbmeta size in footer.\n", NULL);
+ } else {
+ vbmeta_offset = footer.vbmeta_offset;
+ vbmeta_size = footer.vbmeta_size;
+ }
}
-
- vbmeta_offset = footer.vbmeta_offset;
- vbmeta_size = footer.vbmeta_size;
}
vbmeta_buf = avb_malloc(vbmeta_size);
@@ -557,6 +660,18 @@ static AvbSlotVerifyResult load_and_verify_vbmeta(
goto out;
}
+ if (vbmeta_offset != 0) {
+ avb_debugv("Loading vbmeta struct in footer from partition '",
+ full_partition_name,
+ "'.\n",
+ NULL);
+ } else {
+ avb_debugv("Loading vbmeta struct from partition '",
+ full_partition_name,
+ "'.\n",
+ NULL);
+ }
+
io_ret = ops->read_from_partition(ops,
full_partition_name,
vbmeta_offset,
@@ -571,13 +686,14 @@ static AvbSlotVerifyResult load_and_verify_vbmeta(
* go try to get it from the boot partition instead.
*/
if (is_main_vbmeta && io_ret == AVB_IO_RESULT_ERROR_NO_SUCH_PARTITION &&
- is_vbmeta_partition) {
+ !look_for_vbmeta_footer) {
avb_debugv(full_partition_name,
": No such partition. Trying 'boot' instead.\n",
NULL);
ret = load_and_verify_vbmeta(ops,
requested_partitions,
ab_suffix,
+ flags,
allow_verification_error,
0 /* toplevel_vbmeta_flags */,
0 /* rollback_index_location */,
@@ -655,6 +771,8 @@ static AvbSlotVerifyResult load_and_verify_vbmeta(
}
}
+ uint32_t rollback_index_location_to_use = rollback_index_location;
+
/* Check if key used to make signature matches what is expected. */
if (pk_data != NULL) {
if (expected_public_key != NULL) {
@@ -682,9 +800,27 @@ static AvbSlotVerifyResult load_and_verify_vbmeta(
pk_metadata_len = vbmeta_header.public_key_metadata_size;
}
- avb_assert(is_main_vbmeta);
- io_ret = ops->validate_vbmeta_public_key(
- ops, pk_data, pk_len, pk_metadata, pk_metadata_len, &key_is_trusted);
+ // If we're not using a vbmeta partition, need to use another AvbOps...
+ if (flags & AVB_SLOT_VERIFY_FLAGS_NO_VBMETA_PARTITION) {
+ io_ret = ops->validate_public_key_for_partition(
+ ops,
+ full_partition_name,
+ pk_data,
+ pk_len,
+ pk_metadata,
+ pk_metadata_len,
+ &key_is_trusted,
+ &rollback_index_location_to_use);
+ } else {
+ avb_assert(is_main_vbmeta);
+ io_ret = ops->validate_vbmeta_public_key(ops,
+ pk_data,
+ pk_len,
+ pk_metadata,
+ pk_metadata_len,
+ &key_is_trusted);
+ }
+
if (io_ret == AVB_IO_RESULT_ERROR_OOM) {
ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
goto out;
@@ -709,7 +845,7 @@ static AvbSlotVerifyResult load_and_verify_vbmeta(
/* Check rollback index. */
io_ret = ops->read_rollback_index(
- ops, rollback_index_location, &stored_rollback_index);
+ ops, rollback_index_location_to_use, &stored_rollback_index);
if (io_ret == AVB_IO_RESULT_ERROR_OOM) {
ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
goto out;
@@ -735,7 +871,9 @@ static AvbSlotVerifyResult load_and_verify_vbmeta(
if (is_main_vbmeta) {
avb_assert(slot_data->num_vbmeta_images == 0);
} else {
- avb_assert(slot_data->num_vbmeta_images > 0);
+ if (!(flags & AVB_SLOT_VERIFY_FLAGS_NO_VBMETA_PARTITION)) {
+ avb_assert(slot_data->num_vbmeta_images > 0);
+ }
}
if (slot_data->num_vbmeta_images == MAX_NUMBER_OF_VBMETA_IMAGES) {
avb_errorv(full_partition_name, ": Too many vbmeta images.\n", NULL);
@@ -859,6 +997,7 @@ static AvbSlotVerifyResult load_and_verify_vbmeta(
load_and_verify_vbmeta(ops,
requested_partitions,
ab_suffix,
+ flags,
allow_verification_error,
toplevel_vbmeta_flags,
chain_desc.rollback_index_location,
@@ -1019,7 +1158,11 @@ static AvbSlotVerifyResult load_and_verify_vbmeta(
goto out;
}
- ret = read_persistent_digest(ops, part_name, digest_len, digest_buf);
+ ret = read_persistent_digest(ops,
+ part_name,
+ digest_len,
+ NULL /* initial_digest */,
+ digest_buf);
if (ret != AVB_SLOT_VERIFY_RESULT_OK) {
goto out;
}
@@ -1043,7 +1186,8 @@ static AvbSlotVerifyResult load_and_verify_vbmeta(
}
}
- if (rollback_index_location >= AVB_MAX_NUMBER_OF_ROLLBACK_INDEX_LOCATIONS) {
+ if (rollback_index_location < 0 ||
+ rollback_index_location >= AVB_MAX_NUMBER_OF_ROLLBACK_INDEX_LOCATIONS) {
avb_errorv(
full_partition_name, ": Invalid rollback_index_location.\n", NULL);
ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;
@@ -1072,6 +1216,130 @@ out:
return ret;
}
+static AvbIOResult avb_manage_hashtree_error_mode(
+ AvbOps* ops,
+ AvbSlotVerifyFlags flags,
+ AvbSlotVerifyData* data,
+ AvbHashtreeErrorMode* out_hashtree_error_mode) {
+ AvbHashtreeErrorMode ret = AVB_HASHTREE_ERROR_MODE_RESTART;
+ AvbIOResult io_ret = AVB_IO_RESULT_OK;
+ uint8_t vbmeta_digest_sha256[AVB_SHA256_DIGEST_SIZE];
+ uint8_t stored_vbmeta_digest_sha256[AVB_SHA256_DIGEST_SIZE];
+ size_t num_bytes_read;
+
+ avb_assert(out_hashtree_error_mode != NULL);
+ avb_assert(ops->read_persistent_value != NULL);
+ avb_assert(ops->write_persistent_value != NULL);
+
+ // If we're rebooting because of dm-verity corruption, make a note of
+ // the vbmeta hash so we can stay in 'eio' mode until things change.
+ if (flags & AVB_SLOT_VERIFY_FLAGS_RESTART_CAUSED_BY_HASHTREE_CORRUPTION) {
+ avb_debug(
+ "Rebooting because of dm-verity corruption - "
+ "recording OS instance and using 'eio' mode.\n");
+ avb_slot_verify_data_calculate_vbmeta_digest(
+ data, AVB_DIGEST_TYPE_SHA256, vbmeta_digest_sha256);
+ io_ret = ops->write_persistent_value(ops,
+ AVB_NPV_MANAGED_VERITY_MODE,
+ AVB_SHA256_DIGEST_SIZE,
+ vbmeta_digest_sha256);
+ if (io_ret != AVB_IO_RESULT_OK) {
+ avb_error("Error writing to " AVB_NPV_MANAGED_VERITY_MODE ".\n");
+ goto out;
+ }
+ ret = AVB_HASHTREE_ERROR_MODE_EIO;
+ io_ret = AVB_IO_RESULT_OK;
+ goto out;
+ }
+
+ // See if we're in 'eio' mode.
+ io_ret = ops->read_persistent_value(ops,
+ AVB_NPV_MANAGED_VERITY_MODE,
+ AVB_SHA256_DIGEST_SIZE,
+ stored_vbmeta_digest_sha256,
+ &num_bytes_read);
+ if (io_ret == AVB_IO_RESULT_ERROR_NO_SUCH_VALUE ||
+ (io_ret == AVB_IO_RESULT_OK && num_bytes_read == 0)) {
+ // This is the usual case ('eio' mode not set).
+ avb_debug("No dm-verity corruption - using in 'restart' mode.\n");
+ ret = AVB_HASHTREE_ERROR_MODE_RESTART;
+ io_ret = AVB_IO_RESULT_OK;
+ goto out;
+ } else if (io_ret != AVB_IO_RESULT_OK) {
+ avb_error("Error reading from " AVB_NPV_MANAGED_VERITY_MODE ".\n");
+ goto out;
+ }
+ if (num_bytes_read != AVB_SHA256_DIGEST_SIZE) {
+ avb_error(
+ "Unexpected number of bytes read from " AVB_NPV_MANAGED_VERITY_MODE
+ ".\n");
+ io_ret = AVB_IO_RESULT_ERROR_IO;
+ goto out;
+ }
+
+ // OK, so we're currently in 'eio' mode and the vbmeta digest of the OS
+ // that caused this is in |stored_vbmeta_digest_sha256| ... now see if
+ // the OS we're dealing with now is the same.
+ avb_slot_verify_data_calculate_vbmeta_digest(
+ data, AVB_DIGEST_TYPE_SHA256, vbmeta_digest_sha256);
+ if (avb_memcmp(vbmeta_digest_sha256,
+ stored_vbmeta_digest_sha256,
+ AVB_SHA256_DIGEST_SIZE) == 0) {
+ // It's the same so we're still in 'eio' mode.
+ avb_debug("Same OS instance detected - staying in 'eio' mode.\n");
+ ret = AVB_HASHTREE_ERROR_MODE_EIO;
+ io_ret = AVB_IO_RESULT_OK;
+ } else {
+ // It did change!
+ avb_debug(
+ "New OS instance detected - changing from 'eio' to 'restart' mode.\n");
+ io_ret =
+ ops->write_persistent_value(ops,
+ AVB_NPV_MANAGED_VERITY_MODE,
+ 0, // This clears the persistent property.
+ vbmeta_digest_sha256);
+ if (io_ret != AVB_IO_RESULT_OK) {
+ avb_error("Error clearing " AVB_NPV_MANAGED_VERITY_MODE ".\n");
+ goto out;
+ }
+ ret = AVB_HASHTREE_ERROR_MODE_RESTART;
+ io_ret = AVB_IO_RESULT_OK;
+ }
+
+out:
+ *out_hashtree_error_mode = ret;
+ return io_ret;
+}
+
+static bool has_system_partition(AvbOps* ops, const char* ab_suffix) {
+ char part_name[AVB_PART_NAME_MAX_SIZE];
+ char* system_part_name = "system";
+ char guid_buf[37];
+ AvbIOResult io_ret;
+
+ if (!avb_str_concat(part_name,
+ sizeof part_name,
+ system_part_name,
+ avb_strlen(system_part_name),
+ ab_suffix,
+ avb_strlen(ab_suffix))) {
+ avb_error("System partition name and suffix does not fit.\n");
+ return false;
+ }
+
+ io_ret = ops->get_unique_guid_for_partition(
+ ops, part_name, guid_buf, sizeof guid_buf);
+ if (io_ret == AVB_IO_RESULT_ERROR_NO_SUCH_PARTITION) {
+ avb_debug("No system partition.\n");
+ return false;
+ } else if (io_ret != AVB_IO_RESULT_OK) {
+ avb_error("Error getting unique GUID for system partition.\n");
+ return false;
+ }
+
+ return true;
+}
+
AvbSlotVerifyResult avb_slot_verify(AvbOps* ops,
const char* const* requested_partitions,
const char* ab_suffix,
@@ -1087,14 +1355,10 @@ AvbSlotVerifyResult avb_slot_verify(AvbOps* ops,
(flags & AVB_SLOT_VERIFY_FLAGS_ALLOW_VERIFICATION_ERROR);
AvbCmdlineSubstList* additional_cmdline_subst = NULL;
- /* Fail early if we're missing the AvbOps needed for slot verification.
- *
- * For now, handle get_size_of_partition() not being implemented. In
- * a later release we may change that.
- */
+ /* Fail early if we're missing the AvbOps needed for slot verification. */
avb_assert(ops->read_is_device_unlocked != NULL);
avb_assert(ops->read_from_partition != NULL);
- avb_assert(ops->validate_vbmeta_public_key != NULL);
+ avb_assert(ops->get_size_of_partition != NULL);
avb_assert(ops->read_rollback_index != NULL);
avb_assert(ops->get_unique_guid_for_partition != NULL);
@@ -1112,6 +1376,36 @@ AvbSlotVerifyResult avb_slot_verify(AvbOps* ops,
goto fail;
}
+ /* Make sure passed-in AvbOps support persistent values if
+ * asking for libavb to manage verity state.
+ */
+ if (hashtree_error_mode == AVB_HASHTREE_ERROR_MODE_MANAGED_RESTART_AND_EIO) {
+ if (ops->read_persistent_value == NULL ||
+ ops->write_persistent_value == NULL) {
+ avb_error(
+ "Persistent values required for "
+ "AVB_HASHTREE_ERROR_MODE_MANAGED_RESTART_AND_EIO "
+ "but are not implemented in given AvbOps.\n");
+ ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_ARGUMENT;
+ goto fail;
+ }
+ }
+
+ /* Make sure passed-in AvbOps support verifying public keys and getting
+ * rollback index location if not using a vbmeta partition.
+ */
+ if (flags & AVB_SLOT_VERIFY_FLAGS_NO_VBMETA_PARTITION) {
+ if (ops->validate_public_key_for_partition == NULL) {
+ avb_error(
+ "AVB_SLOT_VERIFY_FLAGS_NO_VBMETA_PARTITION was passed but the "
+ "validate_public_key_for_partition() operation isn't implemented.\n");
+ ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_ARGUMENT;
+ goto fail;
+ }
+ } else {
+ avb_assert(ops->validate_vbmeta_public_key != NULL);
+ }
+
slot_data = avb_calloc(sizeof(AvbSlotVerifyData));
if (slot_data == NULL) {
ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
@@ -1136,99 +1430,163 @@ AvbSlotVerifyResult avb_slot_verify(AvbOps* ops,
goto fail;
}
- ret = load_and_verify_vbmeta(ops,
- requested_partitions,
- ab_suffix,
- allow_verification_error,
- 0 /* toplevel_vbmeta_flags */,
- 0 /* rollback_index_location */,
- "vbmeta",
- avb_strlen("vbmeta"),
- NULL /* expected_public_key */,
- 0 /* expected_public_key_length */,
- slot_data,
- &algorithm_type,
- additional_cmdline_subst);
- if (!allow_verification_error && ret != AVB_SLOT_VERIFY_RESULT_OK) {
+ if (flags & AVB_SLOT_VERIFY_FLAGS_NO_VBMETA_PARTITION) {
+ if (requested_partitions == NULL || requested_partitions[0] == NULL) {
+ avb_fatal(
+ "Requested partitions cannot be empty when using "
+ "AVB_SLOT_VERIFY_FLAGS_NO_VBMETA_PARTITION");
+ ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_ARGUMENT;
+ goto fail;
+ }
+
+ /* No vbmeta partition, go through each of the requested partitions... */
+ for (size_t n = 0; requested_partitions[n] != NULL; n++) {
+ ret = load_and_verify_vbmeta(ops,
+ requested_partitions,
+ ab_suffix,
+ flags,
+ allow_verification_error,
+ 0 /* toplevel_vbmeta_flags */,
+ 0 /* rollback_index_location */,
+ requested_partitions[n],
+ avb_strlen(requested_partitions[n]),
+ NULL /* expected_public_key */,
+ 0 /* expected_public_key_length */,
+ slot_data,
+ &algorithm_type,
+ additional_cmdline_subst);
+ if (!allow_verification_error && ret != AVB_SLOT_VERIFY_RESULT_OK) {
+ goto fail;
+ }
+ }
+
+ } else {
+ /* Usual path, load "vbmeta"... */
+ ret = load_and_verify_vbmeta(ops,
+ requested_partitions,
+ ab_suffix,
+ flags,
+ allow_verification_error,
+ 0 /* toplevel_vbmeta_flags */,
+ 0 /* rollback_index_location */,
+ "vbmeta",
+ avb_strlen("vbmeta"),
+ NULL /* expected_public_key */,
+ 0 /* expected_public_key_length */,
+ slot_data,
+ &algorithm_type,
+ additional_cmdline_subst);
+ if (!allow_verification_error && ret != AVB_SLOT_VERIFY_RESULT_OK) {
+ goto fail;
+ }
+ }
+
+ if (!result_should_continue(ret)) {
goto fail;
}
/* If things check out, mangle the kernel command-line as needed. */
- if (result_should_continue(ret)) {
+ if (!(flags & AVB_SLOT_VERIFY_FLAGS_NO_VBMETA_PARTITION)) {
if (avb_strcmp(slot_data->vbmeta_images[0].partition_name, "vbmeta") != 0) {
avb_assert(
avb_strcmp(slot_data->vbmeta_images[0].partition_name, "boot") == 0);
using_boot_for_vbmeta = true;
}
+ }
- /* Byteswap top-level vbmeta header since we'll need it below. */
- avb_vbmeta_image_header_to_host_byte_order(
- (const AvbVBMetaImageHeader*)slot_data->vbmeta_images[0].vbmeta_data,
- &toplevel_vbmeta);
+ /* Byteswap top-level vbmeta header since we'll need it below. */
+ avb_vbmeta_image_header_to_host_byte_order(
+ (const AvbVBMetaImageHeader*)slot_data->vbmeta_images[0].vbmeta_data,
+ &toplevel_vbmeta);
- /* Fill in |ab_suffix| field. */
- slot_data->ab_suffix = avb_strdup(ab_suffix);
- if (slot_data->ab_suffix == NULL) {
- ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
- goto fail;
- }
+ /* Fill in |ab_suffix| field. */
+ slot_data->ab_suffix = avb_strdup(ab_suffix);
+ if (slot_data->ab_suffix == NULL) {
+ ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
+ goto fail;
+ }
- /* If verification is disabled, we are done ... we specifically
- * don't want to add any androidboot.* options since verification
- * is disabled.
+ /* If verification is disabled, we are done ... we specifically
+ * don't want to add any androidboot.* options since verification
+ * is disabled.
+ */
+ if (toplevel_vbmeta.flags & AVB_VBMETA_IMAGE_FLAGS_VERIFICATION_DISABLED) {
+ /* Since verification is disabled we didn't process any
+ * descriptors and thus there's no cmdline... so set root= such
+ * that the system partition is mounted.
*/
- if (toplevel_vbmeta.flags & AVB_VBMETA_IMAGE_FLAGS_VERIFICATION_DISABLED) {
- /* Since verification is disabled we didn't process any
- * descriptors and thus there's no cmdline... so set root= such
- * that the system partition is mounted.
- */
- avb_assert(slot_data->cmdline == NULL);
+ avb_assert(slot_data->cmdline == NULL);
+ // Devices with dynamic partitions won't have system partition.
+ // Instead, it has a large super partition to accommodate *.img files.
+ // See b/119551429 for details.
+ if (has_system_partition(ops, ab_suffix)) {
slot_data->cmdline =
avb_strdup("root=PARTUUID=$(ANDROID_SYSTEM_PARTUUID)");
- if (slot_data->cmdline == NULL) {
- ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
- goto fail;
- }
} else {
- /* Add options - any failure in avb_append_options() is either an
- * I/O or OOM error.
- */
- AvbSlotVerifyResult sub_ret = avb_append_options(ops,
- slot_data,
- &toplevel_vbmeta,
- algorithm_type,
- hashtree_error_mode);
- if (sub_ret != AVB_SLOT_VERIFY_RESULT_OK) {
- ret = sub_ret;
- goto fail;
- }
+ // The |cmdline| field should be a NUL-terminated string.
+ slot_data->cmdline = avb_strdup("");
}
-
- /* Substitute $(ANDROID_SYSTEM_PARTUUID) and friends. */
- if (slot_data->cmdline != NULL) {
- char* new_cmdline;
- new_cmdline = avb_sub_cmdline(ops,
- slot_data->cmdline,
- ab_suffix,
- using_boot_for_vbmeta,
- additional_cmdline_subst);
- if (new_cmdline != slot_data->cmdline) {
- if (new_cmdline == NULL) {
+ if (slot_data->cmdline == NULL) {
+ ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
+ goto fail;
+ }
+ } else {
+ /* If requested, manage dm-verity mode... */
+ AvbHashtreeErrorMode resolved_hashtree_error_mode = hashtree_error_mode;
+ if (hashtree_error_mode ==
+ AVB_HASHTREE_ERROR_MODE_MANAGED_RESTART_AND_EIO) {
+ AvbIOResult io_ret;
+ io_ret = avb_manage_hashtree_error_mode(
+ ops, flags, slot_data, &resolved_hashtree_error_mode);
+ if (io_ret != AVB_IO_RESULT_OK) {
+ ret = AVB_SLOT_VERIFY_RESULT_ERROR_IO;
+ if (io_ret == AVB_IO_RESULT_ERROR_OOM) {
ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
- goto fail;
}
- avb_free(slot_data->cmdline);
- slot_data->cmdline = new_cmdline;
+ goto fail;
}
}
+ slot_data->resolved_hashtree_error_mode = resolved_hashtree_error_mode;
- if (out_data != NULL) {
- *out_data = slot_data;
- } else {
- avb_slot_verify_data_free(slot_data);
+ /* Add options... */
+ AvbSlotVerifyResult sub_ret;
+ sub_ret = avb_append_options(ops,
+ flags,
+ slot_data,
+ &toplevel_vbmeta,
+ algorithm_type,
+ hashtree_error_mode,
+ resolved_hashtree_error_mode);
+ if (sub_ret != AVB_SLOT_VERIFY_RESULT_OK) {
+ ret = sub_ret;
+ goto fail;
+ }
+ }
+
+ /* Substitute $(ANDROID_SYSTEM_PARTUUID) and friends. */
+ if (slot_data->cmdline != NULL && avb_strlen(slot_data->cmdline) != 0) {
+ char* new_cmdline;
+ new_cmdline = avb_sub_cmdline(ops,
+ slot_data->cmdline,
+ ab_suffix,
+ using_boot_for_vbmeta,
+ additional_cmdline_subst);
+ if (new_cmdline != slot_data->cmdline) {
+ if (new_cmdline == NULL) {
+ ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
+ goto fail;
+ }
+ avb_free(slot_data->cmdline);
+ slot_data->cmdline = new_cmdline;
}
}
+ if (out_data != NULL) {
+ *out_data = slot_data;
+ } else {
+ avb_slot_verify_data_free(slot_data);
+ }
+
avb_free_cmdline_subst_list(additional_cmdline_subst);
additional_cmdline_subst = NULL;
diff --git a/lib/libavb/avb_slot_verify.h b/lib/libavb/avb_slot_verify.h
index 73fd70d4ce..8d0fa53693 100644
--- a/lib/libavb/avb_slot_verify.h
+++ b/lib/libavb/avb_slot_verify.h
@@ -51,12 +51,25 @@ typedef enum {
* be used ONLY for diagnostics and debugging. It cannot be used
* unless AVB_SLOT_VERIFY_FLAGS_ALLOW_VERIFICATION_ERROR is also
* used.
+ *
+ * AVB_HASHTREE_ERROR_MODE_MANAGED_RESTART_AND_EIO means that either
+ * AVB_HASHTREE_ERROR_MODE_RESTART or AVB_HASHTREE_ERROR_MODE_EIO is used
+ * depending on state. This mode implements a state machine whereby
+ * AVB_HASHTREE_ERROR_MODE_RESTART is used by default and when
+ * AVB_SLOT_VERIFY_FLAGS_RESTART_CAUSED_BY_HASHTREE_CORRUPTION is passed the
+ * mode transitions to AVB_HASHTREE_ERROR_MODE_EIO. When a new OS has been
+ * detected the device transitions back to the AVB_HASHTREE_ERROR_MODE_RESTART
+ * mode. To do this persistent storage is needed - specifically this means that
+ * the passed in AvbOps will need to have the read_persistent_value() and
+ * write_persistent_value() operations implemented. The name of the persistent
+ * value used is "avb.managed_verity_mode" and 32 bytes of storage is needed.
*/
typedef enum {
AVB_HASHTREE_ERROR_MODE_RESTART_AND_INVALIDATE,
AVB_HASHTREE_ERROR_MODE_RESTART,
AVB_HASHTREE_ERROR_MODE_EIO,
- AVB_HASHTREE_ERROR_MODE_LOGGING
+ AVB_HASHTREE_ERROR_MODE_LOGGING,
+ AVB_HASHTREE_ERROR_MODE_MANAGED_RESTART_AND_EIO
} AvbHashtreeErrorMode;
/* Flags that influence how avb_slot_verify() works.
@@ -80,10 +93,26 @@ typedef enum {
* contents loaded from |requested_partition| will be the contents of
* the entire partition instead of just the size specified in the hash
* descriptor.
+ *
+ * The AVB_SLOT_VERIFY_FLAGS_RESTART_CAUSED_BY_HASHTREE_CORRUPTION flag
+ * should be set if using AVB_HASHTREE_ERROR_MODE_MANAGED_RESTART_AND_EIO
+ * and the reason the boot loader is running is because the device
+ * was restarted by the dm-verity driver.
+ *
+ * If the AVB_SLOT_VERIFY_FLAGS_NO_VBMETA_PARTITION flag is set then
+ * data won't be loaded from the "vbmeta" partition and the
+ * |validate_vbmeta_public_key| operation is never called. Instead, the
+ * vbmeta structs in |requested_partitions| are loaded and processed and the
+ * |validate_public_key_for_partition| operation is called for each of these
+ * vbmeta structs. This flag is useful when booting into recovery on a device
+ * not using A/B - see section "Booting into recovery" in README.md for
+ * more information.
*/
typedef enum {
AVB_SLOT_VERIFY_FLAGS_NONE = 0,
- AVB_SLOT_VERIFY_FLAGS_ALLOW_VERIFICATION_ERROR = (1 << 0)
+ AVB_SLOT_VERIFY_FLAGS_ALLOW_VERIFICATION_ERROR = (1 << 0),
+ AVB_SLOT_VERIFY_FLAGS_RESTART_CAUSED_BY_HASHTREE_CORRUPTION = (1 << 1),
+ AVB_SLOT_VERIFY_FLAGS_NO_VBMETA_PARTITION = (1 << 2),
} AvbSlotVerifyFlags;
/* Get a textual representation of |result|. */
@@ -188,6 +217,10 @@ typedef struct {
* set to AVB_HASHTREE_ERROR_MODE_EIO, and 'logging' if it's set to
* AVB_HASHTREE_ERROR_MODE_LOGGING.
*
+ * androidboot.veritymode.managed: This is set to 'yes' only
+ * if hashtree validation isn't disabled and the passed-in hashtree
+ * error mode is AVB_HASHTREE_ERROR_MODE_MANAGED_RESTART_AND_EIO.
+ *
* androidboot.vbmeta.invalidate_on_error: This is set to 'yes' only
* if hashtree validation isn't disabled and the passed-in hashtree
* error mode is AVB_HASHTREE_ERROR_MODE_RESTART_AND_INVALIDATE.
@@ -203,7 +236,9 @@ typedef struct {
* PARTUUID=$(ANDROID_VBMETA_PARTUUID) before substitution so it
* will end up pointing to the vbmeta partition for the verified
* slot. If there is no vbmeta partition it will point to the boot
- * partition of the verified slot.
+ * partition of the verified slot. If the flag
+ * AVB_SLOT_VERIFY_FLAGS_NO_VBMETA_PARTITION is used, this is not
+ * set.
*
* androidboot.vbmeta.avb_version: This is set to the decimal value
* of AVB_VERSION_MAJOR followed by a dot followed by the decimal
@@ -228,6 +263,15 @@ typedef struct {
* appropriate system partition is substituted in. Note that none of
* the androidboot.* options mentioned above will be set.
*
+ * The |resolved_hashtree_error_mode| is the the value of the passed
+ * avb_slot_verify()'s |hashtree_error_mode| parameter except that it never has
+ * the value AVB_HASHTREE_ERROR_MODE_MANAGED_RESTART_AND_EIO. If this value was
+ * passed in, then the restart/eio state machine is used resulting in
+ * |resolved_hashtree_error_mode| being set to either
+ * AVB_HASHTREE_ERROR_MODE_RESTART or AVB_HASHTREE_ERROR_MODE_EIO. If set to
+ * AVB_HASHTREE_ERROR_MODE_EIO the boot loader should present a RED warning
+ * screen for the user to click through before continuing to boot.
+ *
* This struct may grow in the future without it being considered an
* ABI break.
*/
@@ -239,6 +283,7 @@ typedef struct {
size_t num_loaded_partitions;
char* cmdline;
uint64_t rollback_indexes[AVB_MAX_NUMBER_OF_ROLLBACK_INDEX_LOCATIONS];
+ AvbHashtreeErrorMode resolved_hashtree_error_mode;
} AvbSlotVerifyData;
/* Calculates a digest of all vbmeta images in |data| using
@@ -282,12 +327,8 @@ void avb_slot_verify_data_free(AvbSlotVerifyData* data);
* ignore verification errors which is something needed in the
* UNLOCKED state. See the AvbSlotVerifyFlags enumeration for details.
*
- * The |hashtree_error_mode| parameter should be set to the desired
- * error handling mode when hashtree validation fails inside the
- * HLOS. This value isn't used by libavb per se - it is forwarded to
- * the HLOS through the androidboot.veritymode and
- * androidboot.vbmeta.invalidate_on_error cmdline parameters. See the
- * AvbHashtreeErrorMode enumeration for details.
+ * The |hashtree_error_mode| parameter should be set to the desired error
+ * handling mode. See the AvbHashtreeErrorMode enumeration for details.
*
* Also note that |out_data| is never set if
* AVB_SLOT_VERIFY_RESULT_ERROR_OOM, AVB_SLOT_VERIFY_RESULT_ERROR_IO,
diff --git a/lib/libavb/avb_sysdeps.h b/lib/libavb/avb_sysdeps.h
index f032de4a2e..f52428cc62 100644
--- a/lib/libavb/avb_sysdeps.h
+++ b/lib/libavb/avb_sysdeps.h
@@ -53,6 +53,14 @@ int avb_memcmp(const void* src1,
*/
int avb_strcmp(const char* s1, const char* s2);
+/* Compare |n| bytes in two strings.
+ *
+ * Return an integer less than, equal to, or greater than zero if the
+ * first |n| bytes of |s1| is found, respectively, to be less than,
+ * to match, or be greater than the first |n| bytes of |s2|.
+ */
+int avb_strncmp(const char* s1, const char* s2, size_t n);
+
/* Copy |n| bytes from |src| to |dest|. */
void* avb_memcpy(void* dest, const void* src, size_t n);
diff --git a/lib/libavb/avb_sysdeps_posix.c b/lib/libavb/avb_sysdeps_posix.c
index e9addc1c87..4ccf41e428 100644
--- a/lib/libavb/avb_sysdeps_posix.c
+++ b/lib/libavb/avb_sysdeps_posix.c
@@ -24,14 +24,12 @@ int avb_strcmp(const char* s1, const char* s2) {
return strcmp(s1, s2);
}
-size_t avb_strlen(const char* str) {
- return strlen(str);
+int avb_strncmp(const char* s1, const char* s2, size_t n) {
+ return strncmp(s1, s2, n);
}
-uint32_t avb_div_by_10(uint64_t* dividend) {
- uint32_t rem = (uint32_t)(*dividend % 10);
- *dividend /= 10;
- return rem;
+size_t avb_strlen(const char* str) {
+ return strlen(str);
}
void avb_abort(void) {
@@ -60,3 +58,9 @@ void* avb_malloc_(size_t size) {
void avb_free(void* ptr) {
free(ptr);
}
+
+uint32_t avb_div_by_10(uint64_t* dividend) {
+ uint32_t rem = (uint32_t)(*dividend % 10);
+ *dividend /= 10;
+ return rem;
+}
diff --git a/lib/libavb/avb_vbmeta_image.c b/lib/libavb/avb_vbmeta_image.c
index a7e2322b9e..384f5ac19e 100644
--- a/lib/libavb/avb_vbmeta_image.c
+++ b/lib/libavb/avb_vbmeta_image.c
@@ -35,17 +35,18 @@ AvbVBMetaVerifyResult avb_vbmeta_image_verify(
*out_public_key_length = 0;
}
+ /* Before we byteswap or compare Magic, ensure length is long enough. */
+ if (length < sizeof(AvbVBMetaImageHeader)) {
+ avb_error("Length is smaller than header.\n");
+ goto out;
+ }
+
/* Ensure magic is correct. */
if (avb_safe_memcmp(data, AVB_MAGIC, AVB_MAGIC_LEN) != 0) {
avb_error("Magic is incorrect.\n");
goto out;
}
- /* Before we byteswap, ensure length is long enough. */
- if (length < sizeof(AvbVBMetaImageHeader)) {
- avb_error("Length is smaller than header.\n");
- goto out;
- }
avb_vbmeta_image_header_to_host_byte_order((const AvbVBMetaImageHeader*)data,
&h);
--
2.23.0.rc1
6
14
The requested_partitions[] array should contain only boot partitions.
Usually it's only 'boot' partition, as can be seen in [1]. Also, seems
like the requested_partitions[] are only used when there is no 'vbmeta'
partition [2], which is not a regular use-case.
Make requested_partitions[] contain only 'boot' partition as it was
supposed to be, and also make that array to be a local in
do_avb_verify_part() function, as nobody else needs that.
[1] https://android.googlesource.com/platform/external/avb/+/5fbb42a189aa/test/…
[2] https://android.googlesource.com/platform/external/avb/+/5fbb42a189aa/libav…
Signed-off-by: Sam Protsenko <semen.protsenko(a)linaro.org>
---
Changes in v2:
- fix links in commit message (suggested by Eugeniu Rosca)
cmd/avb.c | 6 +-----
1 file changed, 1 insertion(+), 5 deletions(-)
diff --git a/cmd/avb.c b/cmd/avb.c
index a8a95034ca..a4de5c40a2 100644
--- a/cmd/avb.c
+++ b/cmd/avb.c
@@ -15,11 +15,6 @@
#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;
@@ -232,6 +227,7 @@ int do_avb_get_uuid(cmd_tbl_t *cmdtp, int flag,
int do_avb_verify_part(cmd_tbl_t *cmdtp, int flag,
int argc, char *const argv[])
{
+ const char * const requested_partitions[] = {"boot", NULL};
AvbSlotVerifyResult slot_result;
AvbSlotVerifyData *out_data;
char *cmdline;
--
2.23.0.rc1
3
2
One of major missing features in current UEFI implementation is "secure boot."
The ultimate goal of my attempt is to implement image authentication based
on signature and provide UEFI secure boot support which would be fully
compliant with UEFI specification, section 32[1].
(The code was originally developed by Patrick Wildt.)
While this patch/RFC is still rough-edged, the aim here is to get early
feedbacks from the community as the patch is quite huge (in total) and also
as it's a security enhancement.
Please note, however, this patch doesn't work on its own; there are
a couple of functional dependencies[2], [3] and [4], that I have submitted
before, in addition to related preparatory patches[5], [6], [7] and [8] for
pytest support. For complete workable patch set, see my repository[9],
which also contains exeperimental timestamp-based revocation suuport.
My "non-volatile" support[10], which is under reviews now, is not mandatory
and so not included here, but this inevitably implies that, for example,
signature database variables, like db and dbx, won't be persistent unless you
explicitly run "env save" command and that UEFI variables are not separated
from U-Boot environment. Anyhow, Linaro is also working on implementing
real "secure storage" solution based on TF-A and OP-TEE.
Supported features:
* image authentication based on db and dbx
* supported signature types are
EFI_CERT_SHA256_GUID (SHA256 digest for unsigned images)
EFI_CERT_X509_GUID (x509 certificate for signed images)
* SecureBoot/SignatureSupport variables
* SetupMode and user mode
* variable authentication based on PK and KEK
EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS
* pytest test cases
Unsupported features:
* hash algorithms other than SHA256
* dbt: timestamp(RFC6131)-based certificate revocation
* dbr: OS recovery
* xxxDefault: default values for signature stores
* transition to AuditMode and DeployedMode
* recording rejected images in EFI_IMAGE_EXECUTION_INFO_TABLE
* variable authentication based on PK and KEK
EFI_VARIABLE_ENHANCED_AUTHENTICATED_ACCESS
* real secure storage, including hardware-specific PK (Platform Key)
installation
Known issues:
* [3] and [4] have not been well reviewed yet.
* Some test case(test_efi_var_auth1:1g) still fails.
* Extensive clean-ups
* not bisect-ready (for easier code modification) for now
TODO:
* implement "unsupported" features, in particular, timestamp-based
revocation
* fix some workarounds in the source (marked as TODO/FIXME)
* extensive test suite (or more test cases) to confirm compatibility
with EDK2
Hints about how to use:
(Please see other documents, or my pytest scripts, for details.)
* You can create your own certificates with openssl.
* You can sign your application with pesign (on Ubuntu).
* You can create raw data for signature database with efitools, and
install/manage authenticated variables with "env -set -e" command
or efitools' "UpdateVars.efi" application.
[1] https://uefi.org/sites/default/files/resources/UEFI_Spec_2_8_final.pdf
[2] https://lists.denx.de/pipermail/u-boot/2019-September/382911.html
(support APPEND_WRITE)
[3] https://lists.denx.de/pipermail/u-boot/2019-September/382573.html
(import x509/pkcs7 parsers from linux)
[4] https://lists.denx.de/pipermail/u-boot/2019-September/382917.html
(extend rsa_verify() for UEFI secure boot)
[5] https://lists.denx.de/pipermail/u-boot/2019-August/382027.html
(sandbox: fix cpu property in test.dts for pytest)
[6] https://lists.denx.de/pipermail/u-boot/2019-September/382914.html
(extend "env [set|print] -e to manage UEFI variables v1)
[7] https://lists.denx.de/pipermail/u-boot/2019-September/383343.html
(install FILE_SYSTEM_PROTOCOL to a whole disk)
[8] https://lists.denx.de/pipermail/u-boot/2019-September/383348.html
(support Sandbox's "host" device)
[9] http://git.linaro.org/people/takahiro.akashi/u-boot.git/ efi/secboot
[10] https://lists.denx.de/pipermail/u-boot/2019-September/382835.html
(non-volatile variables support)
AKASHI Takahiro (15):
lib: charset: add u16_str<n>cmp()
test: add tests for u16_str<n>cmp()
include: pe.h: add image-signing-related definitions
include: image.h: add key info to image_sign_info
include: image.h: export hash algorithm helper functions
secure boot: rename CONFIG_SECURE_BOOT
efi_loader: add signature verification functions
efi_loader: variable: support variable authentication
efi_loader: variable: add VendorKeys and SignatureSupport variables
efi_loader: image_loader: support image authentication
efi_loader: initialize secure boot state
efi_loader: add CONFIG_EFI_SECURE_BOOT
cmd: env: provide appropriate guid for well-defined variable
efi_loader, pytest: add UEFI secure boot tests (image)
efi_loader, pytest: add UEFI secure boot tests (authenticated
variables)
Kconfig | 7 +
arch/arm/cpu/armv7/ls102xa/Kconfig | 3 +-
arch/arm/cpu/armv8/fsl-layerscape/Kconfig | 3 +-
arch/arm/mach-imx/Kconfig | 3 +-
arch/powerpc/cpu/mpc85xx/Kconfig | 3 +-
cmd/nvedit_efi.c | 31 +-
include/charset.h | 15 +
include/efi_api.h | 47 +
include/efi_loader.h | 58 +-
include/image.h | 17 +-
include/pe.h | 16 +
lib/charset.c | 25 +
lib/efi_loader/Kconfig | 13 +
lib/efi_loader/Makefile | 1 +
lib/efi_loader/efi_boottime.c | 2 +-
lib/efi_loader/efi_image_loader.c | 364 ++++++-
lib/efi_loader/efi_setup.c | 5 +
lib/efi_loader/efi_signature.c | 602 ++++++++++++
lib/efi_loader/efi_variable.c | 928 ++++++++++++++++--
test/py/tests/test_efi_secboot/conftest.py | 168 ++++
test/py/tests/test_efi_secboot/defs.py | 7 +
.../py/tests/test_efi_secboot/test_authvar.py | 287 ++++++
test/py/tests/test_efi_secboot/test_signed.py | 97 ++
.../tests/test_efi_secboot/test_unsigned.py | 126 +++
test/unicode_ut.c | 13 +
25 files changed, 2714 insertions(+), 127 deletions(-)
create mode 100644 lib/efi_loader/efi_signature.c
create mode 100644 test/py/tests/test_efi_secboot/conftest.py
create mode 100644 test/py/tests/test_efi_secboot/defs.py
create mode 100644 test/py/tests/test_efi_secboot/test_authvar.py
create mode 100644 test/py/tests/test_efi_secboot/test_signed.py
create mode 100644 test/py/tests/test_efi_secboot/test_unsigned.py
--
2.21.0
6
24

[U-Boot] [PATCH v1 0/5] clk: Add a managed API and fix clock self-assignment
by Jean-Jacques Hiblot 30 Oct '19
by Jean-Jacques Hiblot 30 Oct '19
30 Oct '19
This is the second of a few series, the goal of which is to facilitate
porting drivers from the linux kernel. Most of the series will be about
adding managed API to existing infrastructure (GPIO, reset, phy,...)
This particular series is about clocks. It adds a managed API, using
the same API as linux. It also fix a use-case where the clock is
initialized (rate and/or mux) when it is probed using the
assigned-clocks-* properties.
JJ
Jean-Jacques Hiblot (5):
drivers: clk: Handle gracefully NULL pointers
drivers: clk: Add a managed API to get clocks from the device-tree
test: clk: Update tests to also check the managed API
drivers: clk: Fix using assigned-clocks in the node of the clock it
sets up
test: clk: test clock self assignment
arch/sandbox/dts/test.dts | 8 +-
arch/sandbox/include/asm/clk.h | 33 ++++++++
drivers/clk/clk-uclass.c | 139 ++++++++++++++++++++++++++++++---
drivers/clk/clk_sandbox.c | 56 +++++++++++++
drivers/clk/clk_sandbox_test.c | 66 +++++++++++++---
drivers/core/device.c | 2 +-
include/clk.h | 53 ++++++++++++-
test/dm/clk.c | 36 ++++++++-
8 files changed, 364 insertions(+), 29 deletions(-)
--
2.17.1
3
11

29 Oct '19
Hi Matthias,
Hard deadline is Aug 15th, so you should see first series before that.
Regards,
Suneel
On Wed, Jul 24, 2019 at 3:30 AM Matthias Brugger <mbrugger(a)suse.com> wrote:
>
> Hi Suneel,
> Hi Chandrakala,
>
> On 16/05/2019 19:07, Suneel Garapati wrote:
> > Hi Tim,
> >
> > Missed aggressive timeline, first RFC series should be out in three weeks
> > time as priority.
> >
>
> Any news on the patch set?
>
> Regards,
> Matthias
>
> > Regards,
> > Suneel
> >
> >
> > On Tue, May 7, 2019 at 8:10 AM Tim Harvey <tharvey(a)gateworks.com> wrote:
> >>
> >> On Fri, Mar 22, 2019 at 11:23 AM Suneel Garapati <suneelglinux(a)gmail.com>
> > wrote:
> >>>
> >>> Hi Tim,
> >>>
> >>> First series will be out week ending April 20th.
> >>>
> >>> Regards,
> >>> Suneel
> >>
> >> Suneel,
> >>
> >> Any update on a Marvell submitted/maintained patch series for Octeon-TX
> > support?
> >>
> >> Best Regards,
> >>
> >> Tim
> > _______________________________________________
> > U-Boot mailing list
> > U-Boot(a)lists.denx.de
> > https://lists.denx.de/listinfo/u-boot
> >
5
8
The series adds support for icssg_prueth functionality
on u-boot. This series is based on top of master branch.
rproc init needs to be done from uboot command prompt.
The pru/rtu firmware loading is done by prueth driver soon after
config paramters are setup.
Currently only slice0/1 of icssg2 instance on am6-evm
is supported. i.e Both slices of icssg2 instance are supported.
On u-boot prompt following commands to test icssg2_port 0 on am654-evm:
setenv ethact pruss2_eth; setenv serverip 172.24.191.45; fatload mmc 1 ${pru0loadaddr} am65x-pru0-prueth-fw.elf; fatload mmc 1 ${rtu0loadaddr} am65x-rtu0-prueth-fw.elf; rproc init; setenv autoload no; dhcp; tftp 0x82000000 Image; tftp 0x83000000 k3-am654-base-board.dtb; booti 0x82000000 - 0x83000000
This tests tftp on prueth.
Note: Uboot ethernet driver architecture supports once
instance per probe. So only one of the ports are supported
per instance. So DT of prueth node should have either ethernet-mii0
or ethernet-mii1.
Keerthy (14):
net: eth-uclass: eth_get_dev based on SEQ_ALIAS instead of probe order
net: eth-uclass: call stop only for active devices
misc: uclass: Introduce misc_init_by_ofnode
soc: ti: pruss: add a misc driver for PRUSS in TI SoCs
remoteproc: pruss: add PRU remoteproc driver
net: ti: icssg-prueth: Add ICSSG ethernet driver
net: ti: icssg-prueth: Workaround to shutdown the prueth firmware
arm: dts: k3-am65-main: Add msmc_ram node
arm: dts: k3-am654-base-board-u-boot: Add icssg specific msmc_ram
carveout nodes
arm: dts: k3-am65-main: Add scm_conf node
arm: dts: k3-am65-main: Add pruss nodes for ICSSG2
arm64: dts: ti: am654-base-board: add ICSSG2 Ethernet support
configs: am65x_evm_a53_defconfig: Enable CONFIG_REMOTEPROC_TI_PRU
configs: am65x_evm_a53_defconfig: Enable CONFIG_CMD_REMOTEPROC
arch/arm/dts/k3-am65-main.dtsi | 212 ++++++++
arch/arm/dts/k3-am65.dtsi | 4 +-
arch/arm/dts/k3-am654-base-board-u-boot.dtsi | 130 +++++
configs/am65x_evm_a53_defconfig | 5 +
drivers/misc/misc-uclass.c | 25 +
drivers/net/ti/Kconfig | 8 +
drivers/net/ti/Makefile | 1 +
drivers/net/ti/icssg-prueth.c | 525 +++++++++++++++++++
drivers/net/ti/icssg.h | 31 ++
drivers/net/ti/icssg_classifier.c | 397 ++++++++++++++
drivers/remoteproc/Kconfig | 11 +
drivers/remoteproc/Makefile | 1 +
drivers/remoteproc/pru_rproc.c | 384 ++++++++++++++
drivers/soc/ti/Kconfig | 13 +
drivers/soc/ti/Makefile | 1 +
drivers/soc/ti/pruss.c | 143 +++++
include/misc.h | 9 +
include/ti-pruss.h | 13 +
net/eth-uclass.c | 7 +-
19 files changed, 1916 insertions(+), 4 deletions(-)
create mode 100644 drivers/net/ti/icssg-prueth.c
create mode 100644 drivers/net/ti/icssg.h
create mode 100644 drivers/net/ti/icssg_classifier.c
create mode 100644 drivers/remoteproc/pru_rproc.c
create mode 100644 drivers/soc/ti/pruss.c
create mode 100644 include/ti-pruss.h
--
2.17.1
8
29

28 Oct '19
The current rsa_verify() requires five parameters for a RSA public key
for efficiency while RSA, in theory, requires only two. In addition,
those parameters are expected to come from FIT image.
So this function won't fit very well when we want to use it for the purpose
of implementing UEFI secure boot, in particular, image authentication
as well as variable authentication, where the essential two parameters
are set to be retrieved from one of X509 certificates in signature
database.
So, in this patch, additional three parameters will be calculated
on the fly when rsa_verify() is called without fdt which should contain
parameters above.
This calculation heavily relies on "big-number (or multi-precision)
library." Therefore some routines from BearSSL[1] under MIT license are
imported in this implementation. See Patch#2.
# Please let me know if this is not appropriate.
# Checkpatch will complain with lots of warnings/errors, but
# I intentionally don't fix them for maximum maintainability.
[1] https://bearssl.org/
AKASHI Takahiro (3):
lib: rsa: decouple rsa from FIT image verification
lib: rsa: generate additional parameters for public key
lib: rsa: add rsa_verify_with_pkey()
include/u-boot/rsa-mod-exp.h | 3 +
lib/rsa/Kconfig | 14 +
lib/rsa/Makefile | 3 +-
lib/rsa/rsa-keyprop.c | 631 +++++++++++++++++++++++++++++++++++
lib/rsa/rsa-verify.c | 63 +++-
5 files changed, 705 insertions(+), 9 deletions(-)
create mode 100644 lib/rsa/rsa-keyprop.c
--
2.21.0
4
17

27 Oct '19
This series adds support for 88E6071 switches in the mv88e61xx
driver.
Changes in v3:
- Add Reviewed-/Tested-by tags
patch 1
- drop DEVADDR_PORT to avoid macros with local variable
- describe variables added to priv struct
- reword comments in mv88e61xx_priv_reg_offs_pre_init()
- add comment in get_phy_id() to explain why calling
mv88e61xx_priv_reg_offs_pre_init() is required
patch 2
- remove unused PORT_REG_STATUS_SPEED_WIDTH macro
patch 4
- describe model numbers in numerical order
Changes in v2:
- fix port init for 6096/6097 devices in patch 1/6
- update commit description in patch 4/6
Anatolij Gustschin (6):
net: phy: mv88e61xx: rework to enable detection of 88E6071 devices
net: phy: mv88e61xx: add CPU port parameter init for 88E6071
net: phy: mv88E61xx: fix ENERGY_DET init for mv88E6071
net: phy: mv88E61xx: add config option for mv88E6071 support
net: phy: mv88e61xx: register phy_driver struct for 88E6071
net: phy: fix switch vendor name
drivers/net/phy/Kconfig | 9 +-
drivers/net/phy/mv88e61xx.c | 189 ++++++++++++++++++++++++++++--------
2 files changed, 156 insertions(+), 42 deletions(-)
--
2.17.1
2
12

27 Oct '19
This series adds support for 88E6071 switches in the mv88e61xx
driver.
Changes in v2:
- fix port init for 6096/6097 devices in patch 1/6
- update commit description in patch 4/6
Anatolij Gustschin (6):
net: phy: mv88e61xx: rework to enable detection of 88E6071 devices
net: phy: mv88e61xx: add CPU port parameter init for 88E6071
net: phy: mv88E61xx: fix ENERGY_DET init for mv88E6071
net: phy: mv88E61xx: add config option for mv88E6071 support
net: phy: mv88e61xx: register phy_driver struct for 88E6071
net: phy: fix switch vendor name
drivers/net/phy/Kconfig | 9 +-
drivers/net/phy/mv88e61xx.c | 168 +++++++++++++++++++++++++++---------
2 files changed, 137 insertions(+), 40 deletions(-)
--
2.17.1
3
24