diff options
| author | Jakub Kicinski <kuba@kernel.org> | 2026-03-03 08:23:45 -0800 |
|---|---|---|
| committer | Sasha Levin <sashal@kernel.org> | 2026-03-12 07:09:59 -0400 |
| commit | edc988613def90c5b558e025b1b423f48007be06 (patch) | |
| tree | 28bda1cea418482d84fd449df6a43c6870ffe54f | |
| parent | b3fdbc7f59cdfe7094bb1ca7e92957e4ced6b08e (diff) | |
| download | linux-edc988613def90c5b558e025b1b423f48007be06.tar.gz linux-edc988613def90c5b558e025b1b423f48007be06.tar.bz2 linux-edc988613def90c5b558e025b1b423f48007be06.zip | |
nfc: rawsock: cancel tx_work before socket teardown
[ Upstream commit d793458c45df2aed498d7f74145eab7ee22d25aa ]
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: 23b7869c0fd0 ("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>
Signed-off-by: Sasha Levin <sashal@kernel.org>
| -rw-r--r-- | net/nfc/rawsock.c | 11 |
1 files changed, 11 insertions, 0 deletions
diff --git a/net/nfc/rawsock.c b/net/nfc/rawsock.c index 5125392bb68e..028b4daafaf8 100644 --- a/net/nfc/rawsock.c +++ b/net/nfc/rawsock.c @@ -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); |
