From: Radiy Zhambakiev 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@vger.kernel.org Signed-off-by: Radiy Zhambakiev --- 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 #include #include +#include #include /* Processor type for cache alignment. */ #include @@ -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