aboutsummaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
authorJakub Kicinski <kuba@kernel.org>2025-04-15 20:04:47 -0700
committerJakub Kicinski <kuba@kernel.org>2025-04-17 18:55:14 -0700
commit22cbc1ee268b7ec0000848708944daa61c6e4909 (patch)
treed6c50fc047a853e866aea2b61ef0dfe735633609
parentnet/mlx5e: ethtool: Fix formatting of ptp_rq0_csum_complete_tail_slow (diff)
downloadwireguard-linux-22cbc1ee268b7ec0000848708944daa61c6e4909.tar.xz
wireguard-linux-22cbc1ee268b7ec0000848708944daa61c6e4909.zip
netdev: fix the locking for netdev notifications
Kuniyuki reports that the assert for netdev lock fires when there are netdev event listeners (otherwise we skip the netlink event generation). Correct the locking when coming from the notifier. The NETDEV_XDP_FEAT_CHANGE notifier is already fully locked, it's the documentation that's incorrect. Fixes: 99e44f39a8f7 ("netdev: depend on netdev->lock for xdp features") Reported-by: syzkaller <syzkaller@googlegroups.com> Reported-by: Kuniyuki Iwashima <kuniyu@amazon.com> Link: https://lore.kernel.org/20250410171019.62128-1-kuniyu@amazon.com Acked-by: Stanislav Fomichev <sdf@fomichev.me> Link: https://patch.msgid.link/20250416030447.1077551-1-kuba@kernel.org Signed-off-by: Jakub Kicinski <kuba@kernel.org>
-rw-r--r--Documentation/networking/netdevices.rst4
-rw-r--r--include/linux/netdevice.h2
-rw-r--r--include/net/netdev_lock.h16
-rw-r--r--net/core/lock_debug.c4
-rw-r--r--net/core/netdev-genl.c4
5 files changed, 27 insertions, 3 deletions
diff --git a/Documentation/networking/netdevices.rst b/Documentation/networking/netdevices.rst
index 77fe1f7b93be..7ebb6c36482d 100644
--- a/Documentation/networking/netdevices.rst
+++ b/Documentation/networking/netdevices.rst
@@ -387,12 +387,14 @@ For device drivers that implement shaping or queue management APIs,
some of the notifiers (``enum netdev_cmd``) are running under the netdev
instance lock.
+The following netdev notifiers are always run under the instance lock:
+* ``NETDEV_XDP_FEAT_CHANGE``
+
For devices with locked ops, currently only the following notifiers are
running under the lock:
* ``NETDEV_CHANGE``
* ``NETDEV_REGISTER``
* ``NETDEV_UP``
-* ``NETDEV_XDP_FEAT_CHANGE``
The following notifiers are running without the lock:
* ``NETDEV_UNREGISTER``
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index e6036b82ef4c..0321fd952f70 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -2520,7 +2520,7 @@ struct net_device {
* @net_shaper_hierarchy, @reg_state, @threaded
*
* Double protects:
- * @up, @moving_ns, @nd_net, @xdp_flags
+ * @up, @moving_ns, @nd_net, @xdp_features
*
* Double ops protects:
* @real_num_rx_queues, @real_num_tx_queues
diff --git a/include/net/netdev_lock.h b/include/net/netdev_lock.h
index 5706835a660c..2a753813f849 100644
--- a/include/net/netdev_lock.h
+++ b/include/net/netdev_lock.h
@@ -48,6 +48,22 @@ static inline void netdev_unlock_ops(struct net_device *dev)
netdev_unlock(dev);
}
+static inline void netdev_lock_ops_to_full(struct net_device *dev)
+{
+ if (netdev_need_ops_lock(dev))
+ netdev_assert_locked(dev);
+ else
+ netdev_lock(dev);
+}
+
+static inline void netdev_unlock_full_to_ops(struct net_device *dev)
+{
+ if (netdev_need_ops_lock(dev))
+ netdev_assert_locked(dev);
+ else
+ netdev_unlock(dev);
+}
+
static inline void netdev_ops_assert_locked(const struct net_device *dev)
{
if (netdev_need_ops_lock(dev))
diff --git a/net/core/lock_debug.c b/net/core/lock_debug.c
index 6fade574bc2a..9e9fb25314b9 100644
--- a/net/core/lock_debug.c
+++ b/net/core/lock_debug.c
@@ -18,10 +18,12 @@ int netdev_debug_event(struct notifier_block *nb, unsigned long event,
/* Keep enum and don't add default to trigger -Werror=switch */
switch (cmd) {
+ case NETDEV_XDP_FEAT_CHANGE:
+ netdev_assert_locked(dev);
+ fallthrough;
case NETDEV_CHANGE:
case NETDEV_REGISTER:
case NETDEV_UP:
- case NETDEV_XDP_FEAT_CHANGE:
netdev_ops_assert_locked(dev);
fallthrough;
case NETDEV_DOWN:
diff --git a/net/core/netdev-genl.c b/net/core/netdev-genl.c
index b64c614a00c4..2c104947d224 100644
--- a/net/core/netdev-genl.c
+++ b/net/core/netdev-genl.c
@@ -963,10 +963,14 @@ static int netdev_genl_netdevice_event(struct notifier_block *nb,
switch (event) {
case NETDEV_REGISTER:
+ netdev_lock_ops_to_full(netdev);
netdev_genl_dev_notify(netdev, NETDEV_CMD_DEV_ADD_NTF);
+ netdev_unlock_full_to_ops(netdev);
break;
case NETDEV_UNREGISTER:
+ netdev_lock(netdev);
netdev_genl_dev_notify(netdev, NETDEV_CMD_DEV_DEL_NTF);
+ netdev_unlock(netdev);
break;
case NETDEV_XDP_FEAT_CHANGE:
netdev_genl_dev_notify(netdev, NETDEV_CMD_DEV_CHANGE_NTF);