]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
nfc: nci: complete pending data exchange on device close
authorJakub Kicinski <kuba@kernel.org>
Tue, 3 Mar 2026 16:23:43 +0000 (08:23 -0800)
committerJakub Kicinski <kuba@kernel.org>
Thu, 5 Mar 2026 02:18:57 +0000 (18:18 -0800)
In nci_close_device(), complete any pending data exchange before
closing. The data exchange callback (e.g.
rawsock_data_exchange_complete) holds a socket reference.

NIPA occasionally hits this leak:

unreferenced object 0xff1100000f435000 (size 2048):
  comm "nci_dev", pid 3954, jiffies 4295441245
  hex dump (first 32 bytes):
    00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
    27 00 01 40 00 00 00 00 00 00 00 00 00 00 00 00  '..@............
  backtrace (crc ec2b3c5):
    __kmalloc_noprof+0x4db/0x730
    sk_prot_alloc.isra.0+0xe4/0x1d0
    sk_alloc+0x36/0x760
    rawsock_create+0xd1/0x540
    nfc_sock_create+0x11f/0x280
    __sock_create+0x22d/0x630
    __sys_socket+0x115/0x1d0
    __x64_sys_socket+0x72/0xd0
    do_syscall_64+0x117/0xfc0
    entry_SYSCALL_64_after_hwframe+0x4b/0x53

Fixes: 38f04c6b1b68 ("NFC: protect nci_data_exchange transactions")
Reviewed-by: Joe Damato <joe@dama.to>
Link: https://patch.msgid.link/20260303162346.2071888-4-kuba@kernel.org
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
net/nfc/nci/core.c

index e859b834c0f1d0ef96cf080fc70e6bfb418a3fe1..43d871525dbc1c4051f90d40b9cc3b19c662d0b9 100644 (file)
@@ -567,6 +567,10 @@ static int nci_close_device(struct nci_dev *ndev)
                flush_workqueue(ndev->cmd_wq);
                timer_delete_sync(&ndev->cmd_timer);
                timer_delete_sync(&ndev->data_timer);
+               if (test_bit(NCI_DATA_EXCHANGE, &ndev->flags))
+                       nci_data_exchange_complete(ndev, NULL,
+                                                  ndev->cur_conn_id,
+                                                  -ENODEV);
                mutex_unlock(&ndev->req_lock);
                return 0;
        }
@@ -598,6 +602,11 @@ static int nci_close_device(struct nci_dev *ndev)
        flush_workqueue(ndev->cmd_wq);
 
        timer_delete_sync(&ndev->cmd_timer);
+       timer_delete_sync(&ndev->data_timer);
+
+       if (test_bit(NCI_DATA_EXCHANGE, &ndev->flags))
+               nci_data_exchange_complete(ndev, NULL, ndev->cur_conn_id,
+                                          -ENODEV);
 
        /* Clear flags except NCI_UNREG */
        ndev->flags &= BIT(NCI_UNREG);