lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [thread-next>] [day] [month] [year] [list]
Date:   Wed, 28 Jun 2023 11:32:28 +0200
From:   Louis Peens <louis.peens@...igine.com>
To:     David Miller <davem@...emloft.net>,
        Jakub Kicinski <kuba@...nel.org>,
        Paolo Abeni <pabeni@...hat.com>
Cc:     Simon Horman <simon.horman@...igine.com>,
        Yinjun Zhang <yinjun.zhang@...igine.com>,
        netdev@...r.kernel.org, stable@...r.kernel.org,
        oss-drivers@...igine.com
Subject: [PATCH net] nfp: clean mc addresses in application firmware when driver exits

From: Yinjun Zhang <yinjun.zhang@...igine.com>

The configured mc addresses are not removed from application firmware
when driver exits. This will cause resource leak when repeatedly
creating and destroying VFs.

Now use list to track configured mc addresses and remove them when
corresponding driver exits.

Fixes: e20aa071cd95 ("nfp: fix schedule in atomic context when sync mc address")
Cc: stable@...r.kernel.org
Signed-off-by: Yinjun Zhang <yinjun.zhang@...igine.com>
Acked-by: Simon Horman <simon.horman@...igine.com>
Signed-off-by: Louis Peens <louis.peens@...igine.com>
---
 drivers/net/ethernet/netronome/nfp/nfp_net.h  |  8 +++
 .../ethernet/netronome/nfp/nfp_net_common.c   | 66 +++++++++++++++++--
 2 files changed, 67 insertions(+), 7 deletions(-)

diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net.h b/drivers/net/ethernet/netronome/nfp/nfp_net.h
index 939cfce15830..b079b7a92a1d 100644
--- a/drivers/net/ethernet/netronome/nfp/nfp_net.h
+++ b/drivers/net/ethernet/netronome/nfp/nfp_net.h
@@ -621,6 +621,7 @@ struct nfp_net_dp {
  * @mbox_amsg.lock:	Protect message list
  * @mbox_amsg.list:	List of message to process
  * @mbox_amsg.work:	Work to process message asynchronously
+ * @mc_list:		List of multicast mac address
  * @app_priv:		APP private data for this vNIC
  */
 struct nfp_net {
@@ -728,6 +729,8 @@ struct nfp_net {
 		struct work_struct work;
 	} mbox_amsg;
 
+	struct list_head mc_list;
+
 	void *app_priv;
 };
 
@@ -738,6 +741,11 @@ struct nfp_mbox_amsg_entry {
 	char msg[];
 };
 
+struct nfp_mc_entry {
+	struct list_head list;
+	u8 addr[ETH_ALEN];
+};
+
 int nfp_net_sched_mbox_amsg_work(struct nfp_net *nn, u32 cmd, const void *data, size_t len,
 				 int (*cb)(struct nfp_net *, struct nfp_mbox_amsg_entry *));
 
diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_common.c b/drivers/net/ethernet/netronome/nfp/nfp_net_common.c
index 49f2f081ebb5..ccc49b330b51 100644
--- a/drivers/net/ethernet/netronome/nfp/nfp_net_common.c
+++ b/drivers/net/ethernet/netronome/nfp/nfp_net_common.c
@@ -1380,9 +1380,8 @@ static void nfp_net_mbox_amsg_work(struct work_struct *work)
 	}
 }
 
-static int nfp_net_mc_cfg(struct nfp_net *nn, struct nfp_mbox_amsg_entry *entry)
+static int _nfp_net_mc_cfg(struct nfp_net *nn, unsigned char *addr, u32 cmd)
 {
-	unsigned char *addr = entry->msg;
 	int ret;
 
 	ret = nfp_net_mbox_lock(nn, NFP_NET_CFG_MULTICAST_SZ);
@@ -1394,12 +1393,30 @@ static int nfp_net_mc_cfg(struct nfp_net *nn, struct nfp_mbox_amsg_entry *entry)
 	nn_writew(nn, nn->tlv_caps.mbox_off + NFP_NET_CFG_MULTICAST_MAC_LO,
 		  get_unaligned_be16(addr + 4));
 
-	return nfp_net_mbox_reconfig_and_unlock(nn, entry->cmd);
+	return nfp_net_mbox_reconfig_and_unlock(nn, cmd);
+}
+
+static void nfp_net_mc_clean(struct nfp_net *nn)
+{
+	struct nfp_mc_entry *entry, *tmp;
+
+	list_for_each_entry_safe(entry, tmp, &nn->mc_list, list) {
+		_nfp_net_mc_cfg(nn, entry->addr, NFP_NET_CFG_MBOX_CMD_MULTICAST_DEL);
+		list_del(&entry->list);
+		kfree(entry);
+	}
+}
+
+static int nfp_net_mc_cfg(struct nfp_net *nn, struct nfp_mbox_amsg_entry *entry)
+{
+	return _nfp_net_mc_cfg(nn, entry->msg, entry->cmd);
 }
 
 static int nfp_net_mc_sync(struct net_device *netdev, const unsigned char *addr)
 {
 	struct nfp_net *nn = netdev_priv(netdev);
+	struct nfp_mc_entry *entry, *tmp;
+	int err;
 
 	if (netdev_mc_count(netdev) > NFP_NET_CFG_MAC_MC_MAX) {
 		nn_err(nn, "Requested number of MC addresses (%d) exceeds maximum (%d).\n",
@@ -1407,16 +1424,48 @@ static int nfp_net_mc_sync(struct net_device *netdev, const unsigned char *addr)
 		return -EINVAL;
 	}
 
-	return nfp_net_sched_mbox_amsg_work(nn, NFP_NET_CFG_MBOX_CMD_MULTICAST_ADD, addr,
-					    NFP_NET_CFG_MULTICAST_SZ, nfp_net_mc_cfg);
+	list_for_each_entry_safe(entry, tmp, &nn->mc_list, list) {
+		if (ether_addr_equal(entry->addr, addr)) /* already existed */
+			return 0;
+	}
+
+	entry = kmalloc(sizeof(*entry), GFP_ATOMIC);
+	if (!entry)
+		return -ENOMEM;
+
+	err = nfp_net_sched_mbox_amsg_work(nn, NFP_NET_CFG_MBOX_CMD_MULTICAST_ADD, addr,
+					   NFP_NET_CFG_MULTICAST_SZ, nfp_net_mc_cfg);
+	if (!err) {
+		ether_addr_copy(entry->addr, addr);
+		list_add_tail(&entry->list, &nn->mc_list);
+	} else {
+		kfree(entry);
+	}
+
+	return err;
 }
 
 static int nfp_net_mc_unsync(struct net_device *netdev, const unsigned char *addr)
 {
 	struct nfp_net *nn = netdev_priv(netdev);
+	struct nfp_mc_entry *entry, *tmp;
+	int err;
+
+	list_for_each_entry_safe(entry, tmp, &nn->mc_list, list) {
+		if (ether_addr_equal(entry->addr, addr)) {
+			err = nfp_net_sched_mbox_amsg_work(nn, NFP_NET_CFG_MBOX_CMD_MULTICAST_DEL,
+							   addr, NFP_NET_CFG_MULTICAST_SZ,
+							   nfp_net_mc_cfg);
+			if (!err) {
+				list_del(&entry->list);
+				kfree(entry);
+			}
+
+			return err;
+		}
+	}
 
-	return nfp_net_sched_mbox_amsg_work(nn, NFP_NET_CFG_MBOX_CMD_MULTICAST_DEL, addr,
-					    NFP_NET_CFG_MULTICAST_SZ, nfp_net_mc_cfg);
+	return -ENOENT;
 }
 
 static void nfp_net_set_rx_mode(struct net_device *netdev)
@@ -2687,6 +2736,8 @@ int nfp_net_init(struct nfp_net *nn)
 			goto err_clean_mbox;
 
 		nfp_net_ipsec_init(nn);
+
+		INIT_LIST_HEAD(&nn->mc_list);
 	}
 
 	nfp_net_vecs_init(nn);
@@ -2718,5 +2769,6 @@ void nfp_net_clean(struct nfp_net *nn)
 	nfp_net_ipsec_clean(nn);
 	nfp_ccm_mbox_clean(nn);
 	flush_work(&nn->mbox_amsg.work);
+	nfp_net_mc_clean(nn);
 	nfp_net_reconfig_wait_posted(nn);
 }
-- 
2.34.1

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ