nfc: rawsock: cancel tx_work before socket teardown

In rawsock_release(), cancel any pending tx_work and purge the write
queue before orphaning the socket.  rawsock_tx_work runs on the system
workqueue and calls nfc_data_exchange which dereferences the NCI
device.  Without synchronization, tx_work can race with socket and
device teardown when a process is killed (e.g. by SIGKILL), leading
to use-after-free or leaked references.

Set SEND_SHUTDOWN first so that if tx_work is already running it will
see the flag and skip transmitting, then use cancel_work_sync to wait
for any in-progress execution to finish, and finally purge any
remaining queued skbs.

Fixes: 23b7869c0f ("NFC: add the NFC socket raw protocol")
Reviewed-by: Joe Damato <joe@dama.to>
Link: https://patch.msgid.link/20260303162346.2071888-6-kuba@kernel.org
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
Jakub Kicinski 2026-03-03 08:23:45 -08:00
parent 0efdc02f4f
commit d793458c45

View file

@ -67,6 +67,17 @@ static int rawsock_release(struct socket *sock)
if (sock->type == SOCK_RAW)
nfc_sock_unlink(&raw_sk_list, sk);
if (sk->sk_state == TCP_ESTABLISHED) {
/* Prevent rawsock_tx_work from starting new transmits and
* wait for any in-progress work to finish. This must happen
* before the socket is orphaned to avoid a race where
* rawsock_tx_work runs after the NCI device has been freed.
*/
sk->sk_shutdown |= SEND_SHUTDOWN;
cancel_work_sync(&nfc_rawsock(sk)->tx_work);
rawsock_write_queue_purge(sk);
}
sock_orphan(sk);
sock_put(sk);