diff options
| author | Mohit Khanna <mkhannaqca@codeaurora.org> | 2017-02-21 18:54:19 -0800 |
|---|---|---|
| committer | qcabuildsw <qcabuildsw@localhost> | 2017-03-03 14:14:25 -0800 |
| commit | bdbe4ac866ba26af687c8d5ed6dd45fb69bbd834 (patch) | |
| tree | 3880cff8459f56c0ba8bbacae9393543a9806c8b | |
| parent | b01a57a1b9e8ab917ad0c0353702d7b95aa6dc2c (diff) | |
qcacld-3.0: Fix peer poison overwritten issue
In the existing impementation, once wma_is_pkt_drop_candidate gets a
peer from ol_txrx_find_peer_by_addr, the peer can be deleted in the
SOFTIRQ path from the unmap handler. This would make the peer pointer
'stale' resulting in access to already freed memory.
- Use standard API OL_TXRX_PEER_UNREF_DELETE to decrement peer->ref_cnt
instead of directly referencing it.
- Add a new API - ol_txrx_find_peer_by_addr_inc_ref which does not
decrement the peer->ref_cnt until the usage of peer in the caller
function is finished. The existing API ol_txrx_find_peer_by_addr
can be replaced by the new API as and when the issues are seen.
Sample usage:
{
peer = ol_txrx_find_peer_by_addr_inc_ref
/* This API gets the peer and increments its ref_cnt */
...
...
/* Once peer usage is done */
OL_TXRX_PEER_UNREF_DELETE(peer);
/*
* This API deletes the reference to the peer or the peer itself
* if the peer->ref_cnt is 0. This way we no longer depend on
* peer unmaps to delete the peer.
*/
}
Change-Id: I69fb67a4b4c9e26344d2ed1a72c383be7ac62414
CRs-Fixed: 2008583
| -rw-r--r-- | core/dp/txrx/ol_tx_classify.c | 9 | ||||
| -rw-r--r-- | core/dp/txrx/ol_txrx.c | 76 | ||||
| -rw-r--r-- | core/dp/txrx/ol_txrx.h | 4 | ||||
| -rw-r--r-- | core/dp/txrx/ol_txrx_peer_find.c | 17 | ||||
| -rw-r--r-- | core/dp/txrx/ol_txrx_peer_find.h | 5 | ||||
| -rw-r--r-- | core/wma/src/wma_mgmt.c | 7 |
6 files changed, 84 insertions, 34 deletions
diff --git a/core/dp/txrx/ol_tx_classify.c b/core/dp/txrx/ol_tx_classify.c index 195c1155187c..25af6ea049f2 100644 --- a/core/dp/txrx/ol_tx_classify.c +++ b/core/dp/txrx/ol_tx_classify.c @@ -455,7 +455,7 @@ ol_tx_classify( * classify_extension function can check whether to * encrypt multicast / broadcast frames. */ - peer = ol_txrx_peer_find_hash_find(pdev, + peer = ol_txrx_peer_find_hash_find_inc_ref(pdev, vdev->mac_addr.raw, 0, 1); if (!peer) { @@ -533,8 +533,9 @@ ol_tx_classify( #endif peer = ol_tx_tdls_peer_find(pdev, vdev, &peer_id); } else { - peer = ol_txrx_peer_find_hash_find(pdev, dest_addr, - 0, 1); + peer = ol_txrx_peer_find_hash_find_inc_ref(pdev, + dest_addr, + 0, 1); } tx_msdu_info->htt.info.is_unicast = true; if (!peer) { @@ -695,7 +696,7 @@ ol_tx_classify_mgmt( } } else { /* find the peer and increment its reference count */ - peer = ol_txrx_peer_find_hash_find(pdev, dest_addr, + peer = ol_txrx_peer_find_hash_find_inc_ref(pdev, dest_addr, 0, 1); } tx_msdu_info->peer = peer; diff --git a/core/dp/txrx/ol_txrx.c b/core/dp/txrx/ol_txrx.c index 36f9af2c4744..3fa99d33e600 100644 --- a/core/dp/txrx/ol_txrx.c +++ b/core/dp/txrx/ol_txrx.c @@ -284,7 +284,7 @@ ol_txrx_find_peer_by_addr_and_vdev(ol_txrx_pdev_handle pdev, if (!peer) return NULL; *peer_id = peer->local_id; - OL_TXRX_PEER_DEC_REF_CNT(peer); + OL_TXRX_PEER_UNREF_DELETE(peer); return peer; } @@ -328,17 +328,67 @@ void *ol_txrx_get_vdev_by_sta_id(uint8_t sta_id) return peer->vdev; } +/** + * ol_txrx_find_peer_by_addr() - find peer via peer mac addr and peer_id + * @pdev: pointer of type ol_txrx_pdev_handle + * @peer_addr: peer mac addr + * @peer_id: pointer to fill in the value of peer->local_id for caller + * + * This function finds a peer with given mac address and returns its peer_id. + * Note that this function does not increment the peer->ref_cnt. + * This means that the peer may be deleted in some other parallel context after + * its been found. + * + * Return: peer handle if peer is found, NULL if peer is not found. + */ ol_txrx_peer_handle ol_txrx_find_peer_by_addr(ol_txrx_pdev_handle pdev, uint8_t *peer_addr, uint8_t *peer_id) { struct ol_txrx_peer_t *peer; - peer = ol_txrx_peer_find_hash_find(pdev, peer_addr, 0, 1); + peer = ol_txrx_peer_find_hash_find_inc_ref(pdev, peer_addr, 0, 1); + if (!peer) + return NULL; + *peer_id = peer->local_id; + OL_TXRX_PEER_UNREF_DELETE(peer); + return peer; +} + +/** + * ol_txrx_find_peer_by_addr_inc_ref() - find peer via peer mac addr and peer_id + * @pdev: pointer of type ol_txrx_pdev_handle + * @peer_addr: peer mac addr + * @peer_id: pointer to fill in the value of peer->local_id for caller + * + * This function finds the peer with given mac address and returns its peer_id. + * Note that this function increments the peer->ref_cnt. + * This makes sure that peer will be valid. This also means the caller needs to + * call the corresponding API - OL_TXRX_PEER_UNREF_DELETE to delete the peer + * reference. + * Sample usage: + * { + * //the API call below increments the peer->ref_cnt + * peer = ol_txrx_find_peer_by_addr_inc_ref(pdev, peer_addr, peer_id); + * + * // Once peer usage is done + * + * //the API call below decrements the peer->ref_cnt + * OL_TXRX_PEER_UNREF_DELETE(peer); + * } + * + * Return: peer handle if the peer is found, NULL if peer is not found. + */ +ol_txrx_peer_handle ol_txrx_find_peer_by_addr_inc_ref(ol_txrx_pdev_handle pdev, + uint8_t *peer_addr, + uint8_t *peer_id) +{ + struct ol_txrx_peer_t *peer; + + peer = ol_txrx_peer_find_hash_find_inc_ref(pdev, peer_addr, 0, 1); if (!peer) return NULL; *peer_id = peer->local_id; - OL_TXRX_PEER_DEC_REF_CNT(peer); return peer; } @@ -2734,7 +2784,7 @@ QDF_STATUS ol_txrx_peer_state_update(struct ol_txrx_pdev_t *pdev, return QDF_STATUS_E_INVAL; } - peer = ol_txrx_peer_find_hash_find(pdev, peer_mac, 0, 1); + peer = ol_txrx_peer_find_hash_find_inc_ref(pdev, peer_mac, 0, 1); if (NULL == peer) { TXRX_PRINT(TXRX_PRINT_LEVEL_INFO2, "%s: peer is null for peer_mac 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n", @@ -2811,7 +2861,7 @@ ol_txrx_peer_update(ol_txrx_vdev_handle vdev, struct ol_txrx_peer_t *peer; int peer_ref_cnt; - peer = ol_txrx_peer_find_hash_find(vdev->pdev, peer_mac, 0, 1); + peer = ol_txrx_peer_find_hash_find_inc_ref(vdev->pdev, peer_mac, 0, 1); if (!peer) { TXRX_PRINT(TXRX_PRINT_LEVEL_INFO2, "%s: peer is null", __func__); @@ -2985,11 +3035,9 @@ int ol_txrx_peer_unref_delete(ol_txrx_peer_handle peer, if (qdf_atomic_dec_and_test(&peer->ref_cnt)) { u_int16_t peer_id; - TXRX_PRINT(TXRX_PRINT_LEVEL_INFO1, - "(%s) Deleting peer %p (%pM) ref_cnt %d\n", - fname, - peer, - peer->mac_addr.raw, + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_INFO, + "[%s][%d]: Deleting peer %p (%pM) ref_cnt %d\n", + fname, line, peer, peer->mac_addr.raw, qdf_atomic_read(&peer->ref_cnt)); wma_peer_debug_log(vdev->vdev_id, DEBUG_DELETING_PEER_OBJ, @@ -3089,8 +3137,8 @@ int ol_txrx_peer_unref_delete(ol_txrx_peer_handle peer, } else { qdf_spin_unlock_bh(&pdev->peer_ref_mutex); QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_INFO_HIGH, - "ref delete(%s): peer %p peer->ref_cnt = %d", - fname, peer, rc); + "[%s][%d]: ref delete peer %p peer->ref_cnt = %d", + fname, line, peer, rc); } return rc; @@ -3200,7 +3248,7 @@ void ol_txrx_peer_detach(ol_txrx_peer_handle peer) /* debug print to dump rx reorder state */ /* htt_rx_reorder_log_print(vdev->pdev->htt_pdev); */ - TXRX_PRINT(TXRX_PRINT_LEVEL_INFO1, + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_INFO, "%s:peer %p (%02x:%02x:%02x:%02x:%02x:%02x)", __func__, peer, peer->mac_addr.raw[0], peer->mac_addr.raw[1], @@ -3284,7 +3332,7 @@ ol_txrx_peer_handle ol_txrx_peer_find_by_addr(struct ol_txrx_pdev_t *pdev, uint8_t *peer_mac_addr) { struct ol_txrx_peer_t *peer; - peer = ol_txrx_peer_find_hash_find(pdev, peer_mac_addr, 0, 0); + peer = ol_txrx_peer_find_hash_find_inc_ref(pdev, peer_mac_addr, 0, 0); if (peer) { /* release the extra reference */ OL_TXRX_PEER_UNREF_DELETE(peer); diff --git a/core/dp/txrx/ol_txrx.h b/core/dp/txrx/ol_txrx.h index fbe0982c95da..16b2fcf062ce 100644 --- a/core/dp/txrx/ol_txrx.h +++ b/core/dp/txrx/ol_txrx.h @@ -45,7 +45,9 @@ int ol_txrx_peer_unref_delete(ol_txrx_peer_handle peer, const char *fname, int line); - +ol_txrx_peer_handle ol_txrx_find_peer_by_addr_inc_ref(ol_txrx_pdev_handle pdev, + uint8_t *peer_addr, + uint8_t *peer_id); /** * ol_tx_desc_pool_size_hl() - allocate tx descriptor pool size for HL systems * @ctrl_pdev: the control pdev handle diff --git a/core/dp/txrx/ol_txrx_peer_find.c b/core/dp/txrx/ol_txrx_peer_find.c index 9ffc7aa1412b..ccfb71422b34 100644 --- a/core/dp/txrx/ol_txrx_peer_find.c +++ b/core/dp/txrx/ol_txrx_peer_find.c @@ -86,7 +86,7 @@ void __ol_txrx_peer_change_ref_cnt(struct ol_txrx_peer_t *peer, { qdf_atomic_add(change, &peer->ref_cnt); QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_INFO_HIGH, - "[%s][%d]: peer %p peer->ref_cnt changed by(%d) to %d", + "[%s][%d]: peer %p peer->ref_cnt changed by (%d) to %d", fname, line, peer, change, qdf_atomic_read(&peer->ref_cnt)); } @@ -210,7 +210,7 @@ struct ol_txrx_peer_t *ol_txrx_peer_vdev_find_hash(struct ol_txrx_pdev_t *pdev, return NULL; /* failure */ } -struct ol_txrx_peer_t *ol_txrx_peer_find_hash_find(struct ol_txrx_pdev_t *pdev, +struct ol_txrx_peer_t *ol_txrx_peer_find_hash_find_inc_ref(struct ol_txrx_pdev_t *pdev, uint8_t *peer_mac_addr, int mac_addr_is_aligned, uint8_t check_valid) @@ -354,7 +354,7 @@ static inline void ol_txrx_peer_find_add_id(struct ol_txrx_pdev_t *pdev, /* check if there's already a peer object with this MAC address */ peer = - ol_txrx_peer_find_hash_find(pdev, peer_mac_addr, + ol_txrx_peer_find_hash_find_inc_ref(pdev, peer_mac_addr, 1 /* is aligned */, 0); if (!peer || peer_id == HTT_INVALID_PEER) { @@ -413,9 +413,8 @@ static inline void ol_txrx_peer_find_add_id(struct ol_txrx_pdev_t *pdev, peer_id_to_obj_map[peer_id].peer_id_ref_cnt); peer_ref_cnt = qdf_atomic_read(&peer->ref_cnt); QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_INFO_HIGH, - "%s: peer %p ID %d peer_id[%d] peer_id_ref_cnt %d peer->ref_cnt %d", - __func__, peer, peer_id, i, - peer_id_ref_cnt, peer_ref_cnt); + "%s: peer %p ID %d peer_id[%d] peer_id_ref_cnt %d", + __func__, peer, peer_id, i, peer_id_ref_cnt); wma_peer_debug_log(DEBUG_INVALID_VDEV_ID, DEBUG_PEER_MAP_EVENT, peer_id, &peer->mac_addr.raw, peer, @@ -575,7 +574,7 @@ void ol_rx_peer_unmap_handler(ol_txrx_pdev_handle pdev, uint16_t peer_id) DEBUG_PEER_UNMAP_EVENT, peer_id, NULL, NULL, ref_cnt, 0x101); TXRX_PRINT(TXRX_PRINT_LEVEL_INFO1, - "%s: Remove the ID %d reference to deleted peer. del_peer_id_ref_cnt %d", + "%s: peer already deleted, peer_id %d del_peer_id_ref_cnt %d", __func__, peer_id, ref_cnt); return; } @@ -623,8 +622,8 @@ void ol_rx_peer_unmap_handler(ol_txrx_pdev_handle pdev, uint16_t peer_id) */ OL_TXRX_PEER_UNREF_DELETE(peer); - TXRX_PRINT(TXRX_PRINT_LEVEL_INFO1, - "%s: Remove the ID %d reference to peer %p peer_id_ref_cnt %d", + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_INFO, + "%s: peer_id %d peer %p peer_id_ref_cnt %d", __func__, peer_id, peer, ref_cnt); } diff --git a/core/dp/txrx/ol_txrx_peer_find.h b/core/dp/txrx/ol_txrx_peer_find.h index 24167a1968f1..414af1b4d06f 100644 --- a/core/dp/txrx/ol_txrx_peer_find.h +++ b/core/dp/txrx/ol_txrx_peer_find.h @@ -40,9 +40,6 @@ #define OL_TXRX_PEER_INC_REF_CNT(peer) \ __ol_txrx_peer_change_ref_cnt(peer, 1, __func__, __LINE__); -#define OL_TXRX_PEER_DEC_REF_CNT(peer) \ - __ol_txrx_peer_change_ref_cnt(peer, (-1), __func__, __LINE__); - void __ol_txrx_peer_change_ref_cnt(struct ol_txrx_peer_t *peer, int change, const char *fname, @@ -98,7 +95,7 @@ void ol_txrx_peer_find_hash_add(struct ol_txrx_pdev_t *pdev, struct ol_txrx_peer_t *peer); -struct ol_txrx_peer_t *ol_txrx_peer_find_hash_find(struct ol_txrx_pdev_t *pdev, +struct ol_txrx_peer_t *ol_txrx_peer_find_hash_find_inc_ref(struct ol_txrx_pdev_t *pdev, uint8_t *peer_mac_addr, int mac_addr_is_aligned, uint8_t check_valid); diff --git a/core/wma/src/wma_mgmt.c b/core/wma/src/wma_mgmt.c index 0916c12b1879..706a6d9f8958 100644 --- a/core/wma/src/wma_mgmt.c +++ b/core/wma/src/wma_mgmt.c @@ -48,6 +48,7 @@ #include "qdf_types.h" #include "qdf_mem.h" #include "ol_txrx_peer_find.h" +#include "ol_txrx.h" #include "wma_types.h" #include "lim_api.h" @@ -3192,7 +3193,7 @@ int wma_process_rmf_frame(tp_wma_handle wma_handle, 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_peer_t *peer = NULL; struct ol_txrx_pdev_t *pdev_ctx; uint8_t peer_id; bool should_drop = false; @@ -3216,7 +3217,7 @@ static bool wma_is_pkt_drop_candidate(tp_wma_handle wma_handle, goto end; } - peer = ol_txrx_find_peer_by_addr(pdev_ctx, peer_addr, &peer_id); + peer = ol_txrx_find_peer_by_addr_inc_ref(pdev_ctx, peer_addr, &peer_id); if (!peer) { if (SIR_MAC_MGMT_ASSOC_REQ != subtype) { WMA_LOGI( @@ -3265,6 +3266,8 @@ static bool wma_is_pkt_drop_candidate(tp_wma_handle wma_handle, } end: + if (peer) + OL_TXRX_PEER_UNREF_DELETE(peer); return should_drop; } |
