Skip to content

Commit f43ed0c

Browse files
committed
Merge branch 'nfc-fix-leaks-and-races-surfaced-by-nipa'
Jakub Kicinski says: ==================== nfc: fix leaks and races surfaced by NIPA I recently added the nci test to NIPA. Somewhat surprisingly it runs without much settup but hits kmemleaks fairly often. Fix a handful of issues to make the test pass in a stable way. ==================== Link: https://patch.msgid.link/20260303162346.2071888-1-kuba@kernel.org Signed-off-by: Jakub Kicinski <kuba@kernel.org>
2 parents 40bf00e + d793458 commit f43ed0c

4 files changed

Lines changed: 41 additions & 8 deletions

File tree

net/nfc/digital_core.c

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -707,8 +707,10 @@ static int digital_in_send(struct nfc_dev *nfc_dev, struct nfc_target *target,
707707
int rc;
708708

709709
data_exch = kzalloc_obj(*data_exch);
710-
if (!data_exch)
710+
if (!data_exch) {
711+
kfree_skb(skb);
711712
return -ENOMEM;
713+
}
712714

713715
data_exch->cb = cb;
714716
data_exch->cb_context = cb_context;
@@ -731,8 +733,10 @@ static int digital_in_send(struct nfc_dev *nfc_dev, struct nfc_target *target,
731733
data_exch);
732734

733735
exit:
734-
if (rc)
736+
if (rc) {
737+
kfree_skb(skb);
735738
kfree(data_exch);
739+
}
736740

737741
return rc;
738742
}

net/nfc/nci/core.c

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -567,6 +567,10 @@ static int nci_close_device(struct nci_dev *ndev)
567567
flush_workqueue(ndev->cmd_wq);
568568
timer_delete_sync(&ndev->cmd_timer);
569569
timer_delete_sync(&ndev->data_timer);
570+
if (test_bit(NCI_DATA_EXCHANGE, &ndev->flags))
571+
nci_data_exchange_complete(ndev, NULL,
572+
ndev->cur_conn_id,
573+
-ENODEV);
570574
mutex_unlock(&ndev->req_lock);
571575
return 0;
572576
}
@@ -598,6 +602,11 @@ static int nci_close_device(struct nci_dev *ndev)
598602
flush_workqueue(ndev->cmd_wq);
599603

600604
timer_delete_sync(&ndev->cmd_timer);
605+
timer_delete_sync(&ndev->data_timer);
606+
607+
if (test_bit(NCI_DATA_EXCHANGE, &ndev->flags))
608+
nci_data_exchange_complete(ndev, NULL, ndev->cur_conn_id,
609+
-ENODEV);
601610

602611
/* Clear flags except NCI_UNREG */
603612
ndev->flags &= BIT(NCI_UNREG);
@@ -1035,18 +1044,23 @@ static int nci_transceive(struct nfc_dev *nfc_dev, struct nfc_target *target,
10351044
struct nci_conn_info *conn_info;
10361045

10371046
conn_info = ndev->rf_conn_info;
1038-
if (!conn_info)
1047+
if (!conn_info) {
1048+
kfree_skb(skb);
10391049
return -EPROTO;
1050+
}
10401051

10411052
pr_debug("target_idx %d, len %d\n", target->idx, skb->len);
10421053

10431054
if (!ndev->target_active_prot) {
10441055
pr_err("unable to exchange data, no active target\n");
1056+
kfree_skb(skb);
10451057
return -EINVAL;
10461058
}
10471059

1048-
if (test_and_set_bit(NCI_DATA_EXCHANGE, &ndev->flags))
1060+
if (test_and_set_bit(NCI_DATA_EXCHANGE, &ndev->flags)) {
1061+
kfree_skb(skb);
10491062
return -EBUSY;
1063+
}
10501064

10511065
/* store cb and context to be used on receiving data */
10521066
conn_info->data_exchange_cb = cb;

net/nfc/nci/data.c

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,8 @@ void nci_data_exchange_complete(struct nci_dev *ndev, struct sk_buff *skb,
3333
conn_info = nci_get_conn_info_by_conn_id(ndev, conn_id);
3434
if (!conn_info) {
3535
kfree_skb(skb);
36-
goto exit;
36+
clear_bit(NCI_DATA_EXCHANGE, &ndev->flags);
37+
return;
3738
}
3839

3940
cb = conn_info->data_exchange_cb;
@@ -45,6 +46,12 @@ void nci_data_exchange_complete(struct nci_dev *ndev, struct sk_buff *skb,
4546
timer_delete_sync(&ndev->data_timer);
4647
clear_bit(NCI_DATA_EXCHANGE_TO, &ndev->flags);
4748

49+
/* Mark the exchange as done before calling the callback.
50+
* The callback (e.g. rawsock_data_exchange_complete) may
51+
* want to immediately queue another data exchange.
52+
*/
53+
clear_bit(NCI_DATA_EXCHANGE, &ndev->flags);
54+
4855
if (cb) {
4956
/* forward skb to nfc core */
5057
cb(cb_context, skb, err);
@@ -54,9 +61,6 @@ void nci_data_exchange_complete(struct nci_dev *ndev, struct sk_buff *skb,
5461
/* no waiting callback, free skb */
5562
kfree_skb(skb);
5663
}
57-
58-
exit:
59-
clear_bit(NCI_DATA_EXCHANGE, &ndev->flags);
6064
}
6165

6266
/* ----------------- NCI TX Data ----------------- */

net/nfc/rawsock.c

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,17 @@ static int rawsock_release(struct socket *sock)
6767
if (sock->type == SOCK_RAW)
6868
nfc_sock_unlink(&raw_sk_list, sk);
6969

70+
if (sk->sk_state == TCP_ESTABLISHED) {
71+
/* Prevent rawsock_tx_work from starting new transmits and
72+
* wait for any in-progress work to finish. This must happen
73+
* before the socket is orphaned to avoid a race where
74+
* rawsock_tx_work runs after the NCI device has been freed.
75+
*/
76+
sk->sk_shutdown |= SEND_SHUTDOWN;
77+
cancel_work_sync(&nfc_rawsock(sk)->tx_work);
78+
rawsock_write_queue_purge(sk);
79+
}
80+
7081
sock_orphan(sk);
7182
sock_put(sk);
7283

0 commit comments

Comments
 (0)