DivestOS/Patches/Linux_CVEs/CVE-2016-8464/3.10/0001.patch
2017-11-07 17:32:46 -05:00

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;