]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
ethtool: module: fix cleanup if socket used for flashing multiple devices
authorJakub Kicinski <kuba@kernel.org>
Fri, 22 May 2026 23:13:08 +0000 (16:13 -0700)
committerJakub Kicinski <kuba@kernel.org>
Tue, 26 May 2026 15:19:32 +0000 (08:19 -0700)
When a single Netlink socket issues MODULE_FW_FLASH_ACT against multiple
devices, ethnl_sock_priv_set() overwrites sk_priv->dev on each call,
retaining only the last one. The socket priv is used on socket close,
to walk the global work list and mark the uncompleted flashing work
as "orphaned". Otherwise if another socket reuses the PID it will
unexpectedly receive the flashing notifications.

Don't record the device, record net pointer instead. The purpose of
the dev is to scope the work to a netns, anyway. If we store netns
the overrides are safe/a nop since all flashed devices must be in
the same netns as the socket.

Fixes: 32b4c8b53ee7 ("ethtool: Add ability to flash transceiver modules' firmware")
Reviewed-by: Danielle Ratson <danieller@nvidia.com>
Link: https://patch.msgid.link/20260522231312.1710836-6-kuba@kernel.org
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
net/ethtool/module.c
net/ethtool/netlink.c
net/ethtool/netlink.h

index 5b49004ddf60de837910d2ce58a207202f382acd..ea4fb2a7665005bddec877140d0289e8dd4b6571 100644 (file)
@@ -291,11 +291,9 @@ void ethnl_module_fw_flash_sock_destroy(struct ethnl_sock_priv *sk_priv)
 
        spin_lock(&module_fw_flash_work_list_lock);
        list_for_each_entry(work, &module_fw_flash_work_list, list) {
-               if (work->fw_update.dev == sk_priv->dev &&
-                   work->fw_update.ntf_params.portid == sk_priv->portid) {
+               if (work->fw_update.ntf_params.portid == sk_priv->portid &&
+                   dev_net(work->fw_update.dev) == sk_priv->net)
                        work->fw_update.ntf_params.closed_sock = true;
-                       break;
-               }
        }
        spin_unlock(&module_fw_flash_work_list_lock);
 }
@@ -332,7 +330,8 @@ module_flash_fw_schedule(struct net_device *dev, const char *file_name,
        fw_update->ntf_params.seq = info->snd_seq;
        fw_update->ntf_params.closed_sock = false;
 
-       err = ethnl_sock_priv_set(skb, dev, fw_update->ntf_params.portid,
+       err = ethnl_sock_priv_set(skb, dev_net(dev),
+                                 fw_update->ntf_params.portid,
                                  ETHTOOL_SOCK_TYPE_MODULE_FW_FLASH);
        if (err < 0)
                goto err_release_firmware;
index 5046023a30b10089ba33c80106c95248e9829853..7d45f9a884e5071b33664d2bf226e4f59e665f23 100644 (file)
@@ -53,7 +53,7 @@ const struct nla_policy ethnl_header_policy_phy_stats[] = {
        [ETHTOOL_A_HEADER_PHY_INDEX]            = NLA_POLICY_MIN(NLA_U32, 1),
 };
 
-int ethnl_sock_priv_set(struct sk_buff *skb, struct net_device *dev, u32 portid,
+int ethnl_sock_priv_set(struct sk_buff *skb, struct net *net, u32 portid,
                        enum ethnl_sock_type type)
 {
        struct ethnl_sock_priv *sk_priv;
@@ -62,7 +62,7 @@ int ethnl_sock_priv_set(struct sk_buff *skb, struct net_device *dev, u32 portid,
        if (IS_ERR(sk_priv))
                return PTR_ERR(sk_priv);
 
-       sk_priv->dev = dev;
+       sk_priv->net = net;
        sk_priv->portid = portid;
        sk_priv->type = type;
 
index aaf6f246876832a8be9c82412c7fd202ba3009cb..fd2198e45d2bba46940e205786f4838f8b26fc1d 100644 (file)
@@ -318,12 +318,12 @@ enum ethnl_sock_type {
 };
 
 struct ethnl_sock_priv {
-       struct net_device *dev;
+       struct net *net;
        u32 portid;
        enum ethnl_sock_type type;
 };
 
-int ethnl_sock_priv_set(struct sk_buff *skb, struct net_device *dev, u32 portid,
+int ethnl_sock_priv_set(struct sk_buff *skb, struct net *net, u32 portid,
                        enum ethnl_sock_type type);
 
 /**