Re: [PATCH nfc] nfc: nci: fix double completion race in nci_data_exchange_complete
David Heidelberg <[email protected]> Tue, 2 Jun 2026 13:05:07 +0200
| Newsgroups | dev.linux.lists.oe-linux-nfc,org.kernel.vger.netdev |
|---|---|
| Message-ID | <[email protected]> |
On 26/05/2026 12:31, Zhenghang Xiao wrote:
> nci_close_device() and nci_rx_work can both call
> nci_data_exchange_complete() concurrently. After commit 4527025d440ce8
> ("nfc: nci: fix circular locking dependency in nci_close_device") moved
> flush_workqueue(ndev->rx_wq) after mutex_unlock(&ndev->req_lock),
> rx_work is no longer serialized with the explicit completion call in the
> close path. Both callers read the non-NULL callback pointer and invoke
> rawsock_data_exchange_complete(), which calls sock_put() -- but only one
> sock_hold() was taken, so the second sock_put() underflows the refcount
> and frees the socket while it is still in use.
>
> Replace the bare clear_bit(NCI_DATA_EXCHANGE) with
> test_and_clear_bit() so that only the first caller proceeds to invoke
> the callback.
>
> Fixes: 4527025d440c ("nfc: nci: fix circular locking dependency in nci_close_device")
> Signed-off-by: Zhenghang Xiao <[email protected]>
> ---
> net/nfc/nci/data.c | 10 +++++-----
> 1 file changed, 5 insertions(+), 5 deletions(-)
>
> diff --git a/net/nfc/nci/data.c b/net/nfc/nci/data.c
> index 5f98c73db5af..4253edea5c8d 100644
> --- a/net/nfc/nci/data.c
> +++ b/net/nfc/nci/data.c
> @@ -46,11 +46,11 @@ void nci_data_exchange_complete(struct nci_dev *ndev, struct sk_buff *skb,
> timer_delete_sync(&ndev->data_timer);
> clear_bit(NCI_DATA_EXCHANGE_TO, &ndev->flags);
>
> - /* Mark the exchange as done before calling the callback.
> - * The callback (e.g. rawsock_data_exchange_complete) may
> - * want to immediately queue another data exchange.
> - */
> - clear_bit(NCI_DATA_EXCHANGE, &ndev->flags);
> + /* Claim completion atomically -- both close and rx_work may race here */
> + if (!test_and_clear_bit(NCI_DATA_EXCHANGE, &ndev->flags)) {
> + kfree_skb(skb);
> + return;
> + }
>
> if (cb) {
> /* forward skb to nfc core */
Reviewed-by: David Heidelberg <[email protected]>
--
David Heidelberg