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

285 lines
10 KiB
Diff

From 0273cba64b0436d481e09222a631a6acc274b96c Mon Sep 17 00:00:00 2001
From: Arif Hussain <c_arifh@qca.qualcomm.com>
Date: Tue, 7 Jan 2014 20:58:29 -0800
Subject: wlan: Fix ioctl copy issue
Few IOCTL's SET command's uses ODD number,
so we cannot utilize kernel facility "extra".
We need to copy the user data in kernel buffer
using copy_from_user function.
Change-Id: I550bf90fbbacb9d5ac4187ed423fca90fafccad1
CRs-Fixed: 596898
---
CORE/HDD/src/wlan_hdd_wext.c | 146 +++++++++++++++++++++++++++++++++++++------
1 file changed, 127 insertions(+), 19 deletions(-)
(limited to 'CORE/HDD/src/wlan_hdd_wext.c')
diff --git a/CORE/HDD/src/wlan_hdd_wext.c b/CORE/HDD/src/wlan_hdd_wext.c
index 55b2100..90df277 100644
--- a/CORE/HDD/src/wlan_hdd_wext.c
+++ b/CORE/HDD/src/wlan_hdd_wext.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2012-2014, The Linux Foundation. All rights reserved.
*
* Previously licensed under the ISC license by Qualcomm Atheros, Inc.
*
@@ -373,6 +373,56 @@ int wlan_hdd_set_filter(hdd_context_t *pHddCtx, tpPacketFilterCfg pRequest,
/**---------------------------------------------------------------------------
+ \brief mem_alloc_copy_from_user_helper -
+
+ Helper function to allocate buffer and copy user data.
+
+ \param - wrqu - Pointer to IOCTL Data.
+ len - size
+
+ \return - On Success pointer to buffer, On failure NULL
+
+ --------------------------------------------------------------------------*/
+static void *mem_alloc_copy_from_user_helper(const void *wrqu_data, size_t len)
+{
+ u8 *ptr = NULL;
+
+ /* in order to protect the code, an extra byte is post appended to the buffer
+ * and the null termination is added. However, when allocating (len+1) byte
+ * of memory, we need to make sure that there is no uint overflow when doing
+ * addition. In theory check len < UINT_MAX protects the uint overflow. For
+ * wlan private ioctl, the buffer size is much less than UINT_MAX, as a good
+ * guess, now, it is assumed that the private command buffer size is no
+ * greater than 4K (4096 bytes). So we use 4096 as the upper boundary for now.
+ */
+ if (len > MAX_USER_COMMAND_SIZE)
+ {
+ VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
+ "Invalid length");
+ return NULL;
+ }
+
+ ptr = kmalloc(len + 1, GFP_KERNEL);
+ if (NULL == ptr)
+ {
+ VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
+ "unable to allocate memory");
+ return NULL;
+ }
+
+ if (copy_from_user(ptr, wrqu_data, len))
+ {
+ VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
+ "%s: failed to copy data to user buffer", __func__);
+ kfree(ptr);
+ return NULL;
+ }
+ ptr[len] = '\0';
+ return ptr;
+}
+
+/**---------------------------------------------------------------------------
+
\brief hdd_wlan_get_version() -
This function use to get Wlan Driver, Firmware, & Hardware Version.
@@ -4220,15 +4270,13 @@ static int iw_setchar_getnone(struct net_device *dev, struct iw_request_info *in
VOS_STATUS vstatus;
int sub_cmd = wrqu->data.flags;
int ret = 0; /* success */
+ char *pBuffer = NULL;
hdd_adapter_t *pAdapter = (netdev_priv(dev));
hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter);
#ifdef WLAN_FEATURE_VOWIFI
hdd_config_t *pConfig = pHddCtx->cfg_ini;
#endif /* WLAN_FEATURE_VOWIFI */
- VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO, "%s: Received length %d", __func__, wrqu->data.length);
- VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO, "%s: Received data %s", __func__, extra);
-
if ((WLAN_HDD_GET_CTX(pAdapter))->isLogpInProgress)
{
VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_FATAL,
@@ -4236,15 +4284,30 @@ static int iw_setchar_getnone(struct net_device *dev, struct iw_request_info *in
return -EBUSY;
}
+ /* ODD number is used for set, copy data using copy_from_user */
+ pBuffer = mem_alloc_copy_from_user_helper(wrqu->data.pointer,
+ wrqu->data.length);
+ if (NULL == pBuffer)
+ {
+ VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
+ "mem_alloc_copy_from_user_helper fail");
+ return -ENOMEM;
+ }
+
+ VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO,
+ "%s: Received length %d", __func__, wrqu->data.length);
+ VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO,
+ "%s: Received data %s", __func__, pBuffer);
+
switch(sub_cmd)
{
case WE_WOWL_ADD_PTRN:
VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO, "ADD_PTRN");
- hdd_add_wowl_ptrn(pAdapter, extra);
+ hdd_add_wowl_ptrn(pAdapter, pBuffer);
break;
case WE_WOWL_DEL_PTRN:
VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO, "DEL_PTRN");
- hdd_del_wowl_ptrn(pAdapter, extra);
+ hdd_del_wowl_ptrn(pAdapter, pBuffer);
break;
#if defined WLAN_FEATURE_VOWIFI
case WE_NEIGHBOR_REPORT_REQUEST:
@@ -4259,7 +4322,7 @@ static int iw_setchar_getnone(struct net_device *dev, struct iw_request_info *in
if( !neighborReq.no_ssid )
{
neighborReq.ssid.length = (wrqu->data.length - 1) > 32 ? 32 : (wrqu->data.length - 1) ;
- vos_mem_copy( neighborReq.ssid.ssId, extra, neighborReq.ssid.length );
+ vos_mem_copy( neighborReq.ssid.ssId, pBuffer, neighborReq.ssid.length );
}
callbackInfo.neighborRspCallback = NULL;
@@ -4277,10 +4340,10 @@ static int iw_setchar_getnone(struct net_device *dev, struct iw_request_info *in
#endif
case WE_SET_AP_WPS_IE:
hddLog( LOGE, "Received WE_SET_AP_WPS_IE" );
- sme_updateP2pIe( WLAN_HDD_GET_HAL_CTX(pAdapter), extra, wrqu->data.length );
+ sme_updateP2pIe( WLAN_HDD_GET_HAL_CTX(pAdapter), pBuffer, wrqu->data.length );
break;
case WE_SET_CONFIG:
- vstatus = hdd_execute_config_command(pHddCtx, extra);
+ vstatus = hdd_execute_config_command(pHddCtx, pBuffer);
if (VOS_STATUS_SUCCESS != vstatus)
{
ret = -EINVAL;
@@ -4293,6 +4356,7 @@ static int iw_setchar_getnone(struct net_device *dev, struct iw_request_info *in
break;
}
}
+ kfree(pBuffer);
return ret;
}
@@ -5014,7 +5078,6 @@ int iw_set_var_ints_getnone(struct net_device *dev, struct iw_request_info *info
hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev);
tHalHandle hHal = WLAN_HDD_GET_HAL_CTX(pAdapter);
int sub_cmd = wrqu->data.flags;
- int *value = (int*)extra;
int apps_args[MAX_VAR_ARGS] = {0};
int num_args = wrqu->data.length;
hdd_station_ctx_t *pStaCtx = NULL ;
@@ -5035,7 +5098,14 @@ int iw_set_var_ints_getnone(struct net_device *dev, struct iw_request_info *info
{
num_args = MAX_VAR_ARGS;
}
- vos_mem_copy(apps_args, value, (sizeof(int)) * num_args);
+
+ /* ODD number is used for set, copy data using copy_from_user */
+ if (copy_from_user(apps_args, wrqu->data.pointer, (sizeof(int)) * num_args))
+ {
+ VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
+ "%s: failed to copy data to user buffer", __func__);
+ return -EFAULT;
+ }
if(( sub_cmd == WE_MCC_CONFIG_CREDENTIAL ) ||
(sub_cmd == WE_MCC_CONFIG_PARAMS ))
@@ -6377,9 +6447,23 @@ static int iw_set_packet_filter_params(struct net_device *dev, struct iw_request
union iwreq_data *wrqu, char *extra)
{
hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev);
- tpPacketFilterCfg pRequest = (tpPacketFilterCfg) extra;
+ tpPacketFilterCfg pRequest = NULL;
+ int ret;
- return wlan_hdd_set_filter(WLAN_HDD_GET_CTX(pAdapter), pRequest, pAdapter->sessionId);
+ /* ODD number is used for set, copy data using copy_from_user */
+ pRequest = mem_alloc_copy_from_user_helper(wrqu->data.pointer,
+ wrqu->data.length);
+ if (NULL == pRequest)
+ {
+ VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
+ "mem_alloc_copy_from_user_helper fail");
+ return -ENOMEM;
+ }
+
+ ret = wlan_hdd_set_filter(WLAN_HDD_GET_CTX(pAdapter), pRequest, pAdapter->sessionId);
+ kfree(pRequest);
+
+ return ret;
}
#endif
static int iw_get_statistics(struct net_device *dev,
@@ -7053,10 +7137,10 @@ static int iw_set_band_config(struct net_device *dev,
union iwreq_data *wrqu, char *extra)
{
hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev);
- tANI_U8 *ptr = extra;
+ tANI_U8 *ptr = NULL;
int ret = 0;
- VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,"%s: ", __func__);
+ VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO, "%s: ", __func__);
if ((WLAN_HDD_GET_CTX(pAdapter))->isLogpInProgress)
{
@@ -7065,23 +7149,47 @@ static int iw_set_band_config(struct net_device *dev,
return -EBUSY;
}
+ /* ODD number is used for set, copy data using copy_from_user */
+ ptr = mem_alloc_copy_from_user_helper(wrqu->data.pointer,
+ wrqu->data.length);
+ if (NULL == ptr)
+ {
+ VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
+ "mem_alloc_copy_from_user_helper fail");
+ return -ENOMEM;
+ }
+
if (memcmp(ptr, "SETBAND ", 8) == 0)
{
/* Change band request received */
ret = hdd_setBand_helper(dev, ptr);
- return ret;
-
}
- return 0;
+ kfree(ptr);
+
+ return ret;
}
static int iw_set_power_params_priv(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
+ int ret;
+ char *ptr;
VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO,
"Set power params Private");
- return iw_set_power_params(dev,info,wrqu,extra,0);
+ /* ODD number is used for set, copy data using copy_from_user */
+ ptr = mem_alloc_copy_from_user_helper(wrqu->data.pointer,
+ wrqu->data.length);
+ if (NULL == ptr)
+ {
+ VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
+ "mem_alloc_copy_from_user_helper fail");
+ return -ENOMEM;
+ }
+
+ ret = iw_set_power_params(dev, info, wrqu, ptr, 0);
+ kfree(ptr);
+ return ret;
}
--
cgit v1.1