On Fri, Sep 11, 2026 at 12:15 AM Masami Hiramatsu (Google)
<[email protected]> wrote:
>
> From: Masami Hiramatsu (Google) <[email protected]>
>
> 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: [email protected]
> Reported-by: Sashiko <[email protected]>
> Closes: 
> https://lore.kernel.org/all/[email protected]/
> Assisted-by: Antigravity:gemini-3.8-flash
> Signed-off-by: Masami Hiramatsu (Google) <[email protected]>
> ---
>  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 <[email protected]>

Best regards,
Sang-Heon Jeon

Reply via email to