qcacld-2.0: Fix layering violation while handling management frames

qcacld-3.0 to qcacld-2.0 propagation

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
This commit is contained in:
Krishna Kumaar Natarajan 2016-05-04 15:16:36 +05:30 committed by syphyr
parent cd3ae2df46
commit 5d6242a3b5
8 changed files with 136 additions and 183 deletions

View file

@ -461,6 +461,94 @@ is_ccmp_pn_replay_attack(void *vos_ctx, struct ieee80211_frame *wh,
}
#endif
/**
* tlshim_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 tlshim_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;
tANI_BOOLEAN should_drop = eANI_BOOLEAN_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 = vos_get_context(VOS_MODULE_ID_TXRX, wma_handle->vos_context);
if (!pdev_ctx) {
TLSHIM_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) {
TLSHIM_LOGE(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 (adf_os_gettimestamp() - peer->last_assoc_rcvd <
TLSHIM_MGMT_FRAME_DETECT_DOS_TIMER) {
TLSHIM_LOGD(FL("Dropping Assoc Req received"));
should_drop = TRUE;
}
}
peer->last_assoc_rcvd = adf_os_gettimestamp();
break;
case SIR_MAC_MGMT_DISASSOC:
if (peer->last_disassoc_rcvd) {
if (adf_os_gettimestamp() -
peer->last_disassoc_rcvd <
TLSHIM_MGMT_FRAME_DETECT_DOS_TIMER) {
TLSHIM_LOGD(FL("Dropping DisAssoc received"));
should_drop = TRUE;
}
}
peer->last_disassoc_rcvd = adf_os_gettimestamp();
break;
case SIR_MAC_MGMT_DEAUTH:
if (peer->last_deauth_rcvd) {
if (adf_os_gettimestamp() -
peer->last_deauth_rcvd <
TLSHIM_MGMT_FRAME_DETECT_DOS_TIMER) {
TLSHIM_LOGD(FL("Dropping Deauth received"));
should_drop = TRUE;
}
}
peer->last_deauth_rcvd = adf_os_gettimestamp();
break;
default:
break;
}
end:
return should_drop;
}
#define RESERVE_BYTES 100
static int tlshim_mgmt_rx_process(void *context, u_int8_t *data,
u_int32_t data_len, bool saved_beacon, u_int32_t vdev_id)
@ -468,9 +556,7 @@ static int tlshim_mgmt_rx_process(void *context, u_int8_t *data,
void *vos_ctx = vos_get_global_context(VOS_MODULE_ID_TL, NULL);
struct txrx_tl_shim_ctx *tl_shim = vos_get_context(VOS_MODULE_ID_TL,
vos_ctx);
#ifdef FEATURE_WLAN_D0WOW
tp_wma_handle wma_handle = vos_get_context(VOS_MODULE_ID_WDA, vos_ctx);
#endif
WMI_MGMT_RX_EVENTID_param_tlvs *param_tlvs = NULL;
wmi_mgmt_rx_hdr *hdr = NULL;
#ifdef WLAN_FEATURE_11W
@ -804,6 +890,11 @@ static int tlshim_mgmt_rx_process(void *context, u_int8_t *data,
}
}
#endif /* WLAN_FEATURE_11W */
if (tlshim_is_pkt_drop_candidate(wma_handle, wh->i_addr2,
mgt_subtype)) {
vos_pkt_return_packet(rx_pkt);
return -EINVAL;
}
return tl_shim->mgmt_rx(vos_ctx, rx_pkt);
}

View file

@ -34,6 +34,9 @@
#include <adf_os_atomic.h>
#include <vos_sched.h>
/* Time(in ms) to detect DOS attack */
#define TLSHIM_MGMT_FRAME_DETECT_DOS_TIMER 1000
#ifdef FEATURE_WLAN_ESE
typedef struct deferred_iapp_work {
pVosContextType pVosGCtx;

View file

@ -1130,6 +1130,10 @@ 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;
adf_os_atomic_init(&peer->fw_pn_check);
}
@ -1137,6 +1141,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);
adf_os_mem_free(peer->reorder_history);
peer->reorder_history = NULL;

View file

@ -1136,6 +1136,9 @@ struct ol_txrx_peer_t {
u_int16_t tx_limit_flag;
u_int16_t tx_pause_flag;
#endif
adf_os_time_t last_assoc_rcvd;
adf_os_time_t last_disassoc_rcvd;
adf_os_time_t last_deauth_rcvd;
struct ol_rx_reorder_history * reorder_history;
};

View file

@ -179,10 +179,6 @@ void limPsOffloadHandleMissedBeaconInd(tpAniSirGlobal pMac, tpSirMsgQ pMsg);
void
limSendHeartBeatTimeoutInd(tpAniSirGlobal pMac, tpPESession psessionEntry);
tMgmtFrmDropReason limIsPktCandidateForDrop(tpAniSirGlobal pMac, tANI_U8 *pRxPacketInfo, tANI_U32 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
void limMicFailureInd(tpAniSirGlobal pMac, tpSirMsgQ pMsg);
#ifdef WLAN_FEATURE_ROAM_OFFLOAD
void limRoamOffloadSynchInd(tpAniSirGlobal pMac, tpSirMsgQ pMsg);

View file

@ -809,133 +809,6 @@ limCleanup(tpAniSirGlobal pMac)
} /*** end limCleanup() ***/
#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 = WDA_GET_RX_MAC_HEADER(rx_pkt_info);
session_entry = peFindSessionByBssid(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 false;
}
sta_ds = dphLookupHashEntry(mac, mac_hdr->sa, &aid,
&session_entry->dph.dphHashTable);
if (!sta_ds) {
PELOG1(limLog(mac, 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 &&
((vos_timer_get_system_time() -
sta_ds->last_assoc_received_time) < 1000))
return true;
sta_ds->last_assoc_received_time = vos_timer_get_system_time();
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 = WDA_GET_RX_MAC_HEADER(rx_pkt_info);
session_entry = peFindSessionByBssid(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 = dphLookupHashEntry(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 ((WDA_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 ((vos_timer_get_system_time() -
sta_ds->last_unprot_deauth_disassoc) < 1000)
return true;
sta_ds->last_unprot_deauth_disassoc =
vos_timer_get_system_time();
} 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->isDisassocDeauthInProgress)
return true;
else
sta_ds->isDisassocDeauthInProgress++;
}
return false;
}
/** -------------------------------------------------------------
\fn peOpen
\brief will be called in Open sequence from macOpen
@ -2618,17 +2491,6 @@ tMgmtFrmDropReason limIsPktCandidateForDrop(tpAniSirGlobal pMac, tANI_U8 *pRxPac
framelen = WDA_GET_RX_PAYLOAD_LEN(pRxPacketInfo);
pBody = WDA_GET_RX_MPDU_DATA(pRxPacketInfo);
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
//Drop INFRA Beacons and Probe Responses in IBSS Mode
if( (subType == SIR_MAC_MGMT_BEACON) ||
(subType == SIR_MAC_MGMT_PROBE_RSP))

View file

@ -717,6 +717,13 @@ limHandle80211Frames(tpAniSirGlobal pMac, tpSirMsgQ limMsg, tANI_U8 *pDeferMsg)
fcOffset = (v_U8_t)WDA_GET_RX_MPDU_HEADER_OFFSET(pRxPacketInfo);
fc = pHdr->fc;
if (pMac->sap.SapDfsInfo.is_dfs_cac_timer_running) {
psessionEntry = peFindSessionByBssid(pMac, pHdr->bssId, &sessionId);
if (psessionEntry && (VOS_STA_SAP_MODE == psessionEntry->pePersona)) {
limLog(pMac, LOG1, FL("CAC timer running - drop the frame"));
goto end;
}
}
#ifdef WLAN_DUMP_MGMTFRAMES
limLog( pMac, LOGE, FL("ProtVersion %d, Type %d, Subtype %d rateIndex=%d"),
fc.protVer, fc.type, fc.subType,

View file

@ -121,9 +121,6 @@ sysBbtProcessMessageCore(tpAniSirGlobal pMac, tpSirMsgQ pMsg, tANI_U32 type,
vos_pkt_t *pVosPkt = (vos_pkt_t *)pMsg->bodyptr;
VOS_STATUS vosStatus =
WDA_DS_PeekRxPacketInfo( pVosPkt, (v_PVOID_t *)&pBd, VOS_FALSE );
tANI_U8 sessionId;
tpPESession psessionEntry;
tpSirMacMgmtHdr pMacHdr;
pMac->sys.gSysBbtReceived++;
@ -141,20 +138,7 @@ sysBbtProcessMessageCore(tpAniSirGlobal pMac, tpSirMsgQ pMsg, tANI_U32 type,
if(type == SIR_MAC_MGMT_FRAME)
{
if (VOS_TRUE == pMac->sap.SapDfsInfo.is_dfs_cac_timer_running)
{
pMacHdr = WDA_GET_RX_MAC_HEADER(pBd);
psessionEntry = peFindSessionByBssid(pMac,
pMacHdr->bssId, &sessionId);
if (psessionEntry &&
(psessionEntry->pePersona == VOS_STA_SAP_MODE))
{
VOS_TRACE(VOS_MODULE_ID_SYS, VOS_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
* message wrappers.
@ -177,33 +161,33 @@ sysBbtProcessMessageCore(tpAniSirGlobal pMac, tpSirMsgQ pMsg, tANI_U32 type,
goto fail;
}
mac_hdr = WDA_GET_RX_MAC_HEADER(pBd);
if (subType == SIR_MAC_MGMT_ASSOC_REQ) {
sysLog(pMac, 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),
pMac->sys.gSysFrameCount[type][subType]);
}
if (subType == SIR_MAC_MGMT_DEAUTH)
{
tpSirMacMgmtHdr pMacHdr = WDA_GET_RX_MAC_HEADER(pBd);
PELOGE(sysLog( pMac, LOGE,
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(pMacHdr->da),
MAC_ADDR_ARRAY(pMacHdr->sa),
MAC_ADDR_ARRAY(pMacHdr->bssId),
pMac->sys.gSysFrameCount[type][subType] ););
sysLog(pMac, 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),
pMac->sys.gSysFrameCount[type][subType]);
}
if (subType == SIR_MAC_MGMT_DISASSOC)
{
tpSirMacMgmtHdr pMacHdr = WDA_GET_RX_MAC_HEADER(pBd);
PELOGE(sysLog( pMac, LOGE,
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(pMacHdr->da),
MAC_ADDR_ARRAY(pMacHdr->sa),
MAC_ADDR_ARRAY(pMacHdr->bssId),
pMac->sys.gSysFrameCount[type][subType] ););
sysLog(pMac, 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),
pMac->sys.gSysFrameCount[type][subType]);
}
/*