DivestOS/Patches/Linux_CVEs/CVE-2016-8455/ANY/0.patch

121 lines
4.2 KiB
Diff
Raw Normal View History

From 068427b76963929b220a4be40cdf77856374df55 Mon Sep 17 00:00:00 2001
From: Sudhir Kohalli <sudhir.kohalli@broadcom.com>
Date: Fri, 4 Nov 2016 12:09:19 -0700
Subject: [PATCH] net: wireless: bcmdhd: Security V: memory overflow in wifi
driver function __dhd_apf_add_filter
In order to fix the memory overflow added a check
for APF program_len to verify if the program_len is
more than the MAX program length. If the APF program_len
is more than the MAX APF program_len then parse an error.
This check will avoid memory oveflow issue happening
in __dhd_apf_add_filter API. APF referes to Android Packet
filter.
Bug: 32219121
Change-Id: Ibe468dcb51ec4f35c64da4bdc7296130bf145f13
Signed-off-by: Sudhir Kohalli <sudhir.kohalli@broadcom.com>
---
drivers/net/wireless/bcmdhd/dhd_linux.c | 13 ++++++++++-
drivers/net/wireless/bcmdhd/include/wlioctl.h | 2 ++
drivers/net/wireless/bcmdhd/wl_cfgvendor.c | 31 +++++++++++++++++++++++++--
3 files changed, 43 insertions(+), 3 deletions(-)
diff --git a/drivers/net/wireless/bcmdhd/dhd_linux.c b/drivers/net/wireless/bcmdhd/dhd_linux.c
index 4ce5a2f4663d3..2fd2934a7e851 100644
--- a/drivers/net/wireless/bcmdhd/dhd_linux.c
+++ b/drivers/net/wireless/bcmdhd/dhd_linux.c
@@ -9039,13 +9039,24 @@ __dhd_apf_add_filter(struct net_device *ndev, uint32 filter_id,
}
cmd_len = sizeof(cmd);
+
+ /* Check if the program_len is more than the expected len
+ * and if program is initialized to NULL return here.
+ */
+ if ((program_len > WL_APF_PROGRAM_MAX_SIZE) ||
+ (program == NULL)) {
+ DHD_ERROR(("%s Invalid program_len: %d, program: %pK\n",
+ __func__, program_len, program));
+ return -EINVAL;
+ }
buf_len = cmd_len + WL_PKT_FILTER_FIXED_LEN +
WL_APF_PROGRAM_FIXED_LEN + program_len;
kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL;
buf = kzalloc(buf_len, kflags);
if (unlikely(!buf)) {
- DHD_ERROR(("%s: MALLOC failure, %d bytes\n", __FUNCTION__, buf_len));
+ DHD_ERROR(("%s: MALLOC failure, %d bytes\n", __func__,
+ buf_len));
return -ENOMEM;
}
diff --git a/drivers/net/wireless/bcmdhd/include/wlioctl.h b/drivers/net/wireless/bcmdhd/include/wlioctl.h
index 50de89bc5a9c6..808a0bfc3e108 100644
--- a/drivers/net/wireless/bcmdhd/include/wlioctl.h
+++ b/drivers/net/wireless/bcmdhd/include/wlioctl.h
@@ -3291,6 +3291,8 @@ typedef struct wl_tcp_keep_set {
OFFSETOF(wl_pkt_filter_pattern_listel_t, mask_and_data)
#define WL_APF_INTERNAL_VERSION 1
+/* This will be MAX allowable APF program size */
+#define WL_APF_PROGRAM_MAX_SIZE (2 * 1024)
#define WL_APF_PROGRAM_FIXED_LEN OFFSETOF(wl_apf_program_t, instrs)
#define WL_APF_PROGRAM_LEN(apf_program) \
(apf_program->instr_len * sizeof(apf_program->instrs[0]))
diff --git a/drivers/net/wireless/bcmdhd/wl_cfgvendor.c b/drivers/net/wireless/bcmdhd/wl_cfgvendor.c
index d578026885619..5be16a72aa43f 100644
--- a/drivers/net/wireless/bcmdhd/wl_cfgvendor.c
+++ b/drivers/net/wireless/bcmdhd/wl_cfgvendor.c
@@ -2722,12 +2722,33 @@ wl_cfgvendor_apf_set_filter(struct wiphy *wiphy,
int ret, tmp, type;
gfp_t kflags;
- /* assumption: length attribute must come first */
+ if (len <= 0) {
+ WL_ERR((" Invalid len : %d\n", len));
+ ret = -EINVAL;
+ goto exit;
+ }
nla_for_each_attr(iter, data, len, tmp) {
type = nla_type(iter);
switch (type) {
case APF_ATTRIBUTE_PROGRAM_LEN:
- program_len = nla_get_u32(iter);
+ /* check if the iter is valid and program
+ * length is not already initialized.
+ */
+ if (nla_len(iter) == sizeof(uint32) &&
+ !program_len) {
+ program_len = nla_get_u32(iter);
+ } else {
+ ret = -EINVAL;
+ goto exit;
+ }
+
+ if (program_len >
+ WL_APF_PROGRAM_MAX_SIZE) {
+ WL_ERR(("program len is more "));
+ WL_ERR(("than expected len\n"));
+ ret = -EINVAL;
+ goto exit;
+ }
if (unlikely(!program_len)) {
WL_ERR(("zero program length\n"));
ret = -EINVAL;
@@ -2740,6 +2761,12 @@ wl_cfgvendor_apf_set_filter(struct wiphy *wiphy,
ret = -EINVAL;
goto exit;
}
+ if (nla_len(iter) != program_len) {
+ WL_ERR(("program_len is not same\n"));
+ ret = -EINVAL;
+ goto exit;
+ }
+
kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL;
program = kzalloc(program_len, kflags);
if (unlikely(!program)) {