net: qrtr: Use radix_tree_iter_delete to delete tx flow

Below two issues are handled in this change.

1.Use radix_tree_iter_delete instead of radix_tree_delete to properly
remove slots in a radix tree without any dangling references.

2.Flow entry can be deleted when sending process waiting on the queue
if remote socket closes.Which leads to accessing non-valid flow entry.
To resolve this lookup for the tx flow entry each time before reading
flow count or inserting caller process to waiting list to check the
validity of flow entry in the radix tree.

Change-Id: I42b85b53cfcf5cd4256fbd6cb445d0098078a6f0
Signed-off-by: Arun Prakash <app@codeaurora.org>
This commit is contained in:
Arun Prakash
2021-07-14 18:30:10 +05:30
committed by Sivaji Boddupilli
parent e13155f7ef
commit b669e0ea2e

View File

@@ -477,22 +477,20 @@ static int qrtr_tx_wait(struct qrtr_node *node, struct sockaddr_qrtr *to,
/* Assume sk is set correctly for all data type packets */
timeo = sock_sndtimeo(sk, flags & MSG_DONTWAIT);
mutex_lock(&node->qrtr_tx_lock);
flow = radix_tree_lookup(&node->qrtr_tx_flow, key);
if (!flow) {
flow = kzalloc(sizeof(*flow), GFP_KERNEL);
if (!flow) {
mutex_unlock(&node->qrtr_tx_lock);
return 1;
}
INIT_LIST_HEAD(&flow->waiters);
radix_tree_insert(&node->qrtr_tx_flow, key, flow);
}
mutex_unlock(&node->qrtr_tx_lock);
ret = timeo;
for (;;) {
mutex_lock(&node->qrtr_tx_lock);
flow = radix_tree_lookup(&node->qrtr_tx_flow, key);
if (!flow) {
flow = kzalloc(sizeof(*flow), GFP_KERNEL);
if (!flow) {
mutex_unlock(&node->qrtr_tx_lock);
return 1;
}
INIT_LIST_HEAD(&flow->waiters);
radix_tree_insert(&node->qrtr_tx_flow, key, flow);
}
if (atomic_read(&flow->pending) < QRTR_TX_FLOW_HIGH) {
atomic_inc(&flow->pending);
confirm_rx = atomic_read(&flow->pending) ==
@@ -1069,8 +1067,10 @@ static void qrtr_cleanup_flow_control(struct qrtr_node *node,
{
struct qrtr_ctrl_pkt *pkt;
unsigned long key;
void __rcu **slot;
struct sockaddr_qrtr src;
struct qrtr_tx_flow *flow;
struct radix_tree_iter iter;
struct qrtr_tx_flow_waiter *waiter;
struct qrtr_tx_flow_waiter *temp;
u32 cmd;
@@ -1100,8 +1100,15 @@ static void qrtr_cleanup_flow_control(struct qrtr_node *node,
sock_put(waiter->sk);
kfree(waiter);
}
kfree(flow);
radix_tree_delete(&node->qrtr_tx_flow, key);
radix_tree_for_each_slot(slot, &node->qrtr_tx_flow, &iter, 0) {
if (flow == (struct qrtr_tx_flow *)rcu_dereference(*slot)) {
radix_tree_iter_delete(&node->qrtr_tx_flow,
&iter, slot);
kfree(flow);
break;
}
}
mutex_unlock(&node->qrtr_tx_lock);
}
@@ -1132,8 +1139,8 @@ static void qrtr_handle_del_proc(struct qrtr_node *node, struct sk_buff *skb)
sock_put(waiter->sk);
kfree(waiter);
}
radix_tree_iter_delete(&node->qrtr_tx_flow, &iter, slot);
kfree(flow);
radix_tree_delete(&node->qrtr_tx_flow, iter.index);
}
mutex_unlock(&node->qrtr_tx_lock);