summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSurabhi Vishnoi <svishnoi@codeaurora.org>2017-08-31 17:54:50 +0530
committersnandini <snandini@codeaurora.org>2017-10-09 02:43:32 -0700
commite54d4de979419b68cb6f7a73c96923d2af036b58 (patch)
tree54e5f8ab0e47b999976c450648976807b00855e5
parent689f438e735d87ddaeabe710a8022cf2377f03e1 (diff)
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
-rw-r--r--hif/src/ath_procfs.c16
-rw-r--r--hif/src/dispatcher/dummy.c6
-rw-r--r--hif/src/dispatcher/dummy.h2
-rw-r--r--hif/src/dispatcher/multibus.h1
-rw-r--r--hif/src/dispatcher/multibus_ahb.c3
-rw-r--r--hif/src/dispatcher/multibus_pci.c3
-rw-r--r--hif/src/dispatcher/multibus_sdio.c3
-rw-r--r--hif/src/dispatcher/multibus_snoc.c1
-rw-r--r--hif/src/dispatcher/multibus_usb.c3
-rw-r--r--hif/src/pcie/if_pci.c14
-rw-r--r--hif/src/pcie/if_pci.h5
11 files changed, 46 insertions, 11 deletions
diff --git a/hif/src/ath_procfs.c b/hif/src/ath_procfs.c
index 93a14ddd1ed7..30a87087b962 100644
--- a/hif/src/ath_procfs.c
+++ b/hif/src/ath_procfs.c
@@ -72,17 +72,21 @@ static ssize_t ath_procfs_diag_read(struct file *file, char __user *buf,
struct hif_softc *scn;
uint32_t offset = 0, memtype = 0;
+ 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);
if (scn->bus_type == QDF_BUS_TYPE_SNOC) {
memtype = ((uint32_t)(*pos) & 0xff000000) >> 24;
offset = (uint32_t)(*pos) & 0xffffff;
@@ -127,6 +131,12 @@ static ssize_t ath_procfs_diag_write(struct file *file,
struct hif_softc *scn;
uint32_t offset = 0, memtype = 0;
+ 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__);
@@ -139,12 +149,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);
if (scn->bus_type == QDF_BUS_TYPE_SNOC) {
memtype = ((uint32_t)(*pos) & 0xff000000) >> 24;
offset = (uint32_t)(*pos) & 0xffffff;
diff --git a/hif/src/dispatcher/dummy.c b/hif/src/dispatcher/dummy.c
index bfe6bc9c3abe..45380807b3c7 100644
--- a/hif/src/dispatcher/dummy.c
+++ b/hif/src/dispatcher/dummy.c
@@ -331,3 +331,9 @@ int hif_dummy_bus_reset_resume(struct hif_softc *hif_ctx)
{
return 0;
}
+
+int hif_dummy_addr_in_boundary(struct hif_softc *scn, uint32_t offset)
+{
+ return 0;
+}
+
diff --git a/hif/src/dispatcher/dummy.h b/hif/src/dispatcher/dummy.h
index 58557e177343..b82957a206bb 100644
--- a/hif/src/dispatcher/dummy.h
+++ b/hif/src/dispatcher/dummy.h
@@ -60,4 +60,4 @@ void hif_dummy_clear_stats(struct hif_softc *hif_ctx);
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_addr_in_boundary(struct hif_softc *scn, uint32_t offset);
diff --git a/hif/src/dispatcher/multibus.h b/hif/src/dispatcher/multibus.h
index 3247869624a8..cd46b2cc2440 100644
--- a/hif/src/dispatcher/multibus.h
+++ b/hif/src/dispatcher/multibus.h
@@ -83,6 +83,7 @@ struct hif_bus_ops {
void (*hif_set_bundle_mode)(struct hif_softc *hif_ctx, bool enabled,
int rx_bundle_cnt);
int (*hif_bus_reset_resume)(struct hif_softc *hif_ctx);
+ int (*hif_addr_in_boundary)(struct hif_softc *scn, uint32_t offset);
};
#ifdef HIF_SNOC
diff --git a/hif/src/dispatcher/multibus_ahb.c b/hif/src/dispatcher/multibus_ahb.c
index d1bee78d6070..fb486fe052ec 100644
--- a/hif/src/dispatcher/multibus_ahb.c
+++ b/hif/src/dispatcher/multibus_ahb.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2016 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2016-2017 The Linux Foundation. All rights reserved.
*
* Permission to use, copy, modify, and/or distribute this software for
* any purpose with or without fee is hereby granted, provided that the
@@ -66,6 +66,7 @@ QDF_STATUS hif_initialize_ahb_ops(struct hif_bus_ops *bus_ops)
&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;
}
diff --git a/hif/src/dispatcher/multibus_pci.c b/hif/src/dispatcher/multibus_pci.c
index 545910515884..2dd5f6d1e751 100644
--- a/hif/src/dispatcher/multibus_pci.c
+++ b/hif/src/dispatcher/multibus_pci.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2016 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2016-2017 The Linux Foundation. All rights reserved.
*
* Previously licensed under the ISC license by Qualcomm Atheros, Inc.
*
@@ -85,6 +85,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;
return QDF_STATUS_SUCCESS;
}
diff --git a/hif/src/dispatcher/multibus_sdio.c b/hif/src/dispatcher/multibus_sdio.c
index fc272025516a..ab1641cd48d4 100644
--- a/hif/src/dispatcher/multibus_sdio.c
+++ b/hif/src/dispatcher/multibus_sdio.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2016 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2016-2017 The Linux Foundation. All rights reserved.
*
* Permission to use, copy, modify, and/or distribute this software for
* any purpose with or without fee is hereby granted, provided that the
@@ -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;
}
diff --git a/hif/src/dispatcher/multibus_snoc.c b/hif/src/dispatcher/multibus_snoc.c
index b9b41755fb40..01c4da1eecfa 100644
--- a/hif/src/dispatcher/multibus_snoc.c
+++ b/hif/src/dispatcher/multibus_snoc.c
@@ -81,6 +81,7 @@ QDF_STATUS hif_initialize_snoc_ops(struct hif_bus_ops *bus_ops)
&hif_snoc_display_stats;
bus_ops->hif_clear_stats =
&hif_snoc_clear_stats;
+ bus_ops->hif_addr_in_boundary = &hif_dummy_addr_in_boundary;
return QDF_STATUS_SUCCESS;
}
diff --git a/hif/src/dispatcher/multibus_usb.c b/hif/src/dispatcher/multibus_usb.c
index 0f3af6007cb8..68f73bc7cd2e 100644
--- a/hif/src/dispatcher/multibus_usb.c
+++ b/hif/src/dispatcher/multibus_usb.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2016 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2016-2017 The Linux Foundation. All rights reserved.
*
* Permission to use, copy, modify, and/or distribute this software for
* any purpose with or without fee is hereby granted, provided that the
@@ -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;
}
diff --git a/hif/src/pcie/if_pci.c b/hif/src/pcie/if_pci.c
index c785585df1a5..02f9767fdae5 100644
--- a/hif/src/pcie/if_pci.c
+++ b/hif/src/pcie/if_pci.c
@@ -2134,6 +2134,7 @@ static int hif_enable_pci(struct hif_pci_softc *sc,
goto err_iomap;
}
sc->mem = mem;
+ sc->mem_len = pci_resource_len(pdev, BAR_NUM);
sc->pdev = pdev;
sc->dev = &pdev->dev;
sc->devid = id->device;
@@ -4125,3 +4126,16 @@ void hif_runtime_lock_deinit(struct hif_opaque_softc *hif_ctx,
qdf_mem_free(context);
}
#endif /* FEATURE_RUNTIME_PM */
+
+int hif_pci_addr_in_boundary(struct hif_softc *scn, uint32_t offset)
+{
+ struct hif_pci_softc *sc = HIF_GET_PCI_SOFTC(scn);
+
+ if (unlikely(offset + sizeof(unsigned int) > sc->mem_len)) {
+ HIF_TRACE("Refusing to read memory at 0x%x - 0x%x (max 0x%x)\n",
+ offset, offset + sizeof(unsigned int), sc->mem_len);
+ return -EINVAL;
+ }
+
+ return 0;
+}
diff --git a/hif/src/pcie/if_pci.h b/hif/src/pcie/if_pci.h
index b515f6cce195..3a42a4a532ee 100644
--- a/hif/src/pcie/if_pci.h
+++ b/hif/src/pcie/if_pci.h
@@ -109,9 +109,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 */
@@ -149,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