From: bugzilla@dpdk.org
To: dev@dpdk.org
Subject: [DPDK/ethdev Bug 2055] bpf: missing acquire barrier in bpf_eth_cbi_wait() allows use-after-free on unload
Date: Tue, 13 Oct 2026 19:51:41 +0000 [thread overview]
Message-ID: <bug-2055-3@https.bugs.dpdk.org/> (raw)
https://bugs.dpdk.org/show_bug.cgi?id=2055
Bug ID: 2055
Summary: bpf: missing acquire barrier in bpf_eth_cbi_wait()
allows use-after-free on unload
Product: DPDK
Version: 26.11
Hardware: All
OS: All
Status: UNCONFIRMED
Severity: normal
Priority: Normal
Component: ethdev
Assignee: dev@dpdk.org
Reporter: qm2k21@gmail.com
Target Milestone: ---
In bpf_pkt.c:103-117, bpf_eth_cbi_unload() synchronizes with datapath threads
before destroying the BPF program:
```
static void
bpf_eth_cbi_unload(struct bpf_eth_cbi *bc)
{
/* mark this cbi as empty */
bc->cb = NULL;
rte_smp_mb();
/* make sure datapath doesn't use bpf anymore, then destroy bpf */
bpf_eth_cbi_wait(bc);
rte_bpf_destroy(bc->bpf);
bpf_eth_cbi_cleanup(bc);
}
```
The synchronization in bpf_eth_cbi_wait() polls cbi->use:
```
static void
bpf_eth_cbi_wait(const struct bpf_eth_cbi *cbi)
{
uint32_t puse;
/* make sure all previous loads and stores are completed */
rte_smp_mb();
puse = cbi->use;
/* in use, busy wait till current RX/TX iteration is finished */
if ((puse & BPF_ETH_CBI_INUSE) != 0) {
RTE_WAIT_UNTIL_MASKED((__rte_atomic uint32_t
*)(uintptr_t)&cbi->use,
UINT32_MAX, !=, puse, rte_memory_order_relaxed);
}
}
```
While bpf_eth_cbi_wait() begins with a full barrier (rte_smp_mb()), that
barrier precedes reading cbi->use. Its sole purpose is to ensure the store
bc->cb = NULL is visible before reading cbi->use.
When waiting for an in-flight callback to finish, RTE_WAIT_UNTIL_MASKED polls
cbi->use with rte_memory_order_relaxed.
When the condition is met and the loop terminates, bpf_eth_cbi_wait() returns
without any acquire barrier (neither an acquire load nor an acquire/read
fence).
Control plane execution immediately proceeds to rte_bpf_destroy(bc->bpf), which
frees the memory of the BPF program (rte_free(), munmap()).
On weakly ordered architectures (ARM64, PowerPC, RISC-V), without an acquire
barrier observing the datapath's completion, the CPU can speculatively execute
or reorder rte_bpf_destroy() ahead of the datapath completing its memory
accesses into the BPF filter code/context. This produces a race condition and a
use-after-free.
One might assume that because RTE_WAIT_UNTIL_MASKED invokes rte_pause() inside
its spin loop, it might provide memory ordering. This assumption is incorrect
for several reasons:
* semantics of rte_pause() is not explicitly documented, and on some
architectures it does not provide a sufficient barrier (e.g. on arm32 it is an
empty function);
* semantics of RTE_WAIT_UNTIL_MASKED is documented, and explicitly warns that
"With a relaxed memory ordering model, the loads around this helper can be
reordered";
* last but not least, rte_pause() is only executed between the failed
iterations, but not after the last (successful) one -- even with rte_pause()
forming the memory barrier a small gap for reordering still exists.
--
You are receiving this mail because:
You are the assignee for the bug.
reply other threads:[~2026-10-13 19:51 UTC|newest]
Thread overview: [no followups] expand[flat|nested] mbox.gz Atom feed
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=bug-2055-3@https.bugs.dpdk.org/ \
--to=bugzilla@dpdk.org \
--cc=dev@dpdk.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox