On Fri, May 22, 2026 at 04:03:44AM +0000, liu zhenyu wrote:

> Hello U-Boot maintainers,
> 
> I found an integer-overflow bounds-check issue in U-Boot's WGET receive path.
> 
> No CVE is assigned at report time.
> 
> Summary
> -------
> 
> `net/wget.c` checks whether a received HTTP response block fits the 
> configured download buffer by evaluating:
> 
>     wget_info->buffer_size < offset + len
> 
> The addition is performed before the bounds check. Since `offset` and `len` 
> are unsigned inputs to `store_block()`, a large offset can wrap `offset + 
> len` to a small value and bypass the intended `buffer_size` guard before 
> `memcpy()` writes response bytes to `image_load_addr + offset`.
> 
> Affected version
> ----------------
> 
> Observed in current master:
> 
>     38dbe637c9dfcadbd1bc201bfbb27f96b2ad525a
> 
> Affected file:
> 
>     net/wget.c
> 
> Details
> -------
> 
> The vulnerable bounds check is in `store_block()`:
> 
>     net/wget.c:48-55
>         static inline int store_block(uchar *src, unsigned int offset,
>                                       unsigned int len)
>         {
>                 ulong store_addr = image_load_addr + offset;
>                 ...
>                 if (wget_info->buffer_size &&
>                     wget_info->buffer_size < offset + len)
>                         return -1;
> 
> If `offset + len` wraps, the comparison can allow a write whose starting 
> offset is already outside the intended buffer.
> 
> The data is then copied to the computed load address:
> 
>     net/wget.c:67-69
>         ptr = map_sysmem(store_addr, len);
>         memcpy(ptr, src, len);
>         unmap_sysmem(ptr);
> 
> The offset passed into `store_block()` is derived in the TCP receive callback:
> 
>     net/wget.c:234-240
>         static int tcp_stream_rx(struct tcp_stream *tcp, u32 rx_offs,
>                                  void *buf, int len)
>         {
>                 if ((max_rx_pos == (u32)(-1)) ||
>                     (max_rx_pos < rx_offs + len - 1))
>                         max_rx_pos = rx_offs + len - 1;
> 
>                 if (store_block(buf, rx_offs - http_hdr_size, len) < 0)
>                         return -1;
> 
> The same callback also computes `rx_offs + len - 1` before checking for 
> overflow.
> 
> There is an additional adjacent issue while parsing headers:
> 
>     net/wget.c:136-140
>         ptr = map_sysmem(image_load_addr, rx_bytes + 1);
>         saved = ptr[rx_bytes];
>         ptr[rx_bytes] = '\0';
>         pos = strstr((char *)ptr, http_eom);
>         ptr[rx_bytes] = saved;
> 
> This temporarily touches one byte past the received byte count in order to 
> run C-string parsing. If `rx_bytes` is at the configured buffer boundary, 
> this touches one byte beyond the caller's intended receive buffer.
> 
> Minimal host-side PoC
> ---------------------
> 
> The attached/referenced harness uses:
> 
>     buffer_size = 64
>     offset      = 0xfffffff0
>     len         = 0x40
> 
> In unsigned 32-bit arithmetic:
> 
>     offset + len == 48
> 
> The current check therefore sees:
> 
>     buffer_size < wrapped_sum
>     64 < 48  // false
> 
> So the guard allows the write even though the starting offset is far outside 
> the 64-byte buffer.
> 
> Observed harness output:
> 
>     BA2-T6-CAND-006: wrapped_sum=48 allows=1 terminator_one_past=1
> 
> PoC source to attach:
> 
>     poc-wget-bounds.c
> 
> Build and run:
> 
>     gcc -std=c11 -Wall -Wextra -O0 poc-wget-bounds.c -o poc-wget-bounds
>     ./poc-wget-bounds
> 
> Observed output:
> 
>     buffer_size=64
>     offset=0xfffffff0
>     len=64
>     wrapped_sum=48
>     current_check_allows=1
>     VULNERABLE: wrapped offset+len bypasses buffer_size check
> 
> Impact
> ------
> 
> This affects systems using U-Boot WGET/HTTP boot with a configured receive 
> buffer size. A malicious HTTP server on the boot network controls response 
> bytes reaching the WGET receive path. If the TCP stream layer presents a 
> large receive offset, the current arithmetic can bypass the buffer-size check 
> and copy attacker-controlled bytes outside the intended image buffer. The 
> impact is pre-OS denial of service or memory corruption in the bootloader 
> context.
> 
> Expected invariant
> ------------------
> 
> The WGET receive path should reject any `(offset, len)` range that does not 
> fit inside `wget_info->buffer_size` without first computing `offset + len` in 
> a wrapping expression. The usual form is to reject when:
> 
>     offset > buffer_size || len > buffer_size - offset
> 
> Similar non-wrapping checks should be used for `rx_offs + len - 1` and for 
> the temporary HTTP header terminator.
> 
> I can prepare a separate patch or sandbox test if that would be useful, but I 
> am sending this first as a vulnerability report so the security impact can be 
> triaged independently of the fix shape.
> 
> Regards,
> Zhenyu Liu

> #include <stdint.h>
> #include <stdio.h>
> 
> int main(void)
> {
>     const uint32_t buffer_size = 64u;
>     const uint32_t offset = 0xfffffff0u;
>     const uint32_t len = 0x40u;
>     const uint32_t wrapped_sum = offset + len;
>     const int current_check_allows = !(buffer_size < wrapped_sum);
> 
>     /*
>      * This models net/wget.c:
>      *
>      *   if (wget_info->buffer_size &&
>      *       wget_info->buffer_size < offset + len)
>      *       return -1;
>      *
>      * offset + len wraps to 48, so a 64-byte buffer does not reject it.
>      */
>     printf("buffer_size=%u\n", buffer_size);
>     printf("offset=0x%08x\n", offset);
>     printf("len=%u\n", len);
>     printf("wrapped_sum=%u\n", wrapped_sum);
>     printf("current_check_allows=%d\n", current_check_allows);
> 
>     if (offset > buffer_size && current_check_allows) {
>         puts("VULNERABLE: wrapped offset+len bypasses buffer_size check");
>         return 0;
>     }
> 
>     puts("not reproduced");
>     return 1;
> }

Hi,

As this is starting to come up more often now:
https://lore.kernel.org/u-boot/0100019e40e72ac1-c3d57c2e-cac3-4f65-a98f-f1c6173c047d-000...@email.amazonses.com/
https://lore.kernel.org/u-boot/20260520143639.GM1858239@bill-the-cat/

I'm going to repeat what I said to start with in both, and encourage you
to read in full the second thread above.

First, the current stance of this project with respect to AI is, "please
don't" and is well explained over on
https://docs.postmarketos.org/policies-and-processes/development/ai-policy.html

Second, if you're going to use an AI tool anyhow, please read
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=36d49bba19f2c19c933d13b25dcf4eb607a030b3
and specifically the section titled "Responsible use of AI to find
bugs".

Finally, our normal patch submission process is documented at
https://docs.u-boot.org/en/latest/develop/sending_patches.html

-- 
Tom

Attachment: signature.asc
Description: PGP signature

Reply via email to