[lvc-project] [PATCH net 3/3] net: fealnx: allocate the card index from an IDA

Жамбакиев Радий Рикардинович r.zhambakiev at prosoftsystems.ru
Thu Sep 24 13:44:25 MSK 2026


From: Radiy Zhambakiev <r.zhambakiev at prosoftsystems.ru>

card_idx is a static counter that is incremented on every probe.
It can overflow and wrap to a negative value, which then indexes
options[] and full_duplex[] out of bounds. Large values also no
longer fit in the 12-byte boardname[] buffer.

Allocate the card index from an IDA and free it on probe failure and
remove. The IDA reuses ids on re-add, preserving the options[] and
full_duplex[] mapping by probe order.

Store the id in the driver-private data so fealnx_remove_one() can
free it, and size boardname to hold a full 32-bit id.

Found by Linux Verification Center (linuxtesting.org) with SVACE.

Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
Cc: stable at vger.kernel.org
Signed-off-by: Radiy Zhambakiev <r.zhambakiev at prosoftsystems.ru>
---
 drivers/net/ethernet/fealnx.c | 22 +++++++++++++++++-----
 1 file changed, 17 insertions(+), 5 deletions(-)

diff --git a/drivers/net/ethernet/fealnx.c b/drivers/net/ethernet/fealnx.c
index 46a40d00b59a..c474dd5ac4c6 100644
--- a/drivers/net/ethernet/fealnx.c
+++ b/drivers/net/ethernet/fealnx.c
@@ -83,6 +83,7 @@ static int full_duplex[MAX_UNITS] = { -1, -1, -1, -1, -1, -1, -1, -1 };
 #include <linux/crc32.h>
 #include <linux/delay.h>
 #include <linux/bitops.h>
+#include <linux/idr.h>
 
 #include <asm/processor.h>	/* Processor type for cache alignment. */
 #include <asm/io.h>
@@ -143,6 +144,8 @@ struct chip_info {
 	int flags;
 };
 
+static DEFINE_IDA(fealnx_ida);
+
 static const struct chip_info skel_netdrv_tbl[] = {
 	{ "100/10M Ethernet PCI Adapter",	HAS_MII_XCVR },
 	{ "100/10M Ethernet PCI Adapter",	HAS_CHIP_XCVR },
@@ -411,6 +414,8 @@ struct netdev_private {
 	unsigned char phys[2];	/* MII device addresses. */
 	struct mii_if_info mii;
 	void __iomem *mem;
+
+	int card_idx;
 };
 
 
@@ -473,9 +478,8 @@ static int fealnx_init_one(struct pci_dev *pdev,
 			   const struct pci_device_id *ent)
 {
 	struct netdev_private *np;
-	int i, option, err, irq;
-	static int card_idx = -1;
-	char boardname[12];
+	int option, err, irq, i;
+	char boardname[18];
 	void __iomem *ioaddr;
 	unsigned long len;
 	unsigned int chip_id = ent->driver_data;
@@ -483,20 +487,24 @@ static int fealnx_init_one(struct pci_dev *pdev,
 	void *ring_space;
 	dma_addr_t ring_dma;
 	u8 addr[ETH_ALEN];
+	int card_idx;
 #ifdef USE_IO_OPS
 	int bar = 0;
 #else
 	int bar = 1;
 #endif
 
-	card_idx++;
+	card_idx = ida_alloc(&fealnx_ida, GFP_KERNEL);
+	if (card_idx < 0)
+		return card_idx;
+
 	sprintf(boardname, "fealnx%d", card_idx);
 
 	option = card_idx < MAX_UNITS ? options[card_idx] : 0;
 
 	err = pci_enable_device(pdev);
 	if (err)
-		return err;
+		goto err_out_ida;
 	pci_set_master(pdev);
 
 	len = pci_resource_len(pdev, bar);
@@ -536,6 +544,7 @@ static int fealnx_init_one(struct pci_dev *pdev,
 
 	/* Make certain the descriptor lists are aligned. */
 	np = netdev_priv(dev);
+	np->card_idx = card_idx;
 	np->mem = ioaddr;
 	spin_lock_init(&np->lock);
 	np->pci_dev = pdev;
@@ -675,6 +684,8 @@ static int fealnx_init_one(struct pci_dev *pdev,
 	pci_release_regions(pdev);
 err_out_disable:
 	pci_disable_device(pdev);
+err_out_ida:
+	ida_free(&fealnx_ida, card_idx);
 	return err;
 }
 
@@ -699,6 +710,7 @@ static void fealnx_remove_one(struct pci_dev *pdev)
 	pci_iounmap(pdev, np->mem);
 	pci_release_regions(pdev);
 	pci_disable_device(pdev);
+	ida_free(&fealnx_ida, np->card_idx);
 	free_netdev(dev);
 }
 
-- 
2.53.0


More information about the lvc-project mailing list