Merge "wil6210: missing length check in wil_cfg80211_mgmt_tx"
This commit is contained in:
commit
f1091db4f4
5 changed files with 85 additions and 27 deletions
|
@ -977,7 +977,7 @@ int wil_cfg80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
|
||||||
u64 *cookie)
|
u64 *cookie)
|
||||||
{
|
{
|
||||||
const u8 *buf = params->buf;
|
const u8 *buf = params->buf;
|
||||||
size_t len = params->len;
|
size_t len = params->len, total;
|
||||||
struct wil6210_priv *wil = wiphy_to_wil(wiphy);
|
struct wil6210_priv *wil = wiphy_to_wil(wiphy);
|
||||||
int rc;
|
int rc;
|
||||||
bool tx_status = false;
|
bool tx_status = false;
|
||||||
|
@ -1002,7 +1002,11 @@ int wil_cfg80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
|
||||||
if (len < sizeof(struct ieee80211_hdr_3addr))
|
if (len < sizeof(struct ieee80211_hdr_3addr))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
cmd = kmalloc(sizeof(*cmd) + len, GFP_KERNEL);
|
total = sizeof(*cmd) + len;
|
||||||
|
if (total < len)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
cmd = kmalloc(total, GFP_KERNEL);
|
||||||
if (!cmd) {
|
if (!cmd) {
|
||||||
rc = -ENOMEM;
|
rc = -ENOMEM;
|
||||||
goto out;
|
goto out;
|
||||||
|
@ -1012,7 +1016,7 @@ int wil_cfg80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
|
||||||
cmd->len = cpu_to_le16(len);
|
cmd->len = cpu_to_le16(len);
|
||||||
memcpy(cmd->payload, buf, len);
|
memcpy(cmd->payload, buf, len);
|
||||||
|
|
||||||
rc = wmi_call(wil, WMI_SW_TX_REQ_CMDID, cmd, sizeof(*cmd) + len,
|
rc = wmi_call(wil, WMI_SW_TX_REQ_CMDID, cmd, total,
|
||||||
WMI_SW_TX_COMPLETE_EVENTID, &evt, sizeof(evt), 2000);
|
WMI_SW_TX_COMPLETE_EVENTID, &evt, sizeof(evt), 2000);
|
||||||
if (rc == 0)
|
if (rc == 0)
|
||||||
tx_status = !evt.evt.status;
|
tx_status = !evt.evt.status;
|
||||||
|
|
|
@ -26,14 +26,17 @@
|
||||||
prefix_type, rowsize, \
|
prefix_type, rowsize, \
|
||||||
groupsize, buf, len, ascii)
|
groupsize, buf, len, ascii)
|
||||||
|
|
||||||
#define FW_ADDR_CHECK(ioaddr, val, msg) do { \
|
static bool wil_fw_addr_check(struct wil6210_priv *wil,
|
||||||
ioaddr = wmi_buffer(wil, val); \
|
void __iomem **ioaddr, __le32 val,
|
||||||
if (!ioaddr) { \
|
u32 size, const char *msg)
|
||||||
wil_err_fw(wil, "bad " msg ": 0x%08x\n", \
|
{
|
||||||
le32_to_cpu(val)); \
|
*ioaddr = wmi_buffer_block(wil, val, size);
|
||||||
return -EINVAL; \
|
if (!(*ioaddr)) {
|
||||||
} \
|
wil_err_fw(wil, "bad %s: 0x%08x\n", msg, le32_to_cpu(val));
|
||||||
} while (0)
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* wil_fw_verify - verify firmware file validity
|
* wil_fw_verify - verify firmware file validity
|
||||||
|
@ -160,7 +163,8 @@ static int fw_handle_data(struct wil6210_priv *wil, const void *data,
|
||||||
return -EINVAL;
|
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),
|
wil_dbg_fw(wil, "write [0x%08x] <== %zu bytes\n", le32_to_cpu(d->addr),
|
||||||
s);
|
s);
|
||||||
wil_memcpy_toio_32(dst, d->data, s);
|
wil_memcpy_toio_32(dst, d->data, s);
|
||||||
|
@ -192,7 +196,8 @@ static int fw_handle_fill(struct wil6210_priv *wil, const void *data,
|
||||||
return -EINVAL;
|
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);
|
v = le32_to_cpu(d->value);
|
||||||
wil_dbg_fw(wil, "fill [0x%08x] <== 0x%08x, %zu bytes\n",
|
wil_dbg_fw(wil, "fill [0x%08x] <== 0x%08x, %zu bytes\n",
|
||||||
|
@ -248,7 +253,8 @@ static int fw_handle_direct_write(struct wil6210_priv *wil, const void *data,
|
||||||
u32 v = le32_to_cpu(block[i].value);
|
u32 v = le32_to_cpu(block[i].value);
|
||||||
u32 x, y;
|
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);
|
x = readl(dst);
|
||||||
y = (x & m) | (v & ~m);
|
y = (x & m) | (v & ~m);
|
||||||
|
@ -314,10 +320,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",
|
wil_dbg_fw(wil, "gw write record [%3d] blocks, cmd 0x%08x\n",
|
||||||
n, gw_cmd);
|
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,
|
||||||
FW_ADDR_CHECK(gwa_val, d->gateway_value_addr, "gateway_value_addr");
|
"gateway_addr_addr") ||
|
||||||
FW_ADDR_CHECK(gwa_cmd, d->gateway_cmd_addr, "gateway_cmd_addr");
|
!wil_fw_addr_check(wil, &gwa_val, d->gateway_value_addr, 0,
|
||||||
FW_ADDR_CHECK(gwa_ctl, d->gateway_ctrl_address, "gateway_ctrl_address");
|
"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"
|
wil_dbg_fw(wil, "gw addresses: addr 0x%08x val 0x%08x"
|
||||||
" cmd 0x%08x ctl 0x%08x\n",
|
" cmd 0x%08x ctl 0x%08x\n",
|
||||||
|
@ -373,12 +384,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",
|
wil_dbg_fw(wil, "gw4 write record [%3d] blocks, cmd 0x%08x\n",
|
||||||
n, gw_cmd);
|
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++)
|
for (k = 0; k < ARRAY_SIZE(block->value); k++)
|
||||||
FW_ADDR_CHECK(gwa_val[k], d->gateway_value_addr[k],
|
if (!wil_fw_addr_check(wil, &gwa_val[k],
|
||||||
"gateway_value_addr");
|
d->gateway_value_addr[k],
|
||||||
FW_ADDR_CHECK(gwa_cmd, d->gateway_cmd_addr, "gateway_cmd_addr");
|
0, "gateway_value_addr"))
|
||||||
FW_ADDR_CHECK(gwa_ctl, d->gateway_ctrl_address, "gateway_ctrl_address");
|
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",
|
wil_dbg_fw(wil, "gw4 addresses: addr 0x%08x cmd 0x%08x ctl 0x%08x\n",
|
||||||
le32_to_cpu(d->gateway_addr_addr),
|
le32_to_cpu(d->gateway_addr_addr),
|
||||||
|
|
|
@ -358,6 +358,25 @@ static void wil_cache_mbox_regs(struct wil6210_priv *wil)
|
||||||
wil_mbox_ring_le2cpus(&wil->mbox_ctl.tx);
|
wil_mbox_ring_le2cpus(&wil->mbox_ctl.tx);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool wil_validate_mbox_regs(struct wil6210_priv *wil)
|
||||||
|
{
|
||||||
|
size_t min_size = sizeof(struct wil6210_mbox_hdr) +
|
||||||
|
sizeof(struct wmi_cmd_hdr);
|
||||||
|
|
||||||
|
if (wil->mbox_ctl.rx.entry_size < min_size) {
|
||||||
|
wil_err(wil, "rx mbox entry too small (%d)\n",
|
||||||
|
wil->mbox_ctl.rx.entry_size);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (wil->mbox_ctl.tx.entry_size < min_size) {
|
||||||
|
wil_err(wil, "tx mbox entry too small (%d)\n",
|
||||||
|
wil->mbox_ctl.tx.entry_size);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
static irqreturn_t wil6210_irq_misc(int irq, void *cookie)
|
static irqreturn_t wil6210_irq_misc(int irq, void *cookie)
|
||||||
{
|
{
|
||||||
struct wil6210_priv *wil = cookie;
|
struct wil6210_priv *wil = cookie;
|
||||||
|
@ -393,7 +412,8 @@ static irqreturn_t wil6210_irq_misc(int irq, void *cookie)
|
||||||
if (isr & ISR_MISC_FW_READY) {
|
if (isr & ISR_MISC_FW_READY) {
|
||||||
wil_dbg_irq(wil, "IRQ: FW ready\n");
|
wil_dbg_irq(wil, "IRQ: FW ready\n");
|
||||||
wil_cache_mbox_regs(wil);
|
wil_cache_mbox_regs(wil);
|
||||||
set_bit(wil_status_mbox_ready, wil->status);
|
if (wil_validate_mbox_regs(wil))
|
||||||
|
set_bit(wil_status_mbox_ready, wil->status);
|
||||||
/**
|
/**
|
||||||
* Actual FW ready indicated by the
|
* Actual FW ready indicated by the
|
||||||
* WMI_FW_READY_EVENTID
|
* WMI_FW_READY_EVENTID
|
||||||
|
|
|
@ -878,6 +878,7 @@ void wil_mbox_ring_le2cpus(struct wil6210_mbox_ring *r);
|
||||||
int wil_find_cid(struct wil6210_priv *wil, const u8 *mac);
|
int wil_find_cid(struct wil6210_priv *wil, const u8 *mac);
|
||||||
void wil_set_ethtoolops(struct net_device *ndev);
|
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_buffer(struct wil6210_priv *wil, __le32 ptr);
|
||||||
void __iomem *wmi_addr(struct wil6210_priv *wil, u32 ptr);
|
void __iomem *wmi_addr(struct wil6210_priv *wil, u32 ptr);
|
||||||
int wmi_read_hdr(struct wil6210_priv *wil, __le32 ptr,
|
int wmi_read_hdr(struct wil6210_priv *wil, __le32 ptr,
|
||||||
|
|
|
@ -141,13 +141,15 @@ static u32 wmi_addr_remap(u32 x)
|
||||||
/**
|
/**
|
||||||
* Check address validity for WMI buffer; remap if needed
|
* Check address validity for WMI buffer; remap if needed
|
||||||
* @ptr - internal (linker) fw/ucode address
|
* @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
|
* Valid buffer should be DWORD aligned
|
||||||
*
|
*
|
||||||
* return address for accessing buffer from the host;
|
* return address for accessing buffer from the host;
|
||||||
* if buffer is not valid, return NULL.
|
* 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 off;
|
||||||
u32 ptr = le32_to_cpu(ptr_);
|
u32 ptr = le32_to_cpu(ptr_);
|
||||||
|
@ -162,10 +164,17 @@ void __iomem *wmi_buffer(struct wil6210_priv *wil, __le32 ptr_)
|
||||||
off = HOSTADDR(ptr);
|
off = HOSTADDR(ptr);
|
||||||
if (off > wil->bar_size - 4)
|
if (off > wil->bar_size - 4)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
if (size && ((off + size > wil->bar_size) || (off + size < off)))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
return wil->csr + off;
|
return wil->csr + off;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void __iomem *wmi_buffer(struct wil6210_priv *wil, __le32 ptr_)
|
||||||
|
{
|
||||||
|
return wmi_buffer_block(wil, ptr_, 0);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check address validity
|
* Check address validity
|
||||||
*/
|
*/
|
||||||
|
@ -223,7 +232,7 @@ static int __wmi_send(struct wil6210_priv *wil, u16 cmdid, void *buf, u16 len)
|
||||||
uint retry;
|
uint retry;
|
||||||
int rc = 0;
|
int rc = 0;
|
||||||
|
|
||||||
if (sizeof(cmd) + len > r->entry_size) {
|
if (len > r->entry_size - sizeof(cmd)) {
|
||||||
wil_err(wil, "WMI size too large: %d bytes, max is %d\n",
|
wil_err(wil, "WMI size too large: %d bytes, max is %d\n",
|
||||||
(int)(sizeof(cmd) + len), r->entry_size);
|
(int)(sizeof(cmd) + len), r->entry_size);
|
||||||
return -ERANGE;
|
return -ERANGE;
|
||||||
|
@ -1411,8 +1420,14 @@ int wmi_set_ie(struct wil6210_priv *wil, u8 type, u16 ie_len, const void *ie)
|
||||||
};
|
};
|
||||||
int rc;
|
int rc;
|
||||||
u16 len = sizeof(struct wmi_set_appie_cmd) + ie_len;
|
u16 len = sizeof(struct wmi_set_appie_cmd) + ie_len;
|
||||||
struct wmi_set_appie_cmd *cmd = kzalloc(len, GFP_KERNEL);
|
struct wmi_set_appie_cmd *cmd;
|
||||||
|
|
||||||
|
if (len < ie_len) {
|
||||||
|
rc = -EINVAL;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd = kzalloc(len, GFP_KERNEL);
|
||||||
if (!cmd) {
|
if (!cmd) {
|
||||||
rc = -ENOMEM;
|
rc = -ENOMEM;
|
||||||
goto out;
|
goto out;
|
||||||
|
|
Loading…
Add table
Reference in a new issue