summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTom Rini <[email protected]>2026-07-28 07:50:18 -0600
committerTom Rini <[email protected]>2026-07-28 07:52:00 -0600
commit9f934c71810e349949ce674e33099dface1ba6f4 (patch)
tree00ad1b295fa7057c72d46d2d3ed7d91feea42067
parent134ad3c3c0778b5badabdc24fd946a97bdf28c4b (diff)
parente6f091a208276db72596c8f7376648856a276d97 (diff)
Merge tag 'u-boot-dfu-20260728' of https://git.u-boot-project.org/u-boot/custodians/u-boot-dfu
u-boot-dfu-20260728 CI: https://git.u-boot-project.org/u-boot/custodians/u-boot-dfu/-/pipelines/769 Android: * avb: Update libavb to AOSP 1.3.0 * avb: Fix memory leak on mmc_part * bootmeth_android: Fix memory leaks for AvbOps and verify-data * bootmeth_android: Fix out-of-bounds access in bootconfig parsing USB Gadget: * cmd: ums: Set serial# on iSerial device descriptor * dwc2: Set maxpacket_limit and endpoint capabilities to prepare for udc core migration * ci_udc: Fix ep type in ep_enable() * ci_udc: Set usb request status to handle complete callback * ci_udc: Ensure dtds are inactive before completing request
-rw-r--r--boot/bootmeth_android.c37
-rw-r--r--boot/image-android.c30
-rw-r--r--common/avb_verify.c29
-rw-r--r--doc/android/avb2.rst7
-rw-r--r--drivers/usb/gadget/ci_udc.c30
-rw-r--r--drivers/usb/gadget/ci_udc.h4
-rw-r--r--drivers/usb/gadget/dwc2_udc_otg.c26
-rw-r--r--drivers/usb/gadget/f_mass_storage.c8
-rw-r--r--lib/libavb/avb_chain_partition_descriptor.c1
-rw-r--r--lib/libavb/avb_chain_partition_descriptor.h16
-rw-r--r--lib/libavb/avb_cmdline.c42
-rw-r--r--lib/libavb/avb_descriptor.c62
-rw-r--r--lib/libavb/avb_hashtree_descriptor.h3
-rw-r--r--lib/libavb/avb_property_descriptor.h8
-rw-r--r--lib/libavb/avb_rsa.c6
-rw-r--r--lib/libavb/avb_slot_verify.c311
-rw-r--r--lib/libavb/avb_slot_verify.h6
-rw-r--r--lib/libavb/avb_util.c46
-rw-r--r--lib/libavb/avb_util.h140
-rw-r--r--lib/libavb/avb_vbmeta_image.c1
-rw-r--r--lib/libavb/avb_vbmeta_image.h8
-rw-r--r--lib/libavb/avb_version.h2
22 files changed, 500 insertions, 323 deletions
diff --git a/boot/bootmeth_android.c b/boot/bootmeth_android.c
index 1d70e8d5c05..ec255b072af 100644
--- a/boot/bootmeth_android.c
+++ b/boot/bootmeth_android.c
@@ -428,7 +428,7 @@ static int run_avb_verification(struct bootflow *bflow)
const char * const requested_partitions[] = {"boot", "vendor_boot", NULL};
struct AvbOps *avb_ops;
AvbSlotVerifyResult result;
- AvbSlotVerifyData *out_data;
+ AvbSlotVerifyData *out_data = NULL;
enum avb_boot_state boot_state;
char *extra_args;
char slot_suffix[3] = "";
@@ -443,8 +443,10 @@ static int run_avb_verification(struct bootflow *bflow)
sprintf(slot_suffix, "_%s", priv->slot);
ret = avb_ops->read_is_device_unlocked(avb_ops, &unlocked);
- if (ret != AVB_IO_RESULT_OK)
- return log_msg_ret("avb lock", -EIO);
+ if (ret != AVB_IO_RESULT_OK) {
+ ret = log_msg_ret("avb lock", -EIO);
+ goto out;
+ }
result = avb_slot_verify(avb_ops,
requested_partitions,
@@ -458,9 +460,8 @@ static int run_avb_verification(struct bootflow *bflow)
if (result != AVB_SLOT_VERIFY_RESULT_OK) {
printf("Verification failed, reason: %s\n",
str_avb_slot_error(result));
- if (out_data)
- avb_slot_verify_data_free(out_data);
- return log_msg_ret("avb verify", -EIO);
+ ret = log_msg_ret("avb verify", -EIO);
+ goto out;
}
boot_state = AVB_GREEN;
} else {
@@ -469,9 +470,8 @@ static int run_avb_verification(struct bootflow *bflow)
result != AVB_SLOT_VERIFY_RESULT_ERROR_VERIFICATION) {
printf("Unlocked verification failed, reason: %s\n",
str_avb_slot_error(result));
- if (out_data)
- avb_slot_verify_data_free(out_data);
- return log_msg_ret("avb verify unlocked", -EIO);
+ ret = log_msg_ret("avb verify unlocked", -EIO);
+ goto out;
}
boot_state = AVB_ORANGE;
}
@@ -480,23 +480,28 @@ static int run_avb_verification(struct bootflow *bflow)
if (extra_args) {
/* extra_args will be modified after this. This is fine */
ret = avb_append_commandline_arg(bflow, extra_args);
- if (ret < 0)
- goto free_out_data;
+ if (ret < 0) {
+ ret = log_msg_ret("avb cmdline", ret);
+ goto out;
+ }
}
if (result == AVB_SLOT_VERIFY_RESULT_OK) {
ret = avb_append_commandline(bflow, out_data->cmdline);
- if (ret < 0)
- goto free_out_data;
+ if (ret < 0) {
+ ret = log_msg_ret("avb cmdline", ret);
+ goto out;
+ }
}
- return 0;
+ ret = 0;
- free_out_data:
+ out:
if (out_data)
avb_slot_verify_data_free(out_data);
+ avb_ops_free(avb_ops);
- return log_msg_ret("avb cmdline", ret);
+ return ret;
}
#else
static int run_avb_verification(struct bootflow *bflow)
diff --git a/boot/image-android.c b/boot/image-android.c
index fb26290d40c..7740cae8cb6 100644
--- a/boot/image-android.c
+++ b/boot/image-android.c
@@ -131,7 +131,8 @@ static void android_boot_image_v3_v4_parse_hdr(const struct andr_boot_img_hdr_v3
}
static void android_vendor_boot_image_v3_v4_parse_hdr(const struct andr_vnd_boot_img_hdr
- *hdr, struct andr_image_data *data)
+ *hdr, struct andr_image_data *data,
+ bool write_trailer)
{
ulong end;
@@ -167,12 +168,23 @@ static void android_vendor_boot_image_v3_v4_parse_hdr(const struct andr_vnd_boot
end += ALIGN(hdr->vendor_ramdisk_table_size, hdr->page_size);
data->bootconfig_addr = end;
if (hdr->bootconfig_size) {
- void *bootconfig_ptr = map_sysmem(data->bootconfig_addr,
- data->bootconfig_size +
- BOOTCONFIG_TRAILER_SIZE);
- data->bootconfig_size += add_trailer((ulong)bootconfig_ptr,
- data->bootconfig_size);
- unmap_sysmem(bootconfig_ptr);
+ if (write_trailer) {
+ void *bootconfig_ptr = map_sysmem(data->bootconfig_addr,
+ data->bootconfig_size +
+ BOOTCONFIG_TRAILER_SIZE);
+ data->bootconfig_size += add_trailer((ulong)bootconfig_ptr,
+ data->bootconfig_size);
+ unmap_sysmem(bootconfig_ptr);
+ } else {
+ /*
+ * Only the header has been loaded here (this is a
+ * size-only query), so the bootconfig region is not
+ * present in the buffer. Account for the trailer that
+ * will be appended at load time without writing it, to
+ * avoid corrupting memory past the header buffer.
+ */
+ data->bootconfig_size += BOOTCONFIG_TRAILER_SIZE;
+ }
data->ramdisk_size += data->bootconfig_size;
}
end += ALIGN(data->bootconfig_size, hdr->page_size);
@@ -265,7 +277,7 @@ bool android_image_get_vendor_bootimg_size(const void *hdr, u32 *vendor_boot_img
return false;
}
- android_vendor_boot_image_v3_v4_parse_hdr(hdr, &data);
+ android_vendor_boot_image_v3_v4_parse_hdr(hdr, &data, false);
*vendor_boot_img_size = data.vendor_boot_img_total_size;
@@ -304,7 +316,7 @@ bool android_image_get_data(const void *boot_hdr, const void *vendor_boot_hdr,
return false;
}
android_boot_image_v3_v4_parse_hdr((const struct andr_boot_img_hdr_v3 *)bhdr, data);
- android_vendor_boot_image_v3_v4_parse_hdr(vhdr, data);
+ android_vendor_boot_image_v3_v4_parse_hdr(vhdr, data, true);
unmap_sysmem(vhdr);
} else {
android_boot_image_v0_v1_v2_parse_hdr(bhdr, data);
diff --git a/common/avb_verify.c b/common/avb_verify.c
index 29a3272579c..76c523fd0ba 100644
--- a/common/avb_verify.c
+++ b/common/avb_verify.c
@@ -452,6 +452,7 @@ static AvbIOResult mmc_byte_io(AvbOps *ops,
u64 start_offset, start_sector, sectors, residue;
u8 *tmp_buf;
size_t io_cnt = 0;
+ AvbIOResult io_ret = AVB_IO_RESULT_OK;
if (!partition || !buffer || io_type > IO_WRITE)
return AVB_IO_RESULT_ERROR_IO;
@@ -460,8 +461,10 @@ static AvbIOResult mmc_byte_io(AvbOps *ops,
if (!part)
return AVB_IO_RESULT_ERROR_NO_SUCH_PARTITION;
- if (!part->info.blksz)
- return AVB_IO_RESULT_ERROR_IO;
+ if (!part->info.blksz) {
+ io_ret = AVB_IO_RESULT_ERROR_IO;
+ goto out;
+ }
start_offset = calc_offset(part, offset);
while (num_bytes) {
@@ -489,7 +492,8 @@ static AvbIOResult mmc_byte_io(AvbOps *ops,
if (ret != 1) {
printf("%s: read error (%ld, %lld)\n",
__func__, ret, start_sector);
- return AVB_IO_RESULT_ERROR_IO;
+ io_ret = AVB_IO_RESULT_ERROR_IO;
+ goto out;
}
/*
* if this is not aligned at sector start,
@@ -506,7 +510,8 @@ static AvbIOResult mmc_byte_io(AvbOps *ops,
if (ret != 1) {
printf("%s: read error (%ld, %lld)\n",
__func__, ret, start_sector);
- return AVB_IO_RESULT_ERROR_IO;
+ io_ret = AVB_IO_RESULT_ERROR_IO;
+ goto out;
}
memcpy((void *)tmp_buf +
start_offset % part->info.blksz,
@@ -517,7 +522,8 @@ static AvbIOResult mmc_byte_io(AvbOps *ops,
if (ret != 1) {
printf("%s: write error (%ld, %lld)\n",
__func__, ret, start_sector);
- return AVB_IO_RESULT_ERROR_IO;
+ io_ret = AVB_IO_RESULT_ERROR_IO;
+ goto out;
}
}
@@ -543,7 +549,8 @@ static AvbIOResult mmc_byte_io(AvbOps *ops,
if (!ret) {
printf("%s: sector read error\n", __func__);
- return AVB_IO_RESULT_ERROR_IO;
+ io_ret = AVB_IO_RESULT_ERROR_IO;
+ goto out;
}
io_cnt += ret * part->info.blksz;
@@ -557,7 +564,9 @@ static AvbIOResult mmc_byte_io(AvbOps *ops,
if (io_type == IO_READ && out_num_read)
*out_num_read = io_cnt;
- return AVB_IO_RESULT_OK;
+out:
+ free(part);
+ return io_ret;
}
/**
@@ -867,12 +876,15 @@ static AvbIOResult get_unique_guid_for_partition(AvbOps *ops,
return AVB_IO_RESULT_ERROR_NO_SUCH_PARTITION;
uuid_size = sizeof(part->info.uuid);
- if (uuid_size > guid_buf_size)
+ if (uuid_size > guid_buf_size) {
+ free(part);
return AVB_IO_RESULT_ERROR_IO;
+ }
memcpy(guid_buf, part->info.uuid, uuid_size);
guid_buf[uuid_size - 1] = 0;
+ free(part);
return AVB_IO_RESULT_OK;
}
@@ -903,6 +915,7 @@ static AvbIOResult get_size_of_partition(AvbOps *ops,
return AVB_IO_RESULT_ERROR_NO_SUCH_PARTITION;
*out_size_num_bytes = part->info.blksz * part->info.size;
+ free(part);
return AVB_IO_RESULT_OK;
}
diff --git a/doc/android/avb2.rst b/doc/android/avb2.rst
index 4aca7a5c660..178e8a2681e 100644
--- a/doc/android/avb2.rst
+++ b/doc/android/avb2.rst
@@ -22,6 +22,11 @@ Verified Boot establishes a chain of trust from the bootloader to system images:
Integrity of the bootloader (U-Boot BLOB and environment) is out of scope.
+Verification is performed by libavb, which is vendored under ``lib/libavb/``
+from the AOSP ``external/avb`` project (AVB version 1.3.0). Only the U-Boot
+integration in ``common/avb_verify.c`` and the platform port under
+``lib/libavb/avb_sysdeps*`` are U-Boot-specific.
+
For additional details check [1]_.
AVB using OP-TEE (optional)
@@ -135,5 +140,5 @@ partition table::
References
----------
-.. [1] https://android.googlesource.com/platform/external/avb/+/master/README.md
+.. [1] https://android.googlesource.com/platform/external/avb/+/a1fe228b86543a21739c51352f5ce72f134fccfa/README.md
.. [2] https://www.op-tee.org/
diff --git a/drivers/usb/gadget/ci_udc.c b/drivers/usb/gadget/ci_udc.c
index 4729570c525..53796887dac 100644
--- a/drivers/usb/gadget/ci_udc.c
+++ b/drivers/usb/gadget/ci_udc.c
@@ -333,16 +333,16 @@ static void request_complete_list(struct usb_ep *ep, struct list_head *list, int
}
}
-static void ep_enable(int num, int in, int maxpacket)
+static void ep_enable(int num, int in, int type, int maxpacket)
{
struct ci_udc *udc = (struct ci_udc *)controller.ctrl->hcor;
unsigned n;
n = readl(&udc->epctrl[num]);
if (in)
- n |= (CTRL_TXE | CTRL_TXR | CTRL_TXT_BULK);
+ n |= (CTRL_TXE | CTRL_TXR | CTRL_TXT(type));
else
- n |= (CTRL_RXE | CTRL_RXR | CTRL_RXT_BULK);
+ n |= (CTRL_RXE | CTRL_RXR | CTRL_RXT(type));
if (num != 0) {
struct ept_queue_head *head = ci_get_qh(num, in);
@@ -357,7 +357,7 @@ static int ci_ep_enable(struct usb_ep *ep,
const struct usb_endpoint_descriptor *desc)
{
struct ci_ep *ci_ep = container_of(ep, struct ci_ep, ep);
- int num, in;
+ int num, in, type;
num = desc->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK;
in = (desc->bEndpointAddress & USB_DIR_IN) != 0;
@@ -366,6 +366,7 @@ static int ci_ep_enable(struct usb_ep *ep,
return -EBUSY;
}
+ type = usb_endpoint_type(desc);
ci_ep->desc = desc;
ep->desc = desc;
@@ -380,7 +381,7 @@ static int ci_ep_enable(struct usb_ep *ep,
ep->maxpacket = max;
}
}
- ep_enable(num, in, ep->maxpacket);
+ ep_enable(num, in, type, ep->maxpacket);
DBG("%s: num=%d maxpacket=%d\n", __func__, num, ep->maxpacket);
return 0;
}
@@ -679,6 +680,8 @@ static int ci_ep_queue(struct usb_ep *ep,
if (ret)
return ret;
+ req->status = -EINPROGRESS;
+
DBG("ept%d %s pre-queue req %p, buffer %p\n",
num, in ? "in" : "out", ci_req, ci_req->hw_buf);
list_add_tail(&ci_req->queue, &ci_ep->queue);
@@ -730,6 +733,17 @@ static void handle_ep_complete(struct ci_ep *ci_ep)
ci_invalidate_qtd(num);
ci_req = list_first_entry(&ci_ep->queue, struct ci_req, queue);
+ /* Check all dtd are completed, otherwise return for next irq process */
+ next_td = item;
+ for (j = 0; j < ci_req->dtd_count; j++) {
+ ci_invalidate_td(next_td);
+ if (next_td->info & INFO_ACTIVE)
+ return;
+ if (j != ci_req->dtd_count - 1)
+ next_td = (struct ept_queue_item *)(unsigned long)
+ next_td->next;
+ }
+
next_td = item;
len = 0;
for (j = 0; j < ci_req->dtd_count; j++) {
@@ -753,6 +767,7 @@ static void handle_ep_complete(struct ci_ep *ci_ep)
ci_ep_submit_next_request(ci_ep);
ci_req->req.actual = ci_req->req.length - len;
+ ci_req->req.status = 0;
ci_debounce(ci_req, in);
DBG("ept%d %s req %p, complete %x\n",
@@ -783,7 +798,7 @@ static void handle_setup(void)
struct ept_queue_head *head;
struct usb_ctrlrequest r;
int status = 0;
- int num, in, _num, _in, i;
+ int num, in, _num, _in, i, type;
char *buf;
ci_req = controller.ep0_req;
@@ -837,8 +852,9 @@ static void handle_setup(void)
& USB_ENDPOINT_NUMBER_MASK;
in = (ep->desc->bEndpointAddress
& USB_DIR_IN) != 0;
+ type = usb_endpoint_type(ep->desc);
if ((num == _num) && (in == _in)) {
- ep_enable(num, in, ep->ep.maxpacket);
+ ep_enable(num, in, type, ep->ep.maxpacket);
usb_ep_queue(controller.gadget.ep0,
req, 0);
break;
diff --git a/drivers/usb/gadget/ci_udc.h b/drivers/usb/gadget/ci_udc.h
index 807f2084c1e..f1c4537859e 100644
--- a/drivers/usb/gadget/ci_udc.h
+++ b/drivers/usb/gadget/ci_udc.h
@@ -74,8 +74,8 @@ struct ci_udc {
#define CTRL_TXR (1 << 22)
#define CTRL_RXE (1 << 7)
#define CTRL_RXR (1 << 6)
-#define CTRL_TXT_BULK (2 << 18)
-#define CTRL_RXT_BULK (2 << 2)
+#define CTRL_TXT(t) ((t) << 18)
+#define CTRL_RXT(t) ((t) << 2)
struct ci_req {
struct usb_request req;
diff --git a/drivers/usb/gadget/dwc2_udc_otg.c b/drivers/usb/gadget/dwc2_udc_otg.c
index e475b14b9ac..570fed347c9 100644
--- a/drivers/usb/gadget/dwc2_udc_otg.c
+++ b/drivers/usb/gadget/dwc2_udc_otg.c
@@ -828,7 +828,11 @@ static struct dwc2_udc memory = {
.ep = {
.name = ep0name,
.ops = &dwc2_ep_ops,
- .maxpacket = EP0_FIFO_SIZE,
+ .caps = {
+ .type_control = 1,
+ .dir_in = 1,
+ .dir_out = 1,
+ },
},
.dev = &memory,
@@ -843,7 +847,10 @@ static struct dwc2_udc memory = {
.ep = {
.name = "ep1in-bulk",
.ops = &dwc2_ep_ops,
- .maxpacket = EP_FIFO_SIZE,
+ .caps = {
+ .type_bulk = 1,
+ .dir_in = 1,
+ },
},
.dev = &memory,
@@ -858,7 +865,10 @@ static struct dwc2_udc memory = {
.ep = {
.name = "ep2out-bulk",
.ops = &dwc2_ep_ops,
- .maxpacket = EP_FIFO_SIZE,
+ .caps = {
+ .type_bulk = 1,
+ .dir_out = 1,
+ },
},
.dev = &memory,
@@ -873,7 +883,10 @@ static struct dwc2_udc memory = {
.ep = {
.name = "ep3in-int",
.ops = &dwc2_ep_ops,
- .maxpacket = EP_FIFO_SIZE,
+ .caps = {
+ .type_int = 1,
+ .dir_in = 1,
+ },
},
.dev = &memory,
@@ -893,6 +906,7 @@ int dwc2_udc_probe(struct dwc2_plat_otg_data *pdata)
{
struct dwc2_udc *dev = &memory;
int retval = 0;
+ int i;
debug("%s: %p\n", __func__, pdata);
@@ -909,6 +923,10 @@ int dwc2_udc_probe(struct dwc2_plat_otg_data *pdata)
the_controller = dev;
+ usb_ep_set_maxpacket_limit(&dev->ep[0].ep, EP0_FIFO_SIZE);
+ for (i = 1; i < DWC2_MAX_ENDPOINTS; i++)
+ usb_ep_set_maxpacket_limit(&dev->ep[i].ep, EP_FIFO_SIZE);
+
usb_ctrl = memalign(CONFIG_SYS_CACHELINE_SIZE,
ROUND(sizeof(struct usb_ctrlrequest),
CONFIG_SYS_CACHELINE_SIZE));
diff --git a/drivers/usb/gadget/f_mass_storage.c b/drivers/usb/gadget/f_mass_storage.c
index 87ed25e8bb3..7eb667c130d 100644
--- a/drivers/usb/gadget/f_mass_storage.c
+++ b/drivers/usb/gadget/f_mass_storage.c
@@ -241,6 +241,7 @@
#include <config.h>
#include <div64.h>
+#include <env.h>
#include <hexdump.h>
#include <log.h>
#include <malloc.h>
@@ -2662,8 +2663,15 @@ static int fsg_bind(struct usb_configuration *c, struct usb_function *f)
struct usb_gadget *gadget = c->cdev->gadget;
int i;
struct usb_ep *ep;
+ char __maybe_unused *sn;
fsg->gadget = gadget;
+ if (CONFIG_IS_ENABLED(ENV_SUPPORT)) {
+ sn = env_get("serial#");
+ if (sn)
+ g_dnl_set_serialnumber(sn);
+ }
+
/* New interface */
i = usb_interface_id(c, f);
if (i < 0)
diff --git a/lib/libavb/avb_chain_partition_descriptor.c b/lib/libavb/avb_chain_partition_descriptor.c
index e2993063103..0354276c64a 100644
--- a/lib/libavb/avb_chain_partition_descriptor.c
+++ b/lib/libavb/avb_chain_partition_descriptor.c
@@ -24,6 +24,7 @@ bool avb_chain_partition_descriptor_validate_and_byteswap(
dest->rollback_index_location = avb_be32toh(dest->rollback_index_location);
dest->partition_name_len = avb_be32toh(dest->partition_name_len);
dest->public_key_len = avb_be32toh(dest->public_key_len);
+ dest->flags = avb_be32toh(dest->flags);
if (dest->rollback_index_location < 1) {
avb_error("Invalid rollback index location value.\n");
diff --git a/lib/libavb/avb_chain_partition_descriptor.h b/lib/libavb/avb_chain_partition_descriptor.h
index 80e2271782e..31c7298d1df 100644
--- a/lib/libavb/avb_chain_partition_descriptor.h
+++ b/lib/libavb/avb_chain_partition_descriptor.h
@@ -16,6 +16,16 @@
extern "C" {
#endif
+/* Flags for chain descriptors.
+ *
+ * AVB_CHAIN_PARTITION_DESCRIPTOR_FLAGS_DO_NOT_USE_AB: Do not apply the default A/B
+ * partition logic to this partition. This is intentionally a negative boolean
+ * because A/B should be both the default and most used in practice.
+ */
+typedef enum {
+ AVB_CHAIN_PARTITION_DESCRIPTOR_FLAGS_DO_NOT_USE_AB = (1 << 0),
+} AvbChainPartitionDescriptorFlags;
+
/* A descriptor containing a pointer to signed integrity data stored
* on another partition. The descriptor contains the partition name in
* question (without the A/B suffix), the public key used to sign the
@@ -28,13 +38,17 @@ extern "C" {
*
* The |reserved| field is for future expansion and must be set to NUL
* bytes.
+ *
+ * Changes in v1.3:
+ * - flags field is added which supports AVB_CHAIN_PARTITION_DESCRIPTOR_FLAGS_DO_NOT_USE_AB
*/
typedef struct AvbChainPartitionDescriptor {
AvbDescriptor parent_descriptor;
uint32_t rollback_index_location;
uint32_t partition_name_len;
uint32_t public_key_len;
- uint8_t reserved[64];
+ uint32_t flags;
+ uint8_t reserved[60];
} AVB_ATTR_PACKED AvbChainPartitionDescriptor;
/* Copies |src| to |dest| and validates, byte-swapping fields in the
diff --git a/lib/libavb/avb_cmdline.c b/lib/libavb/avb_cmdline.c
index a58ce6c48c0..842629abe0e 100644
--- a/lib/libavb/avb_cmdline.c
+++ b/lib/libavb/avb_cmdline.c
@@ -7,8 +7,6 @@
#include "avb_sha.h"
#include "avb_util.h"
#include "avb_version.h"
-#include <log.h>
-#include <malloc.h>
#define NUM_GUIDS 3
@@ -149,30 +147,6 @@ static int cmdline_append_option(AvbSlotVerifyData* slot_data,
return 1;
}
-#define AVB_MAX_DIGITS_UINT64 32
-
-/* Writes |value| to |digits| in base 10 followed by a NUL byte.
- * Returns number of characters written excluding the NUL byte.
- */
-static size_t uint64_to_base10(uint64_t value,
- char digits[AVB_MAX_DIGITS_UINT64]) {
- char rev_digits[AVB_MAX_DIGITS_UINT64];
- size_t n, num_digits;
-
- for (num_digits = 0; num_digits < AVB_MAX_DIGITS_UINT64 - 1;) {
- rev_digits[num_digits++] = avb_div_by_10(&value) + '0';
- if (value == 0) {
- break;
- }
- }
-
- for (n = 0; n < num_digits; n++) {
- digits[n] = rev_digits[num_digits - 1 - n];
- }
- digits[n] = '\0';
- return n;
-}
-
static int cmdline_append_version(AvbSlotVerifyData* slot_data,
const char* key,
uint64_t major_version,
@@ -182,8 +156,8 @@ static int cmdline_append_version(AvbSlotVerifyData* slot_data,
char combined[AVB_MAX_DIGITS_UINT64 * 2 + 1];
size_t num_major_digits, num_minor_digits;
- num_major_digits = uint64_to_base10(major_version, major_digits);
- num_minor_digits = uint64_to_base10(minor_version, minor_digits);
+ num_major_digits = avb_uint64_to_base10(major_version, major_digits);
+ num_minor_digits = avb_uint64_to_base10(minor_version, minor_digits);
avb_memcpy(combined, major_digits, num_major_digits);
combined[num_major_digits] = '.';
avb_memcpy(combined + num_major_digits + 1, minor_digits, num_minor_digits);
@@ -196,7 +170,7 @@ static int cmdline_append_uint64_base10(AvbSlotVerifyData* slot_data,
const char* key,
uint64_t value) {
char digits[AVB_MAX_DIGITS_UINT64];
- uint64_to_base10(value, digits);
+ avb_uint64_to_base10(value, digits);
return cmdline_append_option(slot_data, key, digits);
}
@@ -359,11 +333,11 @@ AvbSlotVerifyResult avb_append_options(
// Should never get here because MANAGED_RESTART_AND_EIO is
// remapped by avb_manage_hashtree_error_mode().
avb_assert_not_reached();
- ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_ARGUMENT;
- goto out;
- default:
- ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_ARGUMENT;
- goto out;
+ break;
+ case AVB_HASHTREE_ERROR_MODE_PANIC:
+ verity_mode = "panicking";
+ dm_verity_mode = "panic_on_corruption";
+ break;
}
new_ret = avb_replace(
slot_data->cmdline, "$(ANDROID_VERITY_MODE)", dm_verity_mode);
diff --git a/lib/libavb/avb_descriptor.c b/lib/libavb/avb_descriptor.c
index 56a3a91fc23..f4ff16694e6 100644
--- a/lib/libavb/avb_descriptor.c
+++ b/lib/libavb/avb_descriptor.c
@@ -6,8 +6,6 @@
#include "avb_descriptor.h"
#include "avb_util.h"
#include "avb_vbmeta_image.h"
-#include <log.h>
-#include <malloc.h>
bool avb_descriptor_validate_and_byteswap(const AvbDescriptor* src,
AvbDescriptor* dest) {
@@ -31,6 +29,8 @@ bool avb_descriptor_foreach(const uint8_t* image_data,
const uint8_t* desc_start;
const uint8_t* desc_end;
const uint8_t* p;
+ uint64_t desc_offset = 0;
+ uint64_t desc_size = 0;
if (image_data == NULL) {
avb_error("image_data is NULL\n.");
@@ -42,6 +42,9 @@ bool avb_descriptor_foreach(const uint8_t* image_data,
goto out;
}
+ /* The data is supposed to have been cryptographically verified at this point,
+ * This check is just adding defense in depth.
+ */
if (image_size < sizeof(AvbVBMetaImageHeader)) {
avb_error("Length is smaller than header.\n");
goto out;
@@ -58,23 +61,53 @@ bool avb_descriptor_foreach(const uint8_t* image_data,
header = (const AvbVBMetaImageHeader*)image_data;
image_end = image_data + image_size;
- desc_start = image_data + sizeof(AvbVBMetaImageHeader) +
- avb_be64toh(header->authentication_data_block_size) +
- avb_be64toh(header->descriptors_offset);
+ /* Since the data is supposed to have been cryptographically verified at this
+ * point, being overflow-safe is just for defense.
+ * The following lines are overflow-safe version of:
+ * desc_offset = sizeof(AvbVBMetaImageHeader) +
+ * avb_be64toh(header->authentication_data_block_size)) +
+ * avb_be64toh(header->descriptors_offset)
+ */
+ if (!avb_safe_add(&desc_offset,
+ sizeof(AvbVBMetaImageHeader),
+ avb_be64toh(header->authentication_data_block_size))) {
+ avb_error("Invalid authentication data block size.\n");
+ goto out;
+ }
+ if (!avb_safe_add_to(&desc_offset, avb_be64toh(header->descriptors_offset))) {
+ avb_error("Invalid descriptors offset.\n");
+ goto out;
+ }
+
+ if (desc_offset > (uint64_t)(image_end - image_data)) {
+ avb_error("Descriptors not inside passed-in data.\n");
+ goto out;
+ }
- desc_end = desc_start + avb_be64toh(header->descriptors_size);
+ desc_start = image_data + desc_offset;
- if (desc_start < image_data || desc_start > image_end ||
- desc_end < image_data || desc_end > image_end || desc_end < desc_start) {
+ desc_size = avb_be64toh(header->descriptors_size);
+ if (desc_size > (uint64_t)(image_end - desc_start)) {
avb_error("Descriptors not inside passed-in data.\n");
goto out;
}
+ desc_end = desc_start + desc_size;
+
for (p = desc_start; p < desc_end;) {
- const AvbDescriptor* dh = (const AvbDescriptor*)p;
- avb_assert_aligned(dh);
- uint64_t nb_following = avb_be64toh(dh->num_bytes_following);
+ uint64_t nb_following;
uint64_t nb_total = 0;
+ const AvbDescriptor* dh;
+
+ if (sizeof(AvbDescriptor) > (size_t)(desc_end - p)) {
+ avb_error("Invalid descriptor length.\n");
+ goto out;
+ }
+
+ dh = (const AvbDescriptor*)p;
+ avb_assert_aligned(dh);
+ nb_following = avb_be64toh(dh->num_bytes_following);
+
if (!avb_safe_add(&nb_total, sizeof(AvbDescriptor), nb_following)) {
avb_error("Invalid descriptor length.\n");
goto out;
@@ -85,7 +118,7 @@ bool avb_descriptor_foreach(const uint8_t* image_data,
goto out;
}
- if (nb_total + p < desc_start || nb_total + p > desc_end) {
+ if (nb_total > (uint64_t)(desc_end - p)) {
avb_error("Invalid data in descriptors array.\n");
goto out;
}
@@ -94,10 +127,7 @@ bool avb_descriptor_foreach(const uint8_t* image_data,
goto out;
}
- if (!avb_safe_add_to((uint64_t*)(&p), nb_total)) {
- avb_error("Invalid descriptor length.\n");
- goto out;
- }
+ p += nb_total;
}
ret = true;
diff --git a/lib/libavb/avb_hashtree_descriptor.h b/lib/libavb/avb_hashtree_descriptor.h
index d7f3eb501a3..5f74c465fed 100644
--- a/lib/libavb/avb_hashtree_descriptor.h
+++ b/lib/libavb/avb_hashtree_descriptor.h
@@ -21,9 +21,12 @@ extern "C" {
* AVB_HASHTREE_DESCRIPTOR_FLAGS_DO_NOT_USE_AB: Do not apply the default A/B
* partition logic to this partition. This is intentionally a negative boolean
* because A/B should be both the default and most used in practice.
+ * AVB_HASHTREE_DESCRIPTOR_FLAGS_CHECK_AT_MOST_ONCE: supports to validate hashes
+ * at most once in DM-Verity.
*/
typedef enum {
AVB_HASHTREE_DESCRIPTOR_FLAGS_DO_NOT_USE_AB = (1 << 0),
+ AVB_HASHTREE_DESCRIPTOR_FLAGS_CHECK_AT_MOST_ONCE = (1 << 1),
} AvbHashtreeDescriptorFlags;
/* A descriptor containing information about a dm-verity hashtree.
diff --git a/lib/libavb/avb_property_descriptor.h b/lib/libavb/avb_property_descriptor.h
index 917c58f9fea..b4df1c433a6 100644
--- a/lib/libavb/avb_property_descriptor.h
+++ b/lib/libavb/avb_property_descriptor.h
@@ -18,10 +18,10 @@ extern "C" {
/* A descriptor for properties (free-form key/value pairs).
*
- * Following this struct are |key_num_bytes| bytes of key data,
- * followed by a NUL byte, then |value_num_bytes| bytes of value data,
- * followed by a NUL byte and then enough padding to make the combined
- * size a multiple of 8.
+ * Following this struct are |key_num_bytes| bytes of key data encoded
+ * as UTF-8, followed by a NUL byte, then |value_num_bytes| bytes of
+ * value data, followed by a NUL byte and then enough padding to make
+ * the combined size a multiple of 8.
*/
typedef struct AvbPropertyDescriptor {
AvbDescriptor parent_descriptor;
diff --git a/lib/libavb/avb_rsa.c b/lib/libavb/avb_rsa.c
index d7bf8905be2..b64749980c0 100644
--- a/lib/libavb/avb_rsa.c
+++ b/lib/libavb/avb_rsa.c
@@ -3,6 +3,11 @@
* Copyright (C) 2016 The Android Open Source Project
*/
+/* Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
/* Implementation of RSA signature verification which uses a pre-processed
* key for computation. The code extends libmincrypt RSA verification code to
* support multiple RSA key lengths and hash digest algorithms.
@@ -12,7 +17,6 @@
#include "avb_sha.h"
#include "avb_util.h"
#include "avb_vbmeta_image.h"
-#include <malloc.h>
typedef struct IAvbKey {
unsigned int len; /* Length of n[] in number of uint32_t */
diff --git a/lib/libavb/avb_slot_verify.c b/lib/libavb/avb_slot_verify.c
index ae8e1dffa4c..d37ffed0148 100644
--- a/lib/libavb/avb_slot_verify.c
+++ b/lib/libavb/avb_slot_verify.c
@@ -14,8 +14,6 @@
#include "avb_util.h"
#include "avb_vbmeta_image.h"
#include "avb_version.h"
-#include <log.h>
-#include <malloc.h>
/* Maximum number of partitions that can be loaded with avb_slot_verify(). */
#define MAX_NUMBER_OF_LOADED_PARTITIONS 32
@@ -26,6 +24,9 @@
/* Maximum size of a vbmeta image - 64 KiB. */
#define VBMETA_MAX_SIZE (64 * 1024)
+/* Test buffer used to check the existence of a partition. */
+#define TEST_BUFFER_SIZE 1
+
static AvbSlotVerifyResult initialize_persistent_digest(
AvbOps* ops,
const char* part_name,
@@ -72,7 +73,7 @@ static AvbSlotVerifyResult load_full_partition(AvbOps* ops,
/* We are going to implicitly cast image_size from uint64_t to size_t in the
* following code, so we need to make sure that the cast is safe. */
if (image_size != (size_t)(image_size)) {
- avb_errorv(part_name, ": Partition size too large to load.\n", NULL);
+ avb_error(part_name, ": Partition size too large to load.\n");
return AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;
}
@@ -83,16 +84,16 @@ static AvbSlotVerifyResult load_full_partition(AvbOps* ops,
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 loading data from partition.\n", NULL);
+ avb_error(part_name, ": Error loading data from partition.\n");
return AVB_SLOT_VERIFY_RESULT_ERROR_IO;
}
if (*out_image_buf != NULL) {
+ *out_image_preloaded = true;
if (part_num_read != image_size) {
- avb_errorv(part_name, ": Read incorrect number of bytes.\n", NULL);
+ avb_error(part_name, ": Read incorrect number of bytes.\n");
return AVB_SLOT_VERIFY_RESULT_ERROR_IO;
}
- *out_image_preloaded = true;
}
}
@@ -112,11 +113,11 @@ static AvbSlotVerifyResult load_full_partition(AvbOps* ops,
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 loading data from partition.\n", NULL);
+ avb_error(part_name, ": Error loading data from partition.\n");
return AVB_SLOT_VERIFY_RESULT_ERROR_IO;
}
if (part_num_read != image_size) {
- avb_errorv(part_name, ": Read incorrect number of bytes.\n", NULL);
+ avb_error(part_name, ": Read incorrect number of bytes.\n");
return AVB_SLOT_VERIFY_RESULT_ERROR_IO;
}
}
@@ -150,7 +151,7 @@ static AvbSlotVerifyResult read_persistent_digest(AvbOps* ops,
size_t stored_digest_size = 0;
if (ops->read_persistent_value == NULL) {
- avb_errorv(part_name, ": Persistent values are not implemented.\n", NULL);
+ avb_error(part_name, ": Persistent values are not implemented.\n");
return AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;
}
persistent_value_name =
@@ -187,19 +188,17 @@ static AvbSlotVerifyResult read_persistent_digest(AvbOps* ops,
} 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);
+ avb_error(part_name, ": Persistent digest does not exist.\n");
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) {
- avb_errorv(
- part_name, ": Persistent digest is not of expected size.\n", NULL);
+ avb_error(part_name, ": Persistent digest is not of expected size.\n");
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);
+ avb_error(part_name, ": Error reading persistent digest.\n");
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);
+ avb_error(part_name, ": Persistent digest is not of expected size.\n");
return AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;
}
return AVB_SLOT_VERIFY_RESULT_OK;
@@ -225,23 +224,21 @@ static AvbSlotVerifyResult initialize_persistent_digest(
}
if (is_device_unlocked) {
- avb_debugv(part_name,
- ": Digest does not exist, device unlocked so not initializing "
- "digest.\n",
- NULL);
+ avb_debug(part_name,
+ ": Digest does not exist, device unlocked so not initializing "
+ "digest.\n");
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);
+ avb_debug(part_name,
+ ": Digest does not exist, initializing persistent digest.\n");
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);
+ avb_error(part_name, ": Error initializing persistent digest.\n");
return AVB_SLOT_VERIFY_RESULT_ERROR_IO;
}
@@ -251,9 +248,8 @@ static AvbSlotVerifyResult initialize_persistent_digest(
// 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);
+ avb_error(part_name,
+ ": Reading back initialized persistent digest failed!\n");
}
return ret;
}
@@ -356,11 +352,11 @@ static AvbSlotVerifyResult load_and_verify_hash_partition(
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);
+ avb_error(part_name, ": Error determining partition size.\n");
ret = AVB_SLOT_VERIFY_RESULT_ERROR_IO;
goto out;
}
- avb_debugv(part_name, ": Loading entire partition.\n", NULL);
+ avb_debug(part_name, ": Loading entire partition.\n");
}
ret = load_full_partition(
@@ -392,14 +388,14 @@ static AvbSlotVerifyResult load_and_verify_hash_partition(
digest = avb_sha512_final(&sha512_ctx);
digest_len = AVB_SHA512_DIGEST_SIZE;
} else {
- avb_errorv(part_name, ": Unsupported hash algorithm.\n", NULL);
+ avb_error(part_name, ": Unsupported hash algorithm.\n");
ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;
goto out;
}
if (hash_desc.digest_len == 0) {
/* Expect a match to a persistent digest. */
- avb_debugv(part_name, ": No digest, using persistent digest.\n", NULL);
+ avb_debug(part_name, ": No digest, using persistent digest.\n");
expected_digest_len = digest_len;
expected_digest = expected_digest_buf;
avb_assert(expected_digest_len <= sizeof(expected_digest_buf));
@@ -418,16 +414,14 @@ static AvbSlotVerifyResult load_and_verify_hash_partition(
}
if (digest_len != expected_digest_len) {
- avb_errorv(
- part_name, ": Digest in descriptor not of expected size.\n", NULL);
+ avb_error(part_name, ": Digest in descriptor not of expected size.\n");
ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;
goto out;
}
if (avb_safe_memcmp(digest, expected_digest, digest_len) != 0) {
- avb_errorv(part_name,
- ": Hash of data does not match digest in descriptor.\n",
- NULL);
+ avb_error(part_name,
+ ": Hash of data does not match digest in descriptor.\n");
ret = AVB_SLOT_VERIFY_RESULT_ERROR_VERIFICATION;
goto out;
}
@@ -441,7 +435,7 @@ out:
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);
+ avb_error(part_name, ": Too many loaded partitions.\n");
ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
goto fail;
}
@@ -451,6 +445,7 @@ out:
loaded_partition->data_size = image_size;
loaded_partition->data = image_buf;
loaded_partition->preloaded = image_preloaded;
+ loaded_partition->verify_result = ret;
image_buf = NULL;
}
@@ -493,11 +488,11 @@ static AvbSlotVerifyResult load_requested_partitions(
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);
+ avb_error(part_name, ": Error determining partition size.\n");
ret = AVB_SLOT_VERIFY_RESULT_ERROR_IO;
goto out;
}
- avb_debugv(part_name, ": Loading entire partition.\n", NULL);
+ avb_debug(part_name, ": Loading entire partition.\n");
ret = load_full_partition(
ops, part_name, image_size, &image_buf, &image_preloaded);
@@ -507,7 +502,7 @@ static AvbSlotVerifyResult load_requested_partitions(
/* 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);
+ avb_error(part_name, ": Too many loaded partitions.\n");
ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
goto out;
}
@@ -544,18 +539,19 @@ static AvbSlotVerifyResult load_and_verify_vbmeta(
AvbSlotVerifyFlags flags,
bool allow_verification_error,
AvbVBMetaImageFlags toplevel_vbmeta_flags,
- int rollback_index_location,
+ uint32_t rollback_index_location,
const char* partition_name,
size_t partition_name_len,
const uint8_t* expected_public_key,
size_t expected_public_key_length,
AvbSlotVerifyData* slot_data,
AvbAlgorithmType* out_algorithm_type,
- AvbCmdlineSubstList* out_additional_cmdline_subst) {
+ AvbCmdlineSubstList* out_additional_cmdline_subst,
+ bool use_ab_suffix) {
char full_partition_name[AVB_PART_NAME_MAX_SIZE];
AvbSlotVerifyResult ret;
AvbIOResult io_ret;
- size_t vbmeta_offset;
+ uint64_t vbmeta_offset;
size_t vbmeta_size;
uint8_t* vbmeta_buf = NULL;
size_t vbmeta_num_read;
@@ -599,17 +595,27 @@ static AvbSlotVerifyResult load_and_verify_vbmeta(
ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;
goto out;
}
-
- /* Construct full partition name e.g. system_a. */
- if (!avb_str_concat(full_partition_name,
+ if (!use_ab_suffix) {
+ /*No ab_suffix, just copy the partition name as is.*/
+ if (partition_name_len >= AVB_PART_NAME_MAX_SIZE) {
+ avb_error("Partition name does not fit.\n");
+ ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;
+ goto out;
+ }
+ avb_memcpy(full_partition_name, partition_name, partition_name_len);
+ full_partition_name[partition_name_len] = '\0';
+ }else{
+ /* Construct full partition name e.g. system_a. */
+ if (!avb_str_concat(full_partition_name,
sizeof full_partition_name,
partition_name,
partition_name_len,
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;
+ avb_error("Partition name and suffix does not fit.\n");
+ ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;
+ goto out;
+ }
}
/* If we're loading from the main vbmeta partition, the vbmeta struct is in
@@ -635,7 +641,7 @@ static AvbSlotVerifyResult load_and_verify_vbmeta(
ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
goto out;
} else if (io_ret != AVB_IO_RESULT_OK) {
- avb_errorv(full_partition_name, ": Error loading footer.\n", NULL);
+ avb_error(full_partition_name, ": Error loading footer.\n");
ret = AVB_SLOT_VERIFY_RESULT_ERROR_IO;
goto out;
}
@@ -643,43 +649,67 @@ static AvbSlotVerifyResult load_and_verify_vbmeta(
if (!avb_footer_validate_and_byteswap((const AvbFooter*)footer_buf,
&footer)) {
- avb_debugv(full_partition_name, ": No footer detected.\n", NULL);
+ avb_debug(full_partition_name, ": No footer detected.\n");
} 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);
+ avb_error(full_partition_name, ": Invalid vbmeta size in footer.\n");
} else {
vbmeta_offset = footer.vbmeta_offset;
vbmeta_size = footer.vbmeta_size;
}
}
+ } else {
+ uint64_t partition_size = 0;
+ io_ret =
+ ops->get_size_of_partition(ops, full_partition_name, &partition_size);
+ if (io_ret == AVB_IO_RESULT_OK) {
+ if (partition_size < vbmeta_size && partition_size > 0) {
+ avb_debug(full_partition_name,
+ ": Using partition size as vbmeta size\n");
+ vbmeta_size = partition_size;
+ }
+ } else {
+ avb_debug(full_partition_name, ": Failed to get partition size\n");
+ // libavb might fall back to other partitions if current vbmeta partition
+ // isn't found. So AVB_IO_RESULT_ERROR_NO_SUCH_PARTITION is recoverable,
+ // but other errors are not.
+ if (io_ret != AVB_IO_RESULT_ERROR_NO_SUCH_PARTITION) {
+ ret = AVB_SLOT_VERIFY_RESULT_ERROR_IO;
+ goto out;
+ }
+ }
}
- vbmeta_buf = avb_malloc(vbmeta_size);
- if (vbmeta_buf == NULL) {
- ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
- goto out;
- }
+ /* Use result from previous I/O operation to check the existence of the
+ * partition before allocating the big chunk of memory on heap
+ * for vbmeta later. `io_ret` will be used later to decide whether
+ * to fallback on the `boot` partition.
+ */
+ if (io_ret != AVB_IO_RESULT_ERROR_NO_SUCH_PARTITION) {
+ vbmeta_buf = avb_malloc(vbmeta_size);
+ if (vbmeta_buf == NULL) {
+ ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
+ 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);
- }
+ if (vbmeta_offset != 0) {
+ avb_debug("Loading vbmeta struct in footer from partition '",
+ full_partition_name,
+ "'.\n");
+ } else {
+ avb_debug("Loading vbmeta struct from partition '",
+ full_partition_name,
+ "'.\n");
+ }
- io_ret = ops->read_from_partition(ops,
- full_partition_name,
- vbmeta_offset,
- vbmeta_size,
- vbmeta_buf,
- &vbmeta_num_read);
+ io_ret = ops->read_from_partition(ops,
+ full_partition_name,
+ vbmeta_offset,
+ vbmeta_size,
+ vbmeta_buf,
+ &vbmeta_num_read);
+ }
if (io_ret == AVB_IO_RESULT_ERROR_OOM) {
ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
goto out;
@@ -689,9 +719,8 @@ static AvbSlotVerifyResult load_and_verify_vbmeta(
*/
if (is_main_vbmeta && io_ret == AVB_IO_RESULT_ERROR_NO_SUCH_PARTITION &&
!look_for_vbmeta_footer) {
- avb_debugv(full_partition_name,
- ": No such partition. Trying 'boot' instead.\n",
- NULL);
+ avb_debug(full_partition_name,
+ ": No such partition. Trying 'boot' instead.\n");
ret = load_and_verify_vbmeta(ops,
requested_partitions,
ab_suffix,
@@ -705,10 +734,11 @@ static AvbSlotVerifyResult load_and_verify_vbmeta(
0 /* expected_public_key_length */,
slot_data,
out_algorithm_type,
- out_additional_cmdline_subst);
+ out_additional_cmdline_subst,
+ use_ab_suffix);
goto out;
} else {
- avb_errorv(full_partition_name, ": Error loading vbmeta data.\n", NULL);
+ avb_error(full_partition_name, ": Error loading vbmeta data.\n");
ret = AVB_SLOT_VERIFY_RESULT_ERROR_IO;
goto out;
}
@@ -729,11 +759,10 @@ static AvbSlotVerifyResult load_and_verify_vbmeta(
case AVB_VBMETA_VERIFY_RESULT_HASH_MISMATCH:
case AVB_VBMETA_VERIFY_RESULT_SIGNATURE_MISMATCH:
ret = AVB_SLOT_VERIFY_RESULT_ERROR_VERIFICATION;
- avb_errorv(full_partition_name,
- ": Error verifying vbmeta image: ",
- avb_vbmeta_verify_result_to_string(vbmeta_ret),
- "\n",
- NULL);
+ avb_error(full_partition_name,
+ ": Error verifying vbmeta image: ",
+ avb_vbmeta_verify_result_to_string(vbmeta_ret),
+ "\n");
if (!allow_verification_error) {
goto out;
}
@@ -742,17 +771,15 @@ static AvbSlotVerifyResult load_and_verify_vbmeta(
case AVB_VBMETA_VERIFY_RESULT_INVALID_VBMETA_HEADER:
/* No way to continue this case. */
ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;
- avb_errorv(full_partition_name,
- ": Error verifying vbmeta image: invalid vbmeta header\n",
- NULL);
+ avb_error(full_partition_name,
+ ": Error verifying vbmeta image: invalid vbmeta header\n");
goto out;
case AVB_VBMETA_VERIFY_RESULT_UNSUPPORTED_VERSION:
/* No way to continue this case. */
ret = AVB_SLOT_VERIFY_RESULT_ERROR_UNSUPPORTED_VERSION;
- avb_errorv(full_partition_name,
- ": Error verifying vbmeta image: unsupported AVB version\n",
- NULL);
+ avb_error(full_partition_name,
+ ": Error verifying vbmeta image: unsupported AVB version\n");
goto out;
}
@@ -766,14 +793,16 @@ static AvbSlotVerifyResult load_and_verify_vbmeta(
} else {
if (vbmeta_header.flags != 0) {
ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;
- avb_errorv(full_partition_name,
- ": chained vbmeta image has non-zero flags\n",
- NULL);
+ avb_error(full_partition_name,
+ ": chained vbmeta image has non-zero flags\n");
goto out;
}
}
uint32_t rollback_index_location_to_use = rollback_index_location;
+ if (is_main_vbmeta) {
+ rollback_index_location_to_use = vbmeta_header.rollback_index_location;
+ }
/* Check if key used to make signature matches what is expected. */
if (pk_data != NULL) {
@@ -781,10 +810,9 @@ static AvbSlotVerifyResult load_and_verify_vbmeta(
avb_assert(!is_main_vbmeta);
if (expected_public_key_length != pk_len ||
avb_safe_memcmp(expected_public_key, pk_data, pk_len) != 0) {
- avb_errorv(full_partition_name,
- ": Public key used to sign data does not match key in chain "
- "partition descriptor.\n",
- NULL);
+ avb_error(full_partition_name,
+ ": Public key used to sign data does not match key in chain "
+ "partition descriptor.\n");
ret = AVB_SLOT_VERIFY_RESULT_ERROR_PUBLIC_KEY_REJECTED;
if (!allow_verification_error) {
goto out;
@@ -827,16 +855,14 @@ static AvbSlotVerifyResult load_and_verify_vbmeta(
ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
goto out;
} else if (io_ret != AVB_IO_RESULT_OK) {
- avb_errorv(full_partition_name,
- ": Error while checking public key used to sign data.\n",
- NULL);
+ avb_error(full_partition_name,
+ ": Error while checking public key used to sign data.\n");
ret = AVB_SLOT_VERIFY_RESULT_ERROR_IO;
goto out;
}
if (!key_is_trusted) {
- avb_errorv(full_partition_name,
- ": Public key used to sign data rejected.\n",
- NULL);
+ avb_error(full_partition_name,
+ ": Public key used to sign data rejected.\n");
ret = AVB_SLOT_VERIFY_RESULT_ERROR_PUBLIC_KEY_REJECTED;
if (!allow_verification_error) {
goto out;
@@ -852,17 +878,15 @@ static AvbSlotVerifyResult load_and_verify_vbmeta(
ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
goto out;
} else if (io_ret != AVB_IO_RESULT_OK) {
- avb_errorv(full_partition_name,
- ": Error getting rollback index for location.\n",
- NULL);
+ avb_error(full_partition_name,
+ ": Error getting rollback index for location.\n");
ret = AVB_SLOT_VERIFY_RESULT_ERROR_IO;
goto out;
}
if (vbmeta_header.rollback_index < stored_rollback_index) {
- avb_errorv(
+ avb_error(
full_partition_name,
- ": Image rollback index is less than the stored rollback index.\n",
- NULL);
+ ": Image rollback index is less than the stored rollback index.\n");
ret = AVB_SLOT_VERIFY_RESULT_ERROR_ROLLBACK_INDEX;
if (!allow_verification_error) {
goto out;
@@ -878,7 +902,7 @@ static AvbSlotVerifyResult load_and_verify_vbmeta(
}
}
if (slot_data->num_vbmeta_images == MAX_NUMBER_OF_VBMETA_IMAGES) {
- avb_errorv(full_partition_name, ": Too many vbmeta images.\n", NULL);
+ avb_error(full_partition_name, ": Too many vbmeta images.\n");
ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
goto out;
}
@@ -902,8 +926,7 @@ static AvbSlotVerifyResult load_and_verify_vbmeta(
*/
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);
+ avb_debug(full_partition_name, ": VERIFICATION_DISABLED bit is set.\n");
/* 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()
@@ -936,7 +959,7 @@ static AvbSlotVerifyResult load_and_verify_vbmeta(
AvbDescriptor desc;
if (!avb_descriptor_validate_and_byteswap(descriptors[n], &desc)) {
- avb_errorv(full_partition_name, ": Descriptor is invalid.\n", NULL);
+ avb_error(full_partition_name, ": Descriptor is invalid.\n");
ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;
goto out;
}
@@ -966,31 +989,32 @@ static AvbSlotVerifyResult load_and_verify_vbmeta(
/* Only allow CHAIN_PARTITION descriptors in the main vbmeta image. */
if (!is_main_vbmeta) {
- avb_errorv(full_partition_name,
- ": Encountered chain descriptor not in main image.\n",
- NULL);
+ avb_error(full_partition_name,
+ ": Encountered chain descriptor not in main image.\n");
ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;
goto out;
}
if (!avb_chain_partition_descriptor_validate_and_byteswap(
(AvbChainPartitionDescriptor*)descriptors[n], &chain_desc)) {
- avb_errorv(full_partition_name,
- ": Chain partition descriptor is invalid.\n",
- NULL);
+ avb_error(full_partition_name,
+ ": Chain partition descriptor is invalid.\n");
ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;
goto out;
}
if (chain_desc.rollback_index_location == 0) {
- avb_errorv(full_partition_name,
- ": Chain partition has invalid "
- "rollback_index_location field.\n",
- NULL);
+ avb_error(full_partition_name,
+ ": Chain partition has invalid "
+ "rollback_index_location field.\n");
ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;
goto out;
}
-
+ if ((chain_desc.flags & AVB_HASH_DESCRIPTOR_FLAGS_DO_NOT_USE_AB) != 0){
+ use_ab_suffix = false;
+ }else{
+ use_ab_suffix = true;
+ }
chain_partition_name = ((const uint8_t*)descriptors[n]) +
sizeof(AvbChainPartitionDescriptor);
chain_public_key = chain_partition_name + chain_desc.partition_name_len;
@@ -1009,7 +1033,8 @@ static AvbSlotVerifyResult load_and_verify_vbmeta(
chain_desc.public_key_len,
slot_data,
NULL, /* out_algorithm_type */
- NULL /* out_additional_cmdline_subst */);
+ NULL, /* out_additional_cmdline_subst */
+ use_ab_suffix);
if (sub_ret != AVB_SLOT_VERIFY_RESULT_OK) {
ret = sub_ret;
if (!result_should_continue(ret)) {
@@ -1026,9 +1051,8 @@ static AvbSlotVerifyResult load_and_verify_vbmeta(
if (!avb_kernel_cmdline_descriptor_validate_and_byteswap(
(AvbKernelCmdlineDescriptor*)descriptors[n],
&kernel_cmdline_desc)) {
- avb_errorv(full_partition_name,
- ": Kernel cmdline descriptor is invalid.\n",
- NULL);
+ avb_error(full_partition_name,
+ ": Kernel cmdline descriptor is invalid.\n");
ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;
goto out;
}
@@ -1038,9 +1062,8 @@ static AvbSlotVerifyResult load_and_verify_vbmeta(
if (!avb_validate_utf8(kernel_cmdline,
kernel_cmdline_desc.kernel_cmdline_length)) {
- avb_errorv(full_partition_name,
- ": Kernel cmdline is not valid UTF-8.\n",
- NULL);
+ avb_error(full_partition_name,
+ ": Kernel cmdline is not valid UTF-8.\n");
ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;
goto out;
}
@@ -1100,8 +1123,7 @@ static AvbSlotVerifyResult load_and_verify_vbmeta(
if (!avb_hashtree_descriptor_validate_and_byteswap(
(AvbHashtreeDescriptor*)descriptors[n], &hashtree_desc)) {
- avb_errorv(
- full_partition_name, ": Hashtree descriptor is invalid.\n", NULL);
+ avb_error(full_partition_name, ": Hashtree descriptor is invalid.\n");
ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;
goto out;
}
@@ -1155,7 +1177,7 @@ static AvbSlotVerifyResult load_and_verify_vbmeta(
"sha512") == 0) {
digest_len = AVB_SHA512_DIGEST_SIZE;
} else {
- avb_errorv(part_name, ": Unsupported hash algorithm.\n", NULL);
+ avb_error(part_name, ": Unsupported hash algorithm.\n");
ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;
goto out;
}
@@ -1188,15 +1210,14 @@ static AvbSlotVerifyResult load_and_verify_vbmeta(
}
}
- 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);
+ if (rollback_index_location_to_use >=
+ AVB_MAX_NUMBER_OF_ROLLBACK_INDEX_LOCATIONS) {
+ avb_error(full_partition_name, ": Invalid rollback_index_location.\n");
ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;
goto out;
}
- slot_data->rollback_indexes[rollback_index_location] =
+ slot_data->rollback_indexes[rollback_index_location_to_use] =
vbmeta_header.rollback_index;
if (out_algorithm_type != NULL) {
@@ -1315,7 +1336,7 @@ out:
static bool has_system_partition(AvbOps* ops, const char* ab_suffix) {
char part_name[AVB_PART_NAME_MAX_SIZE];
- char* system_part_name = "system";
+ const char* system_part_name = "system";
char guid_buf[37];
AvbIOResult io_ret;
@@ -1348,7 +1369,7 @@ AvbSlotVerifyResult avb_slot_verify(AvbOps* ops,
AvbSlotVerifyFlags flags,
AvbHashtreeErrorMode hashtree_error_mode,
AvbSlotVerifyData** out_data) {
- AvbSlotVerifyResult ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_ARGUMENT;
+ AvbSlotVerifyResult ret;
AvbSlotVerifyData* slot_data = NULL;
AvbAlgorithmType algorithm_type = AVB_ALGORITHM_TYPE_NONE;
bool using_boot_for_vbmeta = false;
@@ -1456,7 +1477,8 @@ AvbSlotVerifyResult avb_slot_verify(AvbOps* ops,
0 /* expected_public_key_length */,
slot_data,
&algorithm_type,
- additional_cmdline_subst);
+ additional_cmdline_subst,
+ true /*use_ab_suffix*/);
if (!allow_verification_error && ret != AVB_SLOT_VERIFY_RESULT_OK) {
goto fail;
}
@@ -1477,7 +1499,8 @@ AvbSlotVerifyResult avb_slot_verify(AvbOps* ops,
0 /* expected_public_key_length */,
slot_data,
&algorithm_type,
- additional_cmdline_subst);
+ additional_cmdline_subst,
+ true /*use_ab_suffix*/);
if (!allow_verification_error && ret != AVB_SLOT_VERIFY_RESULT_OK) {
goto fail;
}
@@ -1686,7 +1709,7 @@ const char* avb_slot_verify_result_to_string(AvbSlotVerifyResult result) {
return ret;
}
-void avb_slot_verify_data_calculate_vbmeta_digest(AvbSlotVerifyData* data,
+void avb_slot_verify_data_calculate_vbmeta_digest(const AvbSlotVerifyData* data,
AvbDigestType digest_type,
uint8_t* out_digest) {
bool ret = false;
diff --git a/lib/libavb/avb_slot_verify.h b/lib/libavb/avb_slot_verify.h
index 8d0fa536935..b86c96cbd06 100644
--- a/lib/libavb/avb_slot_verify.h
+++ b/lib/libavb/avb_slot_verify.h
@@ -69,7 +69,8 @@ typedef enum {
AVB_HASHTREE_ERROR_MODE_RESTART,
AVB_HASHTREE_ERROR_MODE_EIO,
AVB_HASHTREE_ERROR_MODE_LOGGING,
- AVB_HASHTREE_ERROR_MODE_MANAGED_RESTART_AND_EIO
+ AVB_HASHTREE_ERROR_MODE_MANAGED_RESTART_AND_EIO,
+ AVB_HASHTREE_ERROR_MODE_PANIC
} AvbHashtreeErrorMode;
/* Flags that influence how avb_slot_verify() works.
@@ -138,6 +139,7 @@ typedef struct {
uint8_t* data;
size_t data_size;
bool preloaded;
+ AvbSlotVerifyResult verify_result;
} AvbPartitionData;
/* AvbVBMetaData contains a vbmeta struct loaded from a partition when
@@ -291,7 +293,7 @@ typedef struct {
* in |out_digest| which must be large enough to hold a digest
* of the requested type.
*/
-void avb_slot_verify_data_calculate_vbmeta_digest(AvbSlotVerifyData* data,
+void avb_slot_verify_data_calculate_vbmeta_digest(const AvbSlotVerifyData* data,
AvbDigestType digest_type,
uint8_t* out_digest);
diff --git a/lib/libavb/avb_util.c b/lib/libavb/avb_util.c
index 8719ede15a7..25af46075a7 100644
--- a/lib/libavb/avb_util.c
+++ b/lib/libavb/avb_util.c
@@ -4,11 +4,17 @@
*/
#include "avb_util.h"
-#include <log.h>
-#include <malloc.h>
#include <stdarg.h>
+uint16_t avb_be16toh(uint16_t in) {
+ uint8_t* d = (uint8_t*)&in;
+ uint16_t ret;
+ ret = ((uint16_t)d[0]) << 8;
+ ret |= ((uint16_t)d[1]);
+ return ret;
+}
+
uint32_t avb_be32toh(uint32_t in) {
uint8_t* d = (uint8_t*)&in;
uint32_t ret;
@@ -33,6 +39,17 @@ uint64_t avb_be64toh(uint64_t in) {
return ret;
}
+/* Converts a 16-bit unsigned integer from host to big-endian byte order. */
+uint16_t avb_htobe16(uint16_t in) {
+ union {
+ uint16_t word;
+ uint8_t bytes[2];
+ } ret;
+ ret.bytes[0] = (in >> 8) & 0xff;
+ ret.bytes[1] = in & 0xff;
+ return ret.word;
+}
+
/* Converts a 32-bit unsigned integer from host to big-endian byte order. */
uint32_t avb_htobe32(uint32_t in) {
union {
@@ -159,6 +176,12 @@ bool avb_str_concat(char* buf,
size_t str2_len) {
uint64_t combined_len;
+ // Doesn't make sense to pass 0 for buf_size since there's
+ // no room for the terminating NUL byte.
+ if (buf_size == 0) {
+ return false;
+ }
+
if (!avb_safe_add(&combined_len, str1_len, str2_len)) {
avb_error("Overflow when adding string sizes.\n");
return false;
@@ -411,3 +434,22 @@ char* avb_bin2hex(const uint8_t* data, size_t data_len) {
hex_data[n * 2] = '\0';
return hex_data;
}
+
+size_t avb_uint64_to_base10(uint64_t value,
+ char digits[AVB_MAX_DIGITS_UINT64]) {
+ char rev_digits[AVB_MAX_DIGITS_UINT64];
+ size_t n, num_digits;
+
+ for (num_digits = 0; num_digits < AVB_MAX_DIGITS_UINT64 - 1;) {
+ rev_digits[num_digits++] = avb_div_by_10(&value) + '0';
+ if (value == 0) {
+ break;
+ }
+ }
+
+ for (n = 0; n < num_digits; n++) {
+ digits[n] = rev_digits[num_digits - 1 - n];
+ }
+ digits[n] = '\0';
+ return n;
+}
diff --git a/lib/libavb/avb_util.h b/lib/libavb/avb_util.h
index 26dc6b045ac..d0612cc97f3 100644
--- a/lib/libavb/avb_util.h
+++ b/lib/libavb/avb_util.h
@@ -16,9 +16,44 @@
extern "C" {
#endif
+#define AVB_CONCAT(x, y) x##y
#define AVB_STRINGIFY(x) #x
#define AVB_TO_STRING(x) AVB_STRINGIFY(x)
+#define AVB__COUNT_ARGS(_0, _1, _2, _3, _4, _5, _6, _7, x, ...) x
+#define AVB_COUNT_ARGS(...) \
+ AVB__COUNT_ARGS(, ##__VA_ARGS__, 7, 6, 5, 4, 3, 2, 1, 0)
+
+#define AVB__REPEAT0(x)
+#define AVB__REPEAT1(x) x
+#define AVB__REPEAT2(x) AVB__REPEAT1(x) x
+#define AVB__REPEAT3(x) AVB__REPEAT2(x) x
+#define AVB__REPEAT4(x) AVB__REPEAT3(x) x
+#define AVB__REPEAT5(x) AVB__REPEAT4(x) x
+#define AVB__REPEAT6(x) AVB__REPEAT5(x) x
+#define AVB__REPEAT7(x) AVB__REPEAT6(x) x
+#define AVB__REPEAT(n, x) AVB_CONCAT(AVB__REPEAT, n)(x)
+#define AVB_REPEAT(n, x) AVB__REPEAT(n, x)
+
+#ifdef AVB_USE_PRINTF_LOGS
+#define AVB_LOG(level, message, ...) \
+ avb_printf("%s:%d: " level \
+ ": " AVB_REPEAT(AVB_COUNT_ARGS(message, ##__VA_ARGS__), "%s"), \
+ avb_basename(__FILE__), \
+ __LINE__, \
+ message, \
+ ##__VA_ARGS__)
+#else
+#define AVB_LOG(level, message, ...) \
+ avb_printv(avb_basename(__FILE__), \
+ ":", \
+ AVB_TO_STRING(__LINE__), \
+ ": " level ": ", \
+ message, \
+ ##__VA_ARGS__, \
+ NULL)
+#endif
+
#ifdef AVB_ENABLE_DEBUG
/* Aborts the program if |expr| is false.
*
@@ -30,21 +65,28 @@ extern "C" {
avb_fatal("assert fail: " #expr "\n"); \
} \
} while (0)
-#else
-#define avb_assert(expr)
-#endif
/* Aborts the program if reached.
*
* This has no effect unless AVB_ENABLE_DEBUG is defined.
*/
-#ifdef AVB_ENABLE_DEBUG
#define avb_assert_not_reached() \
do { \
avb_fatal("assert_not_reached()\n"); \
} while (0)
+
+/* Print functions, used for diagnostics.
+ *
+ * These have no effect unless AVB_ENABLE_DEBUG is defined.
+ */
+#define avb_debug(message, ...) \
+ do { \
+ AVB_LOG("DEBUG", message, ##__VA_ARGS__); \
+ } while (0)
#else
+#define avb_assert(expr)
#define avb_assert_not_reached()
+#define avb_debug(message, ...)
#endif
/* Aborts the program if |addr| is not word-aligned.
@@ -54,85 +96,42 @@ extern "C" {
#define avb_assert_aligned(addr) \
avb_assert((((uintptr_t)addr) & (AVB_ALIGNMENT_SIZE - 1)) == 0)
-#ifdef AVB_ENABLE_DEBUG
-/* Print functions, used for diagnostics.
- *
- * These have no effect unless AVB_ENABLE_DEBUG is defined.
- */
-#define avb_debug(message) \
- do { \
- avb_printv(avb_basename(__FILE__), \
- ":", \
- AVB_TO_STRING(__LINE__), \
- ": DEBUG: ", \
- message, \
- NULL); \
- } while (0)
-#define avb_debugv(message, ...) \
- do { \
- avb_printv(avb_basename(__FILE__), \
- ":", \
- AVB_TO_STRING(__LINE__), \
- ": DEBUG: ", \
- message, \
- ##__VA_ARGS__); \
- } while (0)
-#else
-#define avb_debug(message)
-#define avb_debugv(message, ...)
-#endif
-
/* Prints out a message. This is typically used if a runtime-error
* occurs.
*/
-#define avb_error(message) \
- do { \
- avb_printv(avb_basename(__FILE__), \
- ":", \
- AVB_TO_STRING(__LINE__), \
- ": ERROR: ", \
- message, \
- NULL); \
- } while (0)
-#define avb_errorv(message, ...) \
- do { \
- avb_printv(avb_basename(__FILE__), \
- ":", \
- AVB_TO_STRING(__LINE__), \
- ": ERROR: ", \
- message, \
- ##__VA_ARGS__); \
+#define avb_error(message, ...) \
+ do { \
+ AVB_LOG("ERROR", message, ##__VA_ARGS__); \
} while (0)
/* Prints out a message and calls avb_abort().
*/
-#define avb_fatal(message) \
- do { \
- avb_printv(avb_basename(__FILE__), \
- ":", \
- AVB_TO_STRING(__LINE__), \
- ": FATAL: ", \
- message, \
- NULL); \
- avb_abort(); \
- } while (0)
-#define avb_fatalv(message, ...) \
- do { \
- avb_printv(avb_basename(__FILE__), \
- ":", \
- AVB_TO_STRING(__LINE__), \
- ": FATAL: ", \
- message, \
- ##__VA_ARGS__); \
- avb_abort(); \
+#define avb_fatal(message, ...) \
+ do { \
+ AVB_LOG("FATAL", message, ##__VA_ARGS__); \
+ avb_abort(); \
} while (0)
+#ifndef AVB_USE_PRINTF_LOGS
+/* Deprecated legacy logging functions -- kept for client compatibility.
+ */
+#define avb_debugv(message, ...) avb_debug(message, ##__VA_ARGS__)
+#define avb_errorv(message, ...) avb_error(message, ##__VA_ARGS__)
+#define avb_fatalv(message, ...) avb_fatal(message, ##__VA_ARGS__)
+#endif
+
+/* Converts a 16-bit unsigned integer from big-endian to host byte order. */
+uint16_t avb_be16toh(uint16_t in) AVB_ATTR_WARN_UNUSED_RESULT;
+
/* Converts a 32-bit unsigned integer from big-endian to host byte order. */
uint32_t avb_be32toh(uint32_t in) AVB_ATTR_WARN_UNUSED_RESULT;
/* Converts a 64-bit unsigned integer from big-endian to host byte order. */
uint64_t avb_be64toh(uint64_t in) AVB_ATTR_WARN_UNUSED_RESULT;
+/* Converts a 16-bit unsigned integer from host to big-endian byte order. */
+uint16_t avb_htobe16(uint16_t in) AVB_ATTR_WARN_UNUSED_RESULT;
+
/* Converts a 32-bit unsigned integer from host to big-endian byte order. */
uint32_t avb_htobe32(uint32_t in) AVB_ATTR_WARN_UNUSED_RESULT;
@@ -261,6 +260,11 @@ void avb_uppercase(char* str);
*/
char* avb_bin2hex(const uint8_t* data, size_t data_len);
+/* Writes |value| to |digits| in base 10 followed by a NUL byte.
+ * Returns number of characters written excluding the NUL byte.
+ */
+#define AVB_MAX_DIGITS_UINT64 32
+size_t avb_uint64_to_base10(uint64_t value, char digits[AVB_MAX_DIGITS_UINT64]);
#ifdef __cplusplus
}
#endif
diff --git a/lib/libavb/avb_vbmeta_image.c b/lib/libavb/avb_vbmeta_image.c
index 384f5ac19e5..44d75fda322 100644
--- a/lib/libavb/avb_vbmeta_image.c
+++ b/lib/libavb/avb_vbmeta_image.c
@@ -254,6 +254,7 @@ void avb_vbmeta_image_header_to_host_byte_order(const AvbVBMetaImageHeader* src,
dest->rollback_index = avb_be64toh(dest->rollback_index);
dest->flags = avb_be32toh(dest->flags);
+ dest->rollback_index_location = avb_be32toh(dest->rollback_index_location);
}
const char* avb_vbmeta_verify_result_to_string(AvbVBMetaVerifyResult result) {
diff --git a/lib/libavb/avb_vbmeta_image.h b/lib/libavb/avb_vbmeta_image.h
index 24f8519ff60..221ccd1d383 100644
--- a/lib/libavb/avb_vbmeta_image.h
+++ b/lib/libavb/avb_vbmeta_image.h
@@ -157,10 +157,12 @@ typedef struct AvbVBMetaImageHeader {
*/
uint32_t flags;
- /* 124: Reserved to ensure |release_string| start on a 16-byte
- * boundary. Must be set to zeroes.
+ /* 124: The location of the rollback index defined in this header.
+ * Only valid for the main vbmeta. For chained partitions, the rollback
+ * index location must be specified in the AvbChainPartitionDescriptor
+ * and this value must be set to 0.
*/
- uint8_t reserved0[4];
+ uint32_t rollback_index_location;
/* 128: The release string from avbtool, e.g. "avbtool 1.0.0" or
* "avbtool 1.0.0 xyz_board Git-234abde89". Is guaranteed to be NUL
diff --git a/lib/libavb/avb_version.h b/lib/libavb/avb_version.h
index 57c6ece851c..e6f7798769d 100644
--- a/lib/libavb/avb_version.h
+++ b/lib/libavb/avb_version.h
@@ -18,7 +18,7 @@ extern "C" {
/* The version number of AVB - keep in sync with avbtool. */
#define AVB_VERSION_MAJOR 1
-#define AVB_VERSION_MINOR 1
+#define AVB_VERSION_MINOR 3
#define AVB_VERSION_SUB 0
/* Returns a NUL-terminated string for the libavb version in use. The