* [PATCH net 0/5] nfc: fix leaks and races surfaced by NIPA
@ 2026-03-03 16:23 Jakub Kicinski
2026-03-03 16:23 ` [PATCH net 1/5] nfc: nci: free skb on nci_transceive early error paths Jakub Kicinski
` (5 more replies)
0 siblings, 6 replies; 13+ messages in thread
From: Jakub Kicinski @ 2026-03-03 16:23 UTC (permalink / raw)
To: davem; +Cc: netdev, edumazet, pabeni, andrew+netdev, horms, Jakub Kicinski
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.
Jakub Kicinski (5):
nfc: nci: free skb on nci_transceive early error paths
nfc: digital: free skb on digital_in_send error paths
nfc: nci: complete pending data exchange on device close
nfc: nci: clear NCI_DATA_EXCHANGE before calling completion callback
nfc: rawsock: cancel tx_work before socket teardown
net/nfc/digital_core.c | 8 ++++++--
net/nfc/nci/core.c | 18 ++++++++++++++++--
net/nfc/nci/data.c | 12 ++++++++----
net/nfc/rawsock.c | 11 +++++++++++
4 files changed, 41 insertions(+), 8 deletions(-)
--
2.53.0
^ permalink raw reply [flat|nested] 13+ messages in thread
* [PATCH net 1/5] nfc: nci: free skb on nci_transceive early error paths
2026-03-03 16:23 [PATCH net 0/5] nfc: fix leaks and races surfaced by NIPA Jakub Kicinski
@ 2026-03-03 16:23 ` Jakub Kicinski
2026-03-03 21:02 ` Joe Damato
2026-03-03 16:23 ` [PATCH net 2/5] nfc: digital: free skb on digital_in_send " Jakub Kicinski
` (4 subsequent siblings)
5 siblings, 1 reply; 13+ messages in thread
From: Jakub Kicinski @ 2026-03-03 16:23 UTC (permalink / raw)
To: davem; +Cc: netdev, edumazet, pabeni, andrew+netdev, horms, Jakub Kicinski
nci_transceive() takes ownership of the skb passed by the caller,
but the -EPROTO, -EINVAL, and -EBUSY error paths return without
freeing it.
Due to issues clearing NCI_DATA_EXCHANGE fixed by subsequent changes
the nci/nci_dev selftest hits the error path occasionally in NIPA,
and kmemleak detects leaks:
unreferenced object 0xff11000015ce6a40 (size 640):
comm "nci_dev", pid 3954, jiffies 4295441246
hex dump (first 32 bytes):
6b 6b 6b 6b 00 a4 00 0c 02 e1 03 6b 6b 6b 6b 6b kkkk.......kkkkk
6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b kkkkkkkkkkkkkkkk
backtrace (crc 7c40cc2a):
kmem_cache_alloc_node_noprof+0x492/0x630
__alloc_skb+0x11e/0x5f0
alloc_skb_with_frags+0xc6/0x8f0
sock_alloc_send_pskb+0x326/0x3f0
nfc_alloc_send_skb+0x94/0x1d0
rawsock_sendmsg+0x162/0x4c0
do_syscall_64+0x117/0xfc0
Fixes: 6a2968aaf50c ("NFC: basic NCI protocol implementation")
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
---
net/nfc/nci/core.c | 9 +++++++--
1 file changed, 7 insertions(+), 2 deletions(-)
diff --git a/net/nfc/nci/core.c b/net/nfc/nci/core.c
index 6e9b76e2cc56..40fc397858ce 100644
--- a/net/nfc/nci/core.c
+++ b/net/nfc/nci/core.c
@@ -1035,18 +1035,23 @@ static int nci_transceive(struct nfc_dev *nfc_dev, struct nfc_target *target,
struct nci_conn_info *conn_info;
conn_info = ndev->rf_conn_info;
- if (!conn_info)
+ if (!conn_info) {
+ kfree_skb(skb);
return -EPROTO;
+ }
pr_debug("target_idx %d, len %d\n", target->idx, skb->len);
if (!ndev->target_active_prot) {
pr_err("unable to exchange data, no active target\n");
+ kfree_skb(skb);
return -EINVAL;
}
- if (test_and_set_bit(NCI_DATA_EXCHANGE, &ndev->flags))
+ if (test_and_set_bit(NCI_DATA_EXCHANGE, &ndev->flags)) {
+ kfree_skb(skb);
return -EBUSY;
+ }
/* store cb and context to be used on receiving data */
conn_info->data_exchange_cb = cb;
--
2.53.0
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [PATCH net 2/5] nfc: digital: free skb on digital_in_send error paths
2026-03-03 16:23 [PATCH net 0/5] nfc: fix leaks and races surfaced by NIPA Jakub Kicinski
2026-03-03 16:23 ` [PATCH net 1/5] nfc: nci: free skb on nci_transceive early error paths Jakub Kicinski
@ 2026-03-03 16:23 ` Jakub Kicinski
2026-03-03 21:04 ` Joe Damato
2026-03-03 16:23 ` [PATCH net 3/5] nfc: nci: complete pending data exchange on device close Jakub Kicinski
` (3 subsequent siblings)
5 siblings, 1 reply; 13+ messages in thread
From: Jakub Kicinski @ 2026-03-03 16:23 UTC (permalink / raw)
To: davem; +Cc: netdev, edumazet, pabeni, andrew+netdev, horms, Jakub Kicinski
digital_in_send() takes ownership of the skb passed by the caller
(nfc_data_exchange), make sure it's freed on all error paths.
Found looking around the real driver for similar bugs to the one
just fixed in nci.
Fixes: 7d0911c02fa2 ("NFC: digital: Add NFC-DEP Initiator-side send/receive support")
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
---
net/nfc/digital_core.c | 8 ++++++--
1 file changed, 6 insertions(+), 2 deletions(-)
diff --git a/net/nfc/digital_core.c b/net/nfc/digital_core.c
index 3670bb33732e..7cb1e6aaae90 100644
--- a/net/nfc/digital_core.c
+++ b/net/nfc/digital_core.c
@@ -707,8 +707,10 @@ static int digital_in_send(struct nfc_dev *nfc_dev, struct nfc_target *target,
int rc;
data_exch = kzalloc_obj(*data_exch);
- if (!data_exch)
+ if (!data_exch) {
+ kfree_skb(skb);
return -ENOMEM;
+ }
data_exch->cb = cb;
data_exch->cb_context = cb_context;
@@ -731,8 +733,10 @@ static int digital_in_send(struct nfc_dev *nfc_dev, struct nfc_target *target,
data_exch);
exit:
- if (rc)
+ if (rc) {
+ kfree_skb(skb);
kfree(data_exch);
+ }
return rc;
}
--
2.53.0
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [PATCH net 3/5] nfc: nci: complete pending data exchange on device close
2026-03-03 16:23 [PATCH net 0/5] nfc: fix leaks and races surfaced by NIPA Jakub Kicinski
2026-03-03 16:23 ` [PATCH net 1/5] nfc: nci: free skb on nci_transceive early error paths Jakub Kicinski
2026-03-03 16:23 ` [PATCH net 2/5] nfc: digital: free skb on digital_in_send " Jakub Kicinski
@ 2026-03-03 16:23 ` Jakub Kicinski
2026-03-03 22:03 ` Joe Damato
2026-03-03 16:23 ` [PATCH net 4/5] nfc: nci: clear NCI_DATA_EXCHANGE before calling completion callback Jakub Kicinski
` (2 subsequent siblings)
5 siblings, 1 reply; 13+ messages in thread
From: Jakub Kicinski @ 2026-03-03 16:23 UTC (permalink / raw)
To: davem; +Cc: netdev, edumazet, pabeni, andrew+netdev, horms, Jakub Kicinski
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")
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
---
net/nfc/nci/core.c | 9 +++++++++
1 file changed, 9 insertions(+)
diff --git a/net/nfc/nci/core.c b/net/nfc/nci/core.c
index 40fc397858ce..f8c0bab2ec07 100644
--- a/net/nfc/nci/core.c
+++ b/net/nfc/nci/core.c
@@ -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);
--
2.53.0
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [PATCH net 4/5] nfc: nci: clear NCI_DATA_EXCHANGE before calling completion callback
2026-03-03 16:23 [PATCH net 0/5] nfc: fix leaks and races surfaced by NIPA Jakub Kicinski
` (2 preceding siblings ...)
2026-03-03 16:23 ` [PATCH net 3/5] nfc: nci: complete pending data exchange on device close Jakub Kicinski
@ 2026-03-03 16:23 ` Jakub Kicinski
2026-03-03 22:46 ` Joe Damato
2026-03-03 16:23 ` [PATCH net 5/5] nfc: rawsock: cancel tx_work before socket teardown Jakub Kicinski
2026-03-05 2:40 ` [PATCH net 0/5] nfc: fix leaks and races surfaced by NIPA patchwork-bot+netdevbpf
5 siblings, 1 reply; 13+ messages in thread
From: Jakub Kicinski @ 2026-03-03 16:23 UTC (permalink / raw)
To: davem; +Cc: netdev, edumazet, pabeni, andrew+netdev, horms, Jakub Kicinski
Move clear_bit(NCI_DATA_EXCHANGE) before invoking the data exchange
callback in nci_data_exchange_complete().
The callback (e.g. rawsock_data_exchange_complete) may immediately
schedule another data exchange via schedule_work(tx_work). On a
multi-CPU system, tx_work can run and reach nci_transceive() before
the current nci_data_exchange_complete() clears the flag, causing
test_and_set_bit(NCI_DATA_EXCHANGE) to return -EBUSY and the new
transfer to fail.
This causes intermittent flakes in nci/nci_dev in NIPA:
# # RUN NCI.NCI1_0.t4t_tag_read ...
# # t4t_tag_read: Test terminated by timeout
# # FAIL NCI.NCI1_0.t4t_tag_read
# not ok 3 NCI.NCI1_0.t4t_tag_read
Fixes: 38f04c6b1b68 ("NFC: protect nci_data_exchange transactions")
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
---
net/nfc/nci/data.c | 12 ++++++++----
1 file changed, 8 insertions(+), 4 deletions(-)
diff --git a/net/nfc/nci/data.c b/net/nfc/nci/data.c
index 78f4131af3cf..efb001b41aa8 100644
--- a/net/nfc/nci/data.c
+++ b/net/nfc/nci/data.c
@@ -33,7 +33,8 @@ void nci_data_exchange_complete(struct nci_dev *ndev, struct sk_buff *skb,
conn_info = nci_get_conn_info_by_conn_id(ndev, conn_id);
if (!conn_info) {
kfree_skb(skb);
- goto exit;
+ clear_bit(NCI_DATA_EXCHANGE, &ndev->flags);
+ return;
}
cb = conn_info->data_exchange_cb;
@@ -45,6 +46,12 @@ 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);
+
if (cb) {
/* forward skb to nfc core */
cb(cb_context, skb, err);
@@ -54,9 +61,6 @@ void nci_data_exchange_complete(struct nci_dev *ndev, struct sk_buff *skb,
/* no waiting callback, free skb */
kfree_skb(skb);
}
-
-exit:
- clear_bit(NCI_DATA_EXCHANGE, &ndev->flags);
}
/* ----------------- NCI TX Data ----------------- */
--
2.53.0
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [PATCH net 5/5] nfc: rawsock: cancel tx_work before socket teardown
2026-03-03 16:23 [PATCH net 0/5] nfc: fix leaks and races surfaced by NIPA Jakub Kicinski
` (3 preceding siblings ...)
2026-03-03 16:23 ` [PATCH net 4/5] nfc: nci: clear NCI_DATA_EXCHANGE before calling completion callback Jakub Kicinski
@ 2026-03-03 16:23 ` Jakub Kicinski
2026-03-03 22:51 ` Joe Damato
2026-03-24 13:31 ` Guenter Roeck
2026-03-05 2:40 ` [PATCH net 0/5] nfc: fix leaks and races surfaced by NIPA patchwork-bot+netdevbpf
5 siblings, 2 replies; 13+ messages in thread
From: Jakub Kicinski @ 2026-03-03 16:23 UTC (permalink / raw)
To: davem; +Cc: netdev, edumazet, pabeni, andrew+netdev, horms, Jakub Kicinski
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")
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
---
net/nfc/rawsock.c | 11 +++++++++++
1 file changed, 11 insertions(+)
diff --git a/net/nfc/rawsock.c b/net/nfc/rawsock.c
index b049022399ae..f7d7a599fade 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);
--
2.53.0
^ permalink raw reply related [flat|nested] 13+ messages in thread
* Re: [PATCH net 1/5] nfc: nci: free skb on nci_transceive early error paths
2026-03-03 16:23 ` [PATCH net 1/5] nfc: nci: free skb on nci_transceive early error paths Jakub Kicinski
@ 2026-03-03 21:02 ` Joe Damato
0 siblings, 0 replies; 13+ messages in thread
From: Joe Damato @ 2026-03-03 21:02 UTC (permalink / raw)
To: Jakub Kicinski; +Cc: davem, netdev, edumazet, pabeni, andrew+netdev, horms
On Tue, Mar 03, 2026 at 08:23:41AM -0800, Jakub Kicinski wrote:
> nci_transceive() takes ownership of the skb passed by the caller,
> but the -EPROTO, -EINVAL, and -EBUSY error paths return without
> freeing it.
>
> Due to issues clearing NCI_DATA_EXCHANGE fixed by subsequent changes
> the nci/nci_dev selftest hits the error path occasionally in NIPA,
> and kmemleak detects leaks:
>
> unreferenced object 0xff11000015ce6a40 (size 640):
> comm "nci_dev", pid 3954, jiffies 4295441246
> hex dump (first 32 bytes):
> 6b 6b 6b 6b 00 a4 00 0c 02 e1 03 6b 6b 6b 6b 6b kkkk.......kkkkk
> 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b kkkkkkkkkkkkkkkk
> backtrace (crc 7c40cc2a):
> kmem_cache_alloc_node_noprof+0x492/0x630
> __alloc_skb+0x11e/0x5f0
> alloc_skb_with_frags+0xc6/0x8f0
> sock_alloc_send_pskb+0x326/0x3f0
> nfc_alloc_send_skb+0x94/0x1d0
> rawsock_sendmsg+0x162/0x4c0
> do_syscall_64+0x117/0xfc0
>
> Fixes: 6a2968aaf50c ("NFC: basic NCI protocol implementation")
> Signed-off-by: Jakub Kicinski <kuba@kernel.org>
> ---
> net/nfc/nci/core.c | 9 +++++++--
> 1 file changed, 7 insertions(+), 2 deletions(-)
>
Reviewed-by: Joe Damato <joe@dama.to>
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH net 2/5] nfc: digital: free skb on digital_in_send error paths
2026-03-03 16:23 ` [PATCH net 2/5] nfc: digital: free skb on digital_in_send " Jakub Kicinski
@ 2026-03-03 21:04 ` Joe Damato
0 siblings, 0 replies; 13+ messages in thread
From: Joe Damato @ 2026-03-03 21:04 UTC (permalink / raw)
To: Jakub Kicinski; +Cc: davem, netdev, edumazet, pabeni, andrew+netdev, horms
On Tue, Mar 03, 2026 at 08:23:42AM -0800, Jakub Kicinski wrote:
> digital_in_send() takes ownership of the skb passed by the caller
> (nfc_data_exchange), make sure it's freed on all error paths.
>
> Found looking around the real driver for similar bugs to the one
> just fixed in nci.
>
> Fixes: 7d0911c02fa2 ("NFC: digital: Add NFC-DEP Initiator-side send/receive support")
> Signed-off-by: Jakub Kicinski <kuba@kernel.org>
> ---
> net/nfc/digital_core.c | 8 ++++++--
> 1 file changed, 6 insertions(+), 2 deletions(-)
>
Reviewed-by: Joe Damato <joe@dama.to>
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH net 3/5] nfc: nci: complete pending data exchange on device close
2026-03-03 16:23 ` [PATCH net 3/5] nfc: nci: complete pending data exchange on device close Jakub Kicinski
@ 2026-03-03 22:03 ` Joe Damato
0 siblings, 0 replies; 13+ messages in thread
From: Joe Damato @ 2026-03-03 22:03 UTC (permalink / raw)
To: Jakub Kicinski; +Cc: davem, netdev, edumazet, pabeni, andrew+netdev, horms
On Tue, Mar 03, 2026 at 08:23:43AM -0800, Jakub Kicinski wrote:
> 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")
> Signed-off-by: Jakub Kicinski <kuba@kernel.org>
> ---
> net/nfc/nci/core.c | 9 +++++++++
> 1 file changed, 9 insertions(+)
Reviewed-by: Joe Damato <joe@dama.to>
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH net 4/5] nfc: nci: clear NCI_DATA_EXCHANGE before calling completion callback
2026-03-03 16:23 ` [PATCH net 4/5] nfc: nci: clear NCI_DATA_EXCHANGE before calling completion callback Jakub Kicinski
@ 2026-03-03 22:46 ` Joe Damato
0 siblings, 0 replies; 13+ messages in thread
From: Joe Damato @ 2026-03-03 22:46 UTC (permalink / raw)
To: Jakub Kicinski; +Cc: davem, netdev, edumazet, pabeni, andrew+netdev, horms
On Tue, Mar 03, 2026 at 08:23:44AM -0800, Jakub Kicinski wrote:
> Move clear_bit(NCI_DATA_EXCHANGE) before invoking the data exchange
> callback in nci_data_exchange_complete().
>
> The callback (e.g. rawsock_data_exchange_complete) may immediately
> schedule another data exchange via schedule_work(tx_work). On a
> multi-CPU system, tx_work can run and reach nci_transceive() before
> the current nci_data_exchange_complete() clears the flag, causing
> test_and_set_bit(NCI_DATA_EXCHANGE) to return -EBUSY and the new
> transfer to fail.
>
> This causes intermittent flakes in nci/nci_dev in NIPA:
>
> # # RUN NCI.NCI1_0.t4t_tag_read ...
> # # t4t_tag_read: Test terminated by timeout
> # # FAIL NCI.NCI1_0.t4t_tag_read
> # not ok 3 NCI.NCI1_0.t4t_tag_read
>
> Fixes: 38f04c6b1b68 ("NFC: protect nci_data_exchange transactions")
> Signed-off-by: Jakub Kicinski <kuba@kernel.org>
> ---
> net/nfc/nci/data.c | 12 ++++++++----
> 1 file changed, 8 insertions(+), 4 deletions(-)
Reviewed-by: Joe Damato <joe@dama.to>
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH net 5/5] nfc: rawsock: cancel tx_work before socket teardown
2026-03-03 16:23 ` [PATCH net 5/5] nfc: rawsock: cancel tx_work before socket teardown Jakub Kicinski
@ 2026-03-03 22:51 ` Joe Damato
2026-03-24 13:31 ` Guenter Roeck
1 sibling, 0 replies; 13+ messages in thread
From: Joe Damato @ 2026-03-03 22:51 UTC (permalink / raw)
To: Jakub Kicinski; +Cc: davem, netdev, edumazet, pabeni, andrew+netdev, horms
On Tue, Mar 03, 2026 at 08:23:45AM -0800, Jakub Kicinski wrote:
> 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")
> Signed-off-by: Jakub Kicinski <kuba@kernel.org>
> ---
> net/nfc/rawsock.c | 11 +++++++++++
> 1 file changed, 11 insertions(+)
>
Reviewed-by: Joe Damato <joe@dama.to>
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH net 0/5] nfc: fix leaks and races surfaced by NIPA
2026-03-03 16:23 [PATCH net 0/5] nfc: fix leaks and races surfaced by NIPA Jakub Kicinski
` (4 preceding siblings ...)
2026-03-03 16:23 ` [PATCH net 5/5] nfc: rawsock: cancel tx_work before socket teardown Jakub Kicinski
@ 2026-03-05 2:40 ` patchwork-bot+netdevbpf
5 siblings, 0 replies; 13+ messages in thread
From: patchwork-bot+netdevbpf @ 2026-03-05 2:40 UTC (permalink / raw)
To: Jakub Kicinski; +Cc: davem, netdev, edumazet, pabeni, andrew+netdev, horms
Hello:
This series was applied to netdev/net.git (main)
by Jakub Kicinski <kuba@kernel.org>:
On Tue, 3 Mar 2026 08:23:40 -0800 you wrote:
> 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.
>
> Jakub Kicinski (5):
> nfc: nci: free skb on nci_transceive early error paths
> nfc: digital: free skb on digital_in_send error paths
> nfc: nci: complete pending data exchange on device close
> nfc: nci: clear NCI_DATA_EXCHANGE before calling completion callback
> nfc: rawsock: cancel tx_work before socket teardown
>
> [...]
Here is the summary with links:
- [net,1/5] nfc: nci: free skb on nci_transceive early error paths
https://git.kernel.org/netdev/net/c/7bd4b0c4779f
- [net,2/5] nfc: digital: free skb on digital_in_send error paths
https://git.kernel.org/netdev/net/c/d42449d2c17c
- [net,3/5] nfc: nci: complete pending data exchange on device close
https://git.kernel.org/netdev/net/c/66083581945b
- [net,4/5] nfc: nci: clear NCI_DATA_EXCHANGE before calling completion callback
https://git.kernel.org/netdev/net/c/0efdc02f4f6d
- [net,5/5] nfc: rawsock: cancel tx_work before socket teardown
https://git.kernel.org/netdev/net/c/d793458c45df
You are awesome, thank you!
--
Deet-doot-dot, I am a bot.
https://korg.docs.kernel.org/patchwork/pwbot.html
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH net 5/5] nfc: rawsock: cancel tx_work before socket teardown
2026-03-03 16:23 ` [PATCH net 5/5] nfc: rawsock: cancel tx_work before socket teardown Jakub Kicinski
2026-03-03 22:51 ` Joe Damato
@ 2026-03-24 13:31 ` Guenter Roeck
1 sibling, 0 replies; 13+ messages in thread
From: Guenter Roeck @ 2026-03-24 13:31 UTC (permalink / raw)
To: Jakub Kicinski; +Cc: davem, netdev, edumazet, pabeni, andrew+netdev, horms
Hi,
On Tue, Mar 03, 2026 at 08:23:45AM -0800, Jakub Kicinski wrote:
> 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")
> Signed-off-by: Jakub Kicinski <kuba@kernel.org>
> ---
> net/nfc/rawsock.c | 11 +++++++++++
> 1 file changed, 11 insertions(+)
>
> diff --git a/net/nfc/rawsock.c b/net/nfc/rawsock.c
> index b049022399ae..f7d7a599fade 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);
> + }
> +
Google's AI agent had the following fedback on this patch:
Does cancel_work_sync() properly wait for the asynchronous nfc_data_exchange()
to complete?
Since rawsock_tx_work() only initiates the exchange and then returns, the work
item is no longer running or pending while the exchange is in flight. This
means cancel_work_sync() might return immediately.
> + rawsock_write_queue_purge(sk);
If the hardware completes the data exchange after cancel_work_sync() has
returned, but before rawsock_write_queue_purge() empties the write queue,
rawsock_data_exchange_complete() will see a non-empty queue and call
schedule_work().
Because cancel_work_sync() has already finished, this newly scheduled tx_work
could execute after rawsock_release() has freed the socket. Can this lead
to a use-after-free?
On top of that, I don't see how the this patch change would prevent the
problem it tries to fix if tx_work is running and has proceeded beyond
the SEND_SHUTDOWN check.
My apologies if this is all just noise. If so, please let me know what is
wrong with the analysis to help improve the agent.
Thanks,
Guenter
^ permalink raw reply [flat|nested] 13+ messages in thread
end of thread, other threads:[~2026-03-24 13:31 UTC | newest]
Thread overview: 13+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-03-03 16:23 [PATCH net 0/5] nfc: fix leaks and races surfaced by NIPA Jakub Kicinski
2026-03-03 16:23 ` [PATCH net 1/5] nfc: nci: free skb on nci_transceive early error paths Jakub Kicinski
2026-03-03 21:02 ` Joe Damato
2026-03-03 16:23 ` [PATCH net 2/5] nfc: digital: free skb on digital_in_send " Jakub Kicinski
2026-03-03 21:04 ` Joe Damato
2026-03-03 16:23 ` [PATCH net 3/5] nfc: nci: complete pending data exchange on device close Jakub Kicinski
2026-03-03 22:03 ` Joe Damato
2026-03-03 16:23 ` [PATCH net 4/5] nfc: nci: clear NCI_DATA_EXCHANGE before calling completion callback Jakub Kicinski
2026-03-03 22:46 ` Joe Damato
2026-03-03 16:23 ` [PATCH net 5/5] nfc: rawsock: cancel tx_work before socket teardown Jakub Kicinski
2026-03-03 22:51 ` Joe Damato
2026-03-24 13:31 ` Guenter Roeck
2026-03-05 2:40 ` [PATCH net 0/5] nfc: fix leaks and races surfaced by NIPA patchwork-bot+netdevbpf
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox