From 6310c77b2325481fa131fb02c93bfeb57298e3c2 Mon Sep 17 00:00:00 2001 From: Hanumanth Reddy Pothula Date: Mon, 16 Jan 2017 14:19:21 +0530 Subject: [PATCH] qcacld-3.0: Process pno ioctl appropriately propagation from qcacld-2.0 to qcacld-3.0. While processing setpno ioctl, input arguments are not validated and also while parsing arguments, there is a possibility of Host accessing memory beyond memory allocated as there is no check whether is Host is accessing valid memory or not. Validate input arguments and make sure Host won't access invalid memory, while processing setpno ioctl. Change-Id: Ica9ea56283d55282cff3ccd349e4bc1c08b80e70 CRs-Fixed: 1097868 --- core/hdd/src/wlan_hdd_cfg80211.c | 2 -- core/hdd/src/wlan_hdd_cfg80211.h | 3 ++ core/hdd/src/wlan_hdd_wext.c | 50 +++++++++++++++++++++++++------- 3 files changed, 42 insertions(+), 13 deletions(-) diff --git a/core/hdd/src/wlan_hdd_cfg80211.c b/core/hdd/src/wlan_hdd_cfg80211.c index 22761531e1be..10698923b38b 100644 --- a/core/hdd/src/wlan_hdd_cfg80211.c +++ b/core/hdd/src/wlan_hdd_cfg80211.c @@ -199,8 +199,6 @@ #define IS_DFS_MODE_VALID(mode) ((mode >= DFS_MODE_NONE && \ mode <= DFS_MODE_DEPRIORITIZE)) -#define IS_CHANNEL_VALID(channel) ((channel >= 0 && channel < 15) \ - || (channel >= 36 && channel <= 184)) #define MAX_TXPOWER_SCALE 4 #define CDS_MAX_FEATURE_SET 8 diff --git a/core/hdd/src/wlan_hdd_cfg80211.h b/core/hdd/src/wlan_hdd_cfg80211.h index 3bc3667dd5de..afd83352d2b8 100644 --- a/core/hdd/src/wlan_hdd_cfg80211.h +++ b/core/hdd/src/wlan_hdd_cfg80211.h @@ -108,6 +108,9 @@ static inline void wlan_hdd_clear_link_layer_stats(hdd_adapter_t *adapter) {} #define MAX_CHANNEL (NUM_24GHZ_CHANNELS + NUM_5GHZ_CHANNELS) #define MAX_SCAN_SSID 10 +#define IS_CHANNEL_VALID(channel) ((channel >= 0 && channel < 15) \ + || (channel >= 36 && channel <= 184)) + #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 12, 0)) \ || defined(BACKPORTED_CHANNEL_SWITCH_PRESENT) #define CHANNEL_SWITCH_SUPPORTED diff --git a/core/hdd/src/wlan_hdd_wext.c b/core/hdd/src/wlan_hdd_wext.c index eb6e24a2eedd..7dc7b45b5033 100644 --- a/core/hdd/src/wlan_hdd_wext.c +++ b/core/hdd/src/wlan_hdd_wext.c @@ -12152,9 +12152,10 @@ static int __iw_set_pno(struct net_device *dev, struct wlan_objmgr_psoc *psoc; int ret = 0; int offset; - char *ptr; + char *ptr, *data; uint8_t i, j, params; QDF_STATUS status; + size_t len; /* request is a large struct, so we make it static to avoid * stack overflow. This API is only invoked via ioctl, so it @@ -12183,9 +12184,18 @@ static int __iw_set_pno(struct net_device *dev, hdd_debug("PNO data len %d data %s", wrqu->data.length, extra); - ptr = extra; + /* making sure argument string ends with '\0' */ + len = (wrqu->data.length + 1); + data = qdf_mem_malloc(len); + if (!data) { + hdd_err("fail to allocate memory %zu", len); + return -EINVAL; + } + qdf_mem_copy(data, extra, (len-1)); + data[len] = '\0'; + ptr = data; - if (1 != sscanf(ptr, "%hhu%n", &value, &offset)) { + if (1 != sscanf(ptr, " %hhu %n", &value, &offset)) { hdd_err("PNO enable input is not valid %s", ptr); ret = -EINVAL; goto exit; @@ -12210,7 +12220,7 @@ static int __iw_set_pno(struct net_device *dev, ptr += offset; - if (1 != sscanf(ptr, "%hhu %n", &value, &offset)) { + if (1 != sscanf(ptr, " %hhu %n", &value, &offset)) { hdd_err("PNO count input not valid %s", ptr); ret = -EINVAL; goto exit; @@ -12234,7 +12244,7 @@ static int __iw_set_pno(struct net_device *dev, req.networks_list[i].ssid.length = 0; - params = sscanf(ptr, "%hhu %n", + params = sscanf(ptr, " %hhu %n", &(req.networks_list[i].ssid.length), &offset); @@ -12259,7 +12269,7 @@ static int __iw_set_pno(struct net_device *dev, req.networks_list[i].ssid.length); ptr += req.networks_list[i].ssid.length; - params = sscanf(ptr, "%u %u %hhu %n", + params = sscanf(ptr, " %u %u %hhu %n", &(req.networks_list[i].authentication), &(req.networks_list[i].encryption), &(req.networks_list[i].channel_cnt), @@ -12292,13 +12302,18 @@ static int __iw_set_pno(struct net_device *dev, if (0 != req.networks_list[i].channel_cnt) { for (j = 0; j < req.networks_list[i].channel_cnt; j++) { - if (1 != sscanf(ptr, "%hhu %n", &value, + if (1 != sscanf(ptr, " %hhu %n", &value, &offset)) { hdd_err("PNO network channel is not valid %s", ptr); ret = -EINVAL; goto exit; } + if (!IS_CHANNEL_VALID(value)) { + hdd_err("invalid channel: %hhu", value); + ret = -EINVAL; + goto exit; + } req.networks_list[i].channels[j] = cds_chan_to_freq(value); /* Advance to next channel number */ @@ -12306,7 +12321,7 @@ static int __iw_set_pno(struct net_device *dev, } } - if (1 != sscanf(ptr, "%u %n", + if (1 != sscanf(ptr, " %u %n", &(req.networks_list[i].bc_new_type), &offset)) { hdd_err("PNO broadcast network type is not valid %s", @@ -12314,13 +12329,19 @@ static int __iw_set_pno(struct net_device *dev, ret = -EINVAL; goto exit; } + if (req.networks_list[i].bc_new_type > 2) { + hdd_err("invalid bcast nw type: %u", + req.networks_list[i].bc_new_type); + ret = -EINVAL; + goto exit; + } hdd_debug("PNO bcastNetwType %d offset %d", req.networks_list[i].bc_new_type, offset); /* Advance to rssi Threshold */ ptr += offset; - if (1 != sscanf(ptr, "%d %n", + if (1 != sscanf(ptr, " %d %n", &(req.networks_list[i].rssi_thresh), &offset)) { hdd_err("PNO rssi threshold input is not valid %s", @@ -12335,13 +12356,19 @@ static int __iw_set_pno(struct net_device *dev, } /* For ucNetworkCount */ req.fast_scan_period = 0; - if (sscanf(ptr, "%u %n", &(req.fast_scan_period), &offset) > 0) { + if (sscanf(ptr, " %u %n", &(req.fast_scan_period), &offset) > 0) { req.fast_scan_period *= MSEC_PER_SEC; ptr += offset; } + if (req.fast_scan_period == 0) { + hdd_err("invalid fast scan period %u", + req.fast_scan_period); + ret = -EINVAL; + goto exit; + } req.fast_scan_max_cycles = 0; - if (sscanf(ptr, "%hhu %n", &value, + if (sscanf(ptr, " %hhu %n", &value, &offset) > 0) ptr += offset; req.fast_scan_max_cycles = value; @@ -12362,6 +12389,7 @@ static int __iw_set_pno(struct net_device *dev, exit: wlan_objmgr_vdev_release_ref(vdev, WLAN_LEGACY_MAC_ID); + qdf_mem_free(data); return ret; }