]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/commitdiff
wil6210: add block size checks during FW load
authorLior David <qca_liord@qca.qualcomm.com>
Tue, 21 Apr 2020 12:40:12 +0000 (13:40 +0100)
committerStefan Bader <stefan.bader@canonical.com>
Thu, 14 May 2020 08:53:58 +0000 (10:53 +0200)
BugLink: https://bugs.launchpad.net/bugs/1875506
[ Upstream commit 705d2fde94b23cd76efbeedde643ffa7c32fac7f ]

When loading FW from file add block size checks to ensure a
corrupted FW file will not cause the driver to write outside
the device memory.

Signed-off-by: Lior David <qca_liord@qca.qualcomm.com>
Signed-off-by: Maya Erez <qca_merez@qca.qualcomm.com>
Signed-off-by: Kalle Valo <kvalo@qca.qualcomm.com>
Signed-off-by: Lee Jones <lee.jones@linaro.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Signed-off-by: Kamal Mostafa <kamal@canonical.com>
Signed-off-by: Stefan Bader <stefan.bader@canonical.com>
drivers/net/wireless/ath/wil6210/fw_inc.c
drivers/net/wireless/ath/wil6210/wil6210.h
drivers/net/wireless/ath/wil6210/wmi.c

index e01acac88825d895dbae09fe67f6e21b0ad3fbd2..7d090150187c873f446170b4f889dc008ed4cd6e 100644 (file)
                                             prefix_type, rowsize,      \
                                             groupsize, buf, len, ascii)
 
-#define FW_ADDR_CHECK(ioaddr, val, msg) do { \
-               ioaddr = wmi_buffer(wil, val); \
-               if (!ioaddr) { \
-                       wil_err_fw(wil, "bad " msg ": 0x%08x\n", \
-                                  le32_to_cpu(val)); \
-                       return -EINVAL; \
-               } \
-       } while (0)
+static bool wil_fw_addr_check(struct wil6210_priv *wil,
+                             void __iomem **ioaddr, __le32 val,
+                             u32 size, const char *msg)
+{
+       *ioaddr = wmi_buffer_block(wil, val, size);
+       if (!(*ioaddr)) {
+               wil_err_fw(wil, "bad %s: 0x%08x\n", msg, le32_to_cpu(val));
+               return false;
+       }
+       return true;
+}
 
 /**
  * wil_fw_verify - verify firmware file validity
@@ -165,7 +168,8 @@ static int fw_handle_data(struct wil6210_priv *wil, const void *data,
                return -EINVAL;
        }
 
-       FW_ADDR_CHECK(dst, d->addr, "address");
+       if (!wil_fw_addr_check(wil, &dst, d->addr, s, "address"))
+               return -EINVAL;
        wil_dbg_fw(wil, "write [0x%08x] <== %zu bytes\n", le32_to_cpu(d->addr),
                   s);
        wil_memcpy_toio_32(dst, d->data, s);
@@ -197,7 +201,8 @@ static int fw_handle_fill(struct wil6210_priv *wil, const void *data,
                return -EINVAL;
        }
 
-       FW_ADDR_CHECK(dst, d->addr, "address");
+       if (!wil_fw_addr_check(wil, &dst, d->addr, s, "address"))
+               return -EINVAL;
 
        v = le32_to_cpu(d->value);
        wil_dbg_fw(wil, "fill [0x%08x] <== 0x%08x, %zu bytes\n",
@@ -253,7 +258,8 @@ static int fw_handle_direct_write(struct wil6210_priv *wil, const void *data,
                u32 v = le32_to_cpu(block[i].value);
                u32 x, y;
 
-               FW_ADDR_CHECK(dst, block[i].addr, "address");
+               if (!wil_fw_addr_check(wil, &dst, block[i].addr, 0, "address"))
+                       return -EINVAL;
 
                x = readl(dst);
                y = (x & m) | (v & ~m);
@@ -319,10 +325,15 @@ static int fw_handle_gateway_data(struct wil6210_priv *wil, const void *data,
        wil_dbg_fw(wil, "gw write record [%3d] blocks, cmd 0x%08x\n",
                   n, gw_cmd);
 
-       FW_ADDR_CHECK(gwa_addr, d->gateway_addr_addr, "gateway_addr_addr");
-       FW_ADDR_CHECK(gwa_val, d->gateway_value_addr, "gateway_value_addr");
-       FW_ADDR_CHECK(gwa_cmd, d->gateway_cmd_addr, "gateway_cmd_addr");
-       FW_ADDR_CHECK(gwa_ctl, d->gateway_ctrl_address, "gateway_ctrl_address");
+       if (!wil_fw_addr_check(wil, &gwa_addr, d->gateway_addr_addr, 0,
+                              "gateway_addr_addr") ||
+           !wil_fw_addr_check(wil, &gwa_val, d->gateway_value_addr, 0,
+                              "gateway_value_addr") ||
+           !wil_fw_addr_check(wil, &gwa_cmd, d->gateway_cmd_addr, 0,
+                              "gateway_cmd_addr") ||
+           !wil_fw_addr_check(wil, &gwa_ctl, d->gateway_ctrl_address, 0,
+                              "gateway_ctrl_address"))
+               return -EINVAL;
 
        wil_dbg_fw(wil, "gw addresses: addr 0x%08x val 0x%08x"
                   " cmd 0x%08x ctl 0x%08x\n",
@@ -378,12 +389,19 @@ static int fw_handle_gateway_data4(struct wil6210_priv *wil, const void *data,
        wil_dbg_fw(wil, "gw4 write record [%3d] blocks, cmd 0x%08x\n",
                   n, gw_cmd);
 
-       FW_ADDR_CHECK(gwa_addr, d->gateway_addr_addr, "gateway_addr_addr");
+       if (!wil_fw_addr_check(wil, &gwa_addr, d->gateway_addr_addr, 0,
+                              "gateway_addr_addr"))
+               return -EINVAL;
        for (k = 0; k < ARRAY_SIZE(block->value); k++)
-               FW_ADDR_CHECK(gwa_val[k], d->gateway_value_addr[k],
-                             "gateway_value_addr");
-       FW_ADDR_CHECK(gwa_cmd, d->gateway_cmd_addr, "gateway_cmd_addr");
-       FW_ADDR_CHECK(gwa_ctl, d->gateway_ctrl_address, "gateway_ctrl_address");
+               if (!wil_fw_addr_check(wil, &gwa_val[k],
+                                      d->gateway_value_addr[k],
+                                      0, "gateway_value_addr"))
+                       return -EINVAL;
+       if (!wil_fw_addr_check(wil, &gwa_cmd, d->gateway_cmd_addr, 0,
+                              "gateway_cmd_addr") ||
+           !wil_fw_addr_check(wil, &gwa_ctl, d->gateway_ctrl_address, 0,
+                              "gateway_ctrl_address"))
+               return -EINVAL;
 
        wil_dbg_fw(wil, "gw4 addresses: addr 0x%08x cmd 0x%08x ctl 0x%08x\n",
                   le32_to_cpu(d->gateway_addr_addr),
index 5ce18aa5f534a2c08c6090e93ba4da0bb657413c..ed4fbef0f5b7a4efc17579bcd6eec57a18a9a3c0 100644 (file)
@@ -865,6 +865,7 @@ void wil_mbox_ring_le2cpus(struct wil6210_mbox_ring *r);
 int wil_find_cid(struct wil6210_priv *wil, const u8 *mac);
 void wil_set_ethtoolops(struct net_device *ndev);
 
+void __iomem *wmi_buffer_block(struct wil6210_priv *wil, __le32 ptr, u32 size);
 void __iomem *wmi_buffer(struct wil6210_priv *wil, __le32 ptr);
 void __iomem *wmi_addr(struct wil6210_priv *wil, u32 ptr);
 int wmi_read_hdr(struct wil6210_priv *wil, __le32 ptr,
index 798516f42f2f97001579183dcb788ee677e98747..6cfb820caa3ee7d1080252675be5f082d0d0288d 100644 (file)
@@ -140,13 +140,15 @@ static u32 wmi_addr_remap(u32 x)
 /**
  * Check address validity for WMI buffer; remap if needed
  * @ptr - internal (linker) fw/ucode address
+ * @size - if non zero, validate the block does not
+ *  exceed the device memory (bar)
  *
  * Valid buffer should be DWORD aligned
  *
  * return address for accessing buffer from the host;
  * if buffer is not valid, return NULL.
  */
-void __iomem *wmi_buffer(struct wil6210_priv *wil, __le32 ptr_)
+void __iomem *wmi_buffer_block(struct wil6210_priv *wil, __le32 ptr_, u32 size)
 {
        u32 off;
        u32 ptr = le32_to_cpu(ptr_);
@@ -161,10 +163,17 @@ void __iomem *wmi_buffer(struct wil6210_priv *wil, __le32 ptr_)
        off = HOSTADDR(ptr);
        if (off > wil->bar_size - 4)
                return NULL;
+       if (size && ((off + size > wil->bar_size) || (off + size < off)))
+               return NULL;
 
        return wil->csr + off;
 }
 
+void __iomem *wmi_buffer(struct wil6210_priv *wil, __le32 ptr_)
+{
+       return wmi_buffer_block(wil, ptr_, 0);
+}
+
 /**
  * Check address validity
  */