[PATCH] nfc: llcp: drop socket reference on undelivered UI frames

From
Noah Weinberger <hidden>
Date
2026-11-08 22:25:42
Also in
lkml
Hello,

nfc_llcp_recv_ui() looks up the destination socket with
nfc_llcp_sock_get(), which takes a reference on the match. When the
socket exists but is not SOCK_DGRAM, the function returns at the type
check without calling nfc_llcp_sock_put():

    llcp_sock = nfc_llcp_sock_get(local, dsap, LLCP_SAP_SDP);
    if (llcp_sock == NULL || llcp_sock->sk.sk_type != SOCK_DGRAM)
            return;

A remote LLCP peer can arrange for non-DGRAM sockets whose (ssap, dsap)
match this lookup (accepted stream sockets take dsap from the peer's
CONNECT ssap; connections by service name use dsap = LLCP_SAP_SDP) and
then send any number of UI PDUs addressed to the socket's ssap. Each
frame leaks one socket reference: the socket is pinned forever, even
after close, which is an unbounded kernel memory leak from an RF peer
(memory-exhaustion DoS, rate-limited only by the LLCP link).

All sibling handlers (hdlc, disc, cc, dm) pair the put on every path;
recv_ui is the exception. The patch below puts the reference on all
paths and only delivers to connectionless sockets.

Affected version/commit: mainline fa4ad798f6f681031775266044ba1b0cf3c670bd (v7.4-rc1, 2026-11-07), net/nfc/llcp_core.c:902-936 (nfc_llcp_recv_ui), llcp_core.c:218-251 (nfc_llcp_sock_get/put).
Longstanding code.

This was found during an assisted (AI-supported) static source review of
mainline fa4ad798f6f681031775266044ba1b0cf3c670bd (v7.4-rc1, 2026-11-07); every code path cited below was re-verified by the
reporter against that tree. The patch below has NOT been compiled and has
NOT been runtime tested, and no reproducer was produced - the triggering
conditions are described above instead. Please treat this as a report for
verification rather than a battle-tested fix.

Reported-by: Noah Weinberger <redacted>
---
diff --git a/net/nfc/llcp_core.c b/net/nfc/llcp_core.c
index 74bf817..78f80c4 100644
--- a/net/nfc/llcp_core.c
+++ b/net/nfc/llcp_core.c
@@ -917,9 +917,15 @@ static void nfc_llcp_recv_ui(struct nfc_llcp_local *local,
 
 	/* We're looking for a bound socket, not a client one */
 	llcp_sock = nfc_llcp_sock_get(local, dsap, LLCP_SAP_SDP);
-	if (llcp_sock == NULL || llcp_sock->sk.sk_type != SOCK_DGRAM)
+	if (llcp_sock == NULL)
 		return;
 
+	/* Only connectionless sockets receive UI frames, but the
+	 * reference taken by nfc_llcp_sock_get() must be dropped on
+	 * every other path as well.
+	 */
+	if (llcp_sock->sk.sk_type == SOCK_DGRAM) {
+
 	/* There is no sequence with UI frames */
 	skb_pull(skb, LLCP_HEADER_SIZE);
 	if (!sock_queue_rcv_skb(&llcp_sock->sk, skb)) {
@@ -932,5 +938,6 @@ static void nfc_llcp_recv_ui(struct nfc_llcp_local *local,
 		pr_err("Receive queue is full\n");
 	}
 
+	}
 	nfc_llcp_sock_put(llcp_sock);
 }
Thread (2 messages) 2 messages, 2 authors, last reply 4d ago
Keyboard shortcuts
hback out one level
jnext message in thread / next series-diff position
kprevious message in thread / previous series-diff position
ldrill in
Escclose help / fold thread tree
?toggle this help