Re: bpf: xdp: unhandled error in xdp_test_run_init_page() leads to crash
From: Martin KaFai Lau <martin.lau@linux.dev>
Date: 2025-12-18 18:26:34
Also in:
bpf
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 <redacted> Reported-by: Kaiyan Mei <redacted> Reviewed-by: Dongliang Mu <dzm91@hust.edu.cn> ## 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 VisualizationVulnerability 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.