From 3686bdd665382f09a3fbf30e5c6947585d7d7284 Mon Sep 17 00:00:00 2001 From: KaFai Wan Date: Mon, 5 Jan 2026 00:23:49 +0800 Subject: [PATCH 1/3] bpf, test_run: Fix user-memory-access vulnerability for LIVE_FRAMES When testing XDP programs with LIVE_FRAMES mode, if the metalen is set to >= (XDP_PACKET_HEADROOM - sizeof(struct xdp_frame)), there won't be enough space for the xdp_frame conversion in xdp_update_frame_from_buff(). Additionally, the xdp_frame structure may be filled with user-provided data, which can lead to a memory access vulnerability when converting to skb. This fix reverts to the original version and ensures data_hard_start correctly points to the xdp_frame structure, eliminating the security risk. bug-url: https://lore.kernel.org/all/fa2be179-bad7-4ee3-8668-4903d1853461@hust.edu.cn/ upstream-patch: https://lore.kernel.org/all/20260104162350.347403-2-kafai.wan@linux.dev/ Reported-by: Yinhao Hu Reported-by: Kaiyan Mei Reviewed-by: Dongliang Mu Fixes: 294635a8165a ("bpf, test_run: fix &xdp_frame misplacement for LIVE_FRAMES") Signed-off-by: KaFai Wan Signed-off-by: xulang --- net/bpf/test_run.c | 23 +++++++++---------- .../bpf/prog_tests/xdp_do_redirect.c | 6 ++--- 2 files changed, 14 insertions(+), 15 deletions(-) diff --git a/net/bpf/test_run.c b/net/bpf/test_run.c index 3a1c82b797a30..f4b928c01d999 100644 --- a/net/bpf/test_run.c +++ b/net/bpf/test_run.c @@ -100,11 +100,9 @@ static bool bpf_test_timer_continue(struct bpf_test_timer *t, int iterations, struct xdp_page_head { struct xdp_buff orig_ctx; struct xdp_buff ctx; - union { - /* ::data_hard_start starts here */ - DECLARE_FLEX_ARRAY(struct xdp_frame, frame); - DECLARE_FLEX_ARRAY(u8, data); - }; + /* ::data_hard_start starts here */ + struct xdp_frame frame; + DECLARE_FLEX_ARRAY(u8, data); }; struct xdp_test_data { @@ -140,10 +138,11 @@ static void xdp_test_run_init_page(struct page *page, void *arg) frm_len = orig_ctx->data_end - orig_ctx->data_meta; meta_len = orig_ctx->data - orig_ctx->data_meta; headroom -= meta_len; + headroom += sizeof(head->frame); new_ctx = &head->ctx; - frm = head->frame; - data = head->data; + frm = &head->frame; + data = frm; memcpy(data + headroom, orig_ctx->data_meta, frm_len); xdp_init_buff(new_ctx, TEST_XDP_FRAME_SIZE, &xdp->rxq); @@ -224,8 +223,8 @@ static bool frame_was_changed(const struct xdp_page_head *head) * i.e. has the highest chances to be overwritten. If those two are * untouched, it's most likely safe to skip the context reset. */ - return head->frame->data != head->orig_ctx.data || - head->frame->flags != head->orig_ctx.flags; + return head->frame.data != head->orig_ctx.data || + head->frame.flags != head->orig_ctx.flags; } static bool ctx_was_changed(struct xdp_page_head *head) @@ -243,8 +242,8 @@ static void reset_ctx(struct xdp_page_head *head) head->ctx.data = head->orig_ctx.data; head->ctx.data_meta = head->orig_ctx.data_meta; head->ctx.data_end = head->orig_ctx.data_end; - xdp_update_frame_from_buff(&head->ctx, head->frame); - head->frame->mem = head->orig_ctx.rxq->mem; + xdp_update_frame_from_buff(&head->ctx, &head->frame); + head->frame.mem = head->orig_ctx.rxq->mem; } static int xdp_recv_frames(struct xdp_frame **frames, int nframes, @@ -306,7 +305,7 @@ static int xdp_test_run_batch(struct xdp_test_data *xdp, struct bpf_prog *prog, head = phys_to_virt(page_to_phys(page)); reset_ctx(head); ctx = &head->ctx; - frm = head->frame; + frm = &head->frame; xdp->frame_cnt++; act = bpf_prog_run_xdp(prog, ctx); diff --git a/tools/testing/selftests/bpf/prog_tests/xdp_do_redirect.c b/tools/testing/selftests/bpf/prog_tests/xdp_do_redirect.c index bad0ea167be70..19716a43d833e 100644 --- a/tools/testing/selftests/bpf/prog_tests/xdp_do_redirect.c +++ b/tools/testing/selftests/bpf/prog_tests/xdp_do_redirect.c @@ -58,12 +58,12 @@ static int attach_tc_prog(struct bpf_tc_hook *hook, int fd) /* The maximum permissible size is: PAGE_SIZE - sizeof(struct xdp_page_head) - * SKB_DATA_ALIGN(sizeof(struct skb_shared_info)) - XDP_PACKET_HEADROOM = - * 3408 bytes for 64-byte cacheline and 3216 for 256-byte one. + * 3368 bytes for 64-byte cacheline and 3216 for 256-byte one. */ #if defined(__s390x__) -#define MAX_PKT_SIZE 3216 +#define MAX_PKT_SIZE 3176 #else -#define MAX_PKT_SIZE 3408 +#define MAX_PKT_SIZE 3368 #endif static void test_max_pkt_size(int fd) { From 770e101324f6289fe864de2eb7291ebe01303d83 Mon Sep 17 00:00:00 2001 From: xulang Date: Thu, 5 Feb 2026 15:43:47 +0800 Subject: [PATCH 2/3] bpf: fix null ptr access caused by bpf_prog_test_run_skb this is a temporary fix bug-url: https://lore.kernel.org/all/de98e423-a113-4a11-853d-9706cbc07e37@hust.edu.cn/ Signed-off-by: xulang --- net/core/lwt_bpf.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/net/core/lwt_bpf.c b/net/core/lwt_bpf.c index 4a0797f0a154b..914498d2fe95f 100644 --- a/net/core/lwt_bpf.c +++ b/net/core/lwt_bpf.c @@ -613,9 +613,12 @@ int bpf_lwt_push_ip_encap(struct sk_buff *skb, void *hdr, u32 len, bool ingress) if (ingress) err = skb_cow_head(skb, len + skb->mac_len); - else + else { + if (unlikely(!skb_dst(skb))) + return -EINVAL; err = skb_cow_head(skb, len + LL_RESERVED_SPACE(skb_dst(skb)->dev)); + } if (unlikely(err)) return err; From 5e1d1b3fabfe0842497c2d67acaf1ee0fd0b919b Mon Sep 17 00:00:00 2001 From: xulang Date: Thu, 5 Feb 2026 15:52:03 +0800 Subject: [PATCH 3/3] bpf: fix: Race condition in bpf_trampoline_unlink_cgroup_shim bug-url: https://lore.kernel.org/all/3c4ebb0b.46ff8.19abab8abe2.Coremail.kaiyanm@hust.edu.cn/ Signed-off-by: xulang --- kernel/bpf/trampoline.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/kernel/bpf/trampoline.c b/kernel/bpf/trampoline.c index e48791442acc5..6fa24109a07f6 100644 --- a/kernel/bpf/trampoline.c +++ b/kernel/bpf/trampoline.c @@ -701,10 +701,8 @@ int bpf_trampoline_link_cgroup_shim(struct bpf_prog *prog, mutex_lock(&tr->mutex); shim_link = cgroup_shim_find(tr, bpf_func); - if (shim_link) { + if (shim_link && atomic64_inc_not_zero(&shim_link->link.link.refcnt)) { /* Reusing existing shim attached by the other program. */ - bpf_link_inc(&shim_link->link.link); - mutex_unlock(&tr->mutex); bpf_trampoline_put(tr); /* bpf_trampoline_get above */ return 0;