From d1cb81fc3e65a5c797b6702877d16f4a852e6646 Mon Sep 17 00:00:00 2001 From: Carter Chen Date: Thu, 13 Apr 2023 01:06:30 -0500 Subject: [PATCH 155/296] brcmfmac: add protection for PCIe Read/Write out-of-bound Fixes: SWWLAN-146124 Signed-off-by: Carter Chen --- .../broadcom/brcm80211/brcmfmac/pcie.c | 121 ++++++++++++++++-- 1 file changed, 110 insertions(+), 11 deletions(-) diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c index 1a1726d63528..9038409c74b2 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c @@ -392,14 +392,12 @@ struct brcmf_pciedev_info { u16 value); struct brcmf_mp_device *settings; struct brcmf_otp_params otp; + ulong bar1_size; #ifdef DEBUG u32 console_interval; bool console_active; struct timer_list timer; #endif -#ifdef CONFIG_BRCMFMAC_PCIE_BARWIN_SZ - ulong bar1_size; -#endif /* CONFIG_BRCMFMAC_PCIE_BARWIN_SZ */ }; struct brcmf_pcie_ringbuf { @@ -541,6 +539,8 @@ brcmf_pcie_write_reg32(struct brcmf_pciedev_info *devinfo, u32 reg_offset, static u8 brcmf_pcie_read_tcm8(struct brcmf_pciedev_info *devinfo, u32 mem_offset) { + struct pci_dev *pdev = devinfo->pdev; + struct brcmf_bus *bus = dev_get_drvdata(&pdev->dev); void __iomem *address = devinfo->tcm + mem_offset; #ifdef CONFIG_BRCMFMAC_PCIE_BARWIN_SZ unsigned long flags; @@ -558,6 +558,13 @@ brcmf_pcie_read_tcm8(struct brcmf_pciedev_info *devinfo, u32 mem_offset) return value; #else + if ((address - devinfo->tcm) >= devinfo->bar1_size) { + brcmf_err(bus, + "mem_offset:%d exceeds device size=%ld\n", + mem_offset, devinfo->bar1_size); + return -EINVAL; + } + return (ioread8(address)); #endif /* CONFIG_BRCMFMAC_PCIE_BARWIN_SZ */ } @@ -566,6 +573,8 @@ brcmf_pcie_read_tcm8(struct brcmf_pciedev_info *devinfo, u32 mem_offset) static u16 brcmf_pcie_read_tcm16(struct brcmf_pciedev_info *devinfo, u32 mem_offset) { + struct pci_dev *pdev = devinfo->pdev; + struct brcmf_bus *bus = dev_get_drvdata(&pdev->dev); void __iomem *address = devinfo->tcm + mem_offset; #ifdef CONFIG_BRCMFMAC_PCIE_BARWIN_SZ u16 value; @@ -583,6 +592,12 @@ brcmf_pcie_read_tcm16(struct brcmf_pciedev_info *devinfo, u32 mem_offset) return value; #else + if ((address - devinfo->tcm) >= devinfo->bar1_size) { + brcmf_err(bus, "mem_offset:%d exceeds device size=%ld\n", + mem_offset, devinfo->bar1_size); + return -EINVAL; + } + return (ioread16(address)); #endif /* CONFIG_BRCMFMAC_PCIE_BARWIN_SZ */ } @@ -592,6 +607,8 @@ static void brcmf_pcie_write_tcm16(struct brcmf_pciedev_info *devinfo, u32 mem_offset, u16 value) { + struct pci_dev *pdev = devinfo->pdev; + struct brcmf_bus *bus = dev_get_drvdata(&pdev->dev); void __iomem *address = devinfo->tcm + mem_offset; #ifdef CONFIG_BRCMFMAC_PCIE_BARWIN_SZ unsigned long flags; @@ -607,6 +624,12 @@ brcmf_pcie_write_tcm16(struct brcmf_pciedev_info *devinfo, u32 mem_offset, pci_write_config_dword(devinfo->pdev, BCMA_PCI_BAR1_WIN, 0x0); raw_spin_unlock_irqrestore(&pcie_lock, flags); #else + if ((address - devinfo->tcm) >= devinfo->bar1_size) { + brcmf_err(bus, "mem_offset:%d exceeds device size=%ld\n", + mem_offset, devinfo->bar1_size); + return; + } + iowrite16(value, address); #endif /* CONFIG_BRCMFMAC_PCIE_BARWIN_SZ */ } @@ -634,6 +657,8 @@ brcmf_pcie_write_idx(struct brcmf_pciedev_info *devinfo, u32 mem_offset, static u32 brcmf_pcie_read_tcm32(struct brcmf_pciedev_info *devinfo, u32 mem_offset) { + struct pci_dev *pdev = devinfo->pdev; + struct brcmf_bus *bus = dev_get_drvdata(&pdev->dev); void __iomem *address = devinfo->tcm + mem_offset; #ifdef CONFIG_BRCMFMAC_PCIE_BARWIN_SZ u32 value; @@ -651,6 +676,12 @@ brcmf_pcie_read_tcm32(struct brcmf_pciedev_info *devinfo, u32 mem_offset) return value; #else + if ((address - devinfo->tcm) >= devinfo->bar1_size) { + brcmf_err(bus, "mem_offset:%d exceeds device size=%ld\n", + mem_offset, devinfo->bar1_size); + return -EINVAL; + } + return (ioread32(address)); #endif /* CONFIG_BRCMFMAC_PCIE_BARWIN_SZ */ } @@ -660,6 +691,8 @@ static void brcmf_pcie_write_tcm32(struct brcmf_pciedev_info *devinfo, u32 mem_offset, u32 value) { + struct pci_dev *pdev = devinfo->pdev; + struct brcmf_bus *bus = dev_get_drvdata(&pdev->dev); void __iomem *address = devinfo->tcm + mem_offset; #ifdef CONFIG_BRCMFMAC_PCIE_BARWIN_SZ unsigned long flags; @@ -674,6 +707,12 @@ brcmf_pcie_write_tcm32(struct brcmf_pciedev_info *devinfo, u32 mem_offset, pci_write_config_dword(devinfo->pdev, BCMA_PCI_BAR1_WIN, 0x0); raw_spin_unlock_irqrestore(&pcie_lock, flags); #else + if ((address - devinfo->tcm) >= devinfo->bar1_size) { + brcmf_err(bus, "mem_offset:%d exceeds device size=%ld\n", + mem_offset, devinfo->bar1_size); + return; + } + iowrite32(value, address); #endif /* CONFIG_BRCMFMAC_PCIE_BARWIN_SZ */ } @@ -682,6 +721,8 @@ brcmf_pcie_write_tcm32(struct brcmf_pciedev_info *devinfo, u32 mem_offset, static u32 brcmf_pcie_read_ram32(struct brcmf_pciedev_info *devinfo, u32 mem_offset) { + struct pci_dev *pdev = devinfo->pdev; + struct brcmf_bus *bus = dev_get_drvdata(&pdev->dev); void __iomem *address = devinfo->tcm + devinfo->ci->rambase + mem_offset; #ifdef CONFIG_BRCMFMAC_PCIE_BARWIN_SZ @@ -700,6 +741,12 @@ brcmf_pcie_read_ram32(struct brcmf_pciedev_info *devinfo, u32 mem_offset) return value; #else + if ((address - devinfo->tcm) >= devinfo->bar1_size) { + brcmf_err(bus, "mem_offset:%d exceeds device size=%ld\n", + mem_offset, devinfo->bar1_size); + return -EINVAL; + } + return (ioread32(address)); #endif /* CONFIG_BRCMFMAC_PCIE_BARWIN_SZ */ } @@ -709,6 +756,8 @@ static void brcmf_pcie_write_ram32(struct brcmf_pciedev_info *devinfo, u32 mem_offset, u32 value) { + struct pci_dev *pdev = devinfo->pdev; + struct brcmf_bus *bus = dev_get_drvdata(&pdev->dev); void __iomem *address = devinfo->tcm + devinfo->ci->rambase + mem_offset; #ifdef CONFIG_BRCMFMAC_PCIE_BARWIN_SZ @@ -724,6 +773,12 @@ brcmf_pcie_write_ram32(struct brcmf_pciedev_info *devinfo, u32 mem_offset, pci_write_config_dword(devinfo->pdev, BCMA_PCI_BAR1_WIN, 0x0); raw_spin_unlock_irqrestore(&pcie_lock, flags); #else + if ((address - devinfo->tcm) >= devinfo->bar1_size) { + brcmf_err(bus, "mem_offset:%d exceeds device size=%ld\n", + mem_offset, devinfo->bar1_size); + return; + } + iowrite32(value, address); #endif /* CONFIG_BRCMFMAC_PCIE_BARWIN_SZ */ } @@ -733,6 +788,8 @@ static void brcmf_pcie_copy_mem_todev(struct brcmf_pciedev_info *devinfo, u32 mem_offset, void *srcaddr, u32 len) { + struct pci_dev *pdev = devinfo->pdev; + struct brcmf_bus *bus = dev_get_drvdata(&pdev->dev); void __iomem *address = devinfo->tcm + mem_offset; __le32 *src32; __le16 *src16; @@ -755,8 +812,15 @@ brcmf_pcie_copy_mem_todev(struct brcmf_pciedev_info *devinfo, u32 mem_offset, devinfo->bar1_size); address = address - devinfo->bar1_size; - } + } else #endif /* CONFIG_BRCMFMAC_PCIE_BARWIN_SZ */ + if ((address - devinfo->tcm) >= + devinfo->bar1_size) { + brcmf_err(bus, + "mem_offset:%d exceeds device size=%ld\n", + mem_offset, devinfo->bar1_size); + return; + } iowrite8(*src8, address); #ifdef CONFIG_BRCMFMAC_PCIE_BARWIN_SZ raw_spin_unlock_irqrestore(&pcie_lock, flags); @@ -779,8 +843,15 @@ brcmf_pcie_copy_mem_todev(struct brcmf_pciedev_info *devinfo, u32 mem_offset, devinfo->bar1_size); address = address - devinfo->bar1_size; - } + } else #endif /* CONFIG_BRCMFMAC_PCIE_BARWIN_SZ */ + if ((address - devinfo->tcm) >= + devinfo->bar1_size) { + brcmf_err(bus, + "mem_offset:%d exceeds device size=%ld\n", + mem_offset, devinfo->bar1_size); + return; + } iowrite16(le16_to_cpu(*src16), address); #ifdef CONFIG_BRCMFMAC_PCIE_BARWIN_SZ raw_spin_unlock_irqrestore(&pcie_lock, flags); @@ -803,8 +874,15 @@ brcmf_pcie_copy_mem_todev(struct brcmf_pciedev_info *devinfo, u32 mem_offset, BCMA_PCI_BAR1_WIN, devinfo->bar1_size); address = address - devinfo->bar1_size; - } + } else #endif /* CONFIG_BRCMFMAC_PCIE_BARWIN_SZ */ + if ((address - devinfo->tcm) >= + devinfo->bar1_size) { + brcmf_err(bus, + "mem_offset:%d exceeds device size=%ld\n", + mem_offset, devinfo->bar1_size); + return; + } iowrite32(le32_to_cpu(*src32), address); #ifdef CONFIG_BRCMFMAC_PCIE_BARWIN_SZ raw_spin_unlock_irqrestore(&pcie_lock, flags); @@ -824,6 +902,8 @@ static void brcmf_pcie_copy_dev_tomem(struct brcmf_pciedev_info *devinfo, u32 mem_offset, void *dstaddr, u32 len) { + struct pci_dev *pdev = devinfo->pdev; + struct brcmf_bus *bus = dev_get_drvdata(&pdev->dev); void __iomem *address = devinfo->tcm + mem_offset; __le32 *dst32; __le16 *dst16; @@ -846,8 +926,15 @@ brcmf_pcie_copy_dev_tomem(struct brcmf_pciedev_info *devinfo, u32 mem_offset, devinfo->bar1_size); address = address - devinfo->bar1_size; - } + } else #endif /* CONFIG_BRCMFMAC_PCIE_BARWIN_SZ */ + if ((address - devinfo->tcm) >= + devinfo->bar1_size) { + brcmf_err(bus, + "mem_offset:%d exceeds device size=%ld\n", + mem_offset, devinfo->bar1_size); + return; + } *dst8 = ioread8(address); #ifdef CONFIG_BRCMFMAC_PCIE_BARWIN_SZ raw_spin_unlock_irqrestore(&pcie_lock, flags); @@ -870,8 +957,15 @@ brcmf_pcie_copy_dev_tomem(struct brcmf_pciedev_info *devinfo, u32 mem_offset, devinfo->bar1_size); address = address - devinfo->bar1_size; - } + } else #endif /* CONFIG_BRCMFMAC_PCIE_BARWIN_SZ */ + if ((address - devinfo->tcm) >= + devinfo->bar1_size) { + brcmf_err(bus, + "mem_offset:%d exceeds device size=%ld\n", + mem_offset, devinfo->bar1_size); + return; + } *dst16 = cpu_to_le16(ioread16(address)); #ifdef CONFIG_BRCMFMAC_PCIE_BARWIN_SZ raw_spin_unlock_irqrestore(&pcie_lock, flags); @@ -894,8 +988,15 @@ brcmf_pcie_copy_dev_tomem(struct brcmf_pciedev_info *devinfo, u32 mem_offset, BCMA_PCI_BAR1_WIN, devinfo->bar1_size); address = address - devinfo->bar1_size; - } + } else #endif /* CONFIG_BRCMFMAC_PCIE_BARWIN_SZ */ + if ((address - devinfo->tcm) >= + devinfo->bar1_size) { + brcmf_err(bus, + "mem_offset:%d exceeds device size=%ld\n", + mem_offset, devinfo->bar1_size); + return; + } *dst32 = cpu_to_le32(ioread32(address)); #ifdef CONFIG_BRCMFMAC_PCIE_BARWIN_SZ raw_spin_unlock_irqrestore(&pcie_lock, flags); @@ -2285,9 +2386,7 @@ static int brcmf_pcie_get_resource(struct brcmf_pciedev_info *devinfo) devinfo->regs = ioremap(bar0_addr, BRCMF_PCIE_REG_MAP_SIZE); devinfo->tcm = ioremap(bar1_addr, bar1_size); -#ifdef CONFIG_BRCMFMAC_PCIE_BARWIN_SZ devinfo->bar1_size = bar1_size; -#endif /* CONFIG_BRCMFMAC_PCIE_BARWIN_SZ */ if (!devinfo->regs || !devinfo->tcm) { brcmf_err(bus, "ioremap() failed (%p,%p)\n", devinfo->regs, -- 2.25.1