From 068427b76963929b220a4be40cdf77856374df55 Mon Sep 17 00:00:00 2001 From: Sudhir Kohalli 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 --- 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)) {