syzbot reported a circular locking dependency involving &net->xdp.lock, &xs->mutex, and netdev_lock_ops(): -> #3 (&net->xdp.lock): xsk_notifier unregister_netdevice_many_notify rtnl_dellink -> #2 (&port->pnodes_lock / netdev_lock): ipvlan_device_event / bond / netdev_change_features -> #1 (netdev_lock_ops): xsk_bind (holds xs->mutex, takes netdev_lock_ops(dev)) -> #0 (&xs->mutex): xsk_diag_dump (holds net->xdp.lock, takes xs->mutex) In xsk_bind(), xs->mutex was acquired before dev_get_by_index() and netdev_lock_ops(dev). However, in netdev notifier callbacks like xsk_notifier(), netdev_lock_ops(dev) is held by the netdev core while taking net->xdp.lock and then xs->mutex, creating an ABBA lock inversion between xs->mutex and netdev_lock_ops(dev). Fix this by looking up the target net_device and acquiring netdev_lock_ops(dev) before acquiring xs->mutex in xsk_bind(). This aligns xsk_bind() with the global lock hierarchy: rtnl_lock -> netdev_lock_ops(dev) -> net->xdp.lock -> xs->mutex. Fixes: 978939c08db1 ("xsk: use netdev_lock_ops in xsk_bind") Reported-by: syzbot+aa48b5fe7bfda62d1682@syzkaller.appspotmail.com Closes: https://syzkaller.appspot.com/bug?extid=aa48b5fe7bfda62d1682 Signed-off-by: Khawar Ahemad --- net/xdp/xsk.c | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/net/xdp/xsk.c b/net/xdp/xsk.c index 7855ee09c4..d2fbbeb7b6 100644 --- a/net/xdp/xsk.c +++ b/net/xdp/xsk.c @@ -1612,19 +1612,18 @@ static int xsk_bind(struct socket *sock, struct sockaddr_unsized *addr, int addr return -EINVAL; rtnl_lock(); - mutex_lock(&xs->mutex); - if (xs->state != XSK_READY) { - err = -EBUSY; - goto out_release; - } - dev = dev_get_by_index(sock_net(sk), sxdp->sxdp_ifindex); if (!dev) { err = -ENODEV; - goto out_release; + goto out_rtnl_unlock; } netdev_lock_ops(dev); + mutex_lock(&xs->mutex); + if (xs->state != XSK_READY) { + err = -EBUSY; + goto out_unlock; + } if (!xs->rx && !xs->tx) { err = -EINVAL; @@ -1771,9 +1770,9 @@ static int xsk_bind(struct socket *sock, struct sockaddr_unsized *addr, int addr smp_wmb(); WRITE_ONCE(xs->state, XSK_BOUND); } - netdev_unlock_ops(dev); -out_release: mutex_unlock(&xs->mutex); + netdev_unlock_ops(dev); +out_rtnl_unlock: rtnl_unlock(); return err; } -- 2.54.0 (Apple Git-157)