diff options
| author | Jakub Kicinski <kuba@kernel.org> | 2026-03-03 08:23:41 -0800 |
|---|---|---|
| committer | Sasha Levin <sashal@kernel.org> | 2026-03-12 07:09:58 -0400 |
| commit | 9d448bbab724b94d6c561e1f314656f5b88a7cb3 (patch) | |
| tree | 91d8d6d8006bff5dcf6f747dbd070a1c8cf4b943 | |
| parent | a77a5423e9c632d8c9eaa480ebf5367ecb16f646 (diff) | |
| download | linux-9d448bbab724b94d6c561e1f314656f5b88a7cb3.tar.gz linux-9d448bbab724b94d6c561e1f314656f5b88a7cb3.tar.bz2 linux-9d448bbab724b94d6c561e1f314656f5b88a7cb3.zip | |
nfc: nci: free skb on nci_transceive early error paths
[ Upstream commit 7bd4b0c4779f978a6528c9b7937d2ca18e936e2c ]
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")
Reviewed-by: Joe Damato <joe@dama.to>
Link: https://patch.msgid.link/20260303162346.2071888-2-kuba@kernel.org
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
| -rw-r--r-- | net/nfc/nci/core.c | 9 |
1 files changed, 7 insertions, 2 deletions
diff --git a/net/nfc/nci/core.c b/net/nfc/nci/core.c index 46681bdaeabf..f6dc0a94b8d5 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; |
