* [PATCH v1 1/2] boot: android: Add Android 13+ bootflow support to bootmeth.
@ 2026-08-18 17:53 Valentin Liu
2026-08-18 17:53 ` [PATCH v1 2/2] boot: android: Add AVB verification support for different bootflow Valentin Liu
2026-08-20 12:31 ` [PATCH v1 1/2] boot: android: Add Android 13+ bootflow support to bootmeth Simon Glass
0 siblings, 2 replies; 6+ messages in thread
From: Valentin Liu @ 2026-08-18 17:53 UTC (permalink / raw)
To: u-boot
Cc: mkorpershoek, sjg, trini, igor.opaniuk, alchark, quentin.schulz,
marek.vasut+renesas, daniel, rs, Valentin Liu
The devices launching Android 13+ were using a new partition
named init_boot to store generic ramdisk.
In the new bootflow, kernel still be stored in boot image,
however, the First Stage files in ramdisk were moved to
init_boot image. We should load it to memory and verify it
so that the kernel can execute init program to continue booting.
Currently, we have supported loading the init_boot image by
abootimg command, but we still need bring this ability to
bootmeth, so that booting Android 13+ will be more easily.
Bootmeth will be able to recognize the new partition layout,
and boot Android normally.
Link: https://source.android.com/docs/core/architecture/partitions/generic-boot
Signed-off-by: Valentin Liu <valentinliu@icloud.com>
---
boot/bootmeth_android.c | 67 ++++++++++++++++++++++++++++++++
boot/image-android.c | 16 ++++++++
cmd/abootimg.c | 5 +++
doc/develop/bootstd/overview.rst | 3 ++
include/android_image.h | 1 +
include/image.h | 35 +++++++++++++++++
6 files changed, 127 insertions(+)
diff --git a/boot/bootmeth_android.c b/boot/bootmeth_android.c
index ec255b072af..904640d360b 100644
--- a/boot/bootmeth_android.c
+++ b/boot/bootmeth_android.c
@@ -29,6 +29,7 @@
#define BCB_FIELD_COMMAND_SZ 32
#define BCB_PART_NAME "misc"
#define BOOT_PART_NAME "boot"
+#define INIT_BOOT_PART_NAME "init_boot"
#define VENDOR_BOOT_PART_NAME "vendor_boot"
#define SLOT_LEN 2
@@ -47,6 +48,7 @@ struct android_priv {
char *slot;
u32 header_version;
u32 boot_img_size;
+ u32 init_boot_img_size;
u32 vendor_boot_img_size;
};
@@ -113,6 +115,51 @@ static int scan_boot_part(struct udevice *blk, struct android_priv *priv)
return 0;
}
+static int scan_init_boot_part(struct udevice *blk, struct android_priv *priv)
+{
+ struct blk_desc *desc = dev_get_uclass_plat(blk);
+ struct disk_partition partition;
+ char partname[PART_NAME_LEN];
+ ulong num_blks, bufsz;
+ char *buf;
+ int ret;
+
+ if (priv->slot)
+ sprintf(partname, INIT_BOOT_PART_NAME "_%s", priv->slot);
+ else
+ sprintf(partname, INIT_BOOT_PART_NAME);
+
+ ret = part_get_info_by_name(desc, partname, &partition);
+ if (ret < 0)
+ return log_msg_ret("part info", ret);
+
+ num_blks = DIV_ROUND_UP(sizeof(struct andr_boot_img_hdr_v3), desc->blksz);
+ bufsz = num_blks * desc->blksz;
+ buf = malloc(bufsz);
+ if (!buf)
+ return log_msg_ret("buf", -ENOMEM);
+
+ ret = blk_read(blk, partition.start, num_blks, buf);
+ if (ret != num_blks) {
+ free(buf);
+ return log_msg_ret("part read", -EIO);
+ }
+
+ if (!is_android_boot_image_header(buf)) {
+ free(buf);
+ return log_msg_ret("header", -ENOENT);
+ }
+
+ if (!android_image_get_bootimg_size(buf, &priv->init_boot_img_size)) {
+ free(buf);
+ return log_msg_ret("get init bootimg size", -EINVAL);
+ }
+
+ free(buf);
+
+ return 0;
+}
+
static int scan_vendor_boot_part(struct udevice *blk, struct android_priv *priv)
{
struct blk_desc *desc = dev_get_uclass_plat(blk);
@@ -291,6 +338,17 @@ static int android_read_bootflow(struct udevice *dev, struct bootflow *bflow)
goto free_priv;
}
+ if (priv->header_version >= 4) {
+ ret = scan_init_boot_part(bflow->blk, priv);
+ if (ret < 0) {
+ /*
+ * Android 12 devices do not have the init_boot partition.
+ * Some devices upgraded to Android 13 or later from
+ * earlier Android versions may also not have one.
+ */
+ log_debug("scan init_boot failed: err=%d\n", ret);
+ }
+ }
if (priv->header_version >= 3) {
ret = scan_vendor_boot_part(bflow->blk, priv);
if (ret < 0) {
@@ -556,6 +614,7 @@ static int boot_android_normal(struct bootflow *bflow)
struct android_priv *priv = bflow->bootmeth_priv;
int ret;
ulong loadaddr = env_get_hex("loadaddr", 0);
+ ulong iloadaddr = env_get_hex("init_boot_comp_addr_r", 0);
ulong vloadaddr = env_get_hex("vendor_boot_comp_addr_r", 0);
ret = run_avb_verification(bflow);
@@ -572,6 +631,14 @@ static int boot_android_normal(struct bootflow *bflow)
if (ret < 0)
return log_msg_ret("read boot", ret);
+ if (priv->header_version >= 4 && priv->init_boot_img_size > 0) {
+ ret = read_slotted_partition(desc, "init_boot", priv->slot,
+ priv->init_boot_img_size,
+ iloadaddr);
+ if (ret < 0)
+ return log_msg_ret("read init_boot", ret);
+ set_ainit_bootimg_addr(iloadaddr);
+ }
if (priv->header_version >= 3) {
ret = read_slotted_partition(desc, "vendor_boot", priv->slot,
priv->vendor_boot_img_size, vloadaddr);
diff --git a/boot/image-android.c b/boot/image-android.c
index 7740cae8cb6..3f5634b469f 100644
--- a/boot/image-android.c
+++ b/boot/image-android.c
@@ -326,6 +326,22 @@ bool android_image_get_data(const void *boot_hdr, const void *vendor_boot_hdr,
return true;
}
+bool android_image_get_data_v4(const void *boot_hdr, const void *vendor_boot_hdr,
+ const void *init_boot_hdr, struct andr_image_data *data)
+{
+ if (!android_image_get_data(boot_hdr, vendor_boot_hdr, data))
+ return false;
+
+ if (!is_android_boot_image_header(init_boot_hdr)) {
+ printf("Incorrect init boot image header\n");
+ return false;
+ }
+
+ android_boot_image_v3_v4_parse_hdr(init_boot_hdr, data);
+
+ return true;
+}
+
static ulong android_image_get_kernel_addr(struct andr_image_data *img_data,
ulong comp)
{
diff --git a/cmd/abootimg.c b/cmd/abootimg.c
index eae3e643b60..e8e6b8f5ced 100644
--- a/cmd/abootimg.c
+++ b/cmd/abootimg.c
@@ -33,6 +33,11 @@ ulong get_ainit_bootimg_addr(void)
return _ainit_bootimg_addr;
}
+void set_ainit_bootimg_addr(ulong addr)
+{
+ _ainit_bootimg_addr = addr;
+}
+
ulong get_avendor_bootimg_addr(void)
{
return _avendor_bootimg_addr;
diff --git a/doc/develop/bootstd/overview.rst b/doc/develop/bootstd/overview.rst
index ec9fafa0fa0..f1306ae0a8f 100644
--- a/doc/develop/bootstd/overview.rst
+++ b/doc/develop/bootstd/overview.rst
@@ -293,6 +293,9 @@ script_offset_f
script_size_f
Size of the script to load, e.g. 0x2000
+init_boot_comp_addr_r
+ Address to which to load the init_boot Android image, e.g. 0xd0000000
+
vendor_boot_comp_addr_r
Address to which to load the vendor_boot Android image, e.g. 0xe0000000
diff --git a/include/android_image.h b/include/android_image.h
index a2d80499ba3..134b5ed74d6 100644
--- a/include/android_image.h
+++ b/include/android_image.h
@@ -357,6 +357,7 @@ struct andr_image_data {
ulong tags_addr; /* physical addr for kernel tags */
u32 header_version; /* version of the boot image header */
u32 boot_img_total_size; /* boot image size */
+ u32 init_boot_img_total_size; /* init boot image size */
u32 vendor_boot_img_total_size; /* vendor boot image size */
};
diff --git a/include/image.h b/include/image.h
index 6edcb1995bf..1c725fc2601 100644
--- a/include/image.h
+++ b/include/image.h
@@ -2041,6 +2041,23 @@ bool android_image_get_vendor_bootimg_size(const void *hdr, u32 *vendor_boot_img
bool android_image_get_data(const void *boot_hdr, const void *vendor_boot_hdr,
struct andr_image_data *data);
+/**
+ * android_image_get_data_v4() - Parse Android header version 4 boot images
+ *
+ * This is used to parse boot, vendor-boot and init boot header into
+ * andr_image_data generic structure.
+ * The Android 13 and newer has splited parameters from boot and
+ * vendor_boot images to the init_boot image.
+ *
+ * @boot_hdr: Pointer to boot image header
+ * @vendor_boot_hdr: Pointer to vendor boot image header
+ * @init_boot_hdr: Pointer to init boot image header
+ * @data: Pointer to generic boot format structure
+ * Return: true if succeeded, false otherwise
+ */
+bool android_image_get_data_v4(const void *boot_hdr, const void *vendor_boot_hdr,
+ const void *init_boot_hdr, struct andr_image_data *data);
+
struct andr_boot_img_hdr_v0;
/**
@@ -2167,6 +2184,17 @@ bool android_image_print_dtb_contents(ulong hdr_addr);
*/
bool is_android_boot_image_header(const void *hdr);
+/**
+ * is_android_init_boot_image_header() - Check the magic of init boot image
+ *
+ * This checks the header of Android init boot image and verifies the
+ * magic is "ANDROID!" (same with the boot image)
+ *
+ * @init_boot_img: Pointer to boot image
+ * Return: non-zero if the magic is correct, zero otherwise
+ */
+bool is_android_init_boot_image_header(const void *init_boot_img);
+
/**
* is_android_vendor_boot_image_header() - Check the magic of vendor boot image
*
@@ -2199,6 +2227,13 @@ void set_abootimg_addr(ulong addr);
*/
ulong get_ainit_bootimg_addr(void);
+/**
+ * set_ainit_bootimg_addr() - Set Android init boot image address
+ *
+ * Return: no returned results
+ */
+void set_ainit_bootimg_addr(ulong addr);
+
/**
* get_avendor_bootimg_addr() - Get Android vendor boot image address
*
--
2.53.0
^ permalink raw reply related [flat|nested] 6+ messages in thread
* [PATCH v1 2/2] boot: android: Add AVB verification support for different bootflow.
2026-08-18 17:53 [PATCH v1 1/2] boot: android: Add Android 13+ bootflow support to bootmeth Valentin Liu
@ 2026-08-18 17:53 ` Valentin Liu
2026-08-20 12:31 ` Simon Glass
2026-08-20 12:31 ` [PATCH v1 1/2] boot: android: Add Android 13+ bootflow support to bootmeth Simon Glass
1 sibling, 1 reply; 6+ messages in thread
From: Valentin Liu @ 2026-08-18 17:53 UTC (permalink / raw)
To: u-boot
Cc: mkorpershoek, sjg, trini, igor.opaniuk, alchark, quentin.schulz,
marek.vasut+renesas, daniel, rs, Valentin Liu
The different Android versions have their own partition layout,
so the AVB verification process should be dynamic.
In the new verification process, we need to use the header version
fetched from boot partition, so we need to check the boot partition
firstly to avoid the downgrade attacking.
If we didn't check boot firstly, just use it, the attacker can
bypass the AVB verification by flashing a boot image with header
version 3 or earlier.
Signed-off-by: Valentin Liu <valentinliu@icloud.com>
---
boot/bootmeth_android.c | 43 ++++++++++++++++++++++++++++++++++++-----
1 file changed, 38 insertions(+), 5 deletions(-)
diff --git a/boot/bootmeth_android.c b/boot/bootmeth_android.c
index 904640d360b..55cd99f3043 100644
--- a/boot/bootmeth_android.c
+++ b/boot/bootmeth_android.c
@@ -479,11 +479,12 @@ static int avb_append_commandline(struct bootflow *bflow, char *cmdline)
return 0;
}
-static int run_avb_verification(struct bootflow *bflow)
+static int run_avb_verification(struct bootflow *bflow, const bool boot_only)
{
struct blk_desc *desc = dev_get_uclass_plat(bflow->blk);
struct android_priv *priv = bflow->bootmeth_priv;
- const char * const requested_partitions[] = {"boot", "vendor_boot", NULL};
+ const char *requested_partitions[4];
+ int requested_partitions_num = 0;
struct AvbOps *avb_ops;
AvbSlotVerifyResult result;
AvbSlotVerifyData *out_data = NULL;
@@ -493,6 +494,28 @@ static int run_avb_verification(struct bootflow *bflow)
bool unlocked = false;
int ret;
+ /*
+ * Always verify boot first.
+ *
+ * When boot_only is true, only verify the boot partition.
+ * Otherwise, select additional partitions according to the
+ * Android boot image header version.
+ */
+ requested_partitions[requested_partitions_num++] = "boot";
+
+ if (!boot_only) {
+ if (priv->header_version >= 3)
+ requested_partitions[requested_partitions_num++] =
+ "vendor_boot";
+
+ if (priv->header_version >= 4 &&
+ priv->init_boot_img_size > 0)
+ requested_partitions[requested_partitions_num++] =
+ "init_boot";
+ }
+
+ requested_partitions[requested_partitions_num] = NULL;
+
avb_ops = avb_ops_alloc(desc->devnum);
if (!avb_ops)
return log_msg_ret("avb ops", -ENOMEM);
@@ -562,9 +585,10 @@ static int run_avb_verification(struct bootflow *bflow)
return ret;
}
#else
-static int run_avb_verification(struct bootflow *bflow)
+static int run_avb_verification(struct bootflow *bflow, const bool boot_only)
{
int ret;
+ (void)boot_only;
/* When AVB is unsupported, pass ORANGE state */
ret = bootflow_cmdline_set_arg(bflow,
@@ -617,9 +641,13 @@ static int boot_android_normal(struct bootflow *bflow)
ulong iloadaddr = env_get_hex("init_boot_comp_addr_r", 0);
ulong vloadaddr = env_get_hex("vendor_boot_comp_addr_r", 0);
- ret = run_avb_verification(bflow);
+ /*
+ * Checking the boot partition firstly because the standard AVB
+ * verification is rely on the header version from boot partition.
+ */
+ ret = run_avb_verification(bflow, true);
if (ret < 0)
- return log_msg_ret("avb", ret);
+ return log_msg_ret("avb boot", ret);
/* Read slot once more to decrement counter from BCB */
ret = android_read_slot_from_bcb(bflow, true);
@@ -631,6 +659,11 @@ static int boot_android_normal(struct bootflow *bflow)
if (ret < 0)
return log_msg_ret("read boot", ret);
+ /* Standard AVB verification */
+ ret = run_avb_verification(bflow, false);
+ if (ret < 0)
+ return log_msg_ret("avb", ret);
+
if (priv->header_version >= 4 && priv->init_boot_img_size > 0) {
ret = read_slotted_partition(desc, "init_boot", priv->slot,
priv->init_boot_img_size,
--
2.53.0
^ permalink raw reply related [flat|nested] 6+ messages in thread
* Re: [PATCH v1 1/2] boot: android: Add Android 13+ bootflow support to bootmeth.
2026-08-18 17:53 [PATCH v1 1/2] boot: android: Add Android 13+ bootflow support to bootmeth Valentin Liu
2026-08-18 17:53 ` [PATCH v1 2/2] boot: android: Add AVB verification support for different bootflow Valentin Liu
@ 2026-08-20 12:31 ` Simon Glass
2026-08-20 15:10 ` Tom Rini
2026-08-20 16:41 ` Re:Re: " 刘垣辰
1 sibling, 2 replies; 6+ messages in thread
From: Simon Glass @ 2026-08-20 12:31 UTC (permalink / raw)
To: valentinliu
Cc: u-boot, mkorpershoek, sjg, trini, igor.opaniuk, alchark,
quentin.schulz, marek.vasut+renesas, daniel, rs
Hi Valentin,
On 2026-08-18T17:53:00, Valentin Liu <valentinliu@icloud.com> wrote:
> boot: android: Add Android 13+ bootflow support to bootmeth.
Please drop the trailing period and keep the subject under 60 characters.
>
> The devices launching Android 13+ were using a new partition
> named init_boot to store generic ramdisk.
>
> In the new bootflow, kernel still be stored in boot image,
> however, the First Stage files in ramdisk were moved to
> init_boot image. We should load it to memory and verify it
> so that the kernel can execute init program to continue booting.
>
> Currently, we have supported loading the init_boot image by
> abootimg command, but we still need bring this ability to
> bootmeth, so that booting Android 13+ will be more easily.
Please use present/imperative tense throughout: 'were using' -> 'use',
'kernel still be stored' -> 'the kernel is still stored', 'were moved'
-> 'are moved', 'we still need bring' -> 'we still need to bring',
'more easily' -> 'easier'.
>
> In the new bootflow, kernel still be stored in boot image,
> however, the First Stage files in ramdisk were moved to
> init_boot image. We should load it to memory and verify it
> so that the kernel can execute init program to continue booting.
>
> Currently, we have supported loading the init_boot image by
> abootimg command, but we still need bring this ability to
> bootmeth, so that booting Android 13+ will be more easily.
> Bootmeth will be able to recognize the new partition layout,
> and boot Android normally.
>
> Link: https://source.android.com/docs/core/architecture/partitions/generic-boot
> Signed-off-by: Valentin Liu <valentinliu@icloud.com>
>
> boot/bootmeth_android.c | 67 ++++++++++++++++++++++++++++++++++++++++
> boot/image-android.c | 16 ++++++++++
> cmd/abootimg.c | 5 +++
> doc/develop/bootstd/overview.rst | 3 ++
> include/android_image.h | 1 +
> include/image.h | 35 +++++++++++++++++++++
> 6 files changed, 127 insertions(+)
Please can you look at how to add a test for this addition?
> diff --git a/boot/bootmeth_android.c b/boot/bootmeth_android.c
> @@ -113,6 +115,51 @@ static int scan_boot_part(struct udevice *blk, struct android_priv *priv)
> +static int scan_init_boot_part(struct udevice *blk, struct android_priv *priv)
> +{
> + struct blk_desc *desc = dev_get_uclass_plat(blk);
> + struct disk_partition partition;
> + char partname[PART_NAME_LEN];
> + ulong num_blks, bufsz;
> + char *buf;
> + int ret;
> +
> + if (priv->slot)
> + sprintf(partname, INIT_BOOT_PART_NAME "_%s", priv->slot);
> + else
> + sprintf(partname, INIT_BOOT_PART_NAME);
This is a near-duplicate of scan_boot_part() and
scan_vendor_boot_part(). Please factor the common logic (build
partname, read the header block, check magic, extract size) into a
helper rather than adding a third copy.
> diff --git a/boot/bootmeth_android.c b/boot/bootmeth_android.c
> @@ -291,6 +338,17 @@ static int android_read_bootflow(struct udevice *dev, struct bootflow *bflow)
> + if (priv->header_version >= 4) {
> + ret = scan_init_boot_part(bflow->blk, priv);
> + if (ret < 0) {
> + /*
> + * Android 12 devices do not have the init_boot partition.
> + * Some devices upgraded to Android 13 or later from
> + * earlier Android versions may also not have one.
> + */
> + log_debug("scan init_boot failed: err=%d\n", ret);
> + }
> + }
priv is allocated with plain malloc() above, so it is not zeroed. On
failure here priv->init_boot_img_size is left uninitialised, then
boot_android_normal() and (in patch 2) run_avb_verification() read it
back as 'priv->init_boot_img_size > 0'. Please use calloc()/memset(),
or explicitly set priv->init_boot_img_size = 0 before the call and on
the failure path.
> diff --git a/boot/bootmeth_android.c b/boot/bootmeth_android.c
> @@ -556,6 +614,7 @@ static int boot_android_normal(struct bootflow *bflow)
> ulong loadaddr = env_get_hex("loadaddr", 0);
> + ulong iloadaddr = env_get_hex("init_boot_comp_addr_r", 0);
> ulong vloadaddr = env_get_hex("vendor_boot_comp_addr_r", 0);
If init_boot_comp_addr_r is unset, env_get_hex() returns 0 and you
silently load init_boot at address 0 and call
set_ainit_bootimg_addr(0). Please check that iloadaddr is non-zero and
error out with a clear message before using it - the vendor_boot path
has the same weakness, but let's not extend the pattern.
> diff --git a/boot/image-android.c b/boot/image-android.c
> @@ -326,6 +326,22 @@ bool android_image_get_data(const void *boot_hdr, const void *vendor_boot_hdr,
> +bool android_image_get_data_v4(const void *boot_hdr, const void *vendor_boot_hdr,
> + const void *init_boot_hdr, struct andr_image_data *data)
> +{
> + if (!android_image_get_data(boot_hdr, vendor_boot_hdr, data))
> + return false;
> +
> + if (!is_android_boot_image_header(init_boot_hdr)) {
> + printf("Incorrect init boot image header\n");
> + return false;
> + }
> +
> + android_boot_image_v3_v4_parse_hdr(init_boot_hdr, data);
> +
> + return true;
> +}
I can't find any caller of android_image_get_data_v4(). Please either
wire it up to whatever consumes init_boot_img_total_size, or drop it
(and the new struct field, and the header declaration) until it is
needed.
> diff --git a/include/image.h b/include/image.h
> @@ -2167,6 +2184,17 @@ bool android_image_print_dtb_contents(ulong hdr_addr);
> +/**
> + * is_android_init_boot_image_header() - Check the magic of init boot image
> + *
> + * This checks the header of Android init boot image and verifies the
> + * magic is "ANDROID!" (same with the boot image)
> + *
> + * @init_boot_img: Pointer to boot image
> + * Return: non-zero if the magic is correct, zero otherwise
> + */
> +bool is_android_init_boot_image_header(const void *init_boot_img);
Declared but never defined or called - scan_init_boot_part() uses
is_android_boot_image_header() directly, which is correct since the
magic is identical. Please drop the declaration.
> diff --git a/include/image.h b/include/image.h
> @@ -2199,6 +2227,13 @@ void set_abootimg_addr(ulong addr);
> +/**
> + * set_ainit_bootimg_addr() - Set Android init boot image address
> + *
> + * Return: no returned results
> + */
> +void set_ainit_bootimg_addr(ulong addr);
Missing @addr: description, and a void function does not need a
Return: line - please drop it.
> diff --git a/doc/develop/bootstd/overview.rst b/doc/develop/bootstd/overview.rst
> @@ -293,6 +293,9 @@ script_offset_f
> +init_boot_comp_addr_r
> + Address to which to load the init_boot Android image, e.g. 0xd0000000
Since this env var is required for Android 13+ to boot, please also
document it in the relevant board README(s) / sample env, and handle
the missing case gracefully in the code (see comment on
boot_android_normal()).
Regards,
Simon
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH v1 2/2] boot: android: Add AVB verification support for different bootflow.
2026-08-18 17:53 ` [PATCH v1 2/2] boot: android: Add AVB verification support for different bootflow Valentin Liu
@ 2026-08-20 12:31 ` Simon Glass
0 siblings, 0 replies; 6+ messages in thread
From: Simon Glass @ 2026-08-20 12:31 UTC (permalink / raw)
To: valentinliu
Cc: u-boot, mkorpershoek, sjg, trini, igor.opaniuk, alchark,
quentin.schulz, marek.vasut+renesas, daniel, rs
Hi Valentin,
On 2026-08-18T17:53:00, Valentin Liu <valentinliu@icloud.com> wrote:
> boot: android: Add AVB verification support for different bootflow.
Drop the trailing period from the subject.
>
> The different Android versions have their own partition layout,
> so the AVB verification process should be dynamic.
>
> In the new verification process, we need to use the header version
> fetched from boot partition, so we need to check the boot partition
> firstly to avoid the downgrade attacking.
>
> If we didn't check boot firstly, just use it, the attacker can
> bypass the AVB verification by flashing a boot image with header
> version 3 or earlier.
Please use present tense throughout, 'first' rather than 'firstly',
and 'downgrade attack' rather than 'downgrade attacking'. I also don't
follow the security argument: priv->header_version is populated by
scan_boot_part() from the unverified on-disk image and is not re-read
after the first AVB pass, so verifying boot on its own does not change
which partitions the second pass includes - an attacker who can flash
a signed v3 boot image would still get init_boot skipped. Can you
explain what the first pass actually protects against, or is the
intent to re-parse the header from the AVB-verified copy before the
second call?
>
> Signed-off-by: Valentin Liu <valentinliu@icloud.com>
>
> boot/bootmeth_android.c | 43 ++++++++++++++++++++++++++++++++++++++-----
> 1 file changed, 38 insertions(+), 5 deletions(-)
> diff --git a/boot/bootmeth_android.c b/boot/bootmeth_android.c
> @@ -479,11 +479,12 @@ static int avb_append_commandline(struct bootflow *bflow, char *cmdline)
> return 0;
> }
>
> -static int run_avb_verification(struct bootflow *bflow)
> +static int run_avb_verification(struct bootflow *bflow, const bool boot_only)
The const on a by-value parameter has no effect on callers and isn't
the style used elsewhere in this file - please drop it.
> diff --git a/boot/bootmeth_android.c b/boot/bootmeth_android.c
> @@ -493,6 +494,28 @@ static int run_avb_verification(struct bootflow *bflow)
> bool unlocked = false;
> int ret;
>
> + /*
> + * Always verify boot first.
> + *
> + * When boot_only is true, only verify the boot partition.
> + * Otherwise, select additional partitions according to the
> + * Android boot image header version.
> + */
> + requested_partitions[requested_partitions_num++] = "boot";
> +
> + if (!boot_only) {
> + if (priv->header_version >= 3)
> + requested_partitions[requested_partitions_num++] =
> + "vendor_boot";
> +
> + if (priv->header_version >= 4 &&
> + priv->init_boot_img_size > 0)
> + requested_partitions[requested_partitions_num++] =
> + "init_boot";
> + }
> +
> + requested_partitions[requested_partitions_num] = NULL;
Please use BOOT_PART_NAME / VENDOR_BOOT_PART_NAME /
INIT_BOOT_PART_NAME instead of open-coded strings. Also 'n' or 'count'
would read better than requested_partitions_num, and the array bound 4
would benefit from a named constant or a comment for the boot +
vendor_boot + init_boot + NULL layout.
> diff --git a/boot/bootmeth_android.c b/boot/bootmeth_android.c
> @@ -562,9 +585,10 @@ static int run_avb_verification(struct bootflow *bflow)
> return ret;
> }
> #else
> -static int run_avb_verification(struct bootflow *bflow)
> +static int run_avb_verification(struct bootflow *bflow, const bool boot_only)
> {
> int ret;
> + (void)boot_only;
Can you use __maybe_unused on the parameter rather than a (void) cast?
That's the U-Boot convention for stubs.
> diff --git a/boot/bootmeth_android.c b/boot/bootmeth_android.c
> @@ -617,9 +641,13 @@ static int boot_android_normal(struct bootflow *bflow)
> ulong iloadaddr = env_get_hex("init_boot_comp_addr_r", 0);
> ulong vloadaddr = env_get_hex("vendor_boot_comp_addr_r", 0);
>
> - ret = run_avb_verification(bflow);
> + /*
> + * Checking the boot partition firstly because the standard AVB
> + * verification is rely on the header version from boot partition.
> + */
> + ret = run_avb_verification(bflow, true);
Grammar: 'Check the boot partition first, because the standard AVB
verification relies on the header version read from the boot
partition.' See my earlier comment - please clarify in the comment and
commit message what the first pass buys us, given that
priv->header_version is not re-read between the two calls.
> diff --git a/boot/bootmeth_android.c b/boot/bootmeth_android.c
> @@ -631,6 +659,11 @@ static int boot_android_normal(struct bootflow *bflow)
> if (ret < 0)
> return log_msg_ret("read boot", ret);
>
> + /* Standard AVB verification */
> + ret = run_avb_verification(bflow, false);
> + if (ret < 0)
> + return log_msg_ret("avb", ret);
> +
This re-verifies boot as well as vendor_boot/init_boot, so the boot
partition (which can be tens of MB) is hashed twice on every boot. Can
you split run_avb_verification() so the second call verifies only the
additional partitions? That would also avoid appending the same
androidboot.vbmeta/verifiedbootstate args twice and relying on
bootflow_cmdline_set_arg() to dedupe by key.
Regards,
Simon
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH v1 1/2] boot: android: Add Android 13+ bootflow support to bootmeth.
2026-08-20 12:31 ` [PATCH v1 1/2] boot: android: Add Android 13+ bootflow support to bootmeth Simon Glass
@ 2026-08-20 15:10 ` Tom Rini
2026-08-20 16:41 ` Re:Re: " 刘垣辰
1 sibling, 0 replies; 6+ messages in thread
From: Tom Rini @ 2026-08-20 15:10 UTC (permalink / raw)
To: Simon Glass
Cc: valentinliu, u-boot, mkorpershoek, igor.opaniuk, alchark,
quentin.schulz, marek.vasut+renesas, daniel, rs
[-- Attachment #1: Type: text/plain, Size: 1286 bytes --]
On Thu, Aug 20, 2026 at 06:31:18AM -0600, Simon Glass wrote:
> Hi Valentin,
>
> On 2026-08-18T17:53:00, Valentin Liu <valentinliu@icloud.com> wrote:
> > boot: android: Add Android 13+ bootflow support to bootmeth.
>
> Please drop the trailing period and keep the subject under 60 characters.
>
> >
> > The devices launching Android 13+ were using a new partition
> > named init_boot to store generic ramdisk.
>
> >
> > In the new bootflow, kernel still be stored in boot image,
> > however, the First Stage files in ramdisk were moved to
> > init_boot image. We should load it to memory and verify it
> > so that the kernel can execute init program to continue booting.
> >
> > Currently, we have supported loading the init_boot image by
> > abootimg command, but we still need bring this ability to
> > bootmeth, so that booting Android 13+ will be more easily.
>
> Please use present/imperative tense throughout: 'were using' -> 'use',
> 'kernel still be stored' -> 'the kernel is still stored', 'were moved'
> -> 'are moved', 'we still need bring' -> 'we still need to bring',
> 'more easily' -> 'easier'.
We do not have any sort of grammar rules and requirements like that in
the project, please stop giving people feedback like this.
--
Tom
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re:Re: [PATCH v1 1/2] boot: android: Add Android 13+ bootflow support to bootmeth.
2026-08-20 12:31 ` [PATCH v1 1/2] boot: android: Add Android 13+ bootflow support to bootmeth Simon Glass
2026-08-20 15:10 ` Tom Rini
@ 2026-08-20 16:41 ` 刘垣辰
1 sibling, 0 replies; 6+ messages in thread
From: 刘垣辰 @ 2026-08-20 16:41 UTC (permalink / raw)
To: Simon Glass
Cc: u-boot, mkorpershoek, sjg, trini, igor.opaniuk, alchark,
quentin.schulz, marek.vasut+renesas, daniel, rs
[-- Attachment #1: Type: text/plain, Size: 6935 bytes --]
Hi Simon, Thanks for your reviewing and suggestions. I can merge all scanning function into one "helper", just introduce a new variable to condition which partition we needed. But I have no idea about test and document and I have not seen anything in test/ or doc/ folder. Can you give me some advice? I will refactor the AVB logic in the next patch in future. Best regards, Valentin Liu 2026年8月20日下午8:31,Simon Glass <sjg@chromium.org> 写道: Hi Valentin, On 2026-08-18T17:53:00, Valentin Liu <valentinliu@icloud.com> wrote: boot: android: Add Android 13+ bootflow support to bootmeth. Please drop the trailing period and keep the subject under 60 characters. The devices launching Android 13+ were using a new partition named init_boot to store generic ramdisk. In the new bootflow, kernel still be stored in boot image, however, the First Stage files in ramdisk were moved to init_boot image. We should load it to memory and verify it so that the kernel can execute init program to continue booting. Currently, we have supported loading the init_boot image by abootimg command, but we still need bring this ability to bootmeth, so that booting Android 13+ will be more easily. Please use present/imperative tense throughout: 'were using' -> 'use', 'kernel still be stored' -> 'the kernel is still stored', 'were moved' -> 'are moved', 'we still need bring' -> 'we still need to bring', 'more easily' -> 'easier'. In the new bootflow, kernel still be stored in boot image, however, the First Stage files in ramdisk were moved to init_boot image. We should load it to memory and verify it so that the kernel can execute init program to continue booting. Currently, we have supported loading the init_boot image by abootimg command, but we still need bring this ability to bootmeth, so that booting Android 13+ will be more easily. Bootmeth will be able to recognize the new partition layout, and boot Android normally. Link: https://source.android.com/docs/core/architecture/partitions/generic-boot Signed-off-by: Valentin Liu <valentinliu@icloud.com> boot/bootmeth_android.c | 67 ++++++++++++++++++++++++++++++++++++++++ boot/image-android.c | 16 ++++++++++ cmd/abootimg.c | 5 +++ doc/develop/bootstd/overview.rst | 3 ++ include/android_image.h | 1 + include/image.h | 35 +++++++++++++++++++++ 6 files changed, 127 insertions(+) Please can you look at how to add a test for this addition? diff --git a/boot/bootmeth_android.c b/boot/bootmeth_android.c @@ -113,6 +115,51 @@ static int scan_boot_part(struct udevice *blk, struct android_priv *priv) +static int scan_init_boot_part(struct udevice *blk, struct android_priv *priv) +{ + struct blk_desc *desc = dev_get_uclass_plat(blk); + struct disk_partition partition; + char partname[PART_NAME_LEN]; + ulong num_blks, bufsz; + char *buf; + int ret; + + if (priv->slot) + sprintf(partname, INIT_BOOT_PART_NAME "_%s", priv->slot); + else + sprintf(partname, INIT_BOOT_PART_NAME); This is a near-duplicate of scan_boot_part() and scan_vendor_boot_part(). Please factor the common logic (build partname, read the header block, check magic, extract size) into a helper rather than adding a third copy. diff --git a/boot/bootmeth_android.c b/boot/bootmeth_android.c @@ -291,6 +338,17 @@ static int android_read_bootflow(struct udevice *dev, struct bootflow *bflow) + if (priv->header_version >= 4) { + ret = scan_init_boot_part(bflow->blk, priv); + if (ret < 0) { + /* + * Android 12 devices do not have the init_boot partition. + * Some devices upgraded to Android 13 or later from + * earlier Android versions may also not have one. + */ + log_debug("scan init_boot failed: err=%d\n", ret); + } + } priv is allocated with plain malloc() above, so it is not zeroed. On failure here priv->init_boot_img_size is left uninitialised, then boot_android_normal() and (in patch 2) run_avb_verification() read it back as 'priv->init_boot_img_size > 0'. Please use calloc()/memset(), or explicitly set priv->init_boot_img_size = 0 before the call and on the failure path. diff --git a/boot/bootmeth_android.c b/boot/bootmeth_android.c @@ -556,6 +614,7 @@ static int boot_android_normal(struct bootflow *bflow) ulong loadaddr = env_get_hex("loadaddr", 0); + ulong iloadaddr = env_get_hex("init_boot_comp_addr_r", 0); ulong vloadaddr = env_get_hex("vendor_boot_comp_addr_r", 0); If init_boot_comp_addr_r is unset, env_get_hex() returns 0 and you silently load init_boot at address 0 and call set_ainit_bootimg_addr(0). Please check that iloadaddr is non-zero and error out with a clear message before using it - the vendor_boot path has the same weakness, but let's not extend the pattern. diff --git a/boot/image-android.c b/boot/image-android.c @@ -326,6 +326,22 @@ bool android_image_get_data(const void *boot_hdr, const void *vendor_boot_hdr, +bool android_image_get_data_v4(const void *boot_hdr, const void *vendor_boot_hdr, + const void *init_boot_hdr, struct andr_image_data *data) +{ + if (!android_image_get_data(boot_hdr, vendor_boot_hdr, data)) + return false; + + if (!is_android_boot_image_header(init_boot_hdr)) { + printf("Incorrect init boot image header\n"); + return false; + } + + android_boot_image_v3_v4_parse_hdr(init_boot_hdr, data); + + return true; +} I can't find any caller of android_image_get_data_v4(). Please either wire it up to whatever consumes init_boot_img_total_size, or drop it (and the new struct field, and the header declaration) until it is needed. diff --git a/include/image.h b/include/image.h @@ -2167,6 +2184,17 @@ bool android_image_print_dtb_contents(ulong hdr_addr); +/** + * is_android_init_boot_image_header() - Check the magic of init boot image + * + * This checks the header of Android init boot image and verifies the + * magic is "ANDROID!" (same with the boot image) + * + * @init_boot_img: Pointer to boot image + * Return: non-zero if the magic is correct, zero otherwise + */ +bool is_android_init_boot_image_header(const void *init_boot_img); Declared but never defined or called - scan_init_boot_part() uses is_android_boot_image_header() directly, which is correct since the magic is identical. Please drop the declaration. diff --git a/include/image.h b/include/image.h @@ -2199,6 +2227,13 @@ void set_abootimg_addr(ulong addr); +/** + * set_ainit_bootimg_addr() - Set Android init boot image address + * + * Return: no returned results + */ +void set_ainit_bootimg_addr(ulong addr); Missing @addr: description, and a void function does not need a Return: line - please drop it. diff --git a/doc/develop/bootstd/overview.rst b/doc/develop/bootstd/overview.rst @@ -293,6 +293,9 @@ script_offset_f +init_boot_comp_addr_r + Address to which to load the init_boot Android image, e.g. 0xd0000000 Since this env var is required for Android 13+ to boot, please also document it in the relevant board README(s) / sample env, and handle the missing case gracefully in the code (see comment on boot_android_normal()). Regards, Simon
[-- Attachment #2.1: Type: text/html, Size: 10793 bytes --]
^ permalink raw reply [flat|nested] 6+ messages in thread
end of thread, other threads:[~2026-08-20 17:59 UTC | newest]
Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-08-18 17:53 [PATCH v1 1/2] boot: android: Add Android 13+ bootflow support to bootmeth Valentin Liu
2026-08-18 17:53 ` [PATCH v1 2/2] boot: android: Add AVB verification support for different bootflow Valentin Liu
2026-08-20 12:31 ` Simon Glass
2026-08-20 12:31 ` [PATCH v1 1/2] boot: android: Add Android 13+ bootflow support to bootmeth Simon Glass
2026-08-20 15:10 ` Tom Rini
2026-08-20 16:41 ` Re:Re: " 刘垣辰
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.