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
This commit is contained in:
Surabhi Vishnoi
2017-08-31 17:54:50 +05:30
committed by snandini
parent 5b55c8e857
commit 6f752b487b
11 changed files with 44 additions and 7 deletions

View File

@@ -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 &&

View File

@@ -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;
}

View File

@@ -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);

View File

@@ -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

View File

@@ -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;
}

View File

@@ -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;

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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