From d1cb81fc3e65a5c797b6702877d16f4a852e6646 Mon Sep 17 00:00:00 2001
From: Carter Chen <carter.chen@infineon.com>
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 <carter.chen@infineon.com>
---
 .../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

