diff options
author | Dmitry Shmidt <dimitrysh@google.com> | 2011-07-29 13:45:06 -0700 |
---|---|---|
committer | Dmitry Shmidt <dimitrysh@google.com> | 2011-07-29 16:05:32 -0700 |
commit | 5fd537ad96aec7b0a2e2f3e19046dcfebf6ab689 (patch) | |
tree | 0fc57efea80a970c09617996e3c09d66d52031c2 /drivers/net | |
parent | 3eb50e2dd03feebcd3a66eb7601f2af328b7bd9c (diff) | |
download | kernel_samsung_crespo-5fd537ad96aec7b0a2e2f3e19046dcfebf6ab689.zip kernel_samsung_crespo-5fd537ad96aec7b0a2e2f3e19046dcfebf6ab689.tar.gz kernel_samsung_crespo-5fd537ad96aec7b0a2e2f3e19046dcfebf6ab689.tar.bz2 |
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>
Diffstat (limited to 'drivers/net')
-rw-r--r-- | drivers/net/wireless/bcmdhd/wl_android.c | 54 |
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 8314bbc..830dbe5 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; } |