[PATCH net v2 3/3] net: fealnx: allocate the card index from an IDA

From: Жамбакиев Радий Рикардинович

Date: Fri Oct 02 2026 - 10:12:57 EST


From: Radiy Zhambakiev <r.zhambakiev@xxxxxxxxxxxxxxxxx>

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@xxxxxxxxxxxxxxx
Signed-off-by: Radiy Zhambakiev <r.zhambakiev@xxxxxxxxxxxxxxxxx>
---
Note on the IDA approach:

I really would like to go that way, as the proposed KISS way does
not really fix the main problem of infinitely incremented static
counter.

Constraining the probe to some arbitrary value also does not feel
right to me.

card_idx is incremented at the top of the probe, so even failing
probes will increment it. A failing device will eventually
exhaust this counter at its retry rate.

drivers/net/ethernet/fealnx.c | 25 +++++++++++++++++++------
1 file changed, 19 insertions(+), 6 deletions(-)

diff --git a/drivers/net/ethernet/fealnx.c b/drivers/net/ethernet/fealnx.c
index b5e96c7037f3..627e570fd399 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,19 +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;

- i = pci_enable_device(pdev);
- if (i) return i;
+ err = pci_enable_device(pdev);
+ if (err)
+ goto err_out_ida;
pci_set_master(pdev);

len = pci_resource_len(pdev, bar);
@@ -535,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;
@@ -674,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;
}

@@ -691,6 +703,7 @@ static void fealnx_remove_one(struct pci_dev *pdev)
dma_free_coherent(&pdev->dev, RX_TOTAL_SIZE, np->rx_ring,
np->rx_ring_dma);
pci_iounmap(pdev, np->mem);
+ ida_free(&fealnx_ida, np->card_idx);
free_netdev(dev);
pci_release_regions(pdev);
pci_disable_device(pdev);
--
2.53.0