bpf, cpumap: Disable page_pool direct xdp_return need larger scope
authorJesper Dangaard Brouer <hawk@kernel.org>
Thu, 14 Aug 2025 18:24:37 +0000 (20:24 +0200)
committerDaniel Borkmann <daniel@iogearbox.net>
Fri, 15 Aug 2025 09:08:08 +0000 (11:08 +0200)
When running an XDP bpf_prog on the remote CPU in cpumap code
then we must disable the direct return optimization that
xdp_return can perform for mem_type page_pool.  This optimization
assumes code is still executing under RX-NAPI of the original
receiving CPU, which isn't true on this remote CPU.

The cpumap code already disabled this via helpers
xdp_set_return_frame_no_direct() and xdp_clear_return_frame_no_direct(),
but the scope didn't include xdp_do_flush().

When doing XDP_REDIRECT towards e.g devmap this causes the
function bq_xmit_all() to run with direct return optimization
enabled. This can lead to hard to find bugs.  The issue
only happens when bq_xmit_all() cannot ndo_xdp_xmit all
frames and them frees them via xdp_return_frame_rx_napi().

Fix by expanding scope to include xdp_do_flush(). This was found
by Dragos Tatulea.

Fixes: 11941f8a8536 ("bpf: cpumap: Implement generic cpumap")
Reported-by: Dragos Tatulea <dtatulea@nvidia.com>
Reported-by: Chris Arges <carges@cloudflare.com>
Signed-off-by: Jesper Dangaard Brouer <hawk@kernel.org>
Signed-off-by: Martin KaFai Lau <martin.lau@kernel.org>
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
Tested-by: Chris Arges <carges@cloudflare.com>
Link: https://patch.msgid.link/175519587755.3008742.1088294435150406835.stgit@firesoul
kernel/bpf/cpumap.c

index b2b7b8ec2c2a1c6d6af58b031991d9b8f10256dd..c46360b278712b56f42406dbae8c70661dd96234 100644 (file)
@@ -186,7 +186,6 @@ static int cpu_map_bpf_prog_run_xdp(struct bpf_cpu_map_entry *rcpu,
        struct xdp_buff xdp;
        int i, nframes = 0;
 
-       xdp_set_return_frame_no_direct();
        xdp.rxq = &rxq;
 
        for (i = 0; i < n; i++) {
@@ -231,7 +230,6 @@ static int cpu_map_bpf_prog_run_xdp(struct bpf_cpu_map_entry *rcpu,
                }
        }
 
-       xdp_clear_return_frame_no_direct();
        stats->pass += nframes;
 
        return nframes;
@@ -255,6 +253,7 @@ static void cpu_map_bpf_prog_run(struct bpf_cpu_map_entry *rcpu, void **frames,
 
        rcu_read_lock();
        bpf_net_ctx = bpf_net_ctx_set(&__bpf_net_ctx);
+       xdp_set_return_frame_no_direct();
 
        ret->xdp_n = cpu_map_bpf_prog_run_xdp(rcpu, frames, ret->xdp_n, stats);
        if (unlikely(ret->skb_n))
@@ -264,6 +263,7 @@ static void cpu_map_bpf_prog_run(struct bpf_cpu_map_entry *rcpu, void **frames,
        if (stats->redirect)
                xdp_do_flush();
 
+       xdp_clear_return_frame_no_direct();
        bpf_net_ctx_clear(bpf_net_ctx);
        rcu_read_unlock();