summaryrefslogtreecommitdiff
path: root/lib/avb/libavb
diff options
context:
space:
mode:
Diffstat (limited to 'lib/avb/libavb')
-rw-r--r--lib/avb/libavb/avb_crc32.c9
-rw-r--r--lib/avb/libavb/avb_ops.h14
-rw-r--r--lib/avb/libavb/avb_rsa.c30
-rw-r--r--lib/avb/libavb/avb_slot_verify.c612
-rw-r--r--lib/avb/libavb/avb_slot_verify.h148
-rw-r--r--lib/avb/libavb/avb_sysdeps.h2
-rw-r--r--lib/avb/libavb/avb_vbmeta_image.h10
-rw-r--r--lib/avb/libavb/avb_version.h4
8 files changed, 643 insertions, 186 deletions
diff --git a/lib/avb/libavb/avb_crc32.c b/lib/avb/libavb/avb_crc32.c
index a6b806d358..7d4cb09035 100644
--- a/lib/avb/libavb/avb_crc32.c
+++ b/lib/avb/libavb/avb_crc32.c
@@ -43,10 +43,11 @@
*/
#include "avb_sysdeps.h"
+#include "avb_util.h"
/* Code taken from FreeBSD 8 */
-static uint32_t crc32_tab[] = {
+static uint32_t iavb_crc32_tab[] = {
0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f,
0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2,
@@ -98,16 +99,16 @@ static uint32_t crc32_tab[] = {
* in sys/libkern.h, where it can be inlined.
*/
-static uint32_t _crc32(uint32_t crc_in, const uint8_t* buf, int size) {
+static uint32_t iavb_crc32(uint32_t crc_in, const uint8_t* buf, int size) {
const uint8_t* p = buf;
uint32_t crc;
crc = crc_in ^ ~0U;
while (size--)
- crc = crc32_tab[(crc ^ *p++) & 0xFF] ^ (crc >> 8);
+ crc = iavb_crc32_tab[(crc ^ *p++) & 0xFF] ^ (crc >> 8);
return crc ^ ~0U;
}
uint32_t avb_crc32(const uint8_t* buf, size_t size) {
- return _crc32(0, buf, size);
+ return iavb_crc32(0, buf, size);
}
diff --git a/lib/avb/libavb/avb_ops.h b/lib/avb/libavb/avb_ops.h
index 908c66c2ff..de36b599c0 100644
--- a/lib/avb/libavb/avb_ops.h
+++ b/lib/avb/libavb/avb_ops.h
@@ -71,6 +71,10 @@ struct AvbAtxOps;
/* High-level operations/functions/methods that are platform
* dependent.
+ *
+ * Operations may be added in the future so when implementing it
+ * always make sure to zero out sizeof(AvbOps) bytes of the struct to
+ * ensure that unimplemented operations are set to NULL.
*/
struct AvbOps {
/* This pointer can be used by the application/bootloader using
@@ -205,6 +209,16 @@ struct AvbOps {
const char* partition,
char* guid_buf,
size_t guid_buf_size);
+
+ /* Gets the size of a partition with the name in |partition|
+ * (NUL-terminated UTF-8 string). Returns the value in
+ * |out_size_num_bytes|.
+ *
+ * Returns AVB_IO_RESULT_OK on success, otherwise an error code.
+ */
+ AvbIOResult (*get_size_of_partition)(AvbOps* ops,
+ const char* partition,
+ uint64_t* out_size_num_bytes);
};
#ifdef __cplusplus
diff --git a/lib/avb/libavb/avb_rsa.c b/lib/avb/libavb/avb_rsa.c
index dcecc16973..f4cb322b9e 100644
--- a/lib/avb/libavb/avb_rsa.c
+++ b/lib/avb/libavb/avb_rsa.c
@@ -37,16 +37,16 @@
#include "avb_util.h"
#include "avb_vbmeta_image.h"
-typedef struct Key {
+typedef struct IAvbKey {
unsigned int len; /* Length of n[] in number of uint32_t */
uint32_t n0inv; /* -1 / n[0] mod 2^32 */
uint32_t* n; /* modulus as array (host-byte order) */
uint32_t* rr; /* R^2 as array (host-byte order) */
-} Key;
+} IAvbKey;
-Key* parse_key_data(const uint8_t* data, size_t length) {
+static IAvbKey* iavb_parse_key_data(const uint8_t* data, size_t length) {
AvbRSAPublicKeyHeader h;
- Key* key = NULL;
+ IAvbKey* key = NULL;
size_t expected_length;
unsigned int i;
const uint8_t* n;
@@ -76,14 +76,14 @@ Key* parse_key_data(const uint8_t* data, size_t length) {
/* Store n and rr following the key header so we only have to do one
* allocation.
*/
- key = (Key*)(avb_malloc(sizeof(Key) + 2 * h.key_num_bits / 8));
+ key = (IAvbKey*)(avb_malloc(sizeof(IAvbKey) + 2 * h.key_num_bits / 8));
if (key == NULL) {
goto fail;
}
key->len = h.key_num_bits / 32;
key->n0inv = h.n0inv;
- key->n = (uint32_t*)(key + 1); /* Skip ahead sizeof(Key) bytes. */
+ key->n = (uint32_t*)(key + 1); /* Skip ahead sizeof(IAvbKey) bytes. */
key->rr = key->n + key->len;
/* Crypto-code below (modpowF4() and friends) expects the key in
@@ -103,12 +103,12 @@ fail:
return NULL;
}
-void free_parsed_key(Key* key) {
+static void iavb_free_parsed_key(IAvbKey* key) {
avb_free(key);
}
/* a[] -= mod */
-static void subM(const Key* key, uint32_t* a) {
+static void subM(const IAvbKey* key, uint32_t* a) {
int64_t A = 0;
uint32_t i;
for (i = 0; i < key->len; ++i) {
@@ -119,7 +119,7 @@ static void subM(const Key* key, uint32_t* a) {
}
/* return a[] >= mod */
-static int geM(const Key* key, uint32_t* a) {
+static int geM(const IAvbKey* key, uint32_t* a) {
uint32_t i;
for (i = key->len; i;) {
--i;
@@ -134,7 +134,7 @@ static int geM(const Key* key, uint32_t* a) {
}
/* montgomery c[] += a * b[] / R % mod */
-static void montMulAdd(const Key* key,
+static void montMulAdd(const IAvbKey* key,
uint32_t* c,
const uint32_t a,
const uint32_t* b) {
@@ -159,7 +159,7 @@ static void montMulAdd(const Key* key,
}
/* montgomery c[] = a[] * b[] / R % mod */
-static void montMul(const Key* key, uint32_t* c, uint32_t* a, uint32_t* b) {
+static void montMul(const IAvbKey* key, uint32_t* c, uint32_t* a, uint32_t* b) {
uint32_t i;
for (i = 0; i < key->len; ++i) {
c[i] = 0;
@@ -172,7 +172,7 @@ static void montMul(const Key* key, uint32_t* c, uint32_t* a, uint32_t* b) {
/* In-place public exponentiation. (65537}
* Input and output big-endian byte array in inout.
*/
-static void modpowF4(const Key* key, uint8_t* inout) {
+static void modpowF4(const IAvbKey* key, uint8_t* inout) {
uint32_t* a = (uint32_t*)avb_malloc(key->len * sizeof(uint32_t));
uint32_t* aR = (uint32_t*)avb_malloc(key->len * sizeof(uint32_t));
uint32_t* aaR = (uint32_t*)avb_malloc(key->len * sizeof(uint32_t));
@@ -237,7 +237,7 @@ bool avb_rsa_verify(const uint8_t* key,
const uint8_t* padding,
size_t padding_num_bytes) {
uint8_t* buf = NULL;
- Key* parsed_key = NULL;
+ IAvbKey* parsed_key = NULL;
bool success = false;
if (key == NULL || sig == NULL || hash == NULL || padding == NULL) {
@@ -245,7 +245,7 @@ bool avb_rsa_verify(const uint8_t* key,
goto out;
}
- parsed_key = parse_key_data(key, key_num_bytes);
+ parsed_key = iavb_parse_key_data(key, key_num_bytes);
if (parsed_key == NULL) {
avb_error("Error parsing key.\n");
goto out;
@@ -290,7 +290,7 @@ bool avb_rsa_verify(const uint8_t* key,
out:
if (parsed_key != NULL) {
- free_parsed_key(parsed_key);
+ iavb_free_parsed_key(parsed_key);
}
if (buf != NULL) {
avb_free(buf);
diff --git a/lib/avb/libavb/avb_slot_verify.c b/lib/avb/libavb/avb_slot_verify.c
index d00b9b9404..0cec5cb7a7 100644
--- a/lib/avb/libavb/avb_slot_verify.c
+++ b/lib/avb/libavb/avb_slot_verify.c
@@ -32,6 +32,7 @@
#include "avb_vbmeta_image.h"
#include "avb_version.h"
#include <common.h>
+#include "android_image.h"
/* Maximum allow length (in bytes) of a partition name, including
* ab_suffix.
@@ -57,6 +58,7 @@ static inline bool result_should_continue(AvbSlotVerifyResult result) {
case AVB_SLOT_VERIFY_RESULT_ERROR_IO:
case AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA:
case AVB_SLOT_VERIFY_RESULT_ERROR_UNSUPPORTED_VERSION:
+ case AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_ARGUMENT:
return false;
case AVB_SLOT_VERIFY_RESULT_OK:
@@ -69,6 +71,8 @@ static inline bool result_should_continue(AvbSlotVerifyResult result) {
return false;
}
+static struct andr_img_hdr boothdr __aligned(ARCH_DMA_MINALIGN);
+
static AvbSlotVerifyResult load_and_verify_hash_partition(
AvbOps* ops,
const char* const* requested_partitions,
@@ -88,6 +92,7 @@ static AvbSlotVerifyResult load_and_verify_hash_partition(
uint8_t* digest;
size_t digest_len;
const char* found;
+ uint64_t image_size;
if (!avb_hash_descriptor_validate_and_byteswap(
(const AvbHashDescriptor*)descriptor, &hash_desc)) {
@@ -106,6 +111,17 @@ static AvbSlotVerifyResult load_and_verify_hash_partition(
goto out;
}
+ /* Don't bother loading or validating unless the partition was
+ * requested in the first place.
+ */
+ found = avb_strv_find_str(requested_partitions,
+ (const char*)desc_partition_name,
+ hash_desc.partition_name_len);
+ if (found == NULL) {
+ ret = AVB_SLOT_VERIFY_RESULT_OK;
+ goto out;
+ }
+
if (!avb_str_concat(part_name,
sizeof part_name,
(const char*)desc_partition_name,
@@ -117,18 +133,70 @@ static AvbSlotVerifyResult load_and_verify_hash_partition(
goto out;
}
- image_buf = avb_malloc(hash_desc.image_size);
- if (image_buf == NULL) {
+ /* If we're allowing verification errors then hash_desc.image_size
+ * may no longer match what's in the partition... so in this case
+ * just load the entire partition.
+ *
+ * For example, this can happen if a developer does 'fastboot flash
+ * boot /path/to/new/and/bigger/boot.img'. We want this to work
+ * since it's such a common workflow.
+ */
+ 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);
+ }
+ }
+
+ /* If we are going to load bootimage, load it to
+ * hdr->kernel_addr - hdr->page_size address directly,
+ * so we don't need to copy it again!*/
+ if (strstr(part_name, "boot") != NULL) {
+ struct andr_img_hdr *hdr = &boothdr;
+ /* read boot header first so we can get the address */
+ if (ops->read_from_partition(ops, part_name,
+ 0, sizeof(boothdr), hdr, &part_num_read) != AVB_IO_RESULT_OK &&
+ part_num_read != sizeof(boothdr)) {
+ printf("Error! read bootimage head error\n");
+ ret = AVB_SLOT_VERIFY_RESULT_ERROR_IO;
+ goto out;
+ }
+ /* check bootimg header to make sure we have a vaild bootimage */
+ if (android_image_check_header(hdr)) {
+ printf("Error! bad boot image magic\n");
+ /* bad boot image magic is critical so we will return
+ * AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA here,
+ * it will make this slot be marked as unbootable.*/
+ ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;
+ goto out;
+ }
+
+ image_buf = (uint8_t*)(unsigned long)(hdr->kernel_addr - hdr->page_size);
+ } else {
+ image_buf = avb_malloc(hash_desc.image_size);
+ if (image_buf == NULL) {
ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
goto out;
+ }
}
- io_ret = ops->read_from_partition(ops,
- part_name,
- 0 /* offset */,
- hash_desc.image_size,
- image_buf,
- &part_num_read);
+ io_ret = ops->read_from_partition(
+ ops, part_name, 0 /* offset */, image_size, image_buf, &part_num_read);
if (io_ret == AVB_IO_RESULT_ERROR_OOM) {
ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
goto out;
@@ -137,7 +205,7 @@ static AvbSlotVerifyResult load_and_verify_hash_partition(
ret = AVB_SLOT_VERIFY_RESULT_ERROR_IO;
goto out;
}
- if (part_num_read != hash_desc.image_size) {
+ if (part_num_read != image_size) {
avb_errorv(part_name, ": Read fewer than requested bytes.\n", NULL);
ret = AVB_SLOT_VERIFY_RESULT_ERROR_IO;
goto out;
@@ -182,25 +250,21 @@ static AvbSlotVerifyResult load_and_verify_hash_partition(
out:
- if (ret == AVB_SLOT_VERIFY_RESULT_OK || result_should_continue(ret)) {
- /* If this is the requested partition, copy to slot_data. */
- found = avb_strv_find_str(requested_partitions,
- (const char*)desc_partition_name,
- hash_desc.partition_name_len);
- if (found != NULL) {
- AvbPartitionData* loaded_partition;
- if (slot_data->num_loaded_partitions == MAX_NUMBER_OF_LOADED_PARTITIONS) {
- avb_errorv(part_name, ": Too many loaded partitions.\n", NULL);
- ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
- goto fail;
- }
- loaded_partition =
- &slot_data->loaded_partitions[slot_data->num_loaded_partitions++];
- loaded_partition->partition_name = avb_strdup(found);
- loaded_partition->data_size = hash_desc.image_size;
- loaded_partition->data = image_buf;
- image_buf = NULL;
+ /* If it worked and something was loaded, copy to slot_data. */
+ if ((ret == AVB_SLOT_VERIFY_RESULT_OK || result_should_continue(ret)) &&
+ image_buf != NULL) {
+ AvbPartitionData* loaded_partition;
+ if (slot_data->num_loaded_partitions == MAX_NUMBER_OF_LOADED_PARTITIONS) {
+ avb_errorv(part_name, ": Too many loaded partitions.\n", NULL);
+ ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
+ goto fail;
}
+ loaded_partition =
+ &slot_data->loaded_partitions[slot_data->num_loaded_partitions++];
+ loaded_partition->partition_name = avb_strdup(found);
+ loaded_partition->data_size = image_size;
+ loaded_partition->data = image_buf;
+ image_buf = NULL;
}
fail:
@@ -210,6 +274,99 @@ fail:
return ret;
}
+static AvbSlotVerifyResult load_requested_partitions(
+ AvbOps* ops,
+ const char* const* requested_partitions,
+ const char* ab_suffix,
+ AvbSlotVerifyData* slot_data) {
+ AvbSlotVerifyResult ret;
+ uint8_t* image_buf = NULL;
+ 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[PART_NAME_MAX_SIZE];
+ AvbIOResult io_ret;
+ uint64_t image_size;
+ size_t part_num_read;
+ AvbPartitionData* loaded_partition;
+
+ if (!avb_str_concat(part_name,
+ sizeof part_name,
+ requested_partitions[n],
+ avb_strlen(requested_partitions[n]),
+ ab_suffix,
+ avb_strlen(ab_suffix))) {
+ avb_error("Partition name and suffix does not fit.\n");
+ ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;
+ goto out;
+ }
+
+ 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);
+
+ image_buf = avb_malloc(image_size);
+ if (image_buf == NULL) {
+ ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
+ goto out;
+ }
+
+ io_ret = ops->read_from_partition(
+ ops, part_name, 0 /* offset */, image_size, image_buf, &part_num_read);
+ 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 loading data from partition.\n", NULL);
+ ret = AVB_SLOT_VERIFY_RESULT_ERROR_IO;
+ goto out;
+ }
+ if (part_num_read != image_size) {
+ avb_errorv(part_name, ": Read fewer than requested bytes.\n", NULL);
+ ret = AVB_SLOT_VERIFY_RESULT_ERROR_IO;
+ goto out;
+ }
+
+ /* Move to slot_data. */
+ if (slot_data->num_loaded_partitions == MAX_NUMBER_OF_LOADED_PARTITIONS) {
+ avb_errorv(part_name, ": Too many loaded partitions.\n", NULL);
+ ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
+ goto out;
+ }
+ loaded_partition =
+ &slot_data->loaded_partitions[slot_data->num_loaded_partitions++];
+ loaded_partition->partition_name = avb_strdup(requested_partitions[n]);
+ if (loaded_partition->partition_name == NULL) {
+ ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
+ goto out;
+ }
+ loaded_partition->data_size = image_size;
+ loaded_partition->data = image_buf;
+ image_buf = NULL;
+ }
+
+ ret = AVB_SLOT_VERIFY_RESULT_OK;
+
+out:
+ if (image_buf != NULL) {
+ avb_free(image_buf);
+ }
+ return ret;
+}
+
static AvbSlotVerifyResult load_and_verify_vbmeta(
AvbOps* ops,
const char* const* requested_partitions,
@@ -442,7 +599,7 @@ static AvbSlotVerifyResult load_and_verify_vbmeta(
}
}
} else {
- bool key_is_trusted = true;
+ bool key_is_trusted = false;
const uint8_t* pk_metadata = NULL;
size_t pk_metadata_len = 0;
@@ -527,6 +684,27 @@ static AvbSlotVerifyResult load_and_verify_vbmeta(
vbmeta_header.auxiliary_data_block_size;
vbmeta_image_data->verify_result = vbmeta_ret;
+ /* If verification has been disabled by setting a bit in the image,
+ * we're done... except that we need to load the entirety of the
+ * requested partitions.
+ */
+ if (vbmeta_header.flags & AVB_VBMETA_IMAGE_FLAGS_VERIFICATION_DISABLED) {
+ AvbSlotVerifyResult sub_ret;
+ avb_debugv(
+ full_partition_name, ": VERIFICATION_DISABLED bit is set.\n", NULL);
+ /* If load_requested_partitions() fail it is always a fatal
+ * failure (e.g. ERROR_INVALID_ARGUMENT, ERROR_OOM, etc.) rather
+ * than recoverable (e.g. one where result_should_continue()
+ * returns true) and we want to convey that error.
+ */
+ sub_ret = load_requested_partitions(
+ ops, requested_partitions, ab_suffix, slot_data);
+ if (sub_ret != AVB_SLOT_VERIFY_RESULT_OK) {
+ ret = sub_ret;
+ }
+ goto out;
+ }
+
/* Now go through all descriptors and take the appropriate action:
*
* - hash descriptor: Load data from partition, calculate hash, and
@@ -920,21 +1098,208 @@ static int cmdline_append_hex(AvbSlotVerifyData* slot_data,
return ret;
}
+static AvbSlotVerifyResult append_options(
+ AvbOps* ops,
+ AvbSlotVerifyData* slot_data,
+ AvbVBMetaImageHeader* toplevel_vbmeta,
+ AvbAlgorithmType algorithm_type,
+ AvbHashtreeErrorMode hashtree_error_mode) {
+ AvbSlotVerifyResult ret;
+ const char* verity_mode = "enforcing";
+ 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.avb_version option. */
+ if (!cmdline_append_version(slot_data,
+ "androidboot.vbmeta.avb_version",
+ AVB_VERSION_MAJOR,
+ AVB_VERSION_MINOR)) {
+ ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
+ goto out;
+ }
+
+ /* Set androidboot.avb.device_state to "locked" or "unlocked". */
+ io_ret = ops->read_is_device_unlocked(ops, &is_device_unlocked);
+ 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_error("Error getting device state.\n");
+ ret = AVB_SLOT_VERIFY_RESULT_ERROR_IO;
+ goto out;
+ }
+ if (!cmdline_append_option(slot_data,
+ "androidboot.vbmeta.device_state",
+ is_device_unlocked ? "unlocked" : "locked")) {
+ ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
+ goto out;
+ }
+
+ /* Set androidboot.vbmeta.{hash_alg, size, digest} - use same hash
+ * function as is used to sign vbmeta.
+ */
+ switch (algorithm_type) {
+ /* Explicit fallthrough. */
+ case AVB_ALGORITHM_TYPE_NONE:
+ case AVB_ALGORITHM_TYPE_SHA256_RSA2048:
+ case AVB_ALGORITHM_TYPE_SHA256_RSA4096:
+ case AVB_ALGORITHM_TYPE_SHA256_RSA8192: {
+ AvbSHA256Ctx ctx;
+ size_t n, total_size = 0;
+ avb_sha256_init(&ctx);
+ for (n = 0; n < slot_data->num_vbmeta_images; n++) {
+ avb_sha256_update(&ctx,
+ slot_data->vbmeta_images[n].vbmeta_data,
+ slot_data->vbmeta_images[n].vbmeta_size);
+ total_size += slot_data->vbmeta_images[n].vbmeta_size;
+ }
+ if (!cmdline_append_option(
+ slot_data, "androidboot.vbmeta.hash_alg", "sha256") ||
+ !cmdline_append_uint64_base10(
+ slot_data, "androidboot.vbmeta.size", total_size) ||
+ !cmdline_append_hex(slot_data,
+ "androidboot.vbmeta.digest",
+ avb_sha256_final(&ctx),
+ AVB_SHA256_DIGEST_SIZE)) {
+ ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
+ goto out;
+ }
+ } break;
+ /* Explicit fallthrough. */
+ case AVB_ALGORITHM_TYPE_SHA512_RSA2048:
+ case AVB_ALGORITHM_TYPE_SHA512_RSA4096:
+ case AVB_ALGORITHM_TYPE_SHA512_RSA8192: {
+ AvbSHA512Ctx ctx;
+ size_t n, total_size = 0;
+ avb_sha512_init(&ctx);
+ for (n = 0; n < slot_data->num_vbmeta_images; n++) {
+ avb_sha512_update(&ctx,
+ slot_data->vbmeta_images[n].vbmeta_data,
+ slot_data->vbmeta_images[n].vbmeta_size);
+ total_size += slot_data->vbmeta_images[n].vbmeta_size;
+ }
+ if (!cmdline_append_option(
+ slot_data, "androidboot.vbmeta.hash_alg", "sha512") ||
+ !cmdline_append_uint64_base10(
+ slot_data, "androidboot.vbmeta.size", total_size) ||
+ !cmdline_append_hex(slot_data,
+ "androidboot.vbmeta.digest",
+ avb_sha512_final(&ctx),
+ AVB_SHA512_DIGEST_SIZE)) {
+ ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
+ goto out;
+ }
+ } break;
+ case _AVB_ALGORITHM_NUM_TYPES:
+ avb_assert_not_reached();
+ break;
+ }
+
+ /* Set androidboot.veritymode and androidboot.vbmeta.invalidate_on_error */
+ if (toplevel_vbmeta->flags & AVB_VBMETA_IMAGE_FLAGS_HASHTREE_DISABLED) {
+ verity_mode = "disabled";
+ } else {
+ const char* dm_verity_mode = "restart_on_corruption";
+ char* new_ret;
+
+ switch (hashtree_error_mode) {
+ case AVB_HASHTREE_ERROR_MODE_RESTART_AND_INVALIDATE:
+ if (!cmdline_append_option(
+ slot_data, "androidboot.vbmeta.invalidate_on_error", "yes")) {
+ ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
+ goto out;
+ }
+ verity_mode = "enforcing";
+ dm_verity_mode = "restart_on_corruption";
+ break;
+ case AVB_HASHTREE_ERROR_MODE_RESTART:
+ verity_mode = "enforcing";
+ dm_verity_mode = "restart_on_corruption";
+ break;
+ case AVB_HASHTREE_ERROR_MODE_EIO:
+ verity_mode = "eio";
+ /* For now there's no option to specify the EIO mode. So
+ * just use 'ignore_zero_blocks' since that's already set
+ * and dm-verity-target.c supports specifying this multiple
+ * times.
+ */
+ dm_verity_mode = "ignore_zero_blocks";
+ break;
+ case AVB_HASHTREE_ERROR_MODE_LOGGING:
+ verity_mode = "logging";
+ dm_verity_mode = "ignore_corruption";
+ break;
+ }
+ new_ret = avb_replace(
+ slot_data->cmdline, "$(ANDROID_VERITY_MODE)", dm_verity_mode);
+ avb_free(slot_data->cmdline);
+ slot_data->cmdline = new_ret;
+ if (slot_data->cmdline == NULL) {
+ ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
+ goto out;
+ }
+ }
+ if (!cmdline_append_option(
+ slot_data, "androidboot.veritymode", verity_mode)) {
+ ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
+ goto out;
+ }
+
+ ret = AVB_SLOT_VERIFY_RESULT_OK;
+
+out:
+
+ return ret;
+}
+
AvbSlotVerifyResult avb_slot_verify(AvbOps* ops,
const char* const* requested_partitions,
const char* ab_suffix,
- bool allow_verification_error,
+ AvbSlotVerifyFlags flags,
+ AvbHashtreeErrorMode hashtree_error_mode,
AvbSlotVerifyData** out_data) {
AvbSlotVerifyResult ret;
AvbSlotVerifyData* slot_data = NULL;
AvbAlgorithmType algorithm_type = AVB_ALGORITHM_TYPE_NONE;
- AvbIOResult io_ret;
bool using_boot_for_vbmeta = false;
+ AvbVBMetaImageHeader toplevel_vbmeta;
+ bool allow_verification_error =
+ (flags & AVB_SLOT_VERIFY_FLAGS_ALLOW_VERIFICATION_ERROR);
+
+ /* 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.
+ */
+ 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->read_rollback_index != NULL);
+ avb_assert(ops->get_unique_guid_for_partition != NULL);
+ /* avb_assert(ops->get_size_of_partition != NULL); */
if (out_data != NULL) {
*out_data = NULL;
}
+ /* Allowing dm-verity errors defeats the purpose of verified boot so
+ * only allow this if set up to allow verification errors
+ * (e.g. typically only UNLOCKED mode).
+ */
+ if (hashtree_error_mode == AVB_HASHTREE_ERROR_MODE_LOGGING &&
+ !allow_verification_error) {
+ ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_ARGUMENT;
+ goto fail;
+ }
+
slot_data = avb_calloc(sizeof(AvbSlotVerifyData));
if (slot_data == NULL) {
ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
@@ -969,14 +1334,19 @@ AvbSlotVerifyResult avb_slot_verify(AvbOps* ops,
goto fail;
}
- 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;
- }
-
/* If things check out, mangle the kernel command-line as needed. */
if (result_should_continue(ret)) {
+ 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);
+
/* Fill in |ab_suffix| field. */
slot_data->ab_suffix = avb_strdup(ab_suffix);
if (slot_data->ab_suffix == NULL) {
@@ -984,21 +1354,35 @@ AvbSlotVerifyResult avb_slot_verify(AvbOps* ops,
goto fail;
}
- /* 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 fail;
- }
-
- /* Add androidboot.vbmeta.avb_version option. */
- if (!cmdline_append_version(slot_data,
- "androidboot.vbmeta.avb_version",
- AVB_VERSION_MAJOR,
- AVB_VERSION_MINOR)) {
- 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 (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);
+ 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 append_options() is either an
+ * I/O or OOM error.
+ */
+ AvbSlotVerifyResult sub_ret = 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;
+ }
}
/* Substitute $(ANDROID_SYSTEM_PARTUUID) and friends. */
@@ -1014,84 +1398,6 @@ AvbSlotVerifyResult avb_slot_verify(AvbOps* ops,
slot_data->cmdline = new_cmdline;
}
- /* Set androidboot.avb.device_state to "locked" or "unlocked". */
- bool is_device_unlocked;
- io_ret = ops->read_is_device_unlocked(ops, &is_device_unlocked);
- if (io_ret == AVB_IO_RESULT_ERROR_OOM) {
- ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
- goto fail;
- } else if (io_ret != AVB_IO_RESULT_OK) {
- avb_error("Error getting device state.\n");
- ret = AVB_SLOT_VERIFY_RESULT_ERROR_IO;
- goto fail;
- }
- if (!cmdline_append_option(slot_data,
- "androidboot.vbmeta.device_state",
- is_device_unlocked ? "unlocked" : "locked")) {
- ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
- goto fail;
- }
-
- /* Set androidboot.vbmeta.{hash_alg, size, digest} - use same hash
- * function as is used to sign vbmeta.
- */
- switch (algorithm_type) {
- /* Explicit fallthrough. */
- case AVB_ALGORITHM_TYPE_NONE:
- case AVB_ALGORITHM_TYPE_SHA256_RSA2048:
- case AVB_ALGORITHM_TYPE_SHA256_RSA4096:
- case AVB_ALGORITHM_TYPE_SHA256_RSA8192: {
- AvbSHA256Ctx ctx;
- size_t n, total_size = 0;
- avb_sha256_init(&ctx);
- for (n = 0; n < slot_data->num_vbmeta_images; n++) {
- avb_sha256_update(&ctx,
- slot_data->vbmeta_images[n].vbmeta_data,
- slot_data->vbmeta_images[n].vbmeta_size);
- total_size += slot_data->vbmeta_images[n].vbmeta_size;
- }
- if (!cmdline_append_option(
- slot_data, "androidboot.vbmeta.hash_alg", "sha256") ||
- !cmdline_append_uint64_base10(
- slot_data, "androidboot.vbmeta.size", total_size) ||
- !cmdline_append_hex(slot_data,
- "androidboot.vbmeta.digest",
- avb_sha256_final(&ctx),
- AVB_SHA256_DIGEST_SIZE)) {
- ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
- goto fail;
- }
- } break;
- /* Explicit fallthrough. */
- case AVB_ALGORITHM_TYPE_SHA512_RSA2048:
- case AVB_ALGORITHM_TYPE_SHA512_RSA4096:
- case AVB_ALGORITHM_TYPE_SHA512_RSA8192: {
- AvbSHA512Ctx ctx;
- size_t n, total_size = 0;
- avb_sha512_init(&ctx);
- for (n = 0; n < slot_data->num_vbmeta_images; n++) {
- avb_sha512_update(&ctx,
- slot_data->vbmeta_images[n].vbmeta_data,
- slot_data->vbmeta_images[n].vbmeta_size);
- total_size += slot_data->vbmeta_images[n].vbmeta_size;
- }
- if (!cmdline_append_option(
- slot_data, "androidboot.vbmeta.hash_alg", "sha512") ||
- !cmdline_append_uint64_base10(
- slot_data, "androidboot.vbmeta.size", total_size) ||
- !cmdline_append_hex(slot_data,
- "androidboot.vbmeta.digest",
- avb_sha512_final(&ctx),
- AVB_SHA512_DIGEST_SIZE)) {
- ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
- goto fail;
- }
- } break;
- case _AVB_ALGORITHM_NUM_TYPES:
- avb_assert_not_reached();
- break;
- }
-
if (out_data != NULL) {
*out_data = slot_data;
} else {
@@ -1107,11 +1413,54 @@ AvbSlotVerifyResult avb_slot_verify(AvbOps* ops,
fail:
if (slot_data != NULL) {
- avb_slot_verify_data_free(slot_data);
+ /* the address of bootimage isn't alloced by malloc,
+ * we should not free it. */
+ avb_slot_verify_data_free_fast(slot_data);
}
return ret;
}
+void avb_slot_verify_data_free_fast(AvbSlotVerifyData* data) {
+ if (data->ab_suffix != NULL) {
+ avb_free(data->ab_suffix);
+ }
+ if (data->cmdline != NULL) {
+ avb_free(data->cmdline);
+ }
+ if (data->vbmeta_images != NULL) {
+ size_t n;
+ for (n = 0; n < data->num_vbmeta_images; n++) {
+ AvbVBMetaData* vbmeta_image = &data->vbmeta_images[n];
+ if (vbmeta_image->partition_name != NULL) {
+ avb_free(vbmeta_image->partition_name);
+ }
+ if (vbmeta_image->vbmeta_data != NULL) {
+ avb_free(vbmeta_image->vbmeta_data);
+ }
+ }
+ avb_free(data->vbmeta_images);
+ }
+ if (data->loaded_partitions != NULL) {
+ size_t n;
+ for (n = 0; n < data->num_loaded_partitions; n++) {
+ AvbPartitionData* loaded_partition = &data->loaded_partitions[n];
+ if (loaded_partition->partition_name != NULL) {
+ /* the address of bootimage isn't alloced by malloc, we don't
+ * need to free it. */
+ if (strstr(loaded_partition->partition_name, "boot") != NULL)
+ continue;
+ else
+ avb_free(loaded_partition->partition_name);
+ }
+ if (loaded_partition->data != NULL) {
+ avb_free(loaded_partition->data);
+ }
+ }
+ avb_free(data->loaded_partitions);
+ }
+ avb_free(data);
+}
+
void avb_slot_verify_data_free(AvbSlotVerifyData* data) {
if (data->ab_suffix != NULL) {
avb_free(data->ab_suffix);
@@ -1176,6 +1525,9 @@ const char* avb_slot_verify_result_to_string(AvbSlotVerifyResult result) {
case AVB_SLOT_VERIFY_RESULT_ERROR_UNSUPPORTED_VERSION:
ret = "ERROR_UNSUPPORTED_VERSION";
break;
+ case AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_ARGUMENT:
+ ret = "ERROR_INVALID_ARGUMENT";
+ break;
/* Do not add a 'default:' case here because of -Wswitch. */
}
diff --git a/lib/avb/libavb/avb_slot_verify.h b/lib/avb/libavb/avb_slot_verify.h
index 08b11fcf1a..60033cfbe3 100644
--- a/lib/avb/libavb/avb_slot_verify.h
+++ b/lib/avb/libavb/avb_slot_verify.h
@@ -50,9 +50,61 @@ typedef enum {
AVB_SLOT_VERIFY_RESULT_ERROR_ROLLBACK_INDEX,
AVB_SLOT_VERIFY_RESULT_ERROR_PUBLIC_KEY_REJECTED,
AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA,
- AVB_SLOT_VERIFY_RESULT_ERROR_UNSUPPORTED_VERSION
+ AVB_SLOT_VERIFY_RESULT_ERROR_UNSUPPORTED_VERSION,
+ AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_ARGUMENT
} AvbSlotVerifyResult;
+/* Various error handling modes for when verification fails using a
+ * hashtree at runtime inside the HLOS.
+ *
+ * AVB_HASHTREE_ERROR_MODE_RESTART_AND_INVALIDATE means that the OS
+ * will invalidate the current slot and restart.
+ *
+ * AVB_HASHTREE_ERROR_MODE_RESTART means that the OS will restart.
+ *
+ * AVB_HASHTREE_ERROR_MODE_EIO means that an EIO error will be
+ * returned to applications.
+ *
+ * AVB_HASHTREE_ERROR_MODE_LOGGING means that errors will be logged
+ * and corrupt data may be returned to applications. This mode should
+ * be used ONLY for diagnostics and debugging. It cannot be used
+ * unless AVB_SLOT_VERIFY_FLAGS_ALLOW_VERIFICATION_ERROR is also
+ * used.
+ */
+typedef enum {
+ AVB_HASHTREE_ERROR_MODE_RESTART_AND_INVALIDATE,
+ AVB_HASHTREE_ERROR_MODE_RESTART,
+ AVB_HASHTREE_ERROR_MODE_EIO,
+ AVB_HASHTREE_ERROR_MODE_LOGGING
+} AvbHashtreeErrorMode;
+
+/* Flags that influence how avb_slot_verify() works.
+ *
+ * If AVB_SLOT_VERIFY_FLAGS_ALLOW_VERIFICATION_ERROR is NOT set then
+ * avb_slot_verify() will bail out as soon as an error is encountered
+ * and |out_data| is set only if AVB_SLOT_VERIFY_RESULT_OK is
+ * returned.
+ *
+ * Otherwise if AVB_SLOT_VERIFY_FLAGS_ALLOW_VERIFICATION_ERROR is set
+ * avb_slot_verify() will continue verification efforts and |out_data|
+ * is also set if AVB_SLOT_VERIFY_RESULT_ERROR_PUBLIC_KEY_REJECTED,
+ * AVB_SLOT_VERIFY_RESULT_ERROR_VERIFICATION, or
+ * AVB_SLOT_VERIFY_RESULT_ERROR_ROLLBACK_INDEX is returned. It is
+ * undefined which error is returned if more than one distinct error
+ * is encountered. It is guaranteed that AVB_SLOT_VERIFY_RESULT_OK is
+ * returned if, and only if, there are no errors. This mode is needed
+ * to boot valid but unverified slots when the device is unlocked.
+ *
+ * Also, if AVB_SLOT_VERIFY_FLAGS_ALLOW_VERIFICATION_ERROR is set the
+ * contents loaded from |requested_partition| will be the contents of
+ * the entire partition instead of just the size specified in the hash
+ * descriptor.
+ */
+typedef enum {
+ AVB_SLOT_VERIFY_FLAGS_NONE = 0,
+ AVB_SLOT_VERIFY_FLAGS_ALLOW_VERIFICATION_ERROR = (1 << 0)
+} AvbSlotVerifyFlags;
+
/* Get a textual representation of |result|. */
const char* avb_slot_verify_result_to_string(AvbSlotVerifyResult result);
@@ -103,7 +155,10 @@ typedef struct {
* avb_slot_verify_data_free() function is called.
*
* The |ab_suffix| field is the copy of the of |ab_suffix| field
- * passed to avb_slot_verify(). It is the A/B suffix of the slot.
+ * passed to avb_slot_verify(). It is the A/B suffix of the slot. This
+ * value includes the leading underscore - typical values are "" (if
+ * no slots are in use), "_a" (for the first slot), and "_b" (for the
+ * second slot).
*
* The VBMeta images that were checked are available in the
* |vbmeta_images| field. The field |num_vbmeta_images| contains the
@@ -132,10 +187,25 @@ typedef struct {
* performing proper substitution of the variables
* $(ANDROID_SYSTEM_PARTUUID), $(ANDROID_BOOT_PARTUUID), and
* $(ANDROID_VBMETA_PARTUUID) using the
- * get_unique_guid_for_partition() operation in |AvbOps|.
+ * get_unique_guid_for_partition() operation in |AvbOps|. Additionally
+ * $(ANDROID_VERITY_MODE) will be replaced with the proper dm-verity
+ * option depending on the value of |hashtree_error_mode|.
*
* Additionally, the |cmdline| field will have the following kernel
- * command-line options set:
+ * command-line options set (unless verification is disabled, see
+ * below):
+ *
+ * androidboot.veritymode: This is set to 'disabled' if the
+ * AVB_VBMETA_IMAGE_FLAGS_HASHTREE_DISABLED flag is set in top-level
+ * vbmeta struct. Otherwise it is set to 'enforcing' if the
+ * passed-in hashtree error mode is AVB_HASHTREE_ERROR_MODE_RESTART
+ * or AVB_HASHTREE_ERROR_MODE_RESTART_AND_INVALIDATE, 'eio' if it's
+ * set to AVB_HASHTREE_ERROR_MODE_EIO, and 'logging' if it's set to
+ * AVB_HASHTREE_ERROR_MODE_LOGGING.
+ *
+ * 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.
*
* androidboot.vbmeta.device_state: set to "locked" or "unlocked"
* depending on the result of the result of AvbOps's
@@ -158,8 +228,20 @@ typedef struct {
* necessarily the same version number of the on-disk metadata for
* the slot that was verified.
*
- * Note that androidboot.slot_suffix is not set in |cmdline| - you
- * will have to pass this command-line option yourself.
+ * Note that androidboot.slot_suffix is not set in the |cmdline| field
+ * in |AvbSlotVerifyData| - you will have to set this yourself.
+ *
+ * If the |AVB_VBMETA_IMAGE_FLAGS_VERIFICATION_DISABLED| flag is set
+ * in the top-level vbmeta struct then only the top-level vbmeta
+ * struct is verified and descriptors will not processed. The return
+ * value will be set accordingly (if this flag is set via 'avbctl
+ * disable-verification' then the return value will be
+ * |AVB_SLOT_VERIFY_RESULT_ERROR_VERIFICATION|) and
+ * |AvbSlotVerifyData| is returned. Additionally all partitions in the
+ * |requested_partitions| are loaded and the |cmdline| field is set to
+ * "root=PARTUUID=$(ANDROID_SYSTEM_PARTUUID)" and the GUID for the
+ * appropriate system partition is substituted in. Note that none of
+ * the androidboot.* options mentioned above will be set.
*
* This struct may grow in the future without it being considered an
* ABI break.
@@ -174,23 +256,28 @@ typedef struct {
uint64_t rollback_indexes[AVB_MAX_NUMBER_OF_ROLLBACK_INDEX_LOCATIONS];
} AvbSlotVerifyData;
+/* Fast version of avb_slot_verify_data_free, this method will not
+ * free bootimage */
+void avb_slot_verify_data_free_fast(AvbSlotVerifyData* data);
/* Frees a |AvbSlotVerifyData| including all data it points to. */
void avb_slot_verify_data_free(AvbSlotVerifyData* data);
/* Performs a full verification of the slot identified by |ab_suffix|
- * and load the contents of the partitions whose name is in the
- * NULL-terminated string array |requested_partitions| (each partition
- * must use hash verification). If not using A/B, pass an empty string
- * (e.g. "", not NULL) for |ab_suffix|.
+ * and load and verify the contents of the partitions whose name is in
+ * the NULL-terminated string array |requested_partitions| (each
+ * partition must use hash verification). If not using A/B, pass an
+ * empty string (e.g. "", not NULL) for |ab_suffix|. This parameter
+ * must include the leading underscore, for example "_a" should be
+ * used to refer to the first slot.
*
* Typically the |requested_partitions| array only contains a single
* item for the boot partition, 'boot'.
*
- * Verification includes loading data from the 'vbmeta', all hash
- * partitions, and possibly other partitions (with |ab_suffix|
- * appended), inspecting rollback indexes, and checking if the public
- * key used to sign the data is acceptable. The functions in |ops|
- * will be used to do this.
+ * Verification includes loading and verifying data from the 'vbmeta',
+ * the requested hash partitions, and possibly other partitions (with
+ * |ab_suffix| appended), inspecting rollback indexes, and checking if
+ * the public key used to sign the data is acceptable. The functions
+ * in |ops| will be used to do this.
*
* If |out_data| is not NULL, it will be set to a newly allocated
* |AvbSlotVerifyData| struct containing all the data needed to
@@ -198,19 +285,18 @@ void avb_slot_verify_data_free(AvbSlotVerifyData* data);
* avb_slot_verify_data_free() when you are done with it. See below
* for when this is returned.
*
- * If |allow_verification_error| is false this function will bail out
- * as soon as an error is encountered and |out_data| is set only if
- * AVB_SLOT_VERIFY_RESULT_OK is returned.
+ * The |flags| parameter is used to influence the semantics of
+ * avb_slot_verify() - for example the
+ * AVB_SLOT_VERIFY_FLAGS_ALLOW_VERIFICATION_ERROR flag can be used to
+ * ignore verification errors which is something needed in the
+ * UNLOCKED state. See the AvbSlotVerifyFlags enumeration for details.
*
- * Otherwise if |allow_verification_error| is true the function will
- * continue verification efforts and |out_data| is also set if
- * AVB_SLOT_VERIFY_RESULT_ERROR_PUBLIC_KEY_REJECTED,
- * AVB_SLOT_VERIFY_RESULT_ERROR_VERIFICATION, or
- * AVB_SLOT_VERIFY_RESULT_ERROR_ROLLBACK_INDEX is returned. It is
- * undefined which error is returned if more than one distinct error
- * is encountered. It is guaranteed that AVB_SLOT_VERIFY_RESULT_OK is
- * returned if, and only if, there are no errors. This mode is needed
- * to boot valid but unverified slots when the device is unlocked.
+ * 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.
*
* Also note that |out_data| is never set if
* AVB_SLOT_VERIFY_RESULT_ERROR_OOM, AVB_SLOT_VERIFY_RESULT_ERROR_IO,
@@ -243,11 +329,17 @@ void avb_slot_verify_data_free(AvbSlotVerifyData* data);
* AVB_SLOT_VERIFY_RESULT_ERROR_UNSUPPORTED_VERSION is returned if
* some of the metadata requires a newer version of libavb than what
* is in use.
+ *
+ * AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_ARGUMENT is returned if the
+ * caller passed invalid parameters, for example trying to use
+ * AVB_HASHTREE_ERROR_MODE_LOGGING without
+ * AVB_SLOT_VERIFY_FLAGS_ALLOW_VERIFICATION_ERROR.
*/
AvbSlotVerifyResult avb_slot_verify(AvbOps* ops,
const char* const* requested_partitions,
const char* ab_suffix,
- bool allow_verification_error,
+ AvbSlotVerifyFlags flags,
+ AvbHashtreeErrorMode hashtree_error_mode,
AvbSlotVerifyData** out_data);
#ifdef __cplusplus
diff --git a/lib/avb/libavb/avb_sysdeps.h b/lib/avb/libavb/avb_sysdeps.h
index dfad04f808..34556e22c8 100644
--- a/lib/avb/libavb/avb_sysdeps.h
+++ b/lib/avb/libavb/avb_sysdeps.h
@@ -38,8 +38,6 @@ extern "C" {
* like uint8_t, uint64_t, and bool (with |false|, |true| keywords)
* must be present.
*/
-
-//#define bool int
#include <common.h>
/* If you don't have gcc or clang, these attribute macros may need to
diff --git a/lib/avb/libavb/avb_vbmeta_image.h b/lib/avb/libavb/avb_vbmeta_image.h
index 0df7126390..d0c9f15376 100644
--- a/lib/avb/libavb/avb_vbmeta_image.h
+++ b/lib/avb/libavb/avb_vbmeta_image.h
@@ -52,9 +52,13 @@ extern "C" {
*
* AVB_VBMETA_IMAGE_FLAGS_HASHTREE_DISABLED: If this flag is set,
* hashtree image verification will be disabled.
+ *
+ * AVB_VBMETA_IMAGE_FLAGS_VERIFICATION_DISABLED: If this flag is set,
+ * verification will be disabled and descriptors will not be parsed.
*/
typedef enum {
- AVB_VBMETA_IMAGE_FLAGS_HASHTREE_DISABLED = (1 << 0)
+ AVB_VBMETA_IMAGE_FLAGS_HASHTREE_DISABLED = (1 << 0),
+ AVB_VBMETA_IMAGE_FLAGS_VERIFICATION_DISABLED = (1 << 1)
} AvbVBMetaImageFlags;
/* Binary format for header of the vbmeta image.
@@ -107,8 +111,8 @@ typedef enum {
* minimum version of libavb required to verify the header and depends
* on the features (e.g. algorithms, descriptors) used. Note that this
* may be 1.0 even if generated by an avbtool from 1.4 but where no
- * features introduced after 1.0 has been used. See the VERSIONING AND
- * COMPATIBILITY section in the README file for more details.
+ * features introduced after 1.0 has been used. See the "Versioning
+ * and compatibility" section in the README.md file for more details.
*
* All fields are stored in network byte order when serialized. To
* generate a copy with fields swapped to native byte order, use the
diff --git a/lib/avb/libavb/avb_version.h b/lib/avb/libavb/avb_version.h
index 7757d090d3..9d92970074 100644
--- a/lib/avb/libavb/avb_version.h
+++ b/lib/avb/libavb/avb_version.h
@@ -52,10 +52,6 @@ extern "C" {
*/
const char* avb_version_string(void);
-/* TODO: remove when there are no more users of AVB_{MAJOR,MINOR}_VERSION. */
-#define AVB_MAJOR_VERSION AVB_VERSION_MAJOR
-#define AVB_MINOR_VERSION AVB_VERSION_MINOR
-
#ifdef __cplusplus
}
#endif