mirror of
https://github.com/Divested-Mobile/DivestOS-Build.git
synced 2024-10-01 01:35:54 -04:00
147 lines
4.8 KiB
Diff
147 lines
4.8 KiB
Diff
From cbf66a616bb08cc6c932e4122f3271df83e253bb Mon Sep 17 00:00:00 2001
|
|
From: Insun Song <insun.song@broadcom.com>
|
|
Date: Tue, 25 Oct 2016 13:33:18 -0700
|
|
Subject: [PATCH] net: wireless: bcmdhd: fix buffer overrun in private command
|
|
path
|
|
|
|
buffer overrun case found when length parameter manipulated.
|
|
|
|
1. if input parameter buffer length is less than 4k,
|
|
then allocate 4k by default. It help to get enough margin
|
|
for output string overwritten.
|
|
|
|
2. added additional length check not to override user space
|
|
allocated buffer size.
|
|
|
|
bug=29000183
|
|
Change-Id: I0c15d764c1648920f0214ec47ada689ca44ebfba
|
|
Signed-off-by: Insun Song <insun.song@broadcom.com>
|
|
---
|
|
drivers/net/wireless/bcmdhd/wl_android.c | 58 ++++++++++++++++++++------------
|
|
1 file changed, 37 insertions(+), 21 deletions(-)
|
|
|
|
diff --git a/drivers/net/wireless/bcmdhd/wl_android.c b/drivers/net/wireless/bcmdhd/wl_android.c
|
|
index c8cae82af2f46..86c56e28f532c 100644
|
|
--- a/drivers/net/wireless/bcmdhd/wl_android.c
|
|
+++ b/drivers/net/wireless/bcmdhd/wl_android.c
|
|
@@ -246,17 +246,22 @@ static int wl_android_get_rssi(struct net_device *net, char *command, int total_
|
|
return -1;
|
|
if ((ssid.SSID_len == 0) || (ssid.SSID_len > DOT11_MAX_SSID_LEN)) {
|
|
DHD_ERROR(("%s: wldev_get_ssid failed\n", __FUNCTION__));
|
|
- } else if (total_len <= ssid.SSID_len) {
|
|
- return -ENOMEM;
|
|
} else {
|
|
- memcpy(command, ssid.SSID, ssid.SSID_len);
|
|
- bytes_written = ssid.SSID_len;
|
|
+ if (total_len > ssid.SSID_len) {
|
|
+ memcpy(command, ssid.SSID, ssid.SSID_len);
|
|
+ bytes_written = ssid.SSID_len;
|
|
+ } else {
|
|
+ return BCME_ERROR;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if ((total_len - bytes_written) >= (strlen(" rssi -XXX") + 1)) {
|
|
+ bytes_written += snprintf(&command[bytes_written], total_len - bytes_written,
|
|
+ " rssi %d", rssi);
|
|
+ command[bytes_written] = '\0';
|
|
+ } else {
|
|
+ return BCME_ERROR;
|
|
}
|
|
- if ((total_len - bytes_written) < (strlen(" rssi -XXX") + 1))
|
|
- return -ENOMEM;
|
|
- bytes_written += scnprintf(&command[bytes_written],
|
|
- total_len - bytes_written, " rssi %d", rssi);
|
|
- command[bytes_written] = '\0';
|
|
|
|
DHD_INFO(("%s: command result is %s (%d)\n", __FUNCTION__, command, bytes_written));
|
|
return bytes_written;
|
|
@@ -1332,13 +1337,17 @@ int wl_android_priv_cmd(struct net_device *net, struct ifreq *ifr, int cmd)
|
|
}
|
|
|
|
if ((priv_cmd.total_len > PRIVATE_COMMAND_MAX_LEN) || (priv_cmd.total_len < 0)) {
|
|
- DHD_ERROR(("%s: buf length invalid:%d\n", __FUNCTION__,
|
|
- priv_cmd.total_len));
|
|
+ DHD_ERROR(("%s: buf length invalid:%d \n", __FUNCTION__, priv_cmd.total_len));
|
|
ret = -EINVAL;
|
|
goto exit;
|
|
}
|
|
|
|
- buf_size = max(priv_cmd.total_len, PRIVATE_COMMAND_DEF_LEN);
|
|
+ if (priv_cmd.total_len < PRIVATE_COMMAND_DEF_LEN) {
|
|
+ buf_size = PRIVATE_COMMAND_DEF_LEN;
|
|
+ } else {
|
|
+ buf_size = priv_cmd.total_len;
|
|
+ }
|
|
+
|
|
command = kmalloc((buf_size + 1), GFP_KERNEL);
|
|
|
|
if (!command)
|
|
@@ -1355,20 +1364,22 @@ int wl_android_priv_cmd(struct net_device *net, struct ifreq *ifr, int cmd)
|
|
|
|
DHD_INFO(("%s: Android private cmd \"%s\" on %s\n", __FUNCTION__, command, ifr->ifr_name));
|
|
|
|
- bytes_written = wl_handle_private_cmd(net, command, priv_cmd.total_len);
|
|
+ bytes_written = wl_handle_private_cmd(net, command, buf_size);
|
|
if (bytes_written >= 0) {
|
|
- if ((bytes_written == 0) && (priv_cmd.total_len > 0))
|
|
+ if ((bytes_written == 0) && (priv_cmd.total_len > 0)) {
|
|
command[0] = '\0';
|
|
+ }
|
|
if (bytes_written >= priv_cmd.total_len) {
|
|
- DHD_ERROR(("%s: err. b_w:%d >= tot:%d\n", __FUNCTION__,
|
|
- bytes_written, priv_cmd.total_len));
|
|
+ DHD_ERROR(("%s: not enough for output. bytes_written:%d >= total_len:%d \n",
|
|
+ __FUNCTION__, bytes_written, priv_cmd.total_len));
|
|
ret = BCME_BUFTOOSHORT;
|
|
goto exit;
|
|
+ } else {
|
|
+ bytes_written++;
|
|
}
|
|
- bytes_written++;
|
|
priv_cmd.used_len = bytes_written;
|
|
if (copy_to_user(priv_cmd.buf, command, bytes_written)) {
|
|
- DHD_ERROR(("%s: failed copy to user\n", __FUNCTION__));
|
|
+ DHD_ERROR(("%s: failed to copy data to user buffer\n", __FUNCTION__));
|
|
ret = -EFAULT;
|
|
}
|
|
} else {
|
|
@@ -1377,13 +1388,17 @@ int wl_android_priv_cmd(struct net_device *net, struct ifreq *ifr, int cmd)
|
|
|
|
exit:
|
|
net_os_wake_unlock(net);
|
|
- kfree(command);
|
|
+ if (command) {
|
|
+ kfree(command);
|
|
+ }
|
|
+
|
|
return ret;
|
|
}
|
|
|
|
int
|
|
wl_handle_private_cmd(struct net_device *net, char *command, u32 buf_size)
|
|
{
|
|
+
|
|
int bytes_written = 0;
|
|
android_wifi_priv_cmd priv_cmd;
|
|
|
|
@@ -1400,7 +1415,7 @@ wl_handle_private_cmd(struct net_device *net, char *command, u32 buf_size)
|
|
|
|
if (!g_wifi_on) {
|
|
DHD_ERROR(("%s: Ignore private cmd \"%s\" - iface is down\n",
|
|
- __FUNCTION__, command));
|
|
+ __FUNCTION__, command));
|
|
return 0;
|
|
}
|
|
|
|
@@ -1558,7 +1573,8 @@ wl_handle_private_cmd(struct net_device *net, char *command, u32 buf_size)
|
|
}
|
|
else {
|
|
DHD_ERROR(("Unknown PRIVATE command %s - ignored\n", command));
|
|
- bytes_written = scnprintf(command, sizeof("FAIL"), "FAIL");
|
|
+ snprintf(command, 5, "FAIL");
|
|
+ bytes_written = strlen("FAIL");
|
|
}
|
|
|
|
return bytes_written;
|