From babadb8bee02c9cb5768980e78736f5e0aad6cf0 Mon Sep 17 00:00:00 2001 From: Mohit Khanna Date: Tue, 21 Feb 2017 18:54:19 -0800 Subject: [PATCH 1/2] 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 --- core/dp/txrx/ol_tx_classify.c | 12 +++--- core/dp/txrx/ol_txrx.c | 72 ++++++++++++++++++++++++++++---- core/dp/txrx/ol_txrx.h | 4 +- core/dp/txrx/ol_txrx_peer_find.c | 20 +++++---- core/dp/txrx/ol_txrx_peer_find.h | 13 +++--- 5 files changed, 90 insertions(+), 31 deletions(-) diff --git a/core/dp/txrx/ol_tx_classify.c b/core/dp/txrx/ol_tx_classify.c index eb4702425657..83169403dbb2 100644 --- a/core/dp/txrx/ol_tx_classify.c +++ b/core/dp/txrx/ol_tx_classify.c @@ -464,7 +464,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) { @@ -523,8 +523,9 @@ ol_tx_classify( */ 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) { @@ -694,8 +695,9 @@ ol_tx_classify_mgmt( } } else { /* find the peer and increment its reference count */ - 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->peer = peer; if (!peer) { diff --git a/core/dp/txrx/ol_txrx.c b/core/dp/txrx/ol_txrx.c index b9841269ce66..04ff47afc700 100644 --- a/core/dp/txrx/ol_txrx.c +++ b/core/dp/txrx/ol_txrx.c @@ -310,7 +310,7 @@ ol_txrx_find_peer_by_addr_and_vdev(struct cdp_pdev *ppdev, if (!peer) return NULL; *peer_id = peer->local_id; - OL_TXRX_PEER_DEC_REF_CNT(peer); + OL_TXRX_PEER_UNREF_DELETE(peer); return peer; } @@ -355,6 +355,19 @@ static struct cdp_vdev *ol_txrx_get_vdev_by_sta_id(uint8_t sta_id) return (struct cdp_vdev *)peer->vdev; } +/** + * ol_txrx_find_peer_by_addr() - find peer via peer mac addr and peer_id + * @ppdev: pointer of type cdp_pdev + * @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. + */ void *ol_txrx_find_peer_by_addr(struct cdp_pdev *ppdev, uint8_t *peer_addr, uint8_t *peer_id) @@ -362,11 +375,48 @@ void *ol_txrx_find_peer_by_addr(struct cdp_pdev *ppdev, struct ol_txrx_peer_t *peer; struct ol_txrx_pdev_t *pdev = (struct ol_txrx_pdev_t *)ppdev; - 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; } @@ -2919,7 +2969,7 @@ QDF_STATUS ol_txrx_peer_state_update(struct cdp_pdev *ppdev, 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) { ol_txrx_err( "%s: peer is null for peer_mac 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n", @@ -2996,7 +3046,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) { ol_txrx_dbg("%s: peer is null", __func__); @@ -3167,6 +3217,11 @@ 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; + 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)); + peer_id = peer->local_id; /* remove the reference to the peer from the hash table */ ol_txrx_peer_find_hash_remove(pdev, peer); @@ -3271,8 +3326,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_DEBUG, - "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; @@ -3496,8 +3551,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) { ol_txrx_info_high( "%s: Delete extra reference %p", __func__, peer); diff --git a/core/dp/txrx/ol_txrx.h b/core/dp/txrx/ol_txrx.h index f4c992743172..036fb2ac5c0e 100644 --- a/core/dp/txrx/ol_txrx.h +++ b/core/dp/txrx/ol_txrx.h @@ -46,7 +46,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 914bf815ce82..44c73a9461be 100644 --- a/core/dp/txrx/ol_txrx_peer_find.c +++ b/core/dp/txrx/ol_txrx_peer_find.c @@ -85,7 +85,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)); } @@ -209,10 +209,12 @@ 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, - uint8_t *peer_mac_addr, - int mac_addr_is_aligned, - uint8_t check_valid) +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) { union ol_txrx_align_mac_addr_t local_mac_addr_aligned, *mac_addr; unsigned int index; @@ -352,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) { @@ -555,7 +557,7 @@ void ol_rx_peer_unmap_handler(ol_txrx_pdev_handle pdev, uint16_t peer_id) del_peer_id_ref_cnt); qdf_spin_unlock_bh(&pdev->peer_map_unmap_lock); ol_txrx_dbg( - "%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; } @@ -597,8 +599,8 @@ void ol_rx_peer_unmap_handler(ol_txrx_pdev_handle pdev, uint16_t peer_id) OL_TXRX_PEER_UNREF_DELETE(peer); QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_DEBUG, - "%s: Remove the ID %d reference to peer %p peer_id_ref_cnt %d", - __func__, peer_id, peer, ref_cnt); + "%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 df717a59c3cc..b11926422ac5 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, @@ -99,10 +96,12 @@ 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, - uint8_t *peer_mac_addr, - int mac_addr_is_aligned, - uint8_t check_valid); +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); struct ol_txrx_peer_t *ol_txrx_peer_vdev_find_hash(struct ol_txrx_pdev_t *pdev, From b0cf09f839c7b491f85aa970fd60bea9e5961d9e Mon Sep 17 00:00:00 2001 From: snandini Date: Tue, 25 Jul 2017 03:45:27 -0700 Subject: [PATCH 2/2] Release 5.2.0.35O Release 5.2.0.35O Change-Id: I98019171133cdd8c0f861f164ae4bfc5054b02c0 CRs-Fixed: 774533 --- core/mac/inc/qwlan_version.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/mac/inc/qwlan_version.h b/core/mac/inc/qwlan_version.h index 45423e8672db..5eea5cf041f1 100644 --- a/core/mac/inc/qwlan_version.h +++ b/core/mac/inc/qwlan_version.h @@ -41,9 +41,9 @@ #define QWLAN_VERSION_MAJOR 5 #define QWLAN_VERSION_MINOR 2 #define QWLAN_VERSION_PATCH 0 -#define QWLAN_VERSION_EXTRA "N" +#define QWLAN_VERSION_EXTRA "O" #define QWLAN_VERSION_BUILD 35 -#define QWLAN_VERSIONSTR "5.2.0.35N" +#define QWLAN_VERSIONSTR "5.2.0.35O" #endif /* QWLAN_VERSION_H */