Re: [PATCH v4 2/2] bootconfig: Fix integer overflow in initrd size check

From: Sang-Heon Jeon

Date: Thu Sep 10 2026 - 12:39:12 EST


On Fri, Sep 11, 2026 at 12:15 AM Masami Hiramatsu (Google)
<mhiramat@xxxxxxxxxx> wrote:
>
> From: Masami Hiramatsu (Google) <mhiramat@xxxxxxxxxx>
>
> Sashiko reported that in get_boot_config_from_initrd(), a crafted initrd
> with a huge bootconfig size (such as 0xFFFFFFFF) can cause the pointer
> arithmetic:
>
> data = ((void *)hdr) - size;
>
> to wrap around on 32-bit systems (or when pointer subtraction overflows).
> Because data wraps around, the subsequent bounds check:
>
> if ((unsigned long)data < initrd_start)
>
> evaluates to false, bypassing the check. The kernel then calls
> xbc_calc_checksum(data, size), which attempts to read 4GB of memory,
> hitting unmapped pages and triggering a fatal kernel page fault during
> early boot. Furthermore, on 64-bit systems with an initrd > 4.29 GB, an
> unbounded 32-bit size can similarly bypass the initrd_start check.
>
> Fix this by:
> 1. Ensuring the initrd is at least large enough to contain the bootconfig
> footer and verifying hdr is within the initrd bounds.
> 2. Checking that size does not exceed XBC_DATA_MAX and does not exceed
> the available space between initrd_start and hdr before performing
> pointer subtraction.
>
> Fixes: de462e5f1071 ("bootconfig: Fix to remove bootconfig data from initrd while boot")
> Cc: stable@xxxxxxxxxxxxxxx
> Reported-by: Sashiko <sashiko-bot@xxxxxxxxxx>
> Closes: https://lore.kernel.org/all/20260910010137.EE0431F000FF@xxxxxxxxxxxxxxx/
> Assisted-by: Antigravity:gemini-3.8-flash
> Signed-off-by: Masami Hiramatsu (Google) <mhiramat@xxxxxxxxxx>
> ---
> Changes in v4:
> - Accurate the error message for size > XBC_DATA_MAX in
> get_boot_config_from_initrd().
> - Remove redundant (and wrong) size >= XBC_DATA_MAX check from
> setup_boot_config().
> ---
> init/main.c | 25 +++++++++++++++----------
> 1 file changed, 15 insertions(+), 10 deletions(-)
>
> diff --git a/init/main.c b/init/main.c
> index 2613d3f9b3ce..16749bb7a219 100644
> --- a/init/main.c
> +++ b/init/main.c
> @@ -277,7 +277,8 @@ static void * __init get_boot_config_from_initrd(size_t *_size)
> u8 *hdr;
> int i;
>
> - if (!initrd_end)
> + if (!initrd_end || initrd_end < initrd_start ||
> + initrd_end - initrd_start < BOOTCONFIG_MAGIC_LEN + 8)
> return NULL;

(nit) how about moving BOOTCONFIG_FOOTER_SIZE from tools and using it instead?

> data = (char *)initrd_end - BOOTCONFIG_MAGIC_LEN;
> @@ -294,16 +295,26 @@ static void * __init get_boot_config_from_initrd(size_t *_size)
>
> found:
> hdr = (u8 *)(data - 8);
> + if ((unsigned long)hdr < initrd_start)
> + return NULL;
> +
> size = get_unaligned_le32(hdr);
> csum = get_unaligned_le32(hdr + 4);
>
> - data = ((void *)hdr) - size;
> - if ((unsigned long)data < initrd_start) {
> - pr_err("bootconfig size %d is greater than initrd size %ld\n",
> + if (size > XBC_DATA_MAX) {
> + pr_err("bootconfig size %u is greater than max size %d\n",
> + size, XBC_DATA_MAX);
> + return NULL;
> + }
> +
> + if (size > ((unsigned long)hdr - initrd_start)) {
> + pr_err("bootconfig size %u is greater than initrd size %lu\n",
> size, initrd_end - initrd_start);
> return NULL;
> }
>
> + data = ((void *)hdr) - size;
> +
> if (xbc_calc_checksum(data, size) != csum) {
> pr_err("bootconfig checksum failed\n");
> return NULL;
> @@ -394,12 +405,6 @@ static void __init setup_boot_config(void)
> return;
> }
>
> - if (size >= XBC_DATA_MAX) {
> - pr_err("bootconfig size %ld greater than max size %d\n",
> - (long)size, XBC_DATA_MAX);
> - return;
> - }
> -

Nice cleanup!

> ret = xbc_init(data, size, &msg, &pos);
> if (ret < 0) {
> if (pos < 0)
>

Thanks for doing this work!

Reviewed-by: Sang-Heon Jeon <ekffu200098@xxxxxxxxx>

Best regards,
Sang-Heon Jeon