From b7f9a35ce8bb2a008cc9d48990dfdf1ac3d18939 Mon Sep 17 00:00:00 2001 From: Krishna Kumaar Natarajan Date: Fri, 18 Mar 2016 11:40:07 -0700 Subject: [PATCH] qcacld-3.0: Fix layering violation while handling management frames Fix layering violation while handling management frames. Currently LIM data structures are accessed before dropping Assoc, Disassoc and Deauth packets to avoid DoS attacks. Since the LIM data structures are accessed in different thread context, data present in them are out of sync resulting in a crash. Fix the layering violation by doing appropriate check in WMA instead of doing the same in LIM Change-Id: I8876a4d4b99948cd9ab3ccec403cf5e4050b1cff CRs-Fixed: 977773 --- core/dp/txrx/ol_rx.c | 8 + core/dp/txrx/ol_txrx_types.h | 3 + core/mac/src/pe/include/lim_api.h | 4 - core/mac/src/pe/lim/lim_api.c | 140 ------------------ .../src/pe/lim/lim_process_message_queue.c | 11 ++ .../legacy/src/system/src/sys_entry_func.c | 44 ++---- core/wma/inc/wma_internal.h | 3 + core/wma/src/wma_mgmt.c | 96 ++++++++++++ 8 files changed, 135 insertions(+), 174 deletions(-) diff --git a/core/dp/txrx/ol_rx.c b/core/dp/txrx/ol_rx.c index 093383b0b4..350d4c7a29 100644 --- a/core/dp/txrx/ol_rx.c +++ b/core/dp/txrx/ol_rx.c @@ -1198,6 +1198,11 @@ void ol_rx_peer_init(struct ol_txrx_pdev_t *pdev, struct ol_txrx_peer_t *peer) peer->security[txrx_sec_ucast].sec_type = peer->security[txrx_sec_mcast].sec_type = htt_sec_type_none; peer->keyinstalled = 0; + + peer->last_assoc_rcvd = 0; + peer->last_disassoc_rcvd = 0; + peer->last_deauth_rcvd = 0; + qdf_atomic_init(&peer->fw_pn_check); } @@ -1205,6 +1210,9 @@ void ol_rx_peer_cleanup(struct ol_txrx_vdev_t *vdev, struct ol_txrx_peer_t *peer) { peer->keyinstalled = 0; + peer->last_assoc_rcvd = 0; + peer->last_disassoc_rcvd = 0; + peer->last_deauth_rcvd = 0; ol_rx_reorder_peer_cleanup(vdev, peer); } diff --git a/core/dp/txrx/ol_txrx_types.h b/core/dp/txrx/ol_txrx_types.h index 43e2461a91..a36346e63f 100644 --- a/core/dp/txrx/ol_txrx_types.h +++ b/core/dp/txrx/ol_txrx_types.h @@ -1000,6 +1000,9 @@ struct ol_txrx_peer_t { uint32_t last_pkt_tsf; uint8_t last_pkt_tid; uint16_t last_pkt_center_freq; + qdf_time_t last_assoc_rcvd; + qdf_time_t last_disassoc_rcvd; + qdf_time_t last_deauth_rcvd; }; enum ol_rx_err_type { diff --git a/core/mac/src/pe/include/lim_api.h b/core/mac/src/pe/include/lim_api.h index 0622887c16..e66de6befd 100644 --- a/core/mac/src/pe/include/lim_api.h +++ b/core/mac/src/pe/include/lim_api.h @@ -160,10 +160,6 @@ void lim_send_heart_beat_timeout_ind(tpAniSirGlobal pMac, tpPESession psessionEn tMgmtFrmDropReason lim_is_pkt_candidate_for_drop(tpAniSirGlobal pMac, uint8_t *pRxPacketInfo, uint32_t subType); -bool lim_is_deauth_diassoc_for_drop(tpAniSirGlobal mac, uint8_t *rx_pkt_info); -#ifdef WLAN_FEATURE_11W -bool lim_is_assoc_req_for_drop(tpAniSirGlobal mac, uint8_t *rx_pkt_info); -#endif #ifdef WLAN_FEATURE_ROAM_OFFLOAD QDF_STATUS pe_roam_synch_callback(tpAniSirGlobal mac_ctx, struct sSirSmeRoamOffloadSynchInd *roam_sync_ind_ptr, diff --git a/core/mac/src/pe/lim/lim_api.c b/core/mac/src/pe/lim/lim_api.c index 176a318dee..5912165c93 100644 --- a/core/mac/src/pe/lim/lim_api.c +++ b/core/mac/src/pe/lim/lim_api.c @@ -1131,134 +1131,6 @@ uint8_t lim_is_system_in_scan_state(tpAniSirGlobal pMac) } } /*** end lim_is_system_in_scan_state() ***/ -#ifdef WLAN_FEATURE_11W -/** - * lim_is_assoc_req_for_drop()- function to decides to drop assoc\reassoc - * frames. - * @mac: pointer to global mac structure - * @rx_pkt_info: rx packet meta information - * - * This function is called before enqueuing the frame to PE queue to - * drop flooded assoc/reassoc frames getting into PE Queue. - * - * Return: true for dropping the frame otherwise false - */ - -bool lim_is_assoc_req_for_drop(tpAniSirGlobal mac, uint8_t *rx_pkt_info) -{ - uint8_t session_id; - uint16_t aid; - tpPESession session_entry; - tpSirMacMgmtHdr mac_hdr; - tpDphHashNode sta_ds; - - mac_hdr = WMA_GET_RX_MAC_HEADER(rx_pkt_info); - session_entry = pe_find_session_by_bssid(mac, mac_hdr->bssId, - &session_id); - if (!session_entry) { - PELOG1(limLog(pMac, LOG1, - FL("session does not exist for given STA [%pM]"), - mac_hdr->sa);); - return false; - } - - sta_ds = dph_lookup_hash_entry(mac, mac_hdr->sa, &aid, - &session_entry->dph.dphHashTable); - if (!sta_ds) { - PELOG1(limLog(pMac, LOG1, FL("pStaDs is NULL"));); - return false; - } - - if (!sta_ds->rmfEnabled) - return false; - - if (sta_ds->pmfSaQueryState == DPH_SA_QUERY_IN_PROGRESS) - return true; - - if (sta_ds->last_assoc_received_time && - ((qdf_mc_timer_get_system_ticks() - - sta_ds->last_assoc_received_time) < 1000)) - return true; - - sta_ds->last_assoc_received_time = qdf_mc_timer_get_system_ticks(); - return false; -} -#endif - -/** - * lim_is_deauth_diassoc_for_drop()- function to decides to drop deauth\diassoc - * frames. - * @mac: pointer to global mac structure - * @rx_pkt_info: rx packet meta information - * - * This function is called before enqueuing the frame to PE queue to - * drop flooded deauth/diassoc frames getting into PE Queue. - * - * Return: true for dropping the frame otherwise false - */ - -bool lim_is_deauth_diassoc_for_drop(tpAniSirGlobal mac, uint8_t *rx_pkt_info) -{ - uint8_t session_id; - uint16_t aid; - tpPESession session_entry; - tpSirMacMgmtHdr mac_hdr; - tpDphHashNode sta_ds; - - mac_hdr = WMA_GET_RX_MAC_HEADER(rx_pkt_info); - session_entry = pe_find_session_by_bssid(mac, mac_hdr->bssId, - &session_id); - if (!session_entry) { - PELOG1(limLog(mac, LOG1, - FL("session does not exist for given STA [%pM]"), - mac_hdr->sa);); - return true; - } - - sta_ds = dph_lookup_hash_entry(mac, mac_hdr->sa, &aid, - &session_entry->dph.dphHashTable); - if (!sta_ds) { - PELOG1(limLog(mac, LOG1, FL("pStaDs is NULL"));); - return true; - } - -#ifdef WLAN_FEATURE_11W - if (session_entry->limRmfEnabled) { - if ((WMA_GET_RX_DPU_FEEDBACK(rx_pkt_info) & - DPU_FEEDBACK_UNPROTECTED_ERROR)) { - /* It may be possible that deauth/diassoc frames from a - * spoofy AP is received. So if all further - * deauth/diassoc frmaes are dropped, then it may - * result in lossing deauth/diassoc frames from genuine - * AP. So process all deauth/diassoc frames with - * a time difference of 1 sec. - */ - if ((qdf_mc_timer_get_system_ticks() - - sta_ds->last_unprot_deauth_disassoc) < 1000) - return true; - - sta_ds->last_unprot_deauth_disassoc = - qdf_mc_timer_get_system_ticks(); - } else { - /* PMF enabed, Management frames are protected */ - if (sta_ds->proct_deauh_disassoc_cnt) - return true; - else - sta_ds->proct_deauh_disassoc_cnt++; - } - } else -#endif - /* PMF disabled */ - { - if (sta_ds->is_disassoc_deauth_in_progress) - return true; - else - sta_ds->is_disassoc_deauth_in_progress++; - } - - return false; -} - /** *\brief lim_received_hb_handler() * @@ -2209,18 +2081,6 @@ tMgmtFrmDropReason lim_is_pkt_candidate_for_drop(tpAniSirGlobal pMac, } } - if ((subType == SIR_MAC_MGMT_DEAUTH || - subType == SIR_MAC_MGMT_DISASSOC) && - lim_is_deauth_diassoc_for_drop(pMac, pRxPacketInfo)) - return eMGMT_DROP_SPURIOUS_FRAME; - -#ifdef WLAN_FEATURE_11W - if ((subType == SIR_MAC_MGMT_ASSOC_REQ || - subType == SIR_MAC_MGMT_REASSOC_REQ) && - lim_is_assoc_req_for_drop(pMac, pRxPacketInfo)) - return eMGMT_DROP_SPURIOUS_FRAME; -#endif - framelen = WMA_GET_RX_PAYLOAD_LEN(pRxPacketInfo); pBody = WMA_GET_RX_MPDU_DATA(pRxPacketInfo); diff --git a/core/mac/src/pe/lim/lim_process_message_queue.c b/core/mac/src/pe/lim/lim_process_message_queue.c index 884b2050a8..27d6a41597 100644 --- a/core/mac/src/pe/lim/lim_process_message_queue.c +++ b/core/mac/src/pe/lim/lim_process_message_queue.c @@ -803,6 +803,17 @@ lim_handle80211_frames(tpAniSirGlobal pMac, tpSirMsgQ limMsg, uint8_t *pDeferMsg isFrmFt = WMA_GET_RX_FT_DONE(pRxPacketInfo); fc = pHdr->fc; + if (pMac->sap.SapDfsInfo.is_dfs_cac_timer_running) { + psessionEntry = pe_find_session_by_bssid(pMac, + pHdr->bssId, &sessionId); + if (psessionEntry && + (QDF_SAP_MODE == psessionEntry->pePersona)) { + lim_log(pMac, LOG1, + FL("CAC timer running - drop the frame")); + goto end; + } + } + #ifdef WLAN_DUMP_MGMTFRAMES lim_log(pMac, LOGE, FL("ProtVersion %d, Type %d, Subtype %d rateIndex=%d"), diff --git a/core/mac/src/sys/legacy/src/system/src/sys_entry_func.c b/core/mac/src/sys/legacy/src/system/src/sys_entry_func.c index 057de0544b..a337ec605c 100644 --- a/core/mac/src/sys/legacy/src/system/src/sys_entry_func.c +++ b/core/mac/src/sys/legacy/src/system/src/sys_entry_func.c @@ -109,9 +109,6 @@ sys_bbt_process_message_core(tpAniSirGlobal mac_ctx, tpSirMsgQ msg, cds_pkt_t *vos_pkt = (cds_pkt_t *) msg->bodyptr; QDF_STATUS qdf_status = wma_ds_peek_rx_packet_info(vos_pkt, &bd_ptr, false); - uint8_t sessionid; - tpPESession pe_session; - tpSirMacMgmtHdr mac_hdr; mac_ctx->sys.gSysBbtReceived++; @@ -130,19 +127,7 @@ sys_bbt_process_message_core(tpAniSirGlobal mac_ctx, tpSirMsgQ msg, framecount = mac_ctx->sys.gSysFrameCount[type][subtype]; if (type == SIR_MAC_MGMT_FRAME) { - if (true == mac_ctx->sap.SapDfsInfo.is_dfs_cac_timer_running) { - mac_hdr = WMA_GET_RX_MAC_HEADER(bd_ptr); - pe_session = pe_find_session_by_bssid(mac_ctx, - mac_hdr->bssId, - &sessionid); - if (pe_session && - (pe_session->pePersona == QDF_SAP_MODE)) { - QDF_TRACE(QDF_MODULE_ID_SYS, - QDF_TRACE_LEVEL_INFO_HIGH, - FL("CAC timer is running, dropping the mgmt frame")); - goto fail; - } - } + tpSirMacMgmtHdr mac_hdr; /* * Drop beacon frames in deferred state to avoid VOSS run out of @@ -169,27 +154,26 @@ sys_bbt_process_message_core(tpAniSirGlobal mac_ctx, tpSirMsgQ msg, goto fail; } + mac_hdr = WMA_GET_RX_MAC_HEADER(bd_ptr); + if (subtype == SIR_MAC_MGMT_ASSOC_REQ) { + sys_log(mac_ctx, LOG1, + FL("ASSOC REQ frame allowed: da: " MAC_ADDRESS_STR ", sa: " MAC_ADDRESS_STR ", bssid: " MAC_ADDRESS_STR ", Assoc Req count so far: %d\n"), + MAC_ADDR_ARRAY(mac_hdr->da), + MAC_ADDR_ARRAY(mac_hdr->sa), + MAC_ADDR_ARRAY(mac_hdr->bssId), + mac_ctx->sys.gSysFrameCount[type][subtype]); + } if (subtype == SIR_MAC_MGMT_DEAUTH) { - tpSirMacMgmtHdr mac_hdr = WMA_GET_RX_MAC_HEADER(bd_ptr); - sys_log(mac_ctx, LOGE, - FL("DEAUTH frame allowed: " - "da: " MAC_ADDRESS_STR ", " - "sa: " MAC_ADDRESS_STR ", " - "bssid: " MAC_ADDRESS_STR ", " - "DEAUTH count so far: %d\n"), + sys_log(mac_ctx, LOG1, + FL("DEAUTH frame allowed: da: " MAC_ADDRESS_STR ", sa: " MAC_ADDRESS_STR ", bssid: " MAC_ADDRESS_STR ", DEAUTH count so far: %d\n"), MAC_ADDR_ARRAY(mac_hdr->da), MAC_ADDR_ARRAY(mac_hdr->sa), MAC_ADDR_ARRAY(mac_hdr->bssId), mac_ctx->sys.gSysFrameCount[type][subtype]); } if (subtype == SIR_MAC_MGMT_DISASSOC) { - tpSirMacMgmtHdr mac_hdr = WMA_GET_RX_MAC_HEADER(bd_ptr); - sys_log(mac_ctx, LOGE, - FL("DISASSOC frame allowed: " - "da: " MAC_ADDRESS_STR ", " - "sa: " MAC_ADDRESS_STR ", " - "bssid: " MAC_ADDRESS_STR ", " - "DISASSOC count so far: %d\n"), + sys_log(mac_ctx, LOG1, + FL("DISASSOC frame allowed: da: " MAC_ADDRESS_STR ", sa: " MAC_ADDRESS_STR ", bssid: " MAC_ADDRESS_STR ", DISASSOC count so far: %d\n"), MAC_ADDR_ARRAY(mac_hdr->da), MAC_ADDR_ARRAY(mac_hdr->sa), MAC_ADDR_ARRAY(mac_hdr->bssId), diff --git a/core/wma/inc/wma_internal.h b/core/wma/inc/wma_internal.h index 6d2dd9acb7..42c2c9d6fe 100644 --- a/core/wma/inc/wma_internal.h +++ b/core/wma/inc/wma_internal.h @@ -119,6 +119,9 @@ #define MAX_ENTRY_HOLD_REQ_QUEUE 2 #define MAX_ENTRY_VDEV_RESP_QUEUE 10 +/* Time(in ms) to detect DOS attack */ +#define WMA_MGMT_FRAME_DETECT_DOS_TIMER 1000 + /** * struct index_data_rate_type - non vht data rate type * @mcs_index: mcs rate index diff --git a/core/wma/src/wma_mgmt.c b/core/wma/src/wma_mgmt.c index 38dcfaf93b..6a2ddde6bd 100644 --- a/core/wma/src/wma_mgmt.c +++ b/core/wma/src/wma_mgmt.c @@ -2858,6 +2858,96 @@ int wma_process_rmf_frame(tp_wma_handle wma_handle, } #endif +/** + * wma_is_pkt_drop_candidate() - check if the mgmt frame should be droppped + * @wma_handle: wma handle + * @peer_addr: peer MAC address + * @subtype: Management frame subtype + * + * This function is used to decide if a particular management frame should be + * dropped to prevent DOS attack. Timestamp is used to decide the DOS attack. + * + * Return: true if the packet should be dropped and false oterwise + */ +static bool wma_is_pkt_drop_candidate(tp_wma_handle wma_handle, + uint8_t *peer_addr, uint8_t subtype) +{ + struct ol_txrx_peer_t *peer; + struct ol_txrx_pdev_t *pdev_ctx; + uint8_t peer_id; + bool should_drop = false; + + /* + * Currently this function handles only Disassoc, + * Deauth and Assoc req frames. Return false for + * all other frames. + */ + if (subtype != IEEE80211_FC0_SUBTYPE_DISASSOC && + subtype != IEEE80211_FC0_SUBTYPE_DEAUTH && + subtype != IEEE80211_FC0_SUBTYPE_ASSOC_REQ) { + should_drop = false; + goto end; + } + + pdev_ctx = cds_get_context(QDF_MODULE_ID_TXRX); + if (!pdev_ctx) { + WMA_LOGE(FL("Failed to get the context")); + should_drop = true; + goto end; + } + + peer = ol_txrx_find_peer_by_addr(pdev_ctx, peer_addr, &peer_id); + if (!peer) { + if (SIR_MAC_MGMT_ASSOC_REQ != subtype) { + WMA_LOGI( + FL("Received mgmt frame: %0x from unknow peer: %pM"), + subtype, peer_addr); + should_drop = true; + } + goto end; + } + + switch (subtype) { + case SIR_MAC_MGMT_ASSOC_REQ: + if (peer->last_assoc_rcvd) { + if (qdf_get_system_timestamp() - peer->last_assoc_rcvd < + WMA_MGMT_FRAME_DETECT_DOS_TIMER) { + WMA_LOGI(FL("Dropping Assoc Req received")); + should_drop = true; + } + } + peer->last_assoc_rcvd = qdf_get_system_timestamp(); + break; + case SIR_MAC_MGMT_DISASSOC: + if (peer->last_disassoc_rcvd) { + if (qdf_get_system_timestamp() - + peer->last_disassoc_rcvd < + WMA_MGMT_FRAME_DETECT_DOS_TIMER) { + WMA_LOGI(FL("Dropping DisAssoc received")); + should_drop = true; + } + } + peer->last_disassoc_rcvd = qdf_get_system_timestamp(); + break; + case SIR_MAC_MGMT_DEAUTH: + if (peer->last_deauth_rcvd) { + if (qdf_get_system_timestamp() - + peer->last_deauth_rcvd < + WMA_MGMT_FRAME_DETECT_DOS_TIMER) { + WMA_LOGI(FL("Dropping Deauth received")); + should_drop = true; + } + } + peer->last_deauth_rcvd = qdf_get_system_timestamp(); + break; + default: + break; + } + +end: + return should_drop; +} + /** * wma_mgmt_rx_process() - process management rx frame. * @handle: wma handle @@ -3028,6 +3118,12 @@ static int wma_mgmt_rx_process(void *handle, uint8_t *data, #endif /* WLAN_FEATURE_11W */ rx_pkt->pkt_meta.sessionId = (vdev_id == WMA_INVALID_VDEV_ID ? 0 : vdev_id); + + if (wma_is_pkt_drop_candidate(wma_handle, wh->i_addr2, mgt_subtype)) { + cds_pkt_return_packet(rx_pkt); + return -EINVAL; + } + wma_handle->mgmt_rx(wma_handle, rx_pkt); return 0; }