From b5112838eb91b71eded4b5ee37338535784e0aef Mon Sep 17 00:00:00 2001 From: Srinivas Girigowda Date: Sun, 10 Apr 2016 00:03:18 -0700 Subject: qcacld-2.0: Add input validation for SENDACTIONFRAME Add input validation for SENDACTIONFRAME driver command. Change-Id: I3d1bf424e5e0f9a3b6f4662dd12a3a7314c7eace CRs-Fixed: 1001449 --- CORE/HDD/src/wlan_hdd_main.c | 97 +++++++++++++++++++++++++++----------------- 1 file changed, 59 insertions(+), 38 deletions(-) diff --git a/CORE/HDD/src/wlan_hdd_main.c b/CORE/HDD/src/wlan_hdd_main.c index a647bb5..8b7a441 100644 --- a/CORE/HDD/src/wlan_hdd_main.c +++ b/CORE/HDD/src/wlan_hdd_main.c @@ -2205,16 +2205,15 @@ hdd_parse_send_action_frame_v1_data(const tANI_U8 *pValue, static int hdd_sendactionframe(hdd_adapter_t *pAdapter, const tANI_U8 *bssid, const tANI_U8 channel, const tANI_U8 dwell_time, - const tANI_U8 payload_len, const tANI_U8 *payload) + const int payload_len, const tANI_U8 *payload) { struct ieee80211_channel chan; - tANI_U8 frame_len; + int frame_len, ret = 0; tANI_U8 *frame; struct ieee80211_hdr_3addr *hdr; u64 cookie; hdd_station_ctx_t *pHddStaCtx; hdd_context_t *pHddCtx; - int ret = 0; tpSirMacVendorSpecificFrameHdr pVendorSpecific = (tpSirMacVendorSpecificFrameHdr) payload; #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,14,0)) || defined(WITH_BACKPORTS) @@ -2371,45 +2370,57 @@ hdd_parse_sendactionframe_v1(hdd_adapter_t *pAdapter, const char *command) return ret; } -/* - \brief hdd_parse_sendactionframe_v2() - parse version 2 of the - SENDACTIONFRAME command - - This function parses the v2 SENDACTIONFRAME command with the format +/** + * hdd_parse_sendactionframe_v2() - parse version 2 of the + * SENDACTIONFRAME command + * @pAdapter: Adapter upon which the command was received + * @command: command that was received, ASCII command followed + * by binary data + * @total_len: total length of command + * + * This function parses the v2 SENDACTIONFRAME command with the format + * SENDACTIONFRAME + * + * Return: 0 for success non-zero for failure + */ +static int +hdd_parse_sendactionframe_v2(hdd_adapter_t *pAdapter, + const char *command, int total_len) +{ + struct android_wifi_af_params *params; + tSirMacAddr bssid; + int ret; - SENDACTIONFRAME + /* The params are located after "SENDACTIONFRAME " */ + total_len -= 16; + params = (struct android_wifi_af_params *)(command + 16); - \param - pAdapter - Adapter upon which the command was received - \param - command - command that was received, ASCII command followed - by binary data + if (params->len <= 0 || params->len > ANDROID_WIFI_ACTION_FRAME_SIZE || + (params->len > total_len)) { + hddLog(LOGE, FL("Invalid payload length: %d"), params->len); + return -EINVAL; + } - \return - 0 for success non-zero for failure + if (!mac_pton(params->bssid, (u8 *)&bssid)) { + hddLog(LOGE, FL("MAC address parsing failed")); + return -EINVAL; + } - --------------------------------------------------------------------------*/ -static int -hdd_parse_sendactionframe_v2(hdd_adapter_t *pAdapter, - const char *command) -{ - struct android_wifi_af_params *params; - tSirMacAddr bssid; - int ret; + if (params->channel < 0 || + params->channel > WNI_CFG_CURRENT_CHANNEL_STAMAX) { + hddLog(LOGE, FL("Invalid channel: %d"), params->channel); + return -EINVAL; + } - /* params are large so keep off the stack */ - params = kmalloc(sizeof(*params), GFP_KERNEL); - if (!params) return -ENOMEM; + if (params->dwell_time < 0) { + hddLog(LOGE, FL("Invalid dwell_time: %d"), params->dwell_time); + return -EINVAL; + } - /* The params are located after "SENDACTIONFRAME " */ - memcpy(params, command + 16, sizeof(*params)); + ret = hdd_sendactionframe(pAdapter, bssid, params->channel, + params->dwell_time, params->len, params->data); - if (!mac_pton(params->bssid, (u8 *)&bssid)) { - hddLog(LOGE, "%s: MAC address parsing failed", __func__); - ret = -EINVAL; - } else { - ret = hdd_sendactionframe(pAdapter, bssid, params->channel, - params->dwell_time, params->len, params->data); - } - kfree(params); - return ret; + return ret; } /* @@ -2429,7 +2440,8 @@ hdd_parse_sendactionframe_v2(hdd_adapter_t *pAdapter, --------------------------------------------------------------------------*/ static int -hdd_parse_sendactionframe(hdd_adapter_t *pAdapter, const char *command) +hdd_parse_sendactionframe(hdd_adapter_t *pAdapter, const char *command, + int total_len) { int ret; @@ -2445,11 +2457,19 @@ hdd_parse_sendactionframe(hdd_adapter_t *pAdapter, const char *command) * SENDACTIONFRAME xx:xx:xx:xx:xx:xx* * 111111111122222222223333 * 0123456789012345678901234567890123 + * + * For both the commands, a valid command must have atleast first 34 length + * of data. */ + if (total_len < 34) { + hddLog(LOGE, FL("Invalid command (total_len=%d)"), total_len); + return -EINVAL; + } + if (command[33]) { ret = hdd_parse_sendactionframe_v1(pAdapter, command); } else { - ret = hdd_parse_sendactionframe_v2(pAdapter, command); + ret = hdd_parse_sendactionframe_v2(pAdapter, command, total_len); } return ret; @@ -5851,7 +5871,8 @@ static int hdd_driver_command(hdd_adapter_t *pAdapter, } else if (strncmp(command, "SENDACTIONFRAME", 15) == 0) { - ret = hdd_parse_sendactionframe(pAdapter, command); + ret = hdd_parse_sendactionframe(pAdapter, command, + priv_data.total_len); } else if (strncmp(command, "GETROAMSCANCHANNELMINTIME", 25) == 0) { -- cgit v1.1