From c24216ef8a185bac63c30fac0abbe1f6db17fdaa Mon Sep 17 00:00:00 2001 From: Ashish Kumar Dhanotiya Date: Thu, 28 Jun 2018 12:43:41 +0530 Subject: [PATCH 01/28] qcacld-3.0: Add data validation for avoid frequency command Currently in avoid frequency vendor command, data validation is not being done, since this data comes from userspace driver should not be using this data pointer without validation. To address this issue add validation for data pointer and data length received in driver. Bug: 117885703 Test: Regression Change-Id: I7b56e2ddcbcb5e98dd93d152033db48063e772d3 CRs-Fixed: 2252793 Signed-off-by: Sunil Ravi --- core/hdd/src/wlan_hdd_cfg80211.c | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/core/hdd/src/wlan_hdd_cfg80211.c b/core/hdd/src/wlan_hdd_cfg80211.c index e7a40552fb6f..03df15028f9f 100644 --- a/core/hdd/src/wlan_hdd_cfg80211.c +++ b/core/hdd/src/wlan_hdd_cfg80211.c @@ -9264,6 +9264,7 @@ __wlan_hdd_cfg80211_avoid_freq(struct wiphy *wiphy, uint16_t unsafe_channel_index, local_unsafe_list_count; tHddAvoidFreqList *channel_list; enum tQDF_GLOBAL_CON_MODE curr_mode; + uint8_t num_args = 0; ENTER_DEV(wdev->netdev); @@ -9281,11 +9282,27 @@ __wlan_hdd_cfg80211_avoid_freq(struct wiphy *wiphy, ret = wlan_hdd_validate_context(hdd_ctx); if (0 != ret) return ret; + if (!data || data_len < (sizeof(channel_list->avoidFreqRangeCount) + + sizeof(tHddAvoidFreqRange))) { + hdd_err("Avoid frequency channel list empty"); + return -EINVAL; + } + num_args = (data_len - sizeof(channel_list->avoidFreqRangeCount)) / + sizeof(channel_list->avoidFreqRange[0].startFreq); + + if (num_args < 2 || num_args > HDD_MAX_AVOID_FREQ_RANGES * 2 || + num_args % 2 != 0) { + hdd_err("Invalid avoid frequency channel list"); + return -EINVAL; + } channel_list = (tHddAvoidFreqList *)data; - if (!channel_list) { - hdd_log(QDF_TRACE_LEVEL_ERROR, - "Avoid frequency channel list empty"); + + if (channel_list->avoidFreqRangeCount == 0 || + channel_list->avoidFreqRangeCount > HDD_MAX_AVOID_FREQ_RANGES || + 2 * channel_list->avoidFreqRangeCount != num_args) { + hdd_err("Invalid frequency range count %d", + channel_list->avoidFreqRangeCount); return -EINVAL; } From 756f27166a048786d38f9e8c0b40a3ab69828aa6 Mon Sep 17 00:00:00 2001 From: Yeshwanth Sriram Guntuka Date: Mon, 11 Jun 2018 17:41:18 +0530 Subject: [PATCH 02/28] qcacld-3.0: Fix possible OOB access in lim_process_disassoc_frame Reason code is extracted from frame data without validating the frame len which could result in out of bound access. Fix is to validate frame len before extracting reason code from frame data. Bug: 78530292 Test: Regression Change-Id: I00795a806abcae903dd0daa019aeab990aedc3a7 CRs-Fixed: 2253984 Signed-off-by: Ahmed ElArabawy --- core/mac/src/pe/lim/lim_process_disassoc_frame.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/core/mac/src/pe/lim/lim_process_disassoc_frame.c b/core/mac/src/pe/lim/lim_process_disassoc_frame.c index c8ae79fc8618..e36ecc939f35 100644 --- a/core/mac/src/pe/lim/lim_process_disassoc_frame.c +++ b/core/mac/src/pe/lim/lim_process_disassoc_frame.c @@ -77,13 +77,12 @@ lim_process_disassoc_frame(tpAniSirGlobal pMac, uint8_t *pRxPacketInfo, uint16_t aid, reasonCode; tpSirMacMgmtHdr pHdr; tpDphHashNode pStaDs; -#ifdef WLAN_FEATURE_11W - uint32_t frameLen; -#endif + uint32_t frame_len; int32_t frame_rssi; pHdr = WMA_GET_RX_MAC_HEADER(pRxPacketInfo); pBody = WMA_GET_RX_MPDU_DATA(pRxPacketInfo); + frame_len = WMA_GET_RX_PAYLOAD_LEN(pRxPacketInfo); frame_rssi = (int32_t)WMA_GET_RX_RSSI_NORMALIZED(pRxPacketInfo); @@ -137,11 +136,10 @@ lim_process_disassoc_frame(tpAniSirGlobal pMac, uint8_t *pRxPacketInfo, /* If the frame received is unprotected, forward it to the supplicant to initiate */ /* an SA query */ - frameLen = WMA_GET_RX_PAYLOAD_LEN(pRxPacketInfo); /* send the unprotected frame indication to SME */ lim_send_sme_unprotected_mgmt_frame_ind(pMac, pHdr->fc.subType, (uint8_t *) pHdr, - (frameLen + + (frame_len + sizeof(tSirMacMgmtHdr)), psessionEntry->smeSessionId, psessionEntry); @@ -149,6 +147,11 @@ lim_process_disassoc_frame(tpAniSirGlobal pMac, uint8_t *pRxPacketInfo, } #endif + if (frame_len < 2) { + pe_err("frame len less than 2"); + return; + } + /* Get reasonCode from Disassociation frame body */ reasonCode = sir_read_u16(pBody); From 9a43b2f0653fa909fd28d684c02653b0d1fc490d Mon Sep 17 00:00:00 2001 From: Pragaspathi Thilagaraj Date: Mon, 25 Jun 2018 18:26:26 +0530 Subject: [PATCH 03/28] qcacld-3.0: Fix possible heap overflow in lim_update_ext_cap_ie In the function lim_process_set_default_scan_ie_request, memory of MAX_DEFAULT_SCAN_IE_LEN (2048) is allocated for local_ie_buf. This local_ie_buf accommodates the ie data and also the ext capabilities. If the local_ie_len, that is used to copy the ie_data to local_ie_buf is greater than MAX_DEFAULT_SCAN_IE_LEN(2048) - (DOT11F_IE_EXTCAP_MAX_LEN(15) + EXT_CAP_IE_HDR_LEN(2)), then heap overflow could occur. Validate the MAX_DEFAULT_SCAN_IE_LEN against the difference between MAX_DEFAULT_SCAN_IE_LEN and sum of EXT_CAP_IE_HDR_LEN and DOT11F_IE_EXTCAP_MAX_LEN. Bug: 112277631 Test: Regression Change-Id: Id2f950440d69ddb09090643f8a426061c0d336c3 CRs-Fixed: 2231300 Signed-off-by: Ecco Park --- core/mac/src/pe/lim/lim_api.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/core/mac/src/pe/lim/lim_api.c b/core/mac/src/pe/lim/lim_api.c index cec8a1ef646f..f0cc82b8544e 100644 --- a/core/mac/src/pe/lim/lim_api.c +++ b/core/mac/src/pe/lim/lim_api.c @@ -2505,6 +2505,11 @@ QDF_STATUS lim_update_ext_cap_ie(tpAniSirGlobal mac_ctx, return QDF_STATUS_E_FAILURE; } + if ((*local_ie_len) > (MAX_DEFAULT_SCAN_IE_LEN - EXT_CAP_IE_HDR_LEN)) { + pe_err("Invalid Scan IE length"); + return QDF_STATUS_E_FAILURE; + } + /* copy ie prior to ext cap to local buffer */ qdf_mem_copy(local_ie_buf, ie_data, (*local_ie_len)); @@ -2521,6 +2526,11 @@ QDF_STATUS lim_update_ext_cap_ie(tpAniSirGlobal mac_ctx, pe_err("Failed %d to create ext cap IE. Use default value instead", status); local_ie_buf[*local_ie_len + 1] = DOT11F_IE_EXTCAP_MAX_LEN; + if ((*local_ie_len) > (MAX_DEFAULT_SCAN_IE_LEN - + (DOT11F_IE_EXTCAP_MAX_LEN + EXT_CAP_IE_HDR_LEN))) { + pe_err("Invalid Scan IE length"); + return QDF_STATUS_E_FAILURE; + } (*local_ie_len) += EXT_CAP_IE_HDR_LEN; qdf_mem_copy(local_ie_buf + (*local_ie_len), default_scan_ext_cap.bytes, @@ -2530,6 +2540,12 @@ QDF_STATUS lim_update_ext_cap_ie(tpAniSirGlobal mac_ctx, } lim_merge_extcap_struct(&driver_ext_cap, &default_scan_ext_cap, true); local_ie_buf[*local_ie_len + 1] = driver_ext_cap.num_bytes; + + if ((*local_ie_len) > (MAX_DEFAULT_SCAN_IE_LEN - + (EXT_CAP_IE_HDR_LEN + driver_ext_cap.num_bytes))) { + pe_err("Invalid Scan IE length"); + return QDF_STATUS_E_FAILURE; + } (*local_ie_len) += EXT_CAP_IE_HDR_LEN; qdf_mem_copy(local_ie_buf + (*local_ie_len), driver_ext_cap.bytes, driver_ext_cap.num_bytes); From a616b92ac3d1acee2ede4d40c29257e2e911d68d Mon Sep 17 00:00:00 2001 From: Pragaspathi Thilagaraj Date: Fri, 6 Jul 2018 15:43:02 +0530 Subject: [PATCH 04/28] qcacld-3.0: Fix possible OOB in lim_chk_n_process_wpa_rsn_ie In the function lim_chk_n_process_wpa_rsn_ie, if wpa IE is present, then dot11f_unpack_ie_wpa is called to copy the wpa IE to destination buffer. assoc_req->wpa.length is passed as the length to copy the IE. As this length includes 4 bytes of the OUI fields also, this could result in OOB read. Change the length passed to the dot11f_unpack_ie_wpa as (assoc_req->wpa.length - 4), so that the additional 4 bytes of the OUI fields are excluded. Bug: 110475457 Test: Regression Change-Id: If972b3a19d239bb955c7b4d4c7d94e25aa878f21 CRs-Fixed: 2267557 Signed-off-by: Sunil Ravi --- core/mac/src/pe/lim/lim_assoc_utils.c | 8 ++++---- .../src/pe/lim/lim_process_assoc_req_frame.c | 19 ++++++++++--------- 2 files changed, 14 insertions(+), 13 deletions(-) diff --git a/core/mac/src/pe/lim/lim_assoc_utils.c b/core/mac/src/pe/lim/lim_assoc_utils.c index e7ca136f209a..a01d87043677 100644 --- a/core/mac/src/pe/lim/lim_assoc_utils.c +++ b/core/mac/src/pe/lim/lim_assoc_utils.c @@ -349,8 +349,8 @@ static inline bool is_non_rsn_cipher(uint8_t cipher_suite) * frame handling to determine whether received RSN in * Assoc/Reassoc request frames include supported cipher suites or not. * - * Return: eSIR_SUCCESS if ALL BSS basic rates are present in the - * received rateset else failure status. + * Return: eSIR_SUCCESS if ALL supported cipher suites are present in the + * received rsn IE else failure status. */ uint8_t @@ -461,8 +461,8 @@ lim_check_rx_rsn_ie_match(tpAniSirGlobal mac_ctx, tDot11fIERSN rx_rsn_ie, * frame handling to determine whether received RSN in * Assoc/Reassoc request frames include supported cipher suites or not. * - * Return: Success if ALL BSS basic rates are present in the - * received rateset else failure status. + * Return: Success if ALL supported cipher suites are present in the + * received wpa IE else failure status. */ uint8_t diff --git a/core/mac/src/pe/lim/lim_process_assoc_req_frame.c b/core/mac/src/pe/lim/lim_process_assoc_req_frame.c index 3e3345768882..6999267fdb3e 100644 --- a/core/mac/src/pe/lim/lim_process_assoc_req_frame.c +++ b/core/mac/src/pe/lim/lim_process_assoc_req_frame.c @@ -737,7 +737,7 @@ static void lim_print_ht_cap(tpAniSirGlobal mac_ctx, tpPESession session, * * wpa ie related checks * - * Return: true of no error, false otherwise + * Return: true if no error, false otherwise */ static bool lim_chk_n_process_wpa_rsn_ie(tpAniSirGlobal mac_ctx, tpSirMacMgmtHdr hdr, @@ -746,6 +746,7 @@ static bool lim_chk_n_process_wpa_rsn_ie(tpAniSirGlobal mac_ctx, uint8_t sub_type, bool *pmf_connection) { uint8_t *wps_ie = NULL; + uint32_t ret; tDot11fIEWPA dot11f_ie_wpa = {0}; tDot11fIERSN dot11f_ie_rsn = {0}; tSirRetStatus status = eSIR_SUCCESS; @@ -776,11 +777,11 @@ static bool lim_chk_n_process_wpa_rsn_ie(tpAniSirGlobal mac_ctx, if (assoc_req->rsnPresent) { if (assoc_req->rsn.length) { /* Unpack the RSN IE */ - if (dot11f_unpack_ie_rsn(mac_ctx, + ret = dot11f_unpack_ie_rsn(mac_ctx, &assoc_req->rsn.info[0], assoc_req->rsn.length, - &dot11f_ie_rsn, false) != - DOT11F_PARSE_SUCCESS) { + &dot11f_ie_rsn, false); + if (!DOT11F_SUCCEEDED(ret)) { pe_err("Invalid RSN ie"); return false; } @@ -852,11 +853,11 @@ static bool lim_chk_n_process_wpa_rsn_ie(tpAniSirGlobal mac_ctx, /* Unpack the WPA IE */ if (assoc_req->wpa.length) { /* OUI is not taken care */ - if (dot11f_unpack_ie_wpa(mac_ctx, - &assoc_req->wpa.info[4], - assoc_req->wpa.length, - &dot11f_ie_wpa, false) != - DOT11F_PARSE_SUCCESS) { + ret = dot11f_unpack_ie_wpa(mac_ctx, + &assoc_req->wpa.info[4], + (assoc_req->wpa.length - 4), + &dot11f_ie_wpa, false); + if (!DOT11F_SUCCEEDED(ret)) { pe_err("Invalid WPA IE"); return false; } From c0f46533bad1290260def4dba2b1b604ac906099 Mon Sep 17 00:00:00 2001 From: Yeshwanth Sriram Guntuka Date: Thu, 14 Jun 2018 18:44:41 +0530 Subject: [PATCH 05/28] qcacld-3.0: Fix possible OOB access in lim_process_assoc_req_frame cfg_get_vendor_ie_ptr_from_oui is invoked in lim_process_assoc_req_frame function with ie pointer pointing to frame buffer plus assoc req ie offset and ie len equal to frame buffer len. This could result in OOB access since offset is not subtracted from frame len. Fix is to subtract the offset from frame len as argument to cfg_get_vendor_ie_ptr_from_oui. Bug: 78657016 Test: Regression Change-Id: Ic107867bcf4d7813c544309a2aff165f2dc7155d CRs-Fixed: 2255369 Signed-off-by: Sunil Ravi --- core/mac/src/pe/lim/lim_process_assoc_req_frame.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/core/mac/src/pe/lim/lim_process_assoc_req_frame.c b/core/mac/src/pe/lim/lim_process_assoc_req_frame.c index 6999267fdb3e..9f8a5d780302 100644 --- a/core/mac/src/pe/lim/lim_process_assoc_req_frame.c +++ b/core/mac/src/pe/lim/lim_process_assoc_req_frame.c @@ -1847,7 +1847,8 @@ void lim_process_assoc_req_frame(tpAniSirGlobal mac_ctx, uint8_t *rx_pkt_info, LIM_ACCESS_POLICY_RESPOND_IF_IE_IS_PRESENT)) { if (!cfg_get_vendor_ie_ptr_from_oui(mac_ctx, &session->access_policy_vendor_ie[2], - 3, frm_body + LIM_ASSOC_REQ_IE_OFFSET, frame_len)) { + 3, frm_body + LIM_ASSOC_REQ_IE_OFFSET, + frame_len - LIM_ASSOC_REQ_IE_OFFSET)) { pe_err("Vendor ie not present and access policy is %x, Rejected association", session->access_policy); lim_send_assoc_rsp_mgmt_frame(mac_ctx, From e95d77b89dcbb17d1f9cfa2e1cbfc8cc3f55fdce Mon Sep 17 00:00:00 2001 From: jitiphil Date: Thu, 7 Jun 2018 22:49:24 +0530 Subject: [PATCH 06/28] qcacld-3.0: Implement descriptor pool for fw stats The kernel address is used as cookie to keep track of stats request. This address can be disclosed to target leading to a security vulnerability. Implement a FW stats descriptor pool, and use a descriptor ID to keep track of stats requests, instead of the kernel address, to prevent kernel address leak. Bug: 112277911 Test: Regression Change-Id: Ib49150da899c0b9314f614868a90867f4aa92d3d CRs-Fixed: 2246110 Signed-off-by: Ecco Park --- core/dp/htt/htt_h2t.c | 8 +- core/dp/htt/htt_t2h.c | 3 +- core/dp/ol/inc/ol_htt_api.h | 4 +- core/dp/ol/inc/ol_txrx_htt_api.h | 2 +- core/dp/txrx/ol_txrx.c | 206 +++++++++++++++++++++++++++++-- core/dp/txrx/ol_txrx.h | 12 ++ core/dp/txrx/ol_txrx_types.h | 17 +++ 7 files changed, 233 insertions(+), 19 deletions(-) diff --git a/core/dp/htt/htt_h2t.c b/core/dp/htt/htt_h2t.c index ddbe9aac5d3e..1b05904b1f7b 100644 --- a/core/dp/htt/htt_h2t.c +++ b/core/dp/htt/htt_h2t.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011-2017 The Linux Foundation. All rights reserved. + * Copyright (c) 2011-2018 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -767,7 +767,7 @@ int htt_h2t_dbg_stats_get(struct htt_pdev_t *pdev, uint32_t stats_type_upload_mask, uint32_t stats_type_reset_mask, - uint8_t cfg_stat_type, uint32_t cfg_val, uint64_t cookie) + uint8_t cfg_stat_type, uint32_t cfg_val, uint8_t cookie) { struct htt_htc_pkt *pkt; qdf_nbuf_t msg; @@ -830,11 +830,11 @@ htt_h2t_dbg_stats_get(struct htt_pdev_t *pdev, /* cookie LSBs */ msg_word++; - *msg_word = cookie & 0xffffffff; + *msg_word = cookie; /* cookie MSBs */ msg_word++; - *msg_word = cookie >> 32; + *msg_word = 0; SET_HTC_PACKET_INFO_TX(&pkt->htc_pkt, htt_h2t_send_complete_free_netbuf, diff --git a/core/dp/htt/htt_t2h.c b/core/dp/htt/htt_t2h.c index a0c4b4401443..d55f19bab488 100644 --- a/core/dp/htt/htt_t2h.c +++ b/core/dp/htt/htt_t2h.c @@ -394,11 +394,10 @@ static void htt_t2h_lp_msg_handler(void *context, qdf_nbuf_t htt_t2h_msg, } case HTT_T2H_MSG_TYPE_STATS_CONF: { - uint64_t cookie; + uint8_t cookie; uint8_t *stats_info_list; cookie = *(msg_word + 1); - cookie |= ((uint64_t) (*(msg_word + 2))) << 32; stats_info_list = (uint8_t *) (msg_word + 3); htc_pm_runtime_put(pdev->htc_pdev); diff --git a/core/dp/ol/inc/ol_htt_api.h b/core/dp/ol/inc/ol_htt_api.h index e597dc748b27..daa6be3bc72c 100644 --- a/core/dp/ol/inc/ol_htt_api.h +++ b/core/dp/ol/inc/ol_htt_api.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2014-2017 The Linux Foundation. All rights reserved. + * Copyright (c) 2011, 2014-2018 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -164,7 +164,7 @@ htt_h2t_dbg_stats_get(struct htt_pdev_t *pdev, uint32_t stats_type_upload_mask, uint32_t stats_type_reset_mask, uint8_t cfg_stats_type, - uint32_t cfg_val, uint64_t cookie); + uint32_t cfg_val, uint8_t cookie); /** * @brief Get the fields from HTT T2H stats upload message's stats info header diff --git a/core/dp/ol/inc/ol_txrx_htt_api.h b/core/dp/ol/inc/ol_txrx_htt_api.h index 277569bbe56a..78e4387b8018 100644 --- a/core/dp/ol/inc/ol_txrx_htt_api.h +++ b/core/dp/ol/inc/ol_txrx_htt_api.h @@ -604,7 +604,7 @@ ol_rx_pn_ind_handler(ol_txrx_pdev_handle pdev, */ void ol_txrx_fw_stats_handler(ol_txrx_pdev_handle pdev, - uint64_t cookie, uint8_t *stats_info_list); + uint8_t cookie, uint8_t *stats_info_list); /** * @brief Process a tx inspect message sent by the target. diff --git a/core/dp/txrx/ol_txrx.c b/core/dp/txrx/ol_txrx.c index d02b1806303f..48bdfb83dd39 100644 --- a/core/dp/txrx/ol_txrx.c +++ b/core/dp/txrx/ol_txrx.c @@ -1468,6 +1468,7 @@ ol_txrx_pdev_attach(ol_pdev_handle ctrl_pdev, TXRX_STATS_INIT(pdev); ol_txrx_tso_stats_init(pdev); + ol_txrx_fw_stats_desc_pool_init(pdev, FW_STATS_DESC_POOL_SIZE); TAILQ_INIT(&pdev->vdev_list); TAILQ_INIT(&pdev->roam_stale_peer_list); @@ -1533,6 +1534,7 @@ ol_txrx_pdev_attach(ol_pdev_handle ctrl_pdev, fail1: ol_txrx_tso_stats_deinit(pdev); + ol_txrx_fw_stats_desc_pool_deinit(pdev); qdf_mem_free(pdev); fail0: @@ -2316,6 +2318,7 @@ void ol_txrx_pdev_detach(ol_txrx_pdev_handle pdev) htt_pdev_free(pdev->htt_pdev); ol_txrx_peer_find_detach(pdev); ol_txrx_tso_stats_deinit(pdev); + ol_txrx_fw_stats_desc_pool_deinit(pdev); ol_txrx_pdev_txq_log_destroy(pdev); ol_txrx_pdev_grp_stat_destroy(pdev); @@ -4141,20 +4144,171 @@ void ol_txrx_fw_stats_cfg(ol_txrx_vdev_handle vdev, uint8_t cfg_stats_type, uint32_t cfg_val) { - uint64_t dummy_cookie = 0; + uint8_t dummy_cookie = 0; htt_h2t_dbg_stats_get(vdev->pdev->htt_pdev, 0 /* upload mask */, 0 /* reset mask */, cfg_stats_type, cfg_val, dummy_cookie); } +/** + * ol_txrx_fw_stats_desc_pool_init() - Initialize the fw stats descriptor pool + * @pdev: handle to ol txrx pdev + * @pool_size: Size of fw stats descriptor pool + * + * Return: 0 for success, error code on failure. + */ +int ol_txrx_fw_stats_desc_pool_init(struct ol_txrx_pdev_t *pdev, + uint8_t pool_size) +{ + int i; + + if (!pdev) { + ol_txrx_err("%s: pdev is NULL", __func__); + return -EINVAL; + } + pdev->ol_txrx_fw_stats_desc_pool.pool = qdf_mem_malloc(pool_size * + sizeof(struct ol_txrx_fw_stats_desc_elem_t)); + if (!pdev->ol_txrx_fw_stats_desc_pool.pool) { + ol_txrx_err("%s: failed to allocate desc pool", __func__); + return -ENOMEM; + } + pdev->ol_txrx_fw_stats_desc_pool.freelist = + &pdev->ol_txrx_fw_stats_desc_pool.pool[0]; + pdev->ol_txrx_fw_stats_desc_pool.pool_size = pool_size; + + for (i = 0; i < (pool_size - 1); i++) { + pdev->ol_txrx_fw_stats_desc_pool.pool[i].desc.desc_id = i; + pdev->ol_txrx_fw_stats_desc_pool.pool[i].desc.req = NULL; + pdev->ol_txrx_fw_stats_desc_pool.pool[i].next = + &pdev->ol_txrx_fw_stats_desc_pool.pool[i + 1]; + } + pdev->ol_txrx_fw_stats_desc_pool.pool[i].desc.desc_id = i; + pdev->ol_txrx_fw_stats_desc_pool.pool[i].desc.req = NULL; + pdev->ol_txrx_fw_stats_desc_pool.pool[i].next = NULL; + qdf_spinlock_create(&pdev->ol_txrx_fw_stats_desc_pool.pool_lock); + qdf_atomic_init(&pdev->ol_txrx_fw_stats_desc_pool.initialized); + qdf_atomic_set(&pdev->ol_txrx_fw_stats_desc_pool.initialized, 1); + return 0; +} + +/** + * ol_txrx_fw_stats_desc_pool_deinit() - Deinitialize the + * fw stats descriptor pool + * @pdev: handle to ol txrx pdev + * + * Return: None + */ +void ol_txrx_fw_stats_desc_pool_deinit(struct ol_txrx_pdev_t *pdev) +{ + struct ol_txrx_fw_stats_desc_elem_t *desc; + uint8_t i; + + if (!pdev) { + ol_txrx_err("%s: pdev is NULL", __func__); + return; + } + if (!qdf_atomic_read(&pdev->ol_txrx_fw_stats_desc_pool.initialized)) { + ol_txrx_err("%s: Pool is not initialized", __func__); + return; + } + if (!pdev->ol_txrx_fw_stats_desc_pool.pool) { + ol_txrx_err("%s: Pool is not allocated", __func__); + return; + } + + qdf_spin_lock_bh(&pdev->ol_txrx_fw_stats_desc_pool.pool_lock); + qdf_atomic_set(&pdev->ol_txrx_fw_stats_desc_pool.initialized, 0); + for (i = 0; i < pdev->ol_txrx_fw_stats_desc_pool.pool_size; i++) { + desc = &pdev->ol_txrx_fw_stats_desc_pool.pool[i]; + if (desc && desc->desc.req) + qdf_mem_free(desc->desc.req); + } + qdf_mem_free(pdev->ol_txrx_fw_stats_desc_pool.pool); + pdev->ol_txrx_fw_stats_desc_pool.pool = NULL; + + pdev->ol_txrx_fw_stats_desc_pool.freelist = NULL; + pdev->ol_txrx_fw_stats_desc_pool.pool_size = 0; + qdf_spin_unlock_bh(&pdev->ol_txrx_fw_stats_desc_pool.pool_lock); +} + +/** + * ol_txrx_fw_stats_desc_alloc() - Get fw stats descriptor from fw stats + * free descriptor pool + * @pdev: handle to ol txrx pdev + * + * Return: pointer to fw stats descriptor, NULL on failure + */ +struct ol_txrx_fw_stats_desc_t + *ol_txrx_fw_stats_desc_alloc(struct ol_txrx_pdev_t *pdev) +{ + struct ol_txrx_fw_stats_desc_t *desc = NULL; + + qdf_spin_lock_bh(&pdev->ol_txrx_fw_stats_desc_pool.pool_lock); + if (!qdf_atomic_read(&pdev->ol_txrx_fw_stats_desc_pool.initialized)) { + qdf_spin_unlock_bh(&pdev-> + ol_txrx_fw_stats_desc_pool.pool_lock); + ol_txrx_err("%s: Pool deinitialized", __func__); + return NULL; + } + if (pdev->ol_txrx_fw_stats_desc_pool.freelist) { + desc = &pdev->ol_txrx_fw_stats_desc_pool.freelist->desc; + pdev->ol_txrx_fw_stats_desc_pool.freelist = + pdev->ol_txrx_fw_stats_desc_pool.freelist->next; + } + qdf_spin_unlock_bh(&pdev->ol_txrx_fw_stats_desc_pool.pool_lock); + + if (desc) + ol_txrx_dbg("%s: desc_id %d allocated", + __func__, desc->desc_id); + else + ol_txrx_err("%s: fw stats descriptors are exhausted", __func__); + + return desc; +} + +/** + * ol_txrx_fw_stats_desc_get_req() - Put fw stats descriptor + * back into free pool + * @pdev: handle to ol txrx pdev + * @fw_stats_desc: fw_stats_desc_get descriptor + * + * Return: pointer to request + */ +struct ol_txrx_stats_req_internal + *ol_txrx_fw_stats_desc_get_req(struct ol_txrx_pdev_t *pdev, + unsigned char desc_id) +{ + struct ol_txrx_fw_stats_desc_elem_t *desc_elem; + struct ol_txrx_stats_req_internal *req; + + qdf_spin_lock_bh(&pdev->ol_txrx_fw_stats_desc_pool.pool_lock); + if (!qdf_atomic_read(&pdev->ol_txrx_fw_stats_desc_pool.initialized)) { + qdf_spin_unlock_bh(&pdev-> + ol_txrx_fw_stats_desc_pool.pool_lock); + ol_txrx_err("%s: Desc ID %u Pool deinitialized", + __func__, desc_id); + return NULL; + } + desc_elem = &pdev->ol_txrx_fw_stats_desc_pool.pool[desc_id]; + req = desc_elem->desc.req; + desc_elem->desc.req = NULL; + desc_elem->next = + pdev->ol_txrx_fw_stats_desc_pool.freelist; + pdev->ol_txrx_fw_stats_desc_pool.freelist = desc_elem; + qdf_spin_unlock_bh(&pdev->ol_txrx_fw_stats_desc_pool.pool_lock); + return req; +} + A_STATUS ol_txrx_fw_stats_get(ol_txrx_vdev_handle vdev, struct ol_txrx_stats_req *req, bool per_vdev, bool response_expected) { struct ol_txrx_pdev_t *pdev = vdev->pdev; - uint64_t cookie; + uint8_t cookie = FW_STATS_DESC_POOL_SIZE; struct ol_txrx_stats_req_internal *non_volatile_req; + struct ol_txrx_fw_stats_desc_t *desc = NULL; + struct ol_txrx_fw_stats_desc_elem_t *elem = NULL; if (!pdev || req->stats_type_upload_mask >= 1 << HTT_DBG_NUM_STATS || @@ -4174,11 +4328,16 @@ ol_txrx_fw_stats_get(ol_txrx_vdev_handle vdev, struct ol_txrx_stats_req *req, non_volatile_req->base = *req; non_volatile_req->serviced = 0; non_volatile_req->offset = 0; - - /* use the non-volatile request object's address as the cookie */ - cookie = ol_txrx_stats_ptr_to_u64(non_volatile_req); - if (response_expected) { + desc = ol_txrx_fw_stats_desc_alloc(pdev); + if (!desc) { + qdf_mem_free(non_volatile_req); + return A_ERROR; + } + + /* use the desc id as the cookie */ + cookie = desc->desc_id; + desc->req = non_volatile_req; qdf_spin_lock_bh(&pdev->req_list_spinlock); TAILQ_INSERT_TAIL(&pdev->req_list, non_volatile_req, req_list_elem); pdev->req_list_depth++; @@ -4192,9 +4351,28 @@ ol_txrx_fw_stats_get(ol_txrx_vdev_handle vdev, struct ol_txrx_stats_req *req, cookie)) { if (response_expected) { qdf_spin_lock_bh(&pdev->req_list_spinlock); - TAILQ_REMOVE(&pdev->req_list, non_volatile_req, req_list_elem); + TAILQ_REMOVE(&pdev->req_list, non_volatile_req, + req_list_elem); pdev->req_list_depth--; qdf_spin_unlock_bh(&pdev->req_list_spinlock); + if (desc) { + qdf_spin_lock_bh(&pdev-> + ol_txrx_fw_stats_desc_pool. + pool_lock); + desc->req = NULL; + elem = container_of(desc, + struct + ol_txrx_fw_stats_desc_elem_t, + desc); + elem->next = + pdev->ol_txrx_fw_stats_desc_pool. + freelist; + pdev->ol_txrx_fw_stats_desc_pool. + freelist = elem; + qdf_spin_unlock_bh(&pdev-> + ol_txrx_fw_stats_desc_pool. + pool_lock); + } } qdf_mem_free(non_volatile_req); @@ -4209,7 +4387,7 @@ ol_txrx_fw_stats_get(ol_txrx_vdev_handle vdev, struct ol_txrx_stats_req *req, void ol_txrx_fw_stats_handler(ol_txrx_pdev_handle pdev, - uint64_t cookie, uint8_t *stats_info_list) + uint8_t cookie, uint8_t *stats_info_list) { enum htt_dbg_stats_type type; enum htt_dbg_stats_status status; @@ -4219,8 +4397,16 @@ ol_txrx_fw_stats_handler(ol_txrx_pdev_handle pdev, int more = 0; int found = 0; - req = ol_txrx_u64_to_stats_ptr(cookie); - + if (cookie >= FW_STATS_DESC_POOL_SIZE) { + ol_txrx_err("%s: Cookie is not valid", __func__); + return; + } + req = ol_txrx_fw_stats_desc_get_req(pdev, (uint8_t)cookie); + if (!req) { + ol_txrx_err("%s: Request not retrieved for cookie %u", __func__, + (uint8_t)cookie); + return; + } qdf_spin_lock_bh(&pdev->req_list_spinlock); TAILQ_FOREACH(tmp, &pdev->req_list, req_list_elem) { if (req == tmp) { diff --git a/core/dp/txrx/ol_txrx.h b/core/dp/txrx/ol_txrx.h index dd9a67e1d225..bde9ae2f9341 100644 --- a/core/dp/txrx/ol_txrx.h +++ b/core/dp/txrx/ol_txrx.h @@ -78,6 +78,9 @@ ol_tx_desc_pool_size_hl(ol_pdev_handle ctrl_pdev); #define OL_TX_DESC_POOL_SIZE_MAX_HL 5000 #endif +#ifndef FW_STATS_DESC_POOL_SIZE +#define FW_STATS_DESC_POOL_SIZE 10 +#endif #ifdef CONFIG_PER_VDEV_TX_DESC_POOL #define TXRX_HL_TX_FLOW_CTRL_VDEV_LOW_WATER_MARK 400 @@ -206,4 +209,13 @@ void ol_txrx_update_mac_id(uint8_t vdev_id, uint8_t mac_id); void ol_txrx_peer_detach_force_delete(ol_txrx_peer_handle peer); void peer_unmap_timer_handler(unsigned long data); +int ol_txrx_fw_stats_desc_pool_init(struct ol_txrx_pdev_t *pdev, + uint8_t pool_size); +void ol_txrx_fw_stats_desc_pool_deinit(struct ol_txrx_pdev_t *pdev); +struct ol_txrx_fw_stats_desc_t + *ol_txrx_fw_stats_desc_alloc(struct ol_txrx_pdev_t + *pdev); +struct ol_txrx_stats_req_internal *ol_txrx_fw_stats_desc_get_req(struct + ol_txrx_pdev_t *pdev, uint8_t desc_id); + #endif /* _OL_TXRX__H_ */ diff --git a/core/dp/txrx/ol_txrx_types.h b/core/dp/txrx/ol_txrx_types.h index df7877d95891..a678bfc1d6a2 100644 --- a/core/dp/txrx/ol_txrx_types.h +++ b/core/dp/txrx/ol_txrx_types.h @@ -556,6 +556,15 @@ struct ol_txrx_stats_req_internal { int offset; }; +struct ol_txrx_fw_stats_desc_t { + struct ol_txrx_stats_req_internal *req; + unsigned char desc_id; +}; + +struct ol_txrx_fw_stats_desc_elem_t { + struct ol_txrx_fw_stats_desc_elem_t *next; + struct ol_txrx_fw_stats_desc_t desc; +}; /* * As depicted in the diagram below, the pdev contains an array of @@ -668,6 +677,14 @@ struct ol_txrx_pdev_t { qdf_atomic_t target_tx_credit; qdf_atomic_t orig_target_tx_credit; + struct { + uint16_t pool_size; + struct ol_txrx_fw_stats_desc_elem_t *pool; + struct ol_txrx_fw_stats_desc_elem_t *freelist; + qdf_spinlock_t pool_lock; + qdf_atomic_t initialized; + } ol_txrx_fw_stats_desc_pool; + /* Peer mac address to staid mapping */ struct ol_mac_addr mac_to_staid[WLAN_MAX_STA_COUNT + 3]; From aa31335ad9ef67aa06abf55b135a5a53034ebe15 Mon Sep 17 00:00:00 2001 From: Tiger Yu Date: Thu, 5 Jul 2018 10:22:19 +0800 Subject: [PATCH 07/28] qcacld-3.0: Fix the double free for the txrx stats req The txrx stats req has been freed in the ol_txrx_pdev_detach by checking req_list of pdev. Remove the txrx stats req free in the ol_txrx_fw_stats_desc_pool_deinit to avoid the double free. Bug: 112277911 Test: Regression CRs-Fixed: 2272696 Change-Id: Idb2d5517e90ee873e7fd62d58c48a4f793266bac Signed-off-by: Ecco Park --- core/dp/txrx/ol_txrx.c | 8 -------- 1 file changed, 8 deletions(-) diff --git a/core/dp/txrx/ol_txrx.c b/core/dp/txrx/ol_txrx.c index 48bdfb83dd39..4cfcb9776f21 100644 --- a/core/dp/txrx/ol_txrx.c +++ b/core/dp/txrx/ol_txrx.c @@ -4201,9 +4201,6 @@ int ol_txrx_fw_stats_desc_pool_init(struct ol_txrx_pdev_t *pdev, */ void ol_txrx_fw_stats_desc_pool_deinit(struct ol_txrx_pdev_t *pdev) { - struct ol_txrx_fw_stats_desc_elem_t *desc; - uint8_t i; - if (!pdev) { ol_txrx_err("%s: pdev is NULL", __func__); return; @@ -4219,11 +4216,6 @@ void ol_txrx_fw_stats_desc_pool_deinit(struct ol_txrx_pdev_t *pdev) qdf_spin_lock_bh(&pdev->ol_txrx_fw_stats_desc_pool.pool_lock); qdf_atomic_set(&pdev->ol_txrx_fw_stats_desc_pool.initialized, 0); - for (i = 0; i < pdev->ol_txrx_fw_stats_desc_pool.pool_size; i++) { - desc = &pdev->ol_txrx_fw_stats_desc_pool.pool[i]; - if (desc && desc->desc.req) - qdf_mem_free(desc->desc.req); - } qdf_mem_free(pdev->ol_txrx_fw_stats_desc_pool.pool); pdev->ol_txrx_fw_stats_desc_pool.pool = NULL; From 2b68f65440386188172a6033e6fea7438c185286 Mon Sep 17 00:00:00 2001 From: Ashish Kumar Dhanotiya Date: Fri, 30 Nov 2018 20:29:09 +0530 Subject: [PATCH 08/28] qcacld-3.0: Validate all channels for avoid_freq channel list In avoid frequency vendor command, only data validation is being done but each individual channel is not getting validated which may lead to an array out of bound access as the array which is used to cache the channels has the size of valid number of channels. To avoid this, add a check to validate each channel before updating the unsafe channel list array. Bug: 117885392 Test: Regression Change-ID: I433e9297207869e43d1a6ee2d621bded2f562656 CRs-Fixed: 2341890 Signed-off-by: Ahmed ElArabawy --- core/hdd/src/wlan_hdd_cfg80211.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/core/hdd/src/wlan_hdd_cfg80211.c b/core/hdd/src/wlan_hdd_cfg80211.c index 03df15028f9f..bb25c1a646df 100644 --- a/core/hdd/src/wlan_hdd_cfg80211.c +++ b/core/hdd/src/wlan_hdd_cfg80211.c @@ -9214,6 +9214,8 @@ static int hdd_validate_avoid_freq_chanlist(hdd_context_t *hdd_ctx, for (ch_idx = channel_list->avoidFreqRange[range_idx].startFreq; ch_idx <= channel_list->avoidFreqRange[range_idx].endFreq; ch_idx++) { + if (INVALID_CHANNEL == cds_get_channel_enum(ch_idx)) + continue; for (unsafe_channel_index = 0; unsafe_channel_index < unsafe_channel_count; unsafe_channel_index++) { From 2be660f14abe76ddc2aa5605832d8e78f9b8c0de Mon Sep 17 00:00:00 2001 From: Yeshwanth Sriram Guntuka Date: Thu, 7 Jun 2018 14:58:29 +0530 Subject: [PATCH 09/28] qcacld-3.0: Fix possible OOB access in lim_process_auth_frame Key id is extracted from data buffer without validating len of data which could result in out of bound access. Fix is to validate frame len before extracting key id from data buffer. Bug: 78528839 Test: Test with provided PoC (before and after the fix) Change-Id: I1f4d88b7ca6201f03a6bc8e6915f1479f571838f CRs-Fixed: 2254141 Signed-off-by: Ahmed ElArabawy --- core/mac/src/pe/lim/lim_process_auth_frame.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/core/mac/src/pe/lim/lim_process_auth_frame.c b/core/mac/src/pe/lim/lim_process_auth_frame.c index eea7cc96a00c..04258ebe797a 100644 --- a/core/mac/src/pe/lim/lim_process_auth_frame.c +++ b/core/mac/src/pe/lim/lim_process_auth_frame.c @@ -1131,6 +1131,11 @@ lim_process_auth_frame(tpAniSirGlobal mac_ctx, uint8_t *rx_pkt_info, body_ptr = WMA_GET_RX_MPDU_DATA(rx_pkt_info); + if (frame_len < 2) { + pe_err("invalid frame len: %d", frame_len); + return; + } + /* Restore default failure timeout */ if (QDF_P2P_CLIENT_MODE == pe_session->pePersona && pe_session->defaultAuthFailureTimeout) { @@ -1176,6 +1181,11 @@ lim_process_auth_frame(tpAniSirGlobal mac_ctx, uint8_t *rx_pkt_info, mac_hdr->sa, pe_session, false); goto free; } + + if (frame_len < 4) { + pe_err("invalid frame len: %d", frame_len); + goto free; + } /* Extract key ID from IV (most 2 bits of 4th byte of IV) */ key_id = (*(body_ptr + 3)) >> 6; From b20c816d3106bc81393456114d4f334cf373e094 Mon Sep 17 00:00:00 2001 From: Pragaspathi Thilagaraj Date: Thu, 25 Oct 2018 19:02:30 +0530 Subject: [PATCH 10/28] qcacld-3.0: Fix OOB read in sme_rrm_process_beacon_report_req_ind When beacon report request action frame is received, rrm_process_beacon_report_req() is called and num_channels value is calculated from the action frame directly from user. This value is assigned to pSmeBcnReportReq->channelList.numChannels and this num channels value along with the channel list is posted to sme for further processing. The sme function sme_rrm_process_beacon_report_req_ind() processes this sme message eWNI_SME_BEACON_REPORT_REQ_IND. In this function, the channels in channel list are looped through the received value pBeaconReq->channelList.numChannels and is copied to the destination pSmeRrmContext->channelList array from the pBeaconReq->channelList.channelNumber[] array. The maximum possible number of channels in channel list BeaconReq->channelList.channelNumber[] allocated statically in the definition of tSirChannelList is SIR_ESE_MAX_MEAS_IE_REQS (8). So when the pBeaconReq->channelList.numChannels, possible OOB read occurs. Validate the value of pBeaconReq->channelList.numChannels received from the action frame against the maximum supported number of channels in channel list SIR_ESE_MAX_MEAS_IE_REQS (8). Place this validation inside the function sme_rrm_process_beacon_report_req_ind() instead of validating it at rrm_process_beacon_report_req() so that it defends from other caller sme_set_ese_beacon_request() which is from user space command through IOCTL. Change-Id: I2074b04081328ceab7eeb29c33631a635e9d93c3 CRs-Fixed: 2335974 Bug: 125677804 Signed-off-by: Srinivas Girigowda --- core/sme/src/rrm/sme_rrm.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/core/sme/src/rrm/sme_rrm.c b/core/sme/src/rrm/sme_rrm.c index 38b756042902..8e7cba1a4e47 100644 --- a/core/sme/src/rrm/sme_rrm.c +++ b/core/sme/src/rrm/sme_rrm.c @@ -845,6 +845,14 @@ QDF_STATUS sme_rrm_process_beacon_report_req_ind(tpAniSirGlobal pMac, sme_debug("Received Beacon report request ind Channel = %d", pBeaconReq->channelInfo.channelNum); + + if (pBeaconReq->channelList.numChannels > + SIR_ESE_MAX_MEAS_IE_REQS) { + sme_err("Beacon report request numChannels:%u exceeds max num channels", + pBeaconReq->channelList.numChannels); + return QDF_STATUS_E_INVAL; + } + /* section 11.10.8.1 (IEEE Std 802.11k-2008) */ /* channel 0 and 255 has special meaning. */ if ((pBeaconReq->channelInfo.channelNum == 0) || From a4a444868654b611cdfc6423d7c061e44da5ac07 Mon Sep 17 00:00:00 2001 From: Sourav Mohapatra Date: Fri, 30 Nov 2018 16:27:05 +0530 Subject: [PATCH 11/28] qcacld-3.0: Validate user input for null termination In hdd_dns_make_name_query() the parameter string is a user controlled input. The driver assumes that the input is null terminated string and accordingly the exit condition of the loop is specified. In case the user sends input with no null termination then it can lead to possible OOB scenario. Add a null termination validation on the string so that any erroneous input is filtered. Change-Id: I2abb4875569c508179c4488347f7c9aae0666332 CRs-Fixed: 2342812 Bug: 125746836 Signed-off-by: Srinivas Girigowda --- core/hdd/src/wlan_hdd_cfg80211.c | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/core/hdd/src/wlan_hdd_cfg80211.c b/core/hdd/src/wlan_hdd_cfg80211.c index bb25c1a646df..68cd1af68add 100644 --- a/core/hdd/src/wlan_hdd_cfg80211.c +++ b/core/hdd/src/wlan_hdd_cfg80211.c @@ -10818,11 +10818,17 @@ static inline uint8_t *hdd_dns_unmake_name_query(uint8_t *name) * * Return: Byte following constructed DNS name */ -static uint8_t *hdd_dns_make_name_query(const uint8_t *string, uint8_t *buf) +static uint8_t *hdd_dns_make_name_query(const uint8_t *string, + uint8_t *buf, uint8_t len) { uint8_t *length_byte = buf++; uint8_t c; + if (string[len - 1]) { + hdd_debug("DNS name is not null terminated"); + return NULL; + } + while ((c = *(string++))) { if (c == '.') { *length_byte = buf - length_byte - 1; @@ -10911,8 +10917,12 @@ static int hdd_set_clear_connectivity_check_stats_info( adapter->track_dns_domain_len = nla_len(tb2[ STATS_DNS_DOMAIN_NAME]); - hdd_dns_make_name_query(domain_name, - adapter->dns_payload); + if (!hdd_dns_make_name_query( + domain_name, + adapter->dns_payload, + adapter->track_dns_domain_len)) + adapter->track_dns_domain_len = + 0; /* DNStracking isn't supported in FW. */ arp_stats_params->pkt_type_bitmap &= ~CONNECTIVITY_CHECK_SET_DNS; From 7bc79a093a1812f6a39f4e5698c5ba79bd258bb1 Mon Sep 17 00:00:00 2001 From: Wu Gao Date: Mon, 16 Jul 2018 09:49:33 +0800 Subject: [PATCH 12/28] qcacld-3.0: Fix potential OOB read when check rx mgmt frames In function is_p2p_action_frame, it just checks frame length with 28, but read 30 bytes actually, and cause OOB read potentially. So, check length with 30. Change-Id: Id2bd4276838f1eae49e8a24e8ab3361a69321a69 CRs-Fixed: 2263727 Bug: 125677805 Signed-off-by: Srinivas Girigowda --- core/hdd/src/wlan_hdd_p2p.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/hdd/src/wlan_hdd_p2p.c b/core/hdd/src/wlan_hdd_p2p.c index 4af5b3c4d8a6..9cdfd01810b4 100644 --- a/core/hdd/src/wlan_hdd_p2p.c +++ b/core/hdd/src/wlan_hdd_p2p.c @@ -3285,8 +3285,8 @@ static inline bool is_public_action_frame(uint8_t *pb_frames, static inline bool is_p2p_action_frame(uint8_t *pb_frames, uint32_t frame_len) { - if (frame_len <= WLAN_HDD_PUBLIC_ACTION_FRAME_OFFSET + - SIR_MAC_P2P_OUI_SIZE) { + if (frame_len <= (WLAN_HDD_PUBLIC_ACTION_FRAME_OFFSET + + SIR_MAC_P2P_OUI_SIZE + 2)) { hdd_debug("Not a p2p action frame len: %d", frame_len); return false; } From 81d3ef5a182cace464e23064c6fee40681cfcded Mon Sep 17 00:00:00 2001 From: Dundi Raviteja Date: Mon, 8 Oct 2018 11:55:00 +0530 Subject: [PATCH 13/28] qcacld-3.0: Possible OOB access in wlan_hdd_cfg80211_start_bss() Currently in function wlan_hdd_cfg80211_start_bss(), copying supported rates and extended rates from information element pointer without checking for array bounds which may cause OOB access. To address this issue, add length checks before copying supported rates and extended rates. Bug: 112432329 Test: Regression Change-Id: Ic6363e97bb3498a5dd23bc5e5f9b9f3ce093509d CRs-Fixed: 2312995 Signed-off-by: Ahmed ElArabawy --- core/hdd/src/wlan_hdd_hostapd.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/core/hdd/src/wlan_hdd_hostapd.c b/core/hdd/src/wlan_hdd_hostapd.c index c78c6676f17b..573057216642 100644 --- a/core/hdd/src/wlan_hdd_hostapd.c +++ b/core/hdd/src/wlan_hdd_hostapd.c @@ -8420,6 +8420,12 @@ int wlan_hdd_cfg80211_start_bss(hdd_adapter_t *pHostapdAdapter, if (pIe != NULL) { pIe++; + if (pIe[0] > SIR_MAC_RATESET_EID_MAX) { + hdd_err("Invalid supported rates %d", + pIe[0]); + ret = -EINVAL; + goto error; + } pConfig->supported_rates.numRates = pIe[0]; pIe++; for (i = 0; @@ -8436,6 +8442,12 @@ int wlan_hdd_cfg80211_start_bss(hdd_adapter_t *pHostapdAdapter, WLAN_EID_EXT_SUPP_RATES); if (pIe != NULL) { pIe++; + if (pIe[0] > SIR_MAC_RATESET_EID_MAX) { + hdd_err("Invalid supported rates %d", + pIe[0]); + ret = -EINVAL; + goto error; + } pConfig->extended_rates.numRates = pIe[0]; pIe++; for (i = 0; i < pConfig->extended_rates.numRates; i++) { From e6b297b46e1d0f53980671f7a6d5c932e77cac1e Mon Sep 17 00:00:00 2001 From: Yu Wang Date: Thu, 13 Sep 2018 16:58:45 +0800 Subject: [PATCH 14/28] qcacld-3.0: check the data length when downloading firmware When downloading a corrupted firmware file that has chunk length in header which doesn't match the contents, buffer over-read may occur. To fix it, before downloading the data, ensure the length is equal or smaller than the left size of the firmware file. Change-Id: I4e0c6c4423f94f26a8c4573b5d234296890f4ecf CRs-Fixed: 2314182 Bug: 128344381 Signed-off-by: Srinivas Girigowda --- core/bmi/src/ol_fw.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/core/bmi/src/ol_fw.c b/core/bmi/src/ol_fw.c index 7d181b290ad5..243b3dbfcf24 100644 --- a/core/bmi/src/ol_fw.c +++ b/core/bmi/src/ol_fw.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014-2017 The Linux Foundation. All rights reserved. + * Copyright (c) 2014-2018 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -376,18 +376,22 @@ __ol_transfer_bin_file(struct ol_context *ol_ctx, enum ATH_BIN_FILE file, || chip_id == AR6320_REV1_3_VERSION || chip_id == AR6320_REV2_1_VERSION)) { + bin_off = sizeof(SIGN_HEADER_T); status = bmi_sign_stream_start(address, (uint8_t *)fw_entry->data, - sizeof(SIGN_HEADER_T), ol_ctx); + bin_off, ol_ctx); if (status != EOK) { BMI_ERR("unable to start sign stream"); status = -EINVAL; goto end; } - bin_off = sizeof(SIGN_HEADER_T); - bin_len = sign_header->rampatch_len - - sizeof(SIGN_HEADER_T); + bin_len = sign_header->rampatch_len - bin_off; + if (bin_len <= 0 || bin_len > fw_entry_size - bin_off) { + BMI_ERR("Invalid sign header"); + status = -EINVAL; + goto end; + } } else { bin_sign = false; bin_off = 0; @@ -418,7 +422,7 @@ __ol_transfer_bin_file(struct ol_context *ol_ctx, enum ATH_BIN_FILE file, bin_off += bin_len; bin_len = sign_header->total_len - sign_header->rampatch_len; - if (bin_len > 0) { + if (bin_len > 0 && bin_len <= fw_entry_size - bin_off) { status = bmi_sign_stream_start(0, (uint8_t *)fw_entry->data + bin_off, bin_len, ol_ctx); From 8fe89814aec6a961ce0fc0b27124eb6e87b9dd62 Mon Sep 17 00:00:00 2001 From: Pragaspathi Thilagaraj Date: Tue, 17 Jul 2018 11:43:18 +0530 Subject: [PATCH 15/28] qcacld-3.0: Fix possible integer underflow in cfg80211_rx_mgmt In the function cfg80211_rx_mgmt, data_len is calculated as len - ieee80211_hdrlen(mgmt->frame_control). Len is not validated before this calculation. So a possible integer underflow will occur if len value is less than the value of ieee80211_hdrlen(mgmt->frame_control). Validate the value of len against ieee80211_hdrlen(mgmt->frame_control) in the caller. Change-Id: Iae776daf37b0c052bd4ce4da44ea728d121eae51 CRs-Fixed: 2263758 Bug: 128343981 Signed-off-by: Srinivas Girigowda --- core/hdd/src/wlan_hdd_main.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/core/hdd/src/wlan_hdd_main.c b/core/hdd/src/wlan_hdd_main.c index 9a22a94015be..8b9e16eb11f6 100644 --- a/core/hdd/src/wlan_hdd_main.c +++ b/core/hdd/src/wlan_hdd_main.c @@ -8301,6 +8301,8 @@ void hdd_indicate_mgmt_frame(tSirSmeMgmtFrameInd *frame_ind) hdd_adapter_t *adapter = NULL; void *cds_context = NULL; int i; + struct ieee80211_mgmt *mgmt = + (struct ieee80211_mgmt *)frame_ind->frameBuf; /* Get the global VOSS context.*/ cds_context = cds_get_global_context(); @@ -8314,6 +8316,11 @@ void hdd_indicate_mgmt_frame(tSirSmeMgmtFrameInd *frame_ind) if (0 != wlan_hdd_validate_context(hdd_ctx)) return; + if (frame_ind->frame_len < ieee80211_hdrlen(mgmt->frame_control)) { + hdd_err(" Invalid frame length"); + return; + } + if (SME_SESSION_ID_ANY == frame_ind->sessionId) { for (i = 0; i < CSR_ROAM_SESSION_MAX; i++) { adapter = From d4b5964cb300db40389099089132af67e0416181 Mon Sep 17 00:00:00 2001 From: Arun Kumar Khandavalli Date: Mon, 4 Mar 2019 14:51:23 +0530 Subject: [PATCH 16/28] qcacld-3.0: Update connect_timeout correctly in case of scan for ssid Incase there is a scan for ssid failure connect_timeout is set to true even when there is no BSSID has been found in the scan result. Set the connect_timeout to false for the cases wherein there is a scan for ssid failure. Change-Id: I822371bbbe2a034b673798b28c993ba53468aa49 CRs-Fixed: 2404646 Bug: 124491207 Signed-off-by: Varun Reddy Yeturu --- core/hdd/src/wlan_hdd_assoc.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/core/hdd/src/wlan_hdd_assoc.c b/core/hdd/src/wlan_hdd_assoc.c index a85844c34cb3..199549c4b75f 100644 --- a/core/hdd/src/wlan_hdd_assoc.c +++ b/core/hdd/src/wlan_hdd_assoc.c @@ -3158,7 +3158,9 @@ static QDF_STATUS hdd_association_completion_handler(hdd_adapter_t *pAdapter, pRoamInfo ? pRoamInfo->bssid.bytes : pWextState->req_bssId.bytes); - connect_timeout = true; + if (roamResult != + eCSR_ROAM_RESULT_SCAN_FOR_SSID_FAILURE) + connect_timeout = true; } /* From 754900c13a8fdc9ef377b9607c27a6d13ff4798c Mon Sep 17 00:00:00 2001 From: Lin Bai Date: Tue, 11 Sep 2018 22:53:28 +0800 Subject: [PATCH 17/28] qcacld-3.0: Check channel_count in DCC_GET_STATS command Invalid channel_count may be sent to driver with QCA_NL80211_VENDOR_SUBCMD_DCC_GET_STATS vendor command, and may also pass the sanity check with get_stats_param->request_array_len as integer overflow, in send_dcc_get_stats_cmd_tlv(). Then it will finally lead to heap overflow when initializing TLV header for each channel. Change-Id: I1d81b5fc4de80829433f2a0ab41c964c41f750c3 CRs-Fixed: 2300516 Bug: 128343982 Signed-off-by: Srinivas Girigowda --- core/hdd/src/wlan_hdd_ocb.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/core/hdd/src/wlan_hdd_ocb.c b/core/hdd/src/wlan_hdd_ocb.c index 3cc55703d8f8..cf46c118be55 100644 --- a/core/hdd/src/wlan_hdd_ocb.c +++ b/core/hdd/src/wlan_hdd_ocb.c @@ -1663,6 +1663,12 @@ static int __wlan_hdd_cfg80211_dcc_get_stats(struct wiphy *wiphy, request_array = nla_data( tb[QCA_WLAN_VENDOR_ATTR_DCC_GET_STATS_REQUEST_ARRAY]); + /* Check channel count. Per 11p spec, max 2 channels allowed */ + if (!channel_count || channel_count > TGT_NUM_OCB_CHANNELS) { + hdd_err("Invalid channel_count %d", channel_count); + return -EINVAL; + } + hdd_request = hdd_request_alloc(¶ms); if (!hdd_request) { hdd_err("Request allocation failure"); From 51239b5b5ebfe62ebad31e9097fcf70ace6b4723 Mon Sep 17 00:00:00 2001 From: Sravan Kumar Kairam Date: Fri, 3 Aug 2018 17:54:21 +0530 Subject: [PATCH 18/28] qcacld-3.0: Do rx inorder replenish for fragmented packets Currently for fragment packets received legacy rx buffer replenish is done which does not take in to account number of msdu count but depends on fill count. Variable fill count is not protected and the value becomes incorrect if AP sends both the fragmented and normal packets at the same time. This leads to rx buffer replenish failure and eventually data stall. To fix this do rx inorder replenish for fragmented packets similar to normal ones if rx full reorder offload is enabled. Change-Id: I144c10be7b45268300b040e07ecb909a1ca113cc CRs-Fixed: 2289797 Bug: 126215098 Signed-off-by: Varun Reddy Yeturu --- core/dp/ol/inc/ol_htt_rx_api.h | 6 ++++++ core/dp/txrx/ol_rx_defrag.c | 29 ++++++++++++++++++++++++++++- 2 files changed, 34 insertions(+), 1 deletion(-) diff --git a/core/dp/ol/inc/ol_htt_rx_api.h b/core/dp/ol/inc/ol_htt_rx_api.h index 950751aa9f4e..85dd80954b9f 100644 --- a/core/dp/ol/inc/ol_htt_rx_api.h +++ b/core/dp/ol/inc/ol_htt_rx_api.h @@ -815,6 +815,12 @@ void htt_rx_msdu_buff_replenish(htt_pdev_handle pdev); * Return: number of buffers actually replenished */ int htt_rx_msdu_buff_in_order_replenish(htt_pdev_handle pdev, uint32_t num); +#else +static inline +int htt_rx_msdu_buff_in_order_replenish(htt_pdev_handle pdev, uint32_t num) +{ + return 0; +} #endif /** diff --git a/core/dp/txrx/ol_rx_defrag.c b/core/dp/txrx/ol_rx_defrag.c index 4496b21eabbf..60ec62624669 100644 --- a/core/dp/txrx/ol_rx_defrag.c +++ b/core/dp/txrx/ol_rx_defrag.c @@ -316,6 +316,26 @@ void ol_rx_frag_send_pktlog_event(struct ol_txrx_pdev_t *pdev, #endif +#ifndef CONFIG_HL_SUPPORT +static int ol_rx_frag_get_inord_msdu_cnt(qdf_nbuf_t rx_ind_msg) +{ + uint32_t *msg_word; + uint8_t *rx_ind_data; + uint32_t msdu_cnt; + + rx_ind_data = qdf_nbuf_data(rx_ind_msg); + msg_word = (uint32_t *)rx_ind_data; + msdu_cnt = HTT_RX_IN_ORD_PADDR_IND_MSDU_CNT_GET(*(msg_word + 1)); + + return msdu_cnt; +} +#else +static int ol_rx_frag_get_inord_msdu_cnt(qdf_nbuf_t rx_ind_msg) +{ + return 0; +} +#endif + /* * Process incoming fragments */ @@ -353,7 +373,10 @@ ol_rx_frag_indication_handler(ol_txrx_pdev_handle pdev, * separate from normal frames */ ol_rx_reorder_flush_frag(htt_pdev, peer, tid, seq_num_start); + } else { + msdu_count = ol_rx_frag_get_inord_msdu_cnt(rx_frag_ind_msg); } + pktlog_bit = (htt_rx_amsdu_rx_in_order_get_pktlog(rx_frag_ind_msg) == 0x01); ret = htt_rx_frag_pop(htt_pdev, rx_frag_ind_msg, &head_msdu, @@ -389,7 +412,11 @@ ol_rx_frag_indication_handler(ol_txrx_pdev_handle pdev, htt_rx_desc_frame_free(htt_pdev, head_msdu); } /* request HTT to provide new rx MSDU buffers for the target to fill. */ - htt_rx_msdu_buff_replenish(htt_pdev); + if (ol_cfg_is_full_reorder_offload(pdev->ctrl_pdev) && + !pdev->cfg.is_high_latency) + htt_rx_msdu_buff_in_order_replenish(htt_pdev, msdu_count); + else + htt_rx_msdu_buff_replenish(htt_pdev); } /* From 8678b9b107657257bd4ccd645ba50eabea86374c Mon Sep 17 00:00:00 2001 From: Yeshwanth Sriram Guntuka Date: Mon, 11 Feb 2019 18:56:05 +0530 Subject: [PATCH 19/28] qcacld-3.0: Do not add MME for bcast non RMF action frames MME is added to broadcast DPP public action frame sent by initiator which results in DPP authentication failure. Fix is to add MME only for broadcast Robust Managemnt Action frames. Change-Id: Ie225a0d0197f61209acd4e5a482dcc20ec5e7a16 CRs-Fixed: 2397136 Bug: 123957145 Signed-off-by: Srinivas Girigowda --- core/wma/src/wma_data.c | 44 +++++++++++++++++++++++++++++++++++++++-- 1 file changed, 42 insertions(+), 2 deletions(-) diff --git a/core/wma/src/wma_data.c b/core/wma/src/wma_data.c index 6037f0872f59..ce3aedc5d967 100644 --- a/core/wma/src/wma_data.c +++ b/core/wma/src/wma_data.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013-2018 The Linux Foundation. All rights reserved. + * Copyright (c) 2013-2019 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -2579,6 +2579,37 @@ static void wma_update_tx_send_params(struct tx_send_params *tx_param, tx_param->preamble_type); } +/** + * wma_is_rmf_mgmt_action_frame() - check RMF action frame by category + * @action_category: action frame actegory + * + * This function check the frame is robust mgmt action frame or not + * + * Return: true - if category is robust mgmt type + */ +static bool wma_is_rmf_mgmt_action_frame(uint8_t action_category) +{ + switch (action_category) { + case SIR_MAC_ACTION_SPECTRUM_MGMT: + case SIR_MAC_ACTION_QOS_MGMT: + case SIR_MAC_ACTION_DLP: + case SIR_MAC_ACTION_BLKACK: + case SIR_MAC_ACTION_RRM: + case SIR_MAC_ACTION_FAST_BSS_TRNST: + case SIR_MAC_ACTION_SA_QUERY: + case SIR_MAC_ACTION_PROT_DUAL_PUB: + case SIR_MAC_ACTION_WNM: + case SIR_MAC_ACITON_MESH: + case SIR_MAC_ACTION_MHF: + case SIR_MAC_ACTION_FST: + return true; + default: + break; + } + return false; + +} + /** * wma_tx_packet() - Sends Tx Frame to TxRx * @wma_context: wma context @@ -2620,6 +2651,8 @@ QDF_STATUS wma_tx_packet(void *wma_context, void *tx_frame, uint16_t frmLen, uint8_t *pFrame = NULL; void *pPacket = NULL; uint16_t newFrmLen = 0; + uint8_t action_category = 0; + bool deauth_disassoc = false; #endif /* WLAN_FEATURE_11W */ struct wma_txrx_node *iface; tpAniSirGlobal pMac; @@ -2676,6 +2709,12 @@ QDF_STATUS wma_tx_packet(void *wma_context, void *tx_frame, uint16_t frmLen, pFc->subType == SIR_MAC_MGMT_ACTION)) { struct ieee80211_frame *wh = (struct ieee80211_frame *)qdf_nbuf_data(tx_frame); + if (pFc->subType == SIR_MAC_MGMT_ACTION) + action_category = + *((uint8_t *)(qdf_nbuf_data(tx_frame)) + + sizeof(struct ieee80211_frame)); + else + deauth_disassoc = true; if (!IEEE80211_IS_BROADCAST(wh->i_addr1) && !IEEE80211_IS_MULTICAST(wh->i_addr1)) { if (pFc->wep) { @@ -2717,7 +2756,8 @@ QDF_STATUS wma_tx_packet(void *wma_context, void *tx_frame, uint16_t frmLen, pFc = (tpSirMacFrameCtl) (qdf_nbuf_data(tx_frame)); } - } else { + } else if (deauth_disassoc || + wma_is_rmf_mgmt_action_frame(action_category)) { /* Allocate extra bytes for MMIE */ newFrmLen = frmLen + IEEE80211_MMIE_LEN; qdf_status = cds_packet_alloc((uint16_t) newFrmLen, From a852e1cb33318f2ce6af98499f07f829a742c9d9 Mon Sep 17 00:00:00 2001 From: Ashish Kumar Dhanotiya Date: Wed, 20 Feb 2019 22:13:25 +0530 Subject: [PATCH 20/28] qcacld-3.0: Clear PMK cache from driver Currently PMK cache is not getting cleared inside driver, which can lead to information disclosure. To address this issue, clear PMK information from all the possible places in the driver. Change-Id: I83758920f414c5287292ebdbebdcc9bf7238103c CRs-Fixed: 2403441 Bug: 123907624 Signed-off-by: Srinivas Girigowda --- core/hdd/src/wlan_hdd_cfg80211.c | 6 ++++++ core/hdd/src/wlan_hdd_main.c | 8 +++++++- core/sme/src/common/sme_api.c | 4 +++- core/sme/src/csr/csr_api_roam.c | 2 ++ core/sme/src/csr/csr_util.c | 1 + core/wma/src/wma_main.c | 6 ++++-- 6 files changed, 23 insertions(+), 4 deletions(-) diff --git a/core/hdd/src/wlan_hdd_cfg80211.c b/core/hdd/src/wlan_hdd_cfg80211.c index 68cd1af68add..52ca6f53cab5 100644 --- a/core/hdd/src/wlan_hdd_cfg80211.c +++ b/core/hdd/src/wlan_hdd_cfg80211.c @@ -4930,6 +4930,8 @@ static int __wlan_hdd_cfg80211_keymgmt_set_key(struct wiphy *wiphy, qdf_mem_copy(local_pmk, data, data_len); sme_roam_set_psk_pmk(WLAN_HDD_GET_HAL_CTX(hdd_adapter_ptr), hdd_adapter_ptr->sessionId, local_pmk, data_len); + qdf_mem_zero(&local_pmk, SIR_ROAM_SCAN_PSK_SIZE); + return 0; } @@ -20005,6 +20007,8 @@ static int __wlan_hdd_cfg80211_set_pmksa(struct wiphy *wiphy, sme_set_del_pmkid_cache(halHandle, pAdapter->sessionId, &pmk_cache, true); + qdf_mem_zero(&pmk_cache, sizeof(pmk_cache)); + EXIT(); return QDF_IS_STATUS_SUCCESS(result) ? 0 : -EINVAL; } @@ -20095,6 +20099,8 @@ static int __wlan_hdd_cfg80211_del_pmksa(struct wiphy *wiphy, sme_set_del_pmkid_cache(halHandle, pAdapter->sessionId, &pmk_cache, false); + qdf_mem_zero(&pmk_cache, sizeof(pmk_cache)); + EXIT(); return status; } diff --git a/core/hdd/src/wlan_hdd_main.c b/core/hdd/src/wlan_hdd_main.c index 8b9e16eb11f6..7dfa84c7fdb2 100644 --- a/core/hdd/src/wlan_hdd_main.c +++ b/core/hdd/src/wlan_hdd_main.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2018 The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2019 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -4679,6 +4679,12 @@ QDF_STATUS hdd_stop_adapter(hdd_context_t *hdd_ctx, hdd_adapter_t *adapter, wlan_hdd_tdls_exit(adapter); wlan_hdd_cleanup_remain_on_channel_ctx(adapter); hdd_clear_fils_connection_info(adapter); + qdf_ret_status = sme_roam_del_pmkid_from_cache( + hdd_ctx->hHal, + adapter->sessionId, + NULL, true); + if (QDF_IS_STATUS_ERROR(qdf_ret_status)) + hdd_err("Cannot flush PMKIDCache"); #ifdef WLAN_OPEN_SOURCE cancel_work_sync(&adapter->ipv4NotifierWorkQueue); diff --git a/core/sme/src/common/sme_api.c b/core/sme/src/common/sme_api.c index 2863ea3f99f0..af088da524d6 100644 --- a/core/sme/src/common/sme_api.c +++ b/core/sme/src/common/sme_api.c @@ -18380,8 +18380,10 @@ QDF_STATUS sme_set_del_pmkid_cache(tHalHandle hal, uint8_t session_id, cds_mq_post_message(QDF_MODULE_ID_WMA, &msg)) { sme_err("Not able to post message to WDA"); - if (pmk_cache) + if (pmk_cache) { + qdf_mem_zero(pmk_cache, sizeof(*pmk_cache)); qdf_mem_free(pmk_cache); + } return QDF_STATUS_E_FAILURE; } diff --git a/core/sme/src/csr/csr_api_roam.c b/core/sme/src/csr/csr_api_roam.c index 4ff87dc2ee1f..7ccfc325d886 100644 --- a/core/sme/src/csr/csr_api_roam.c +++ b/core/sme/src/csr/csr_api_roam.c @@ -14500,6 +14500,8 @@ QDF_STATUS csr_roam_del_pmkid_from_cache(tpAniSirGlobal pMac, sizeof(tPmkidCacheInfo) * CSR_MAX_PMKID_ALLOWED); pSession->NumPmkidCache = 0; pSession->curr_cache_idx = 0; + qdf_mem_zero(pSession->psk_pmk, sizeof(pSession->psk_pmk)); + pSession->pmk_len = 0; return QDF_STATUS_SUCCESS; } diff --git a/core/sme/src/csr/csr_util.c b/core/sme/src/csr/csr_util.c index 6820c8945bc1..a3f12e474243 100644 --- a/core/sme/src/csr/csr_util.c +++ b/core/sme/src/csr/csr_util.c @@ -3756,6 +3756,7 @@ uint8_t csr_construct_rsn_ie(tHalHandle hHal, uint32_t sessionId, } else { pPMK->cPMKIDs = 0; } + qdf_mem_zero(&pmkid_cache, sizeof(pmkid_cache)); #ifdef WLAN_FEATURE_11W /* Advertise BIP in group cipher key management only if PMF is diff --git a/core/wma/src/wma_main.c b/core/wma/src/wma_main.c index 5a71b110673b..fb546c0b22a4 100644 --- a/core/wma/src/wma_main.c +++ b/core/wma/src/wma_main.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013-2018 The Linux Foundation. All rights reserved. + * Copyright (c) 2013-2019 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -8304,8 +8304,10 @@ QDF_STATUS wma_mc_process_msg(void *cds_context, cds_msg_t *msg) case SIR_HAL_SET_DEL_PMKID_CACHE: wma_set_del_pmkid_cache(wma_handle, (wmi_pmk_cache *) msg->bodyptr, msg->reserved); - if (msg->bodyptr) + if (msg->bodyptr) { + qdf_mem_zero(msg->bodyptr, sizeof(wmi_pmk_cache)); qdf_mem_free(msg->bodyptr); + } break; case SIR_HAL_HLP_IE_INFO: wma_roam_scan_send_hlp(wma_handle, From 637f12ca9d6d27d3147e6b2f11cd700207afcd03 Mon Sep 17 00:00:00 2001 From: Varun Reddy Yeturu Date: Tue, 12 Feb 2019 17:27:26 -0800 Subject: [PATCH 21/28] qcacld-3.0: Clear PTK, GTK and IGTK keys on sta disconnection Currently PTK, GTK and IGTK keys are not getting cleared on wifi link disconnection from wifi driver memory, which can lead to information disclosure. Clear PTK, GTK and IGTK keys from wifi driver memory to avoid any potential information disclore after wifi is turned off. Change-Id: I309cd7af8d396167e9ec3ef9c6c443e8c08903d8 CRs-Fixed: 2396603 Bug: 123907624 Signed-off-by: Srinivas Girigowda --- core/hdd/src/wlan_hdd_assoc.c | 7 ++++++- core/hdd/src/wlan_hdd_cfg80211.c | 9 +++++++++ core/hdd/src/wlan_hdd_wext.c | 5 ++++- .../src/pe/lim/lim_process_mlm_req_messages.c | 7 ++++++- .../src/pe/lim/lim_process_mlm_rsp_messages.c | 5 ++++- .../src/pe/lim/lim_process_sme_req_messages.c | 6 +++++- core/mac/src/pe/lim/lim_security_utils.c | 2 ++ core/mac/src/pe/lim/lim_session.c | 5 ++++- core/sme/inc/sme_ft_api.h | 11 +++++++++- core/sme/src/common/sme_ft_api.c | 20 ++++++++++++++++++- core/sme/src/csr/csr_api_roam.c | 19 ++++++++++++++++++ core/wma/src/wma_dev_if.c | 15 +++++++++++++- 12 files changed, 102 insertions(+), 9 deletions(-) diff --git a/core/hdd/src/wlan_hdd_assoc.c b/core/hdd/src/wlan_hdd_assoc.c index 199549c4b75f..88f7481e0231 100644 --- a/core/hdd/src/wlan_hdd_assoc.c +++ b/core/hdd/src/wlan_hdd_assoc.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2018 The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2019 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -949,6 +949,8 @@ static void hdd_save_bss_info(hdd_adapter_t *adapter, } else { hdd_sta_ctx->conn_info.conn_flag.vht_op_present = false; } + qdf_mem_zero(&hdd_sta_ctx->ibss_enc_key, + sizeof(hdd_sta_ctx->ibss_enc_key)); } /** @@ -1754,6 +1756,7 @@ static QDF_STATUS hdd_dis_connect_handler(hdd_adapter_t *pAdapter, hdd_wmm_adapter_clear(pAdapter); sme_ft_reset(WLAN_HDD_GET_HAL_CTX(pAdapter), pAdapter->sessionId); + sme_reset_key(WLAN_HDD_GET_HAL_CTX(pAdapter), pAdapter->sessionId); if (hdd_remove_beacon_filter(pAdapter) != 0) hdd_err("hdd_remove_beacon_filter() failed"); @@ -3234,6 +3237,8 @@ static QDF_STATUS hdd_association_completion_handler(hdd_adapter_t *pAdapter, timeout_reason); } hdd_clear_roam_profile_ie(pAdapter); + sme_reset_key(WLAN_HDD_GET_HAL_CTX(pAdapter), + pAdapter->sessionId); } else if ((eCSR_ROAM_CANCELLED == roamStatus && !hddDisconInProgress)) { hdd_connect_result(dev, diff --git a/core/hdd/src/wlan_hdd_cfg80211.c b/core/hdd/src/wlan_hdd_cfg80211.c index 52ca6f53cab5..5d5bd94aac42 100644 --- a/core/hdd/src/wlan_hdd_cfg80211.c +++ b/core/hdd/src/wlan_hdd_cfg80211.c @@ -15413,6 +15413,7 @@ static int __wlan_hdd_cfg80211_add_key(struct wiphy *wiphy, default: hdd_err("Unsupported cipher type: %u", params->cipher); + qdf_mem_zero(&setKey, sizeof(tCsrRoamSetKey)); return -EOPNOTSUPP; } @@ -15433,6 +15434,7 @@ static int __wlan_hdd_cfg80211_add_key(struct wiphy *wiphy, /* if a key is already installed, block all subsequent ones */ if (pAdapter->sessionCtx.station.ibss_enc_key_installed) { hdd_debug("IBSS key installed already"); + qdf_mem_zero(&setKey, sizeof(tCsrRoamSetKey)); return 0; } @@ -15443,6 +15445,7 @@ static int __wlan_hdd_cfg80211_add_key(struct wiphy *wiphy, if (0 != status) { hdd_err("sme_roam_set_key failed, status: %d", status); + qdf_mem_zero(&setKey, sizeof(tCsrRoamSetKey)); return -EINVAL; } /*Save the keys here and call sme_roam_set_key for setting @@ -15451,6 +15454,7 @@ static int __wlan_hdd_cfg80211_add_key(struct wiphy *wiphy, &setKey, sizeof(tCsrRoamSetKey)); pAdapter->sessionCtx.station.ibss_enc_key_installed = 1; + qdf_mem_zero(&setKey, sizeof(tCsrRoamSetKey)); return status; } if ((pAdapter->device_mode == QDF_SAP_MODE) || @@ -15513,9 +15517,11 @@ static int __wlan_hdd_cfg80211_add_key(struct wiphy *wiphy, pAdapter->sessionId, &setKey); if (qdf_ret_status == QDF_STATUS_FT_PREAUTH_KEY_SUCCESS) { hdd_debug("Update PreAuth Key success"); + qdf_mem_zero(&setKey, sizeof(tCsrRoamSetKey)); return 0; } else if (qdf_ret_status == QDF_STATUS_FT_PREAUTH_KEY_FAILED) { hdd_err("Update PreAuth Key failed"); + qdf_mem_zero(&setKey, sizeof(tCsrRoamSetKey)); return -EINVAL; } @@ -15527,6 +15533,7 @@ static int __wlan_hdd_cfg80211_add_key(struct wiphy *wiphy, hdd_err("sme_roam_set_key failed, status: %d", status); pHddStaCtx->roam_info.roamingState = HDD_ROAM_STATE_NONE; + qdf_mem_zero(&setKey, sizeof(tCsrRoamSetKey)); return -EINVAL; } @@ -15560,10 +15567,12 @@ static int __wlan_hdd_cfg80211_add_key(struct wiphy *wiphy, hdd_err("sme_roam_set_key failed for group key (IBSS), returned %d", status); pHddStaCtx->roam_info.roamingState = HDD_ROAM_STATE_NONE; + qdf_mem_zero(&setKey, sizeof(tCsrRoamSetKey)); return -EINVAL; } } } + qdf_mem_zero(&setKey, sizeof(tCsrRoamSetKey)); EXIT(); return 0; } diff --git a/core/hdd/src/wlan_hdd_wext.c b/core/hdd/src/wlan_hdd_wext.c index 70c554683f2c..8a451d8c65ea 100644 --- a/core/hdd/src/wlan_hdd_wext.c +++ b/core/hdd/src/wlan_hdd_wext.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011-2018 The Linux Foundation. All rights reserved. + * Copyright (c) 2011-2019 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -4051,6 +4051,9 @@ void hdd_clear_roam_profile_ie(hdd_adapter_t *pAdapter) qdf_mem_zero(pWextState->roamProfile.Keys.KeyLength, CSR_MAX_NUM_KEY); + qdf_mem_zero(pWextState->roamProfile.Keys.KeyMaterial, + sizeof(pWextState->roamProfile.Keys.KeyMaterial)); + #ifdef FEATURE_WLAN_WAPI pAdapter->wapi_info.wapiAuthMode = WAPI_AUTH_MODE_OPEN; pAdapter->wapi_info.nWapiMode = 0; diff --git a/core/mac/src/pe/lim/lim_process_mlm_req_messages.c b/core/mac/src/pe/lim/lim_process_mlm_req_messages.c index 7f44b876022e..2bcb5409ad86 100644 --- a/core/mac/src/pe/lim/lim_process_mlm_req_messages.c +++ b/core/mac/src/pe/lim/lim_process_mlm_req_messages.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011-2018 The Linux Foundation. All rights reserved. + * Copyright (c) 2011-2019 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -2091,6 +2091,7 @@ lim_process_mlm_set_keys_req(tpAniSirGlobal mac_ctx, uint32_t *msg_buf) mlm_set_keys_req->sessionId); if (NULL == session) { pe_err("session does not exist for given sessionId"); + qdf_mem_zero(mlm_set_keys_req, sizeof(tLimMlmSetKeysReq)); qdf_mem_free(mlm_set_keys_req); mac_ctx->lim.gpLimMlmSetKeysReq = NULL; return; @@ -2228,6 +2229,8 @@ lim_process_mlm_set_keys_req(tpAniSirGlobal mac_ctx, uint32_t *msg_buf) session->peSessionId); /* Package WMA_SET_BSSKEY_REQ message parameters */ lim_send_set_bss_key_req(mac_ctx, mlm_set_keys_req, session); + + qdf_mem_zero(mlm_set_keys_req, sizeof(tLimMlmSetKeysReq)); return; } else { /* @@ -2237,11 +2240,13 @@ lim_process_mlm_set_keys_req(tpAniSirGlobal mac_ctx, uint32_t *msg_buf) lim_send_set_sta_key_req(mac_ctx, mlm_set_keys_req, sta_idx, (uint8_t) default_key_id, session, true); + qdf_mem_zero(mlm_set_keys_req, sizeof(tLimMlmSetKeysReq)); return; } end: mlm_set_keys_cnf.sessionId = mlm_set_keys_req->sessionId; lim_post_sme_set_keys_cnf(mac_ctx, mlm_set_keys_req, &mlm_set_keys_cnf); + qdf_mem_zero(mlm_set_keys_req, sizeof(tLimMlmSetKeysReq)); } /** diff --git a/core/mac/src/pe/lim/lim_process_mlm_rsp_messages.c b/core/mac/src/pe/lim/lim_process_mlm_rsp_messages.c index 6b9b5b65a882..20207f6315cc 100644 --- a/core/mac/src/pe/lim/lim_process_mlm_rsp_messages.c +++ b/core/mac/src/pe/lim/lim_process_mlm_rsp_messages.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2018 The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2019 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -2722,6 +2722,7 @@ void lim_process_mlm_set_sta_key_rsp(tpAniSirGlobal mac_ctx, session_entry = pe_find_session_by_session_id(mac_ctx, session_id); if (session_entry == NULL) { pe_err("session does not exist for given session_id"); + qdf_mem_zero(msg->bodyptr, sizeof(tSetBssKeyParams)); qdf_mem_free(msg->bodyptr); msg->bodyptr = NULL; lim_send_sme_set_context_rsp(mac_ctx, @@ -2747,6 +2748,7 @@ void lim_process_mlm_set_sta_key_rsp(tpAniSirGlobal mac_ctx, else mlm_set_key_cnf.key_len_nonzero = false; + qdf_mem_zero(msg->bodyptr, sizeof(tSetBssKeyParams)); qdf_mem_free(msg->bodyptr); msg->bodyptr = NULL; @@ -2844,6 +2846,7 @@ void lim_process_mlm_set_bss_key_rsp(tpAniSirGlobal mac_ctx, set_key_cnf.resultCode = result_status; } + qdf_mem_zero(msg->bodyptr, sizeof(tSetBssKeyParams)); qdf_mem_free(msg->bodyptr); msg->bodyptr = NULL; /* Restore MLME state */ diff --git a/core/mac/src/pe/lim/lim_process_sme_req_messages.c b/core/mac/src/pe/lim/lim_process_sme_req_messages.c index c0dd14f0921e..15ff763f5f9d 100644 --- a/core/mac/src/pe/lim/lim_process_sme_req_messages.c +++ b/core/mac/src/pe/lim/lim_process_sme_req_messages.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2018 The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2019 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -2962,6 +2962,9 @@ __lim_process_sme_set_context_req(tpAniSirGlobal mac_ctx, uint32_t *msg_buf) } qdf_mem_copy(set_context_req, msg_buf, sizeof(struct sSirSmeSetContextReq)); + + qdf_mem_zero(msg_buf, sizeof(tSirSmeSetContextReq)); + sme_session_id = set_context_req->sessionId; sme_transaction_id = set_context_req->transactionId; @@ -3069,6 +3072,7 @@ __lim_process_sme_set_context_req(tpAniSirGlobal mac_ctx, uint32_t *msg_buf) sme_transaction_id); } end: + qdf_mem_zero(set_context_req, sizeof(tSirSmeSetContextReq)); qdf_mem_free(set_context_req); return; } diff --git a/core/mac/src/pe/lim/lim_security_utils.c b/core/mac/src/pe/lim/lim_security_utils.c index 6e2c75e1c347..1d4f723e1569 100644 --- a/core/mac/src/pe/lim/lim_security_utils.c +++ b/core/mac/src/pe/lim/lim_security_utils.c @@ -758,6 +758,7 @@ void lim_post_sme_set_keys_cnf(tpAniSirGlobal pMac, &pMlmSetKeysReq->peer_macaddr); /* Free up buffer allocated for mlmSetKeysReq */ + qdf_mem_zero(pMlmSetKeysReq, sizeof(tLimMlmSetKeysReq)); qdf_mem_free(pMlmSetKeysReq); pMac->lim.gpLimMlmSetKeysReq = NULL; @@ -1034,6 +1035,7 @@ void lim_send_set_sta_key_req(tpAniSirGlobal pMac, return; /* Continue after WMA_SET_STAKEY_RSP... */ free_sta_key: + qdf_mem_zero(pSetStaKeyParams, sizeof(tSetStaKeyParams)); qdf_mem_free(pSetStaKeyParams); fail: /* Respond to SME with LIM_MLM_SETKEYS_CNF */ diff --git a/core/mac/src/pe/lim/lim_session.c b/core/mac/src/pe/lim/lim_session.c index 70865f2fa58b..97748c81bbd8 100644 --- a/core/mac/src/pe/lim/lim_session.c +++ b/core/mac/src/pe/lim/lim_session.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011-2018 The Linux Foundation. All rights reserved. + * Copyright (c) 2011-2019 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -839,6 +839,9 @@ void pe_delete_session(tpAniSirGlobal mac_ctx, tpPESession session) pe_delete_fils_info(session); session->valid = false; + qdf_mem_zero(session->WEPKeyMaterial, + sizeof(session->WEPKeyMaterial)); + if (session->access_policy_vendor_ie) qdf_mem_free(session->access_policy_vendor_ie); diff --git a/core/sme/inc/sme_ft_api.h b/core/sme/inc/sme_ft_api.h index 3b0ff3aaf19c..09ba3357a7c0 100644 --- a/core/sme/inc/sme_ft_api.h +++ b/core/sme/inc/sme_ft_api.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013-2016 The Linux Foundation. All rights reserved. + * Copyright (c) 2013-2016,2019 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -94,6 +94,15 @@ void sme_get_ft_pre_auth_response(tHalHandle hHal, uint32_t sessionId, uint16_t *ft_ies_length); void sme_get_rici_es(tHalHandle hHal, uint32_t sessionId, uint8_t *ric_ies, uint32_t ric_ies_ip_len, uint32_t *ric_ies_length); +/** + * sme_reset_key() -Reset key information + * @mac_handle: MAC handle + * @vdev_id: vdev identifier + * + * Return: None + */ +void sme_reset_key(tHalHandle mac_handle, uint32_t vdev_id); + void sme_preauth_reassoc_intvl_timer_callback(void *context); void sme_set_ft_pre_auth_state(tHalHandle hHal, uint32_t sessionId, bool state); bool sme_get_ft_pre_auth_state(tHalHandle hHal, uint32_t sessionId); diff --git a/core/sme/src/common/sme_ft_api.c b/core/sme/src/common/sme_ft_api.c index bbfcaf1b1bd6..325dad5e3929 100644 --- a/core/sme/src/common/sme_ft_api.c +++ b/core/sme/src/common/sme_ft_api.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2017 The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2017,2019 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -480,6 +480,24 @@ void sme_preauth_reassoc_intvl_timer_callback(void *context) pUsrCtx->sessionId); } +void sme_reset_key(tHalHandle mac_handle, uint32_t vdev_id) +{ + tpAniSirGlobal mac = PMAC_STRUCT(mac_handle); + tCsrRoamSession *session = NULL; + + if (!mac) { + sme_err("mac is NULL"); + return; + } + + session = CSR_GET_SESSION(mac, vdev_id); + if (!session) + return; + qdf_mem_zero(&session->psk_pmk, sizeof(session->psk_pmk)); + session->pmk_len = 0; + qdf_mem_zero(&session->eseCckmInfo, sizeof(session->eseCckmInfo)); +} + /* Reset the FT context. */ void sme_ft_reset(tHalHandle hHal, uint32_t sessionId) { diff --git a/core/sme/src/csr/csr_api_roam.c b/core/sme/src/csr/csr_api_roam.c index 7ccfc325d886..afbd3782337e 100644 --- a/core/sme/src/csr/csr_api_roam.c +++ b/core/sme/src/csr/csr_api_roam.c @@ -4700,6 +4700,23 @@ static QDF_STATUS csr_roam_get_qos_info_from_bss(tpAniSirGlobal pMac, return status; } +static void csr_reset_cfg_privacy(tpAniSirGlobal pMac) +{ + uint8_t Key0[WNI_CFG_WEP_DEFAULT_KEY_1_LEN] = {0}; + uint8_t Key1[WNI_CFG_WEP_DEFAULT_KEY_2_LEN] = {0}; + uint8_t Key2[WNI_CFG_WEP_DEFAULT_KEY_3_LEN] = {0}; + uint8_t Key3[WNI_CFG_WEP_DEFAULT_KEY_4_LEN] = {0}; + + cfg_set_int(pMac, WNI_CFG_PRIVACY_ENABLED, 0); + cfg_set_int(pMac, WNI_CFG_RSN_ENABLED, 0); + cfg_set_str(pMac, WNI_CFG_WEP_DEFAULT_KEY_1, Key0, 0); + cfg_set_str(pMac, WNI_CFG_WEP_DEFAULT_KEY_2, Key1, 0); + cfg_set_str(pMac, WNI_CFG_WEP_DEFAULT_KEY_3, Key2, 0); + cfg_set_str(pMac, WNI_CFG_WEP_DEFAULT_KEY_4, Key3, 0); + cfg_set_int(pMac, WNI_CFG_WEP_KEY_LENGTH, 0); + cfg_set_int(pMac, WNI_CFG_WEP_DEFAULT_KEYID, 0); +} + void csr_set_cfg_privacy(tpAniSirGlobal pMac, tCsrRoamProfile *pProfile, bool fPrivacy) { @@ -17296,6 +17313,8 @@ void csr_cleanup_session(tpAniSirGlobal pMac, uint32_t sessionId) /* Clean up FT related data structures */ sme_ft_close(pMac, sessionId); + sme_reset_key((tHalHandle)pMac, sessionId); + csr_reset_cfg_privacy(pMac); csr_free_connect_bss_desc(pMac, sessionId); csr_roam_free_connect_profile(&pSession->connectedProfile); csr_roam_free_connected_info(pMac, &pSession->connectedInfo); diff --git a/core/wma/src/wma_dev_if.c b/core/wma/src/wma_dev_if.c index 3b2da0866420..56d4542cead2 100644 --- a/core/wma/src/wma_dev_if.c +++ b/core/wma/src/wma_dev_if.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013-2018 The Linux Foundation. All rights reserved. + * Copyright (c) 2013-2019 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -1881,6 +1881,17 @@ wma_remove_peer_by_reference(ol_txrx_pdev_handle pdev, return status; } +#ifdef WLAN_FEATURE_11W +static void wma_clear_iface_key(struct wma_txrx_node *iface) +{ + qdf_mem_zero(&iface->key, sizeof(iface->key)); +} +#else +static void wma_clear_iface_key(struct wma_txrx_node *iface) +{ +} +#endif + /** * wma_vdev_stop_resp_handler() - vdev stop response handler * @handle: wma handle @@ -1932,6 +1943,8 @@ int wma_vdev_stop_resp_handler(void *handle, uint8_t *cmd_param_info, resp_event->vdev_id); } + /* Clear key information */ + wma_clear_iface_key(iface); wma_release_wakelock(&iface->vdev_stop_wakelock); req_msg = wma_find_vdev_req(wma, resp_event->vdev_id, From 7f05e5396c089c9fbdb5171feb23a355eeddfa52 Mon Sep 17 00:00:00 2001 From: gaurank kathpalia Date: Thu, 7 Mar 2019 20:25:28 +0530 Subject: [PATCH 22/28] qcacld-3.0: Clear Key information from driver memory after disconnect Currently the key information i.e the key, and the number of keys are not getting cleared on wifi link disconnection from wifi driver memory, which can lead to information disclosure. Clear the key information i.e the number of keys and keys from wifi driver memory to avoid any potential information disclore after wifi is turned off. Change-Id: I45306e0d648c500f63f723b4e3ccb6098c055158 CRs-Fixed: 2637541 Bug: 123907624 Signed-off-by: Varun Reddy Yeturu --- core/mac/src/pe/lim/lim_api.c | 4 +++- .../src/pe/lim/lim_process_mlm_req_messages.c | 6 ++---- .../src/pe/lim/lim_process_mlm_rsp_messages.c | 9 +++++++-- .../src/pe/lim/lim_process_sme_req_messages.c | 2 ++ core/mac/src/pe/lim/lim_security_utils.c | 2 ++ core/sme/src/common/sme_api.c | 1 + core/sme/src/csr/csr_api_roam.c | 16 +++++++++++----- core/wma/src/wma_mgmt.c | 6 +++++- core/wma/src/wma_scan_roam.c | 6 +++++- 9 files changed, 38 insertions(+), 14 deletions(-) diff --git a/core/mac/src/pe/lim/lim_api.c b/core/mac/src/pe/lim/lim_api.c index f0cc82b8544e..5a7f43ce601e 100644 --- a/core/mac/src/pe/lim/lim_api.c +++ b/core/mac/src/pe/lim/lim_api.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011-2018 The Linux Foundation. All rights reserved. + * Copyright (c) 2011-2019 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -615,6 +615,8 @@ void lim_cleanup(tpAniSirGlobal pMac) } if (pMac->lim.gpLimMlmSetKeysReq != NULL) { + qdf_mem_zero(pMac->lim.gpLimMlmSetKeysReq, + sizeof(tLimMlmSetKeysReq)); qdf_mem_free(pMac->lim.gpLimMlmSetKeysReq); pMac->lim.gpLimMlmSetKeysReq = NULL; } diff --git a/core/mac/src/pe/lim/lim_process_mlm_req_messages.c b/core/mac/src/pe/lim/lim_process_mlm_req_messages.c index 2bcb5409ad86..41090c31d4f8 100644 --- a/core/mac/src/pe/lim/lim_process_mlm_req_messages.c +++ b/core/mac/src/pe/lim/lim_process_mlm_req_messages.c @@ -2082,6 +2082,8 @@ lim_process_mlm_set_keys_req(tpAniSirGlobal mac_ctx, uint32_t *msg_buf) mlm_set_keys_req = (tLimMlmSetKeysReq *) msg_buf; if (mac_ctx->lim.gpLimMlmSetKeysReq != NULL) { + qdf_mem_zero(mac_ctx->lim.gpLimMlmSetKeysReq, + sizeof(tLimMlmSetKeysReq)); qdf_mem_free(mac_ctx->lim.gpLimMlmSetKeysReq); mac_ctx->lim.gpLimMlmSetKeysReq = NULL; } @@ -2229,8 +2231,6 @@ lim_process_mlm_set_keys_req(tpAniSirGlobal mac_ctx, uint32_t *msg_buf) session->peSessionId); /* Package WMA_SET_BSSKEY_REQ message parameters */ lim_send_set_bss_key_req(mac_ctx, mlm_set_keys_req, session); - - qdf_mem_zero(mlm_set_keys_req, sizeof(tLimMlmSetKeysReq)); return; } else { /* @@ -2240,13 +2240,11 @@ lim_process_mlm_set_keys_req(tpAniSirGlobal mac_ctx, uint32_t *msg_buf) lim_send_set_sta_key_req(mac_ctx, mlm_set_keys_req, sta_idx, (uint8_t) default_key_id, session, true); - qdf_mem_zero(mlm_set_keys_req, sizeof(tLimMlmSetKeysReq)); return; } end: mlm_set_keys_cnf.sessionId = mlm_set_keys_req->sessionId; lim_post_sme_set_keys_cnf(mac_ctx, mlm_set_keys_req, &mlm_set_keys_cnf); - qdf_mem_zero(mlm_set_keys_req, sizeof(tLimMlmSetKeysReq)); } /** diff --git a/core/mac/src/pe/lim/lim_process_mlm_rsp_messages.c b/core/mac/src/pe/lim/lim_process_mlm_rsp_messages.c index 20207f6315cc..2f6e0e97c436 100644 --- a/core/mac/src/pe/lim/lim_process_mlm_rsp_messages.c +++ b/core/mac/src/pe/lim/lim_process_mlm_rsp_messages.c @@ -2722,7 +2722,7 @@ void lim_process_mlm_set_sta_key_rsp(tpAniSirGlobal mac_ctx, session_entry = pe_find_session_by_session_id(mac_ctx, session_id); if (session_entry == NULL) { pe_err("session does not exist for given session_id"); - qdf_mem_zero(msg->bodyptr, sizeof(tSetBssKeyParams)); + qdf_mem_zero(msg->bodyptr, sizeof(tSetStaKeyParams)); qdf_mem_free(msg->bodyptr); msg->bodyptr = NULL; lim_send_sme_set_context_rsp(mac_ctx, @@ -2748,7 +2748,7 @@ void lim_process_mlm_set_sta_key_rsp(tpAniSirGlobal mac_ctx, else mlm_set_key_cnf.key_len_nonzero = false; - qdf_mem_zero(msg->bodyptr, sizeof(tSetBssKeyParams)); + qdf_mem_zero(msg->bodyptr, sizeof(tSetStaKeyParams)); qdf_mem_free(msg->bodyptr); msg->bodyptr = NULL; @@ -2767,6 +2767,8 @@ void lim_process_mlm_set_sta_key_rsp(tpAniSirGlobal mac_ctx, * Free the buffer cached for the global * mac_ctx->lim.gpLimMlmSetKeysReq */ + qdf_mem_zero(mac_ctx->lim.gpLimMlmSetKeysReq, + sizeof(tLimMlmSetKeysReq)); qdf_mem_free(mac_ctx->lim.gpLimMlmSetKeysReq); mac_ctx->lim.gpLimMlmSetKeysReq = NULL; } @@ -2810,6 +2812,7 @@ void lim_process_mlm_set_bss_key_rsp(tpAniSirGlobal mac_ctx, if (session_entry == NULL) { pe_err("session does not exist for given sessionId [%d]", session_id); + qdf_mem_zero(msg->bodyptr, sizeof(tSetBssKeyParams)); qdf_mem_free(msg->bodyptr); msg->bodyptr = NULL; lim_send_sme_set_context_rsp(mac_ctx, set_key_cnf.peer_macaddr, @@ -2867,6 +2870,8 @@ void lim_process_mlm_set_bss_key_rsp(tpAniSirGlobal mac_ctx, * Free the buffer cached for the * global mac_ctx->lim.gpLimMlmSetKeysReq */ + qdf_mem_zero(mac_ctx->lim.gpLimMlmSetKeysReq, + sizeof(tLimMlmSetKeysReq)); qdf_mem_free(mac_ctx->lim.gpLimMlmSetKeysReq); mac_ctx->lim.gpLimMlmSetKeysReq = NULL; } diff --git a/core/mac/src/pe/lim/lim_process_sme_req_messages.c b/core/mac/src/pe/lim/lim_process_sme_req_messages.c index 15ff763f5f9d..096bb85fd0be 100644 --- a/core/mac/src/pe/lim/lim_process_sme_req_messages.c +++ b/core/mac/src/pe/lim/lim_process_sme_req_messages.c @@ -4144,6 +4144,7 @@ static void __lim_process_roam_scan_offload_req(tpAniSirGlobal mac_ctx, local_ie_buf = qdf_mem_malloc(MAX_DEFAULT_SCAN_IE_LEN); if (!local_ie_buf) { pe_err("Mem Alloc failed for local_ie_buf"); + qdf_mem_zero(req_buffer, sizeof(tSirRoamOffloadScanReq)); qdf_mem_free(req_buffer); return; } @@ -4171,6 +4172,7 @@ static void __lim_process_roam_scan_offload_req(tpAniSirGlobal mac_ctx, status = wma_post_ctrl_msg(mac_ctx, &wma_msg); if (eSIR_SUCCESS != status) { pe_err("Posting WMA_ROAM_SCAN_OFFLOAD_REQ failed"); + qdf_mem_zero(req_buffer, sizeof(tSirRoamOffloadScanReq)); qdf_mem_free(req_buffer); } } diff --git a/core/mac/src/pe/lim/lim_security_utils.c b/core/mac/src/pe/lim/lim_security_utils.c index 1d4f723e1569..66257ad8df9b 100644 --- a/core/mac/src/pe/lim/lim_security_utils.c +++ b/core/mac/src/pe/lim/lim_security_utils.c @@ -863,6 +863,8 @@ void lim_send_set_bss_key_req(tpAniSirGlobal pMac, /* Respond to SME with LIM_MLM_SETKEYS_CNF */ mlmSetKeysCnf.resultCode = eSIR_SME_HAL_SEND_MESSAGE_FAIL; + qdf_mem_zero(pSetBssKeyParams, sizeof(tSetBssKeyParams)); + qdf_mem_free(pSetBssKeyParams); } else return; /* Continue after WMA_SET_BSSKEY_RSP... */ diff --git a/core/sme/src/common/sme_api.c b/core/sme/src/common/sme_api.c index af088da524d6..6f8a4d3fe727 100644 --- a/core/sme/src/common/sme_api.c +++ b/core/sme/src/common/sme_api.c @@ -9354,6 +9354,7 @@ QDF_STATUS sme_stop_roaming(tHalHandle hal, uint8_t session_id, uint8_t reason) status = wma_post_ctrl_msg(mac_ctx, &wma_msg); if (eSIR_SUCCESS != status) { sme_err("Posting WMA_ROAM_SCAN_OFFLOAD_REQ failed"); + qdf_mem_zero(req, sizeof(tSirRoamOffloadScanReq)); qdf_mem_free(req); return QDF_STATUS_E_FAULT; } diff --git a/core/sme/src/csr/csr_api_roam.c b/core/sme/src/csr/csr_api_roam.c index afbd3782337e..15696c95ef92 100644 --- a/core/sme/src/csr/csr_api_roam.c +++ b/core/sme/src/csr/csr_api_roam.c @@ -4709,10 +4709,14 @@ static void csr_reset_cfg_privacy(tpAniSirGlobal pMac) cfg_set_int(pMac, WNI_CFG_PRIVACY_ENABLED, 0); cfg_set_int(pMac, WNI_CFG_RSN_ENABLED, 0); - cfg_set_str(pMac, WNI_CFG_WEP_DEFAULT_KEY_1, Key0, 0); - cfg_set_str(pMac, WNI_CFG_WEP_DEFAULT_KEY_2, Key1, 0); - cfg_set_str(pMac, WNI_CFG_WEP_DEFAULT_KEY_3, Key2, 0); - cfg_set_str(pMac, WNI_CFG_WEP_DEFAULT_KEY_4, Key3, 0); + cfg_set_str(pMac, WNI_CFG_WEP_DEFAULT_KEY_1, Key0, + WNI_CFG_WEP_DEFAULT_KEY_1_LEN); + cfg_set_str(pMac, WNI_CFG_WEP_DEFAULT_KEY_2, Key1, + WNI_CFG_WEP_DEFAULT_KEY_2_LEN); + cfg_set_str(pMac, WNI_CFG_WEP_DEFAULT_KEY_3, Key2, + WNI_CFG_WEP_DEFAULT_KEY_3_LEN); + cfg_set_str(pMac, WNI_CFG_WEP_DEFAULT_KEY_4, Key3, + WNI_CFG_WEP_DEFAULT_KEY_4_LEN); cfg_set_int(pMac, WNI_CFG_WEP_KEY_LENGTH, 0); cfg_set_int(pMac, WNI_CFG_WEP_DEFAULT_KEYID, 0); } @@ -16506,8 +16510,10 @@ QDF_STATUS csr_send_mb_set_context_req_msg(tpAniSirGlobal pMac, status = cds_mq_post_message_by_priority( QDF_MODULE_ID_PE, &cds_msg, LOW_PRIORITY); - if (QDF_IS_STATUS_ERROR(status)) + if (QDF_IS_STATUS_ERROR(status)) { + qdf_mem_zero(pMsg, msgLen); qdf_mem_free(pMsg); + } } while (0); return status; } diff --git a/core/wma/src/wma_mgmt.c b/core/wma/src/wma_mgmt.c index b7e4ed4ce78f..1a0fc4287cb5 100644 --- a/core/wma/src/wma_mgmt.c +++ b/core/wma/src/wma_mgmt.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013-2018 The Linux Foundation. All rights reserved. + * Copyright (c) 2013-2019 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -1754,6 +1754,7 @@ static QDF_STATUS wma_setup_install_key_cmd(tp_wma_handle wma_handle, if (iface) iface->is_waiting_for_key = false; + qdf_mem_zero(¶ms, sizeof(struct set_key_params)); return status; } @@ -1880,6 +1881,8 @@ void wma_set_bsskey(tp_wma_handle wma_handle, tpSetBssKeyParams key_info) /* TODO: Should we wait till we get HTT_T2H_MSG_TYPE_SEC_IND? */ key_info->status = QDF_STATUS_SUCCESS; + qdf_mem_zero(&key_params, sizeof(struct wma_set_key_params)); + out: wma_send_msg_high_priority(wma_handle, WMA_SET_BSSKEY_RSP, (void *)key_info, 0); @@ -2170,6 +2173,7 @@ void wma_set_stakey(tp_wma_handle wma_handle, tpSetStaKeyParams key_info) key_params.key_len = key_info->key[i].keyLength; status = wma_setup_install_key_cmd(wma_handle, &key_params, opmode); + qdf_mem_zero(&key_params, sizeof(struct wma_set_key_params)); if (status == QDF_STATUS_E_NOMEM) { WMA_LOGE("%s:Failed to setup install key buf", __func__); diff --git a/core/wma/src/wma_scan_roam.c b/core/wma/src/wma_scan_roam.c index 4409ca97cffb..d03eb5bf8cf5 100644 --- a/core/wma/src/wma_scan_roam.c +++ b/core/wma/src/wma_scan_roam.c @@ -988,11 +988,12 @@ QDF_STATUS wma_roam_scan_offload_mode(tp_wma_handle wma_handle, status = wmi_unified_roam_scan_offload_mode_cmd(wma_handle->wmi_handle, scan_cmd_fp, params); + qdf_mem_zero(params, sizeof(struct roam_offload_scan_params)); + qdf_mem_free(params); if (QDF_IS_STATUS_ERROR(status)) return status; WMA_LOGD("%s: WMA --> WMI_ROAM_SCAN_MODE", __func__); - qdf_mem_free(params); return status; } @@ -2052,6 +2053,7 @@ QDF_STATUS wma_process_roaming_config(tp_wma_handle wma_handle, if (NULL == pMac) { WMA_LOGE("%s: pMac is NULL", __func__); + qdf_mem_zero(roam_req, sizeof(tSirRoamOffloadScanReq)); qdf_mem_free(roam_req); return QDF_STATUS_E_FAILURE; } @@ -2060,6 +2062,7 @@ QDF_STATUS wma_process_roaming_config(tp_wma_handle wma_handle, /* roam scan offload is not enabled in firmware. * Cannot initialize it in the middle of connection. */ + qdf_mem_zero(roam_req, sizeof(tSirRoamOffloadScanReq)); qdf_mem_free(roam_req); return QDF_STATUS_E_PERM; } @@ -2422,6 +2425,7 @@ QDF_STATUS wma_process_roaming_config(tp_wma_handle wma_handle, default: break; } + qdf_mem_zero(roam_req, sizeof(tSirRoamOffloadScanReq)); qdf_mem_free(roam_req); return qdf_status; } From df6626993c648390cccd03de66f7267c3444f3d9 Mon Sep 17 00:00:00 2001 From: Abhinav Kumar Date: Thu, 2 Aug 2018 15:49:39 +0530 Subject: [PATCH 23/28] qcacld-3.0: Update last_scan_reject_timestamp with proper value When the scan is rejected, driver saves the scan reject reason and the rejected time by converting the jiffies to msec. In case when HZ is 100 while converting jiffies to msec, jiffies_to_msecs() return wrapped value of jiffies(in msec). This result value of the current jiffies (return value of jiffies_to_msecs API) becomes greater than scan reject time (pHddCtx->last_scan_reject_timestamp) and __wlan_hdd_cfg80211_scan trigger SSR in case of scan rejection. Fix is to Use jiffiy directly instead of using jiffies_to_msecs() while updating scan reject time(pHddCtx->last_scan_reject_timestamp). Change-Id: Ib86830456fdc48143bf282779216ab94aed11923 CRs-Fixed: 2289992 Bug: 123489092 Signed-off-by: Srinivas Girigowda --- core/hdd/src/wlan_hdd_scan.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/core/hdd/src/wlan_hdd_scan.c b/core/hdd/src/wlan_hdd_scan.c index 26aea5a2e6db..2ecb0e74fc05 100644 --- a/core/hdd/src/wlan_hdd_scan.c +++ b/core/hdd/src/wlan_hdd_scan.c @@ -2112,19 +2112,20 @@ static int __wlan_hdd_cfg80211_scan(struct wiphy *wiphy, !pHddCtx->last_scan_reject_timestamp) { pHddCtx->last_scan_reject_session_id = curr_session_id; pHddCtx->last_scan_reject_reason = curr_reason; - pHddCtx->last_scan_reject_timestamp = - jiffies_to_msecs(jiffies) + - SCAN_REJECT_THRESHOLD_TIME; + pHddCtx->last_scan_reject_timestamp = jiffies + + msecs_to_jiffies(SCAN_REJECT_THRESHOLD_TIME); pHddCtx->scan_reject_cnt = 0; } else { pHddCtx->scan_reject_cnt++; if ((pHddCtx->scan_reject_cnt >= SCAN_REJECT_THRESHOLD) && - qdf_system_time_after(jiffies_to_msecs(jiffies), + qdf_system_time_after(jiffies, pHddCtx->last_scan_reject_timestamp)) { - hdd_err("scan reject threshold reached Session %d Reason %d count %d", + hdd_err("scan reject threshold reached Session %d Reason %d count %d reject timestamp %lu jiffies %lu", curr_session_id, curr_reason, - pHddCtx->scan_reject_cnt); + pHddCtx->scan_reject_cnt, + pHddCtx->last_scan_reject_timestamp, + jiffies); pHddCtx->last_scan_reject_timestamp = 0; pHddCtx->scan_reject_cnt = 0; if (pHddCtx->config->enable_fatal_event) { From 361576c55cee424045509609593bd24ae22f0c09 Mon Sep 17 00:00:00 2001 From: Paul Zhang Date: Mon, 15 Oct 2018 17:36:10 +0800 Subject: [PATCH 24/28] qcacld-3.0: Fix false alarm scan reject issue Currently, the scan is rejected if connection is in progress. And it uses last_scan_reject_timestamp and reset scan_reject_cnt to avoid scan stuck issue. last_scan_reject_timestamp and scan_reject_cnt reset when the next scan issues successfully. If: 1\ Scan happens and connection is in progress. Initialized last_scan_reject_timestamp and reset scan_reject_cnt; 2\ Maybe no scan happens for a long time; 3\ scan happens but unfortunately connection is in progress again. Then false alarm may happen because the time has already expired and scan_reject_cnt >= 15. Reset scan reject params if connection is success or it receives final failure from CSR after trying with all APs. Change-Id: Icd72d1d2c0adee8bb5b5b9c6537e1c48e37a7121 CRs-Fixed: 2333283 Bug: 123489092 Signed-off-by: Srinivas Girigowda --- core/hdd/src/wlan_hdd_assoc.c | 7 +++++++ core/hdd/src/wlan_hdd_power.c | 6 ++---- core/hdd/src/wlan_hdd_scan.c | 33 +++++++++++++++++++++++++++++---- core/hdd/src/wlan_hdd_scan.h | 20 ++++++++++++++++++++ 4 files changed, 58 insertions(+), 8 deletions(-) diff --git a/core/hdd/src/wlan_hdd_assoc.c b/core/hdd/src/wlan_hdd_assoc.c index 88f7481e0231..dfafcc7d6277 100644 --- a/core/hdd/src/wlan_hdd_assoc.c +++ b/core/hdd/src/wlan_hdd_assoc.c @@ -62,6 +62,7 @@ #include "wlan_hdd_napi.h" #include #include "wlan_hdd_tsf.h" +#include "wlan_hdd_scan.h" /* These are needed to recognize WPA and RSN suite types */ #define HDD_WPA_OUI_SIZE 4 @@ -2608,6 +2609,12 @@ static QDF_STATUS hdd_association_completion_handler(hdd_adapter_t *pAdapter, return QDF_STATUS_E_NULL_VALUE; } + /* + * reset scan reject params if connection is success or we received + * final failure from CSR after trying with all APs. + */ + hdd_reset_scan_reject_params(pHddCtx, roamStatus, roamResult); + /* * Enable roaming on other STA iface except this one. * Firmware dosent support connection on one STA iface while diff --git a/core/hdd/src/wlan_hdd_power.c b/core/hdd/src/wlan_hdd_power.c index d58b310070b9..c5e657947483 100644 --- a/core/hdd/src/wlan_hdd_power.c +++ b/core/hdd/src/wlan_hdd_power.c @@ -1654,10 +1654,8 @@ QDF_STATUS hdd_wlan_re_init(void) /* Restart all adapters */ hdd_start_all_adapters(pHddCtx); - pHddCtx->last_scan_reject_session_id = 0xFF; - pHddCtx->last_scan_reject_reason = 0; - pHddCtx->last_scan_reject_timestamp = 0; - pHddCtx->scan_reject_cnt = 0; + /* init the scan reject params */ + hdd_init_scan_reject_params(pHddCtx); hdd_set_roaming_in_progress(false); complete(&pAdapter->roaming_comp_var); diff --git a/core/hdd/src/wlan_hdd_scan.c b/core/hdd/src/wlan_hdd_scan.c index 2ecb0e74fc05..8f2ef5bbb2a7 100644 --- a/core/hdd/src/wlan_hdd_scan.c +++ b/core/hdd/src/wlan_hdd_scan.c @@ -437,6 +437,32 @@ static int hdd_add_scan_event_from_ies(struct hdd_scan_info *scanInfo, return 0; } +void hdd_init_scan_reject_params(hdd_context_t *hdd_ctx) +{ + if (hdd_ctx) { + hdd_ctx->last_scan_reject_timestamp = 0; + hdd_ctx->last_scan_reject_session_id = 0xFF; + hdd_ctx->last_scan_reject_reason = 0; + hdd_ctx->scan_reject_cnt = 0; + } + + return; +} + +void hdd_reset_scan_reject_params(hdd_context_t *hdd_ctx, + eRoamCmdStatus roam_status, + eCsrRoamResult roam_result) +{ + + if ((roam_status == eCSR_ROAM_ASSOCIATION_FAILURE) || + (roam_status == eCSR_ROAM_CANCELLED) || + (roam_result == eCSR_ROAM_RESULT_ASSOCIATED)) { + hdd_debug("Reset scan reject params"); + hdd_init_scan_reject_params(hdd_ctx); + } + + return; +} /** * hdd_indicate_scan_result() - indicate scan results @@ -2146,10 +2172,9 @@ static int __wlan_hdd_cfg80211_scan(struct wiphy *wiphy, } return -EBUSY; } - pHddCtx->last_scan_reject_timestamp = 0; - pHddCtx->last_scan_reject_session_id = 0xFF; - pHddCtx->last_scan_reject_reason = 0; - pHddCtx->scan_reject_cnt = 0; + + /* reinit the scan reject params */ + hdd_init_scan_reject_params(pHddCtx); /* Check whether SAP scan can be skipped or not */ if (pAdapter->device_mode == QDF_SAP_MODE && diff --git a/core/hdd/src/wlan_hdd_scan.h b/core/hdd/src/wlan_hdd_scan.h index 518b0497bc63..04c64d34a699 100644 --- a/core/hdd/src/wlan_hdd_scan.h +++ b/core/hdd/src/wlan_hdd_scan.h @@ -164,6 +164,26 @@ void wlan_hdd_fill_whitelist_ie_attrs(bool *ie_whitelist, uint32_t *voui, hdd_context_t *hdd_ctx); +/** + * hdd_init_scan_reject_params() - init scan reject params + * @hdd_ctx: hdd contxt + * + * Return: None + */ +void hdd_init_scan_reject_params(hdd_context_t *hdd_ctx); + +/** + * hdd_reset_scan_reject_params() - reset scan reject params per roam stats + * @hdd_ctx: hdd contxt + * @roam_status: roam status + * @roam_result: roam result + * + * Return: None + */ +void hdd_reset_scan_reject_params(hdd_context_t *hdd_ctx, + eRoamCmdStatus roam_status, + eCsrRoamResult roam_result); + /** * wlan_hdd_cfg80211_scan_block_cb() - scan block work handler * @work: Pointer to work From ab8506aaa84ae37f17b7d8f72664e9ee7f0aa1ae Mon Sep 17 00:00:00 2001 From: Abhinav Kumar Date: Mon, 18 Mar 2019 19:04:41 +0530 Subject: [PATCH 25/28] qcacld-3.0: Fix false alarm scan reject issue Currently, the scan is rejected if roaming in progress on STA or if a client of SAP is in the middle of WPS/EAPOL exchange. And it uses last_scan_reject_timestamp and reset scan_reject_cnt to avoid scan stuck issue. last_scan_reject_timestamp and scan_reject_cnt reset when the next scan issues successfully. If: 1\ Scan happens and roaming is in progress on STA or client of SAP is in the middle of the WPS/EAPOL exchange. Initialized last_scan_reject_timestamp and reset scan_reject_cnt; 2\ Maybe no scan happens for a long time; 3\ scan happens but unfortunately, a connection is in progress again. Then false alarm may happen because the time has already expired and scan_reject_cnt >= 15. Reset scan reject params after successful set key and successful roam. Change-Id: I1197e66483e3bc8da38d6bcbc8b8c32b193ef6c9 CRs-Fixed: 2418658 Bug: 123489092 Signed-off-by: Srinivas Girigowda --- core/hdd/src/wlan_hdd_assoc.c | 3 +++ core/hdd/src/wlan_hdd_main.c | 5 +++++ 2 files changed, 8 insertions(+) diff --git a/core/hdd/src/wlan_hdd_assoc.c b/core/hdd/src/wlan_hdd_assoc.c index dfafcc7d6277..85845d622f35 100644 --- a/core/hdd/src/wlan_hdd_assoc.c +++ b/core/hdd/src/wlan_hdd_assoc.c @@ -1938,6 +1938,9 @@ QDF_STATUS hdd_change_peer_state(hdd_adapter_t *pAdapter, #endif if (sta_state == OL_TXRX_PEER_STATE_AUTH) { + /* Reset scan reject params on successful set key */ + hdd_debug("Reset scan reject params"); + hdd_init_scan_reject_params(pAdapter->pHddCtx); #ifdef QCA_LL_LEGACY_TX_FLOW_CONTROL /* make sure event is reset */ INIT_COMPLETION(pAdapter->sta_authorized_event); diff --git a/core/hdd/src/wlan_hdd_main.c b/core/hdd/src/wlan_hdd_main.c index 7dfa84c7fdb2..333368ceb5de 100644 --- a/core/hdd/src/wlan_hdd_main.c +++ b/core/hdd/src/wlan_hdd_main.c @@ -12948,6 +12948,11 @@ void hdd_set_roaming_in_progress(bool value) hdd_ctx->roaming_in_progress = value; hdd_debug("Roaming in Progress set to %d", value); + if (!hdd_ctx->roaming_in_progress) { + /* Reset scan reject params on successful roam complete */ + hdd_debug("Reset scan reject params"); + hdd_init_scan_reject_params(hdd_ctx); + } } /** From e307c843fc81e9c23c2e67544a3c7784cd048c35 Mon Sep 17 00:00:00 2001 From: Min Liu Date: Thu, 17 May 2018 11:51:53 +0800 Subject: [PATCH 26/28] qcacld-3.0: Cleanup blocked scan requests The following memory leak issues of blocked scan requests need to be addressed: 1. Add list for blocked scan requests There could be multiple scan requests are blocked before related callback can be executed. Currently there is only one pointer for such requests. A list is added accordingly. 2. Cleanup blocked scan request when ifdown Scheduled work for blocked scan might not be able to be executed before ifdown. When the work is cancelled, related scan request is not freed and will caused memory leak. Call the relate callback when blocked scan work is cancelled to cleanup the pending scan request. Change-Id: Ifb5fc1b14a043ad67e4ba1d305ce4133b471188c CRs-Fixed: 2166111 Bug: 129651626 Signed-off-by: Srinivas Girigowda --- core/hdd/inc/wlan_hdd_main.h | 4 +- core/hdd/src/wlan_hdd_main.c | 12 +++-- core/hdd/src/wlan_hdd_scan.c | 92 ++++++++++++++++++++++++------------ 3 files changed, 73 insertions(+), 35 deletions(-) diff --git a/core/hdd/inc/wlan_hdd_main.h b/core/hdd/inc/wlan_hdd_main.h index 06f6f9d24cf3..888226665059 100644 --- a/core/hdd/inc/wlan_hdd_main.h +++ b/core/hdd/inc/wlan_hdd_main.h @@ -1368,8 +1368,6 @@ struct hdd_adapter_s { /* TODO Move this to sta Ctx */ struct wireless_dev wdev; - struct cfg80211_scan_request *request; - struct cfg80211_scan_request *vendor_request; /** ops checks if Opportunistic Power Save is Enable or Not * ctw stores ctWindow value once we receive Opps command from @@ -1526,6 +1524,8 @@ struct hdd_adapter_s { struct delayed_work acs_pending_work; struct work_struct scan_block_work; + qdf_list_t blocked_scan_request_q; + qdf_mutex_t blocked_scan_request_q_lock; #ifdef MSM_PLATFORM unsigned long prev_rx_packets; unsigned long prev_tx_packets; diff --git a/core/hdd/src/wlan_hdd_main.c b/core/hdd/src/wlan_hdd_main.c index 333368ceb5de..5cb41e52f441 100644 --- a/core/hdd/src/wlan_hdd_main.c +++ b/core/hdd/src/wlan_hdd_main.c @@ -517,10 +517,13 @@ static int __hdd_netdev_notifier_call(struct notifier_block *nb, msecs_to_jiffies(WLAN_WAIT_TIME_ABORTSCAN)); if (!rc) hdd_err("Timeout occurred while waiting for abortscan"); - } else { - cds_flush_work(&adapter->scan_block_work); - hdd_debug("Scan is not Pending from user"); } + cds_flush_work(&adapter->scan_block_work); + /* Need to clean up blocked scan request */ + wlan_hdd_cfg80211_scan_block_cb(&adapter->scan_block_work); + qdf_list_destroy(&adapter->blocked_scan_request_q); + qdf_mutex_destroy(&adapter->blocked_scan_request_q_lock); + hdd_debug("Scan is not Pending from user"); /* * After NETDEV_GOING_DOWN, kernel calls hdd_stop.Irrespective * of return status of hdd_stop call, kernel resets the IFF_UP @@ -4306,6 +4309,9 @@ hdd_adapter_t *hdd_open_adapter(hdd_context_t *hdd_ctx, uint8_t session_type, } INIT_WORK(&adapter->scan_block_work, wlan_hdd_cfg80211_scan_block_cb); + qdf_list_create(&adapter->blocked_scan_request_q, + CFG_MAX_SCAN_COUNT_MAX); + qdf_mutex_create(&adapter->blocked_scan_request_q_lock); cfgState = WLAN_HDD_GET_CFG_STATE_PTR(adapter); mutex_init(&cfgState->remain_on_chan_ctx_lock); diff --git a/core/hdd/src/wlan_hdd_scan.c b/core/hdd/src/wlan_hdd_scan.c index 8f2ef5bbb2a7..dd8e313ae605 100644 --- a/core/hdd/src/wlan_hdd_scan.c +++ b/core/hdd/src/wlan_hdd_scan.c @@ -1655,35 +1655,35 @@ static void __wlan_hdd_cfg80211_scan_block_cb(struct work_struct *work) hdd_adapter_t *adapter = container_of(work, hdd_adapter_t, scan_block_work); struct cfg80211_scan_request *request; - hdd_context_t *hdd_ctx; + struct hdd_scan_req *blocked_scan_req; + qdf_list_node_t *node = NULL; if (WLAN_HDD_ADAPTER_MAGIC != adapter->magic) { hdd_err("HDD adapter context is invalid"); return; } - hdd_ctx = WLAN_HDD_GET_CTX(adapter); - if (0 != wlan_hdd_validate_context(hdd_ctx)) - return; + qdf_mutex_acquire(&adapter->blocked_scan_request_q_lock); - request = adapter->request; - if (request) { + while (!qdf_list_empty(&adapter->blocked_scan_request_q)) { + qdf_list_remove_front(&adapter->blocked_scan_request_q, + &node); + blocked_scan_req = qdf_container_of(node, struct hdd_scan_req, + node); + request = blocked_scan_req->scan_request; request->n_ssids = 0; request->n_channels = 0; - - hdd_err("##In DFS Master mode. Scan aborted. Null result sent"); - hdd_cfg80211_scan_done(adapter, request, true); - adapter->request = NULL; + if (blocked_scan_req->source == NL_SCAN) { + hdd_err("Scan aborted. Null result sent"); + hdd_cfg80211_scan_done(adapter, request, true); + } else { + hdd_err("Vendor scan aborted. Null result sent"); + hdd_vendor_scan_callback(adapter, request, true); + } + qdf_mem_free(blocked_scan_req); } - request = adapter->vendor_request; - if (request) { - request->n_ssids = 0; - request->n_channels = 0; - hdd_err("In DFS Master mode. Scan aborted. Null result sent"); - hdd_vendor_scan_callback(adapter, request, true); - adapter->vendor_request = NULL; - } + qdf_mutex_release(&adapter->blocked_scan_request_q_lock); } void wlan_hdd_cfg80211_scan_block_cb(struct work_struct *work) @@ -1949,6 +1949,43 @@ static void wlan_hdd_free_voui(tCsrScanRequest *scan_req) qdf_mem_free(scan_req->voui); } +static int +wlan_hdd_enqueue_blocked_scan_request(struct net_device *dev, + struct cfg80211_scan_request *request, + uint8_t source) +{ + hdd_adapter_t *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + struct hdd_scan_req *blocked_scan_req = + qdf_mem_malloc(sizeof(*blocked_scan_req)); + int ret = 0; + + if (!blocked_scan_req) { + hdd_err("Failed to allocate scan_req"); + return -EINVAL; + } + + blocked_scan_req->adapter = adapter; + blocked_scan_req->scan_request = request; + blocked_scan_req->source = source; + blocked_scan_req->scan_id = 0; + + qdf_mutex_acquire(&adapter->blocked_scan_request_q_lock); + if (qdf_list_size(&adapter->blocked_scan_request_q) < + CFG_MAX_SCAN_COUNT_MAX) + qdf_list_insert_back(&adapter->blocked_scan_request_q, + &blocked_scan_req->node); + else + ret = -EINVAL; + qdf_mutex_release(&adapter->blocked_scan_request_q_lock); + + if (ret) { + hdd_err("Maximum number of block scan request reached!"); + qdf_mem_free(blocked_scan_req); + } + + return ret; +} + /* Define short name to use in cds_trigger_recovery */ #define SCAN_FAILURE CDS_SCAN_ATTEMPT_FAILURES @@ -2016,10 +2053,8 @@ static int __wlan_hdd_cfg80211_scan(struct wiphy *wiphy, conn_info.connState) && (!pHddCtx->config->enable_connected_scan)) { hdd_info("enable_connected_scan is false, Aborting scan"); - if (NL_SCAN == source) - pAdapter->request = request; - else - pAdapter->vendor_request = request; + if (wlan_hdd_enqueue_blocked_scan_request(dev, request, source)) + return -EAGAIN; schedule_work(&pAdapter->scan_block_work); return 0; } @@ -2076,10 +2111,9 @@ static int __wlan_hdd_cfg80211_scan(struct wiphy *wiphy, * startup. */ hdd_err("##In DFS Master mode. Scan aborted"); - if (NL_SCAN == source) - pAdapter->request = request; - else - pAdapter->vendor_request = request; + if (wlan_hdd_enqueue_blocked_scan_request(dev, request, + source)) + return -EAGAIN; schedule_work(&pAdapter->scan_block_work); return 0; } @@ -2180,10 +2214,8 @@ static int __wlan_hdd_cfg80211_scan(struct wiphy *wiphy, if (pAdapter->device_mode == QDF_SAP_MODE && wlan_hdd_sap_skip_scan_check(pHddCtx, request)) { hdd_debug("sap scan skipped"); - if (NL_SCAN == source) - pAdapter->request = request; - else - pAdapter->vendor_request = request; + if (wlan_hdd_enqueue_blocked_scan_request(dev, request, source)) + return -EAGAIN; schedule_work(&pAdapter->scan_block_work); return 0; } From 5936573ee430fbd10c9181be8a71b9602418f71c Mon Sep 17 00:00:00 2001 From: Min Liu Date: Mon, 25 Jun 2018 18:08:54 +0800 Subject: [PATCH 27/28] qcacld-3.0: Fix assert when netdev is going down Move destruction of blocked_scan_request_q and related lock from __hdd_netdev_notifier_call to hdd_close_adapter for the former one might be invoked for more than once and could cause issues. CRs-Fixed: 2267481 Change-Id: Ifb62750a09a2dcca381217a41280ad943942ee35 Bug: 129651626 Signed-off-by: Srinivas Girigowda --- core/hdd/src/wlan_hdd_main.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/core/hdd/src/wlan_hdd_main.c b/core/hdd/src/wlan_hdd_main.c index 5cb41e52f441..b9f2b07a00d7 100644 --- a/core/hdd/src/wlan_hdd_main.c +++ b/core/hdd/src/wlan_hdd_main.c @@ -521,8 +521,6 @@ static int __hdd_netdev_notifier_call(struct notifier_block *nb, cds_flush_work(&adapter->scan_block_work); /* Need to clean up blocked scan request */ wlan_hdd_cfg80211_scan_block_cb(&adapter->scan_block_work); - qdf_list_destroy(&adapter->blocked_scan_request_q); - qdf_mutex_destroy(&adapter->blocked_scan_request_q_lock); hdd_debug("Scan is not Pending from user"); /* * After NETDEV_GOING_DOWN, kernel calls hdd_stop.Irrespective @@ -4390,6 +4388,9 @@ QDF_STATUS hdd_close_adapter(hdd_context_t *hdd_ctx, hdd_adapter_t *adapter, hdd_bus_bw_compute_timer_stop(hdd_ctx); cancel_work_sync(&hdd_ctx->bus_bw_work); + qdf_list_destroy(&adapter->blocked_scan_request_q); + qdf_mutex_destroy(&adapter->blocked_scan_request_q_lock); + /* cleanup adapter */ cds_clear_concurrency_mode(adapter->device_mode); hdd_cleanup_adapter(hdd_ctx, adapterNode->pAdapter, rtnl_held); From 83e593bc9a8b0b814c37f3a5669137962d99eb3f Mon Sep 17 00:00:00 2001 From: Himanshu Agarwal Date: Fri, 6 Apr 2018 17:39:37 +0530 Subject: [PATCH 28/28] qcacld-3.0: Send frames with GCMP MIC LEN if encryption is GCMP CCMP and GCMP both have different lengths of their MIC part. MIC length for CCMP is 8 bytes whereas it is 16 bytes for GCMP. When encryption type is GCMP/GCMP-256, sending packets with CCMP MIC length causes fw to drop the GCMP encrypted management packets leading to connection issues. Send GCMP encrypted frames with GCMP MIC length. Change-Id: Ia83fa6ffde880fe69e5e4c3e3c3ce9c62ad8fa3c CRs-Fixed: 2203224 Bug: 129483359 Signed-off-by: Srinivas Girigowda --- core/cds/inc/cds_ieee80211_common.h | 4 +++- core/wma/inc/wma.h | 2 ++ core/wma/src/wma_data.c | 15 ++++++++++++--- core/wma/src/wma_mgmt.c | 20 ++++++++++++++++---- 4 files changed, 33 insertions(+), 8 deletions(-) diff --git a/core/cds/inc/cds_ieee80211_common.h b/core/cds/inc/cds_ieee80211_common.h index b3c036bea771..c9a3448c7d49 100644 --- a/core/cds/inc/cds_ieee80211_common.h +++ b/core/cds/inc/cds_ieee80211_common.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011,2014-2015, 2017 The Linux Foundation. All rights reserved. + * Copyright (c) 2011,2014-2018 The Linux Foundation. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -1815,6 +1815,8 @@ enum { #define IEEE80211_CCMP_HEADERLEN 8 #define IEEE80211_CCMP_MICLEN 8 +#define WLAN_IEEE80211_GCMP_HEADERLEN 8 +#define WLAN_IEEE80211_GCMP_MICLEN 16 /* * 802.11w defines a MMIE chunk to be attached at the end of diff --git a/core/wma/inc/wma.h b/core/wma/inc/wma.h index 3083c1ebc967..47b6532af101 100644 --- a/core/wma/inc/wma.h +++ b/core/wma/inc/wma.h @@ -1050,6 +1050,7 @@ struct roam_synch_frame_ind { * @aid: association id * @rmfEnabled: Robust Management Frame (RMF) enabled/disabled * @key: GTK key + * @ucast_key_cipher: unicast cipher key * @uapsd_cached_val: uapsd cached value * @stats_rsp: stats response * @fw_stats_set: fw stats value @@ -1126,6 +1127,7 @@ struct wma_txrx_node { uint8_t rmfEnabled; #ifdef WLAN_FEATURE_11W wma_igtk_key_t key; + uint32_t ucast_key_cipher; #endif /* WLAN_FEATURE_11W */ uint32_t uapsd_cached_val; tAniGetPEStatsRsp *stats_rsp; diff --git a/core/wma/src/wma_data.c b/core/wma/src/wma_data.c index ce3aedc5d967..5b3e978cffc2 100644 --- a/core/wma/src/wma_data.c +++ b/core/wma/src/wma_data.c @@ -2718,11 +2718,20 @@ QDF_STATUS wma_tx_packet(void *wma_context, void *tx_frame, uint16_t frmLen, if (!IEEE80211_IS_BROADCAST(wh->i_addr1) && !IEEE80211_IS_MULTICAST(wh->i_addr1)) { if (pFc->wep) { + uint8_t mic_len, hdr_len; + /* Allocate extra bytes for privacy header and * trailer */ - newFrmLen = frmLen + IEEE80211_CCMP_HEADERLEN + - IEEE80211_CCMP_MICLEN; + if (iface->ucast_key_cipher == + WMI_CIPHER_AES_GCM) { + hdr_len = WLAN_IEEE80211_GCMP_HEADERLEN; + mic_len = WLAN_IEEE80211_GCMP_MICLEN; + } else { + hdr_len = IEEE80211_CCMP_HEADERLEN; + mic_len = IEEE80211_CCMP_MICLEN; + } + newFrmLen = frmLen + hdr_len + mic_len; qdf_status = cds_packet_alloc((uint16_t) newFrmLen, (void **)&pFrame, @@ -2745,7 +2754,7 @@ QDF_STATUS wma_tx_packet(void *wma_context, void *tx_frame, uint16_t frmLen, qdf_mem_set(pFrame, newFrmLen, 0); qdf_mem_copy(pFrame, wh, sizeof(*wh)); qdf_mem_copy(pFrame + sizeof(*wh) + - IEEE80211_CCMP_HEADERLEN, + hdr_len, pData + sizeof(*wh), frmLen - sizeof(*wh)); diff --git a/core/wma/src/wma_mgmt.c b/core/wma/src/wma_mgmt.c index 1a0fc4287cb5..5e61e621384a 100644 --- a/core/wma/src/wma_mgmt.c +++ b/core/wma/src/wma_mgmt.c @@ -1714,10 +1714,11 @@ static QDF_STATUS wma_setup_install_key_cmd(tp_wma_handle wma_handle, params.key_len = key_params->key_len; #ifdef WLAN_FEATURE_11W + iface = &wma_handle->interfaces[key_params->vdev_id]; + if ((key_params->key_type == eSIR_ED_AES_128_CMAC) || (key_params->key_type == eSIR_ED_AES_GMAC_128) || (key_params->key_type == eSIR_ED_AES_GMAC_256)) { - iface = &wma_handle->interfaces[key_params->vdev_id]; if (iface) { iface->key.key_length = key_params->key_len; iface->key.key_cipher = params.key_cipher; @@ -1731,6 +1732,9 @@ static QDF_STATUS wma_setup_install_key_cmd(tp_wma_handle wma_handle, CMAC_IPN_LEN); } } + + if (key_params->unicast && iface) + iface->ucast_key_cipher = params.key_cipher; #endif /* WLAN_FEATURE_11W */ WMA_LOGD("Key setup : vdev_id %d key_idx %d key_type %d key_len %d", @@ -3361,6 +3365,7 @@ int wma_process_rmf_frame(tp_wma_handle wma_handle, { uint8_t *orig_hdr; uint8_t *ccmp; + uint8_t mic_len, hdr_len; if ((wh)->i_fc[1] & IEEE80211_FC1_WEP) { if (IEEE80211_IS_BROADCAST(wh->i_addr1) || @@ -3387,15 +3392,22 @@ int wma_process_rmf_frame(tp_wma_handle wma_handle, return -EINVAL; } + if (iface->ucast_key_cipher == WMI_CIPHER_AES_GCM) { + hdr_len = WLAN_IEEE80211_GCMP_HEADERLEN; + mic_len = WLAN_IEEE80211_GCMP_MICLEN; + } else { + hdr_len = IEEE80211_CCMP_HEADERLEN; + mic_len = IEEE80211_CCMP_MICLEN; + } /* Strip privacy headers (and trailer) * for a received frame */ qdf_mem_move(orig_hdr + - IEEE80211_CCMP_HEADERLEN, wh, + hdr_len, wh, sizeof(*wh)); qdf_nbuf_pull_head(wbuf, - IEEE80211_CCMP_HEADERLEN); - qdf_nbuf_trim_tail(wbuf, IEEE80211_CCMP_MICLEN); + hdr_len); + qdf_nbuf_trim_tail(wbuf, mic_len); /* * CCMP header has been pulled off * reinitialize the start pointer of mac header