[PATCH bpf-next v2] xsk: Fix circular locking dependency in xsk_notifier
From: Khawar Ahemad
Date: Wed Aug 26 2026 - 12:22:24 EST
syzbot reported a circular locking dependency involving &net->xdp.lock,
&xs->mutex, and netdev_lock_ops():
-> #2 (&net->xdp.lock):
xsk_notifier
unregister_netdevice_many_notify
-> #1 (&xs->mutex):
xsk_diag_dump
-> #0 (netdev_lock_ops):
xsk_bind
In xsk_notifier(), xp_clear_dev() was called while holding &xs->mutex.
Because xp_clear_dev() acquires netdev_lock_ops(netdev), this created a
nested dependency of &xs->mutex -> netdev_lock_ops. Combined with
xsk_diag_dump() (&net->xdp.lock -> &xs->mutex) and device unregistration
(netdev_lock_ops -> &net->xdp.lock), this formed a circular locking cycle.
xp_clear_dev() operates strictly on the buffer pool and net_device, and
does not require &xs->mutex once the socket is unbound by xsk_unbind_dev().
Both xsk_notifier() and deferred pool release are serialized by rtnl_lock.
Fix this by capturing the pool pointer under &xs->mutex and calling
xp_clear_dev(pool) after releasing &xs->mutex in xsk_notifier().
Fixes: 975b11ae9077 ("xsk: add socket allocate, create and bind")
Reported-by: syzbot+aa48b5fe7bfda62d1682@xxxxxxxxxxxxxxxxxxxxxxxxx
Closes: https://syzkaller.appspot.com/bug?extid=aa48b5fe7bfda62d1682
Signed-off-by: Khawar Ahemad <ahemadkhawar123@xxxxxxxxx>
---
v1 -> v2:
- Resolve the circular locking dependency in xsk_notifier() instead of
reordering locks in xsk_bind(), avoiding ABBA lock inversion with
xp_clear_dev().
- Preserve user-space errno precedence in xsk_bind().
- Reference the correct Fixes commit 2495b430e382.
- Link to v1: https://lore.kernel.org/bpf/20260825152152.86092-1-ahemadkhawar123@xxxxxxxxx/
net/xdp/xsk.c | 11 ++++++++---
1 file changed, 8 insertions(+), 3 deletions(-)
diff --git a/net/xdp/xsk.c b/net/xdp/xsk.c
index 7855ee09c4..c2f47182dc 100644
--- a/net/xdp/xsk.c
+++ b/net/xdp/xsk.c
@@ -2106,6 +2106,7 @@ static int xsk_notifier(struct notifier_block *this,
mutex_lock(&net->xdp.lock);
sk_for_each(sk, &net->xdp.list) {
struct xdp_sock *xs = xdp_sk(sk);
+ struct xsk_buff_pool *pool = NULL;
mutex_lock(&xs->mutex);
if (xs->dev == dev) {
@@ -2113,12 +2114,16 @@ static int xsk_notifier(struct notifier_block *this,
if (!sock_flag(sk, SOCK_DEAD))
sk_error_report(sk);
+ pool = xs->pool;
xsk_unbind_dev(xs);
-
- /* Clear device references. */
- xp_clear_dev(xs->pool);
}
mutex_unlock(&xs->mutex);
+
+ /* Clear device references outside xs->mutex to avoid
+ * lock inversion with netdev_lock_ops().
+ */
+ if (pool)
+ xp_clear_dev(pool);
}
mutex_unlock(&net->xdp.lock);
break;
--
2.54.0 (Apple Git-157)