Parcourir la source

qcacmn: Check target address boundary before access

Athdiag procfs entry does not have address sanity check, this is
resulting in invalid ioread32/iowrite32 if out of PCIE BAR address
is used.

Fix this by allowing address with in PCIE BAR range.

Change-Id: I8365eacca7ccc4f489b7d0bda6c998384d0fec7b
CRs-Fixed: 2112270
Surabhi Vishnoi il y a 7 ans
Parent
commit
6f752b487b

+ 12 - 4
hif/src/ath_procfs.c

@@ -73,17 +73,21 @@ static ssize_t ath_procfs_diag_read(struct file *file, char __user *buf,
 	uint32_t offset = 0, memtype = 0;
 	struct hif_target_info *tgt_info;
 
+	hif_hdl = get_hif_hdl_from_file(file);
+	scn = HIF_GET_SOFTC(hif_hdl);
+
+	if (scn->bus_ops.hif_addr_in_boundary(hif_hdl, (uint32_t)(*pos)))
+		return -EINVAL;
+
 	read_buffer = qdf_mem_malloc(count);
 	if (NULL == read_buffer) {
 		HIF_ERROR("%s: cdf_mem_alloc failed", __func__);
 		return -ENOMEM;
 	}
 
-	hif_hdl = get_hif_hdl_from_file(file);
 	HIF_DBG("rd buff 0x%pK cnt %zu offset 0x%x buf 0x%pK",
 		 read_buffer, count, (int)*pos, buf);
 
-	scn = HIF_GET_SOFTC(hif_hdl);
 	tgt_info = hif_get_target_info_handle(GET_HIF_OPAQUE_HDL(hif_hdl));
 	if (scn->bus_type == QDF_BUS_TYPE_SNOC ||
 			(scn->bus_type ==  QDF_BUS_TYPE_PCI &&
@@ -133,6 +137,12 @@ static ssize_t ath_procfs_diag_write(struct file *file,
 	uint32_t offset = 0, memtype = 0;
 	struct hif_target_info *tgt_info;
 
+	hif_hdl = get_hif_hdl_from_file(file);
+	scn = HIF_GET_SOFTC(hif_hdl);
+
+	if (scn->bus_ops.hif_addr_in_boundary(hif_hdl, (uint32_t)(*pos)))
+		return -EINVAL;
+
 	write_buffer = qdf_mem_malloc(count);
 	if (NULL == write_buffer) {
 		HIF_ERROR("%s: cdf_mem_alloc failed", __func__);
@@ -145,12 +155,10 @@ static ssize_t ath_procfs_diag_write(struct file *file,
 		return -EFAULT;
 	}
 
-	hif_hdl = get_hif_hdl_from_file(file);
 	HIF_DBG("wr buff 0x%pK buf 0x%pK cnt %zu offset 0x%x value 0x%x",
 		 write_buffer, buf, count,
 		 (int)*pos, *((uint32_t *) write_buffer));
 
-	scn = HIF_GET_SOFTC(hif_hdl);
 	tgt_info = hif_get_target_info_handle(GET_HIF_OPAQUE_HDL(hif_hdl));
 	if (scn->bus_type == QDF_BUS_TYPE_SNOC ||
 			(scn->bus_type ==  QDF_BUS_TYPE_PCI &&

+ 5 - 0
hif/src/dispatcher/dummy.c

@@ -372,3 +372,8 @@ int hif_dummy_map_ce_to_irq(struct hif_softc *scn, int ce_id)
 	return -(1);
 }
 
+int hif_dummy_addr_in_boundary(struct hif_softc *scn, uint32_t offset)
+{
+	return 0;
+}
+

+ 1 - 1
hif/src/dispatcher/dummy.h

@@ -66,4 +66,4 @@ void hif_dummy_set_bundle_mode(struct hif_softc *hif_ctx,
 					bool enabled, int rx_bundle_cnt);
 int hif_dummy_bus_reset_resume(struct hif_softc *hif_ctx);
 int hif_dummy_map_ce_to_irq(struct hif_softc *scn, int ce_id);
-
+int hif_dummy_addr_in_boundary(struct hif_softc *scn, uint32_t offset);

+ 1 - 0
hif/src/dispatcher/multibus.h

@@ -87,6 +87,7 @@ struct hif_bus_ops {
 					int rx_bundle_cnt);
 	int (*hif_bus_reset_resume)(struct hif_softc *hif_ctx);
 	int (*hif_map_ce_to_irq)(struct hif_softc *hif_sc, int ce_id);
+	int (*hif_addr_in_boundary)(struct hif_softc *scn, uint32_t offset);
 };
 
 #ifdef HIF_SNOC

+ 1 - 0
hif/src/dispatcher/multibus_ahb.c

@@ -67,6 +67,7 @@ QDF_STATUS hif_initialize_ahb_ops(struct hif_bus_ops *bus_ops)
 	bus_ops->hif_disable_power_management =
 		&hif_dummy_disable_power_management;
 	bus_ops->hif_grp_irq_configure = &hif_ahb_configure_grp_irq;
+	bus_ops->hif_addr_in_boundary = &hif_dummy_addr_in_boundary;
 
 	return QDF_STATUS_SUCCESS;
 }

+ 1 - 0
hif/src/dispatcher/multibus_pci.c

@@ -88,6 +88,7 @@ QDF_STATUS hif_initialize_pci_ops(struct hif_softc *hif_sc)
 		&hif_pci_display_stats;
 	bus_ops->hif_clear_stats =
 		&hif_pci_clear_stats;
+	bus_ops->hif_addr_in_boundary = &hif_pci_addr_in_boundary;
 
 	/* default to legacy mapping handler; override as needed */
 	bus_ops->hif_map_ce_to_irq = &hif_pci_legacy_map_ce_to_irq;

+ 1 - 0
hif/src/dispatcher/multibus_sdio.c

@@ -64,6 +64,7 @@ QDF_STATUS hif_initialize_sdio_ops(struct hif_softc *hif_sc)
 		&hif_dummy_enable_power_management;
 	bus_ops->hif_disable_power_management =
 		&hif_dummy_disable_power_management;
+	bus_ops->hif_addr_in_boundary = &hif_dummy_addr_in_boundary;
 
 	return QDF_STATUS_SUCCESS;
 }

+ 1 - 0
hif/src/dispatcher/multibus_snoc.c

@@ -82,6 +82,7 @@ QDF_STATUS hif_initialize_snoc_ops(struct hif_bus_ops *bus_ops)
 	bus_ops->hif_clear_stats =
 		&hif_snoc_clear_stats;
 	bus_ops->hif_map_ce_to_irq = &hif_snoc_map_ce_to_irq;
+	bus_ops->hif_addr_in_boundary = &hif_dummy_addr_in_boundary;
 
 	return QDF_STATUS_SUCCESS;
 }

+ 1 - 0
hif/src/dispatcher/multibus_usb.c

@@ -64,6 +64,7 @@ QDF_STATUS hif_initialize_usb_ops(struct hif_bus_ops *bus_ops)
 			&hif_dummy_disable_power_management;
 	bus_ops->hif_set_bundle_mode = hif_usb_set_bundle_mode;
 	bus_ops->hif_bus_reset_resume = hif_usb_bus_reset_resume;
+	bus_ops->hif_addr_in_boundary = &hif_dummy_addr_in_boundary;
 
 	return QDF_STATUS_SUCCESS;
 }

+ 16 - 0
hif/src/pcie/if_pci.c

@@ -2208,6 +2208,7 @@ static int hif_enable_pci(struct hif_pci_softc *sc,
 			__func__, sc->mem);
 	}
 
+	sc->mem_len = pci_resource_len(pdev, BAR_NUM);
 	ol_sc->mem = mem;
 	ol_sc->mem_pa = pci_resource_start(pdev, BAR_NUM);
 	sc->pci_enabled = true;
@@ -4464,3 +4465,18 @@ int hif_pci_legacy_map_ce_to_irq(struct hif_softc *scn, int ce_id)
 	/* legacy case only has one irq */
 	return pci_scn->irq;
 }
+
+int hif_pci_addr_in_boundary(struct hif_softc *scn, uint32_t offset)
+{
+	struct hif_pci_softc *sc = HIF_GET_PCI_SOFTC(scn);
+
+	if ((offset >= DRAM_BASE_ADDRESS && offset <= DRAM_BASE_ADDRESS + DRAM_SIZE)
+		 || (offset + sizeof(unsigned int) <= sc->mem_len)) {
+		return 0;
+	}
+
+	HIF_TRACE("Refusing to read memory at 0x%x - 0x%lx (max 0x%zx)\n",
+		 offset, offset + sizeof(unsigned int), sc->mem_len);
+
+	return -EINVAL;
+}

+ 4 - 2
hif/src/pcie/if_pci.h

@@ -33,6 +33,7 @@
 #include <linux/interrupt.h>
 
 #define ATH_DBG_DEFAULT   0
+#define DRAM_SIZE               0x000a8000
 #include "hif.h"
 #include "cepci.h"
 #include "ce_main.h"
@@ -109,9 +110,9 @@ struct hif_msi_info {
 struct hif_pci_softc {
 	struct HIF_CE_state ce_sc;
 	void __iomem *mem;      /* PCI address. */
-	/* For efficiency, should be first in struct */
+	size_t mem_len;
 
-	struct device *dev;
+	struct device *dev;	/* For efficiency, should be first in struct */
 	struct pci_dev *pdev;
 	int num_msi_intrs;      /* number of MSI interrupts granted */
 	/* 0 --> using legacy PCI line interrupts */
@@ -148,6 +149,7 @@ int hif_configure_irq(struct hif_softc *sc);
 void hif_pci_cancel_deferred_target_sleep(struct hif_softc *scn);
 void wlan_tasklet(unsigned long data);
 irqreturn_t hif_pci_interrupt_handler(int irq, void *arg);
+int hif_pci_addr_in_boundary(struct hif_softc *scn, uint32_t offset);
 
 /*
  * A firmware interrupt to the Host is indicated by the