summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDmitry Shmidt <dimitrysh@google.com>2011-07-29 13:45:06 -0700
committerJonas ABERG <jonas.aberg@stericsson.com>2011-10-28 11:00:47 +0200
commit1e283dad3b0374419c171ed52b37e27738e5d3d5 (patch)
tree91690c789092e4253939e0f36aba3c68a0cc3996
parent2f46d250515ba6960b734046af4a89b7197768be (diff)
net: wireless: bcmdhd: Fix memory corruption in wl_android_get_rssi()
In case of FW problem wldev_get_ssid() doesn't return error and ssid structure has garbage. Signed-off-by: Dmitry Shmidt <dimitrysh@google.com> Change-Id: I8d84a9b1ed1a0e423131a24da563151cd930a154 Reviewed-on: http://gerrit.lud.stericsson.com/gerrit/35562 Tested-by: Per VAHLNE <per.xx.vahlne@stericsson.com> Reviewed-by: Jonas ABERG <jonas.aberg@stericsson.com>
-rw-r--r--drivers/net/wireless/bcmdhd/wl_android.c54
1 files changed, 32 insertions, 22 deletions
diff --git a/drivers/net/wireless/bcmdhd/wl_android.c b/drivers/net/wireless/bcmdhd/wl_android.c
index 8314bbc5f44..830dbe5f2a4 100644
--- a/drivers/net/wireless/bcmdhd/wl_android.c
+++ b/drivers/net/wireless/bcmdhd/wl_android.c
@@ -149,22 +149,25 @@ static int wl_android_get_link_speed(struct net_device *net, char *command, int
static int wl_android_get_rssi(struct net_device *net, char *command, int total_len)
{
- wlc_ssid_t ssid;
+ wlc_ssid_t ssid = {0};
int rssi;
- int bytes_written;
+ int bytes_written = 0;
int error;
error = wldev_get_rssi(net, &rssi);
if (error)
return -1;
-
error = wldev_get_ssid(net, &ssid);
if (error)
return -1;
- memcpy(command, ssid.SSID, ssid.SSID_len);
- bytes_written = ssid.SSID_len;
+ if ((ssid.SSID_len == 0) || (ssid.SSID_len > DOT11_MAX_SSID_LEN)) {
+ DHD_ERROR(("%s: wldev_get_ssid failed\n", __FUNCTION__));
+ } else {
+ memcpy(command, ssid.SSID, ssid.SSID_len);
+ bytes_written = ssid.SSID_len;
+ }
bytes_written += snprintf(&command[bytes_written], total_len, " rssi %d", rssi);
- DHD_INFO(("%s: command result is %s \n", __FUNCTION__, command));
+ DHD_INFO(("%s: command result is %s (%d)\n", __FUNCTION__, command, bytes_written));
return bytes_written;
}
@@ -367,24 +370,26 @@ int wl_android_priv_cmd(struct net_device *net, struct ifreq *ifr, int cmd)
int ret = 0;
char *command = NULL;
int bytes_written = 0;
- android_wifi_priv_cmd *priv_cmd;
+ android_wifi_priv_cmd priv_cmd;
net_os_wake_lock(net);
- priv_cmd = (android_wifi_priv_cmd*)ifr->ifr_data;
- if (!priv_cmd)
- {
+ if (!ifr->ifr_data) {
ret = -EINVAL;
goto exit;
}
- command = kmalloc(priv_cmd->total_len, GFP_KERNEL);
+ if (copy_from_user(&priv_cmd, ifr->ifr_data, sizeof(android_wifi_priv_cmd))) {
+ ret = -EFAULT;
+ goto exit;
+ }
+ command = kmalloc(priv_cmd.total_len, GFP_KERNEL);
if (!command)
{
DHD_ERROR(("%s: failed to allocate memory\n", __FUNCTION__));
ret = -ENOMEM;
goto exit;
}
- if (copy_from_user(command, priv_cmd->buf, priv_cmd->total_len)) {
+ if (copy_from_user(command, priv_cmd.buf, priv_cmd.total_len)) {
ret = -EFAULT;
goto exit;
}
@@ -396,7 +401,7 @@ int wl_android_priv_cmd(struct net_device *net, struct ifreq *ifr, int cmd)
bytes_written = wl_android_wifi_on(net);
}
else if (strnicmp(command, CMD_SETFWPATH, strlen(CMD_SETFWPATH)) == 0) {
- bytes_written = wl_android_set_fwpath(net, command, priv_cmd->total_len);
+ bytes_written = wl_android_set_fwpath(net, command, priv_cmd.total_len);
}
if (!g_wifi_on) {
@@ -416,10 +421,10 @@ int wl_android_priv_cmd(struct net_device *net, struct ifreq *ifr, int cmd)
/* TBD: SCAN-PASSIVE */
}
else if (strnicmp(command, CMD_RSSI, strlen(CMD_RSSI)) == 0) {
- bytes_written = wl_android_get_rssi(net, command, priv_cmd->total_len);
+ bytes_written = wl_android_get_rssi(net, command, priv_cmd.total_len);
}
else if (strnicmp(command, CMD_LINKSPEED, strlen(CMD_LINKSPEED)) == 0) {
- bytes_written = wl_android_get_link_speed(net, command, priv_cmd->total_len);
+ bytes_written = wl_android_get_link_speed(net, command, priv_cmd.total_len);
}
else if (strnicmp(command, CMD_RXFILTER_START, strlen(CMD_RXFILTER_START)) == 0) {
bytes_written = net_os_set_packet_filter(net, 1);
@@ -445,14 +450,14 @@ int wl_android_priv_cmd(struct net_device *net, struct ifreq *ifr, int cmd)
/* TBD: BTCOEXMODE */
}
else if (strnicmp(command, CMD_SETSUSPENDOPT, strlen(CMD_SETSUSPENDOPT)) == 0) {
- bytes_written = wl_android_set_suspendopt(net, command, priv_cmd->total_len);
+ bytes_written = wl_android_set_suspendopt(net, command, priv_cmd.total_len);
}
else if (strnicmp(command, CMD_SETBAND, strlen(CMD_SETBAND)) == 0) {
uint band = *(command + strlen(CMD_SETBAND) + 1) - '0';
bytes_written = wldev_set_band(net, band);
}
else if (strnicmp(command, CMD_GETBAND, strlen(CMD_GETBAND)) == 0) {
- bytes_written = wl_android_get_band(net, command, priv_cmd->total_len);
+ bytes_written = wl_android_get_band(net, command, priv_cmd.total_len);
}
else if (strnicmp(command, CMD_COUNTRY, strlen(CMD_COUNTRY)) == 0) {
char *country_code = command + strlen(CMD_COUNTRY) + 1;
@@ -463,7 +468,7 @@ int wl_android_priv_cmd(struct net_device *net, struct ifreq *ifr, int cmd)
bytes_written = dhd_dev_pno_reset(net);
}
else if (strnicmp(command, CMD_PNOSETUP_SET, strlen(CMD_PNOSETUP_SET)) == 0) {
- bytes_written = wl_android_set_pno_setup(net, command, priv_cmd->total_len);
+ bytes_written = wl_android_set_pno_setup(net, command, priv_cmd.total_len);
}
else if (strnicmp(command, CMD_PNOENABLE_SET, strlen(CMD_PNOENABLE_SET)) == 0) {
uint pfn_enabled = *(command + strlen(CMD_PNOENABLE_SET) + 1) - '0';
@@ -471,7 +476,7 @@ int wl_android_priv_cmd(struct net_device *net, struct ifreq *ifr, int cmd)
}
#endif
else if (strnicmp(command, CMD_P2P_DEV_ADDR, strlen(CMD_P2P_DEV_ADDR)) == 0) {
- bytes_written = wl_android_get_p2p_dev_addr(net, command, priv_cmd->total_len);
+ bytes_written = wl_android_get_p2p_dev_addr(net, command, priv_cmd.total_len);
} else {
DHD_ERROR(("Unknown PRIVATE command %s - ignored\n", command));
snprintf(command, 3, "OK");
@@ -479,9 +484,14 @@ int wl_android_priv_cmd(struct net_device *net, struct ifreq *ifr, int cmd)
}
if (bytes_written > 0) {
- bytes_written++;
- priv_cmd->used_len = bytes_written;
- if (copy_to_user(priv_cmd->buf, command, bytes_written)) {
+ if (bytes_written > priv_cmd.total_len) {
+ DHD_ERROR(("%s: bytes_written = %d\n", __FUNCTION__, bytes_written));
+ bytes_written = priv_cmd.total_len;
+ } else {
+ bytes_written++;
+ }
+ priv_cmd.used_len = bytes_written;
+ if (copy_to_user(priv_cmd.buf, command, bytes_written)) {
DHD_ERROR(("%s: failed to copy data to user buffer\n", __FUNCTION__));
ret = -EFAULT;
}