From: Stephen Hemminger <stephen@networkplumber.org>
To: sandeep.penigalapati@intel.com
Cc: dev@dpdk.org, stable@dpdk.org, ciara.loftus@intel.com
Subject: Re: [PATCH v6] net/af_xdp: fix shared UMEM refcount corruption
Date: Fri, 21 Aug 2026 11:10:52 -0700 [thread overview]
Message-ID: <20260821111052.0985727f@phoenix.local> (raw)
In-Reply-To: <20260821021607.232149-1-sandeep.penigalapati@intel.com>
On Thu, 20 Aug 2026 22:16:07 -0400
sandeep.penigalapati@intel.com wrote:
> From: Sandeep Penigalapati <sandeep.penigalapati@intel.com>
>
> Shared UMEM is meant to be shared by a limited number of sockets,
> governed by the mempool size (max_xsks). When the UMEM was already at
> capacity (refcnt >= max_xsks), xdp_umem_configure() returned the UMEM
> without incrementing its refcount, so the extra socket used it
> unaccounted for.
>
> This missing reference has two consequences. During queue setup the
> fill-queue reservation is chosen from the refcount, so the sharing
> socket reserves into its own uninitialised fill queue and crashes. At
> close, the under-counted refcount reaches zero while the UMEM is still
> in use, freeing it early and causing a use-after-free.
>
> Reject sharing once the UMEM is at capacity by returning NULL. The
> error is propagated from xsk_configure(), so Rx queue setup fails
> cleanly with -ENOMEM. This applies the per-mempool socket limit that
> shared UMEM was always intended to respect.
>
> Harden the failure path this makes reachable:
> - clear rxq->umem and its paired txq->umem when xsk_configure() fails,
> and skip queues whose UMEM is not yet set in get_shared_umem(), so a
> later scan over the same mempool cannot dereference a NULL or
> dangling UMEM;
> - free the fill-queue mbufs that were allocated but not yet handed to
> the fill queue when a sharing socket fails to bind, so it no longer
> leaks a burst of mbufs back out of the shared mempool;
> - propagate the map-insert failures in xsk_configure() instead of
> returning success, so a failed xsks_map update no longer leaves the
> caller using a deleted socket;
> - continue past, rather than stop at, a failed queue in eth_dev_close()
> so later successful queues and their UMEM references are still freed;
> - clamp max_xsks to UINT8_MAX so the cap stays within the uint8_t
> refcount.
>
> Also correct the UMEM refcount memory ordering: release on the shared
> increment and acquire-release on the final decrement, so the thread that
> drops the last reference observes all prior users' writes before it
> frees the UMEM.
>
> Document the shared mempool sizing requirement (4096 mbufs per socket).
>
> Note: on stable branches this is a behaviour change. Shared-UMEM setups
> that previously appeared to start, until the fill-queue crash or the
> use-after-free at close, now fail cleanly at Rx queue setup with
> -ENOMEM.
>
> Fixes: 74b46340e2d4 ("net/af_xdp: support shared UMEM")
> Cc: stable@dpdk.org
>
> Signed-off-by: Sandeep Penigalapati <sandeep.penigalapati@intel.com>
I am ok with it as is but AI still has some Info level comments.
Will take it as is, or you can revise (your choice).
Trimmed away the noise..
Review of [PATCH v6] net/af_xdp: fix shared UMEM refcount corruption
1. The refcount increment does not need release ordering.
rte_atomic_fetch_add_explicit(&umem->refcnt, 1,
rte_memory_order_release);
rte_memory_order_relaxed is the correct weakest choice here. The
incrementing thread has no prior writes to publish; the UMEM was
built by whoever created it, and that publication is already covered
by the release store of refcnt = 1 at the end of
xdp_umem_configure().
The commit message attributes the guarantee to the wrong operation:
"release on the shared increment ... so the thread that drops the
last reference observes all prior users' writes" is what the acq_rel
on the fetch_sub provides, not the increment. Worth correcting in
the message even if the ordering is left as is; it is harmless but
the rationale will outlive the patch in git history.
2. The capacity check and the increment are still not atomic, and
rxq->umem is mutated outside internal_list_lock.
get_shared_umem() releases internal_list_lock before returning, so
the load of refcnt in xdp_umem_configure() and the fetch_add that
follows are separate steps; two threads configuring queues on the
same mempool can both observe refcnt < max_xsks and both increment.
Separately, xsk_configure() and eth_dev_close() write rxq->umem
without the lock that get_shared_umem() holds when reading it, so a
concurrent failure could in principle free a UMEM between the NULL
check and the dereference.
Both are pre-existing and control-path setup is single threaded in
practice, so this is a note rather than a request. A
compare-exchange loop on refcnt would make the cap the patch adds
actually enforceable if that ever changes.
3. Mbufs already submitted to the fill queue are still lost at
out_xsk.
Once reserve_fill_queue() succeeds, the 2048 mbufs live in rxq->fq.
A later failure (map insert, busy-poll config) deletes the socket
and takes out_umem, and nothing drains the fill ring, so those mbufs
never return to the mempool. free_fq_bufs is correctly false at
that point, so this is not a regression from the patch, and
recovering them would mean unwinding the fill ring. Noting it as a
remaining gap rather than something to fix here.
next prev parent reply other threads:[~2026-08-21 18:11 UTC|newest]
Thread overview: 5+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-08-20 23:05 [PATCH v4] net/af_xdp: fix shared UMEM refcount corruption sandeep.penigalapati
2026-08-21 0:44 ` [PATCH v5] " sandeep.penigalapati
2026-08-21 2:16 ` [PATCH v6] " sandeep.penigalapati
2026-08-21 18:10 ` Stephen Hemminger [this message]
2026-08-24 12:10 ` Penigalapati, Sandeep
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=20260821111052.0985727f@phoenix.local \
--to=stephen@networkplumber.org \
--cc=ciara.loftus@intel.com \
--cc=dev@dpdk.org \
--cc=sandeep.penigalapati@intel.com \
--cc=stable@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