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
Этот коммит содержится в:

коммит произвёл
snandini

родитель
58ce86229c
Коммит
babadb8bee
@@ -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) {
|
||||
|
@@ -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);
|
||||
|
@@ -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
|
||||
|
@@ -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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -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,
|
||||
|
Ссылка в новой задаче
Block a user