Subject: Re: bpf: xdp: unhandled error in xdp_test_run_init_page() leads to crash

From: Martin KaFai Lau <[email-masked]>
Date: Thu, 18 Dec 2025 10:26:14 -0800

On 12/18/25 2:43 AM, Yinhao Hu wrote:
> Our fuzzer tool discovered a user-memory-access vulnerability in the BPF
> subsystem. The vulnerability is triggered when building an `sk_buff`
> from an XDP frame that has not been properly initialized due to an
> unhandled initialization failure, causing the kernel to access an
> invalid memory address.
> 
> Reported-by: Yinhao Hu <[email-masked]>
> Reported-by: Kaiyan Mei <[email-masked]>
> Reviewed-by: Dongliang Mu <[email-masked]>
> 
> ## Root Cause
> 
> `xdp_test_run_setup()` attempts to create a `page_pool` with the page
> initialization callback `xdp_test_run_init_page()`.
> 
> During page initialization, `xdp_test_run_init_page()` calls
> `xdp_update_frame_from_buff()` to initialize an `xdp_frame`. However, if
> the available headroom in the associated `xdp_buff` is insufficient,
> `xdp_update_frame_from_buff()` returns an error. This error is not
> handled by `xdp_test_run_init_page()`, leaving the `xdp_frame`
> uninitialized.
> 
> Later, `xdp_test_run_batch()` retrieves this `xdp_frame` from the
> `page_pool`. Although it may attempt to partially reinitialize the frame
> via `reset_ctx()`, the failure from `xdp_update_frame_from_buff()` is
> still ignored.
> 
> Finally, `__xdp_build_skb_from_frame()` attempts to construct an
> `sk_buff` from the uninitialized `xdp_frame`. It reads uninitialized
> members (e.g., `data`, `headroom`, `frame_sz`) to compute a `hard_start`
> address, which is then passed to `build_skb_around()`. The underlying
> `__build_skb_around()` attempts to write to this invalid address,
> resulting in a kernel crash.
> 
> ## Execution Flow Visualization
> 
> ```
> Vulnerability Execution Flow
> |
> |--- 1. An XDP program is loaded with act XDP_PASS
> |
> |--- 2. `bpf(BPF_PROG_TEST_RUN, ...)` Syscall Execution
> |    |
> |    `-- bpf_test_run_xdp_live
> |        |
> |        `-- xdp_test_run_setup
> |        |   |
> |        |   `--> page_pool_create() with init callback
> xdp_test_run_init_page()
> |        |         |
> |        |         `--> xdp_update_frame_from_buff() may fail, but error
> is ignored, leaving xdp_frame uninitialized
> |        |
> |        `-- xdp_test_run_batch
> |             |
> |             |--> page_pool_dev_alloc_pages() returns page with
> uninitialized xdp_frame
> |             |
> |             `--> xdp_recv_frames
> |                   |
> |                   |--> __xdp_build_skb_from_frame() reads
> uninitialized xdpf members, computes invalid hard_start address, passes
> it to build_skb_around()
> |                   |
> |                   `--> __build_skb_around() writes to invalid address
> -> CRASH
> ```
> 

This looks a legit issue. Toke, please help to take a look.