Commit 760d04eb authored by Jakub Kicinski's avatar Jakub Kicinski
Browse files

ethtool: module: fix cleanup if socket used for flashing multiple devices



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: 32b4c8b5 ("ethtool: Add ability to flash transceiver modules' firmware")
Reviewed-by: default avatarDanielle Ratson <danieller@nvidia.com>
Link: https://patch.msgid.link/20260522231312.1710836-6-kuba@kernel.org


Signed-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parent 504eaefa
Loading
Loading
Loading
Loading
+4 −5
Original line number Diff line number Diff line
@@ -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;
+2 −2
Original line number Diff line number Diff line
@@ -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;

+2 −2
Original line number Diff line number Diff line
@@ -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);

/**