Commit aeae5b4c authored by Michal Kazior's avatar Michal Kazior Committed by Kalle Valo
Browse files

ath10k: prevent debugfs mmio access crash kernel



It was possible to force an out of bounds MMIO
read/write via debugfs. E.g. on QCA988X this could
be triggered with:

 echo 0x2080e0 | tee /sys/kernel/debug/ieee80211/*/ath10k/reg_addr
 cat /sys/kernel/debug/ieee80211/*/ath10k/reg_value

 BUG: unable to handle kernel paging request at ffffc90001e080e0
 IP: [<ffffffff8135c860>] ioread32+0x40/0x50
 ...
 Call Trace:
  [<ffffffffa00d0c7f>] ? ath10k_pci_read32+0x4f/0x70 [ath10k_pci]
  [<ffffffffa0080f50>] ath10k_reg_value_read+0x90/0xf0 [ath10k_core]
  [<ffffffff8115c2c1>] ? handle_mm_fault+0xa91/0x1050
  [<ffffffff81189758>] __vfs_read+0x28/0xe0
  [<ffffffff812e4694>] ? security_file_permission+0x84/0xa0
  [<ffffffff81189ce3>] ? rw_verify_area+0x53/0x100
  [<ffffffff81189e1a>] vfs_read+0x8a/0x140
  [<ffffffff8118acb9>] SyS_read+0x49/0xb0
  [<ffffffff8104e39c>] ? trace_do_page_fault+0x3c/0xc0
  [<ffffffff8196596e>] system_call_fastpath+0x12/0x71
Reported-by: default avatarBen Greear <greearb@candelatech.com>
Signed-off-by: default avatarMichal Kazior <michal.kazior@tieto.com>
Signed-off-by: default avatarKalle Valo <kvalo@qca.qualcomm.com>
parent c702534a
...@@ -479,6 +479,12 @@ void ath10k_pci_write32(struct ath10k *ar, u32 offset, u32 value) ...@@ -479,6 +479,12 @@ void ath10k_pci_write32(struct ath10k *ar, u32 offset, u32 value)
struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
int ret; int ret;
if (unlikely(offset + sizeof(value) > ar_pci->mem_len)) {
ath10k_warn(ar, "refusing to write mmio out of bounds at 0x%08x - 0x%08zx (max 0x%08zx)\n",
offset, offset + sizeof(value), ar_pci->mem_len);
return;
}
ret = ath10k_pci_wake(ar); ret = ath10k_pci_wake(ar);
if (ret) { if (ret) {
ath10k_warn(ar, "failed to wake target for write32 of 0x%08x at 0x%08x: %d\n", ath10k_warn(ar, "failed to wake target for write32 of 0x%08x at 0x%08x: %d\n",
...@@ -496,6 +502,12 @@ u32 ath10k_pci_read32(struct ath10k *ar, u32 offset) ...@@ -496,6 +502,12 @@ u32 ath10k_pci_read32(struct ath10k *ar, u32 offset)
u32 val; u32 val;
int ret; int ret;
if (unlikely(offset + sizeof(val) > ar_pci->mem_len)) {
ath10k_warn(ar, "refusing to read mmio out of bounds at 0x%08x - 0x%08zx (max 0x%08zx)\n",
offset, offset + sizeof(val), ar_pci->mem_len);
return 0;
}
ret = ath10k_pci_wake(ar); ret = ath10k_pci_wake(ar);
if (ret) { if (ret) {
ath10k_warn(ar, "failed to wake target for read32 at 0x%08x: %d\n", ath10k_warn(ar, "failed to wake target for read32 at 0x%08x: %d\n",
...@@ -2679,6 +2691,7 @@ static int ath10k_pci_claim(struct ath10k *ar) ...@@ -2679,6 +2691,7 @@ static int ath10k_pci_claim(struct ath10k *ar)
pci_set_master(pdev); pci_set_master(pdev);
/* Arrange for access to Target SoC registers. */ /* Arrange for access to Target SoC registers. */
ar_pci->mem_len = pci_resource_len(pdev, BAR_NUM);
ar_pci->mem = pci_iomap(pdev, BAR_NUM, 0); ar_pci->mem = pci_iomap(pdev, BAR_NUM, 0);
if (!ar_pci->mem) { if (!ar_pci->mem) {
ath10k_err(ar, "failed to iomap BAR%d\n", BAR_NUM); ath10k_err(ar, "failed to iomap BAR%d\n", BAR_NUM);
......
...@@ -162,6 +162,7 @@ struct ath10k_pci { ...@@ -162,6 +162,7 @@ struct ath10k_pci {
struct device *dev; struct device *dev;
struct ath10k *ar; struct ath10k *ar;
void __iomem *mem; void __iomem *mem;
size_t mem_len;
/* /*
* Number of MSI interrupts granted, 0 --> using legacy PCI line * Number of MSI interrupts granted, 0 --> using legacy PCI line
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment