All of lore.kernel.org
 help / color / mirror / Atom feed
From: Yuchao Zhang <ndaugoing@gmail.com>
To: David Heidelberg <david@ixit.cz>
Cc: "David S . Miller" <davem@davemloft.net>,
	Eric Dumazet <edumazet@google.com>,
	Jakub Kicinski <kuba@kernel.org>, Paolo Abeni <pabeni@redhat.com>,
	Simon Horman <horms@kernel.org>,
	oe-linux-nfc@lists.linux.dev, netdev@vger.kernel.org,
	linux-kernel@vger.kernel.org, Yuchao Zhang <ndaugoing@gmail.com>
Subject: [PATCH 1/1] nfc: llcp: reject connect() on sockets not in LLCP_CLOSED state
Date: Fri, 18 Sep 2026 11:39:20 +0800	[thread overview]
Message-ID: <20260918033920.85025-2-ndaugoing@gmail.com> (raw)
In-Reply-To: <20260918033920.85025-1-ndaugoing@gmail.com>

When a socket is bound via llcp_sock_bind(), its state transitions to
LLCP_BOUND and it is linked into the local->sockets hlist via
nfc_llcp_sock_link().

Currently, llcp_sock_connect() only checks if the socket is already
connected (LLCP_CONNECTED) or in progress (LLCP_CONNECTING):

	if (sk->sk_state == LLCP_CONNECTED) {
		ret = -EISCONN;
		goto error;
	}
	if (sk->sk_state == LLCP_CONNECTING) {
		ret = -EINPROGRESS;
		goto error;
	}

Crucially, it does not check for the LLCP_BOUND (or LLCP_LISTEN) state.
Previous fixes addressing CVE-2020-25670 / CVE-2020-25673 added the check
for LLCP_CONNECTING to prevent duplicate in-flight connection attempts
from corrupting the connecting_sockets list. However, they assumed any
other non-connected socket was in LLCP_CLOSED, leaving the LLCP_BOUND
state window unhandled.

If connect() is invoked on a socket that has already been bound:
1. llcp_sock_connect() silently overwrites llcp_sock->dev and
   llcp_sock->local without releasing previous references or freeing the
   bound service_name, leading to refcount and memory leaks.
2. The socket remains linked in local->sockets, while llcp_sock_connect()
   links it again into local->connecting_sockets via nfc_llcp_sock_link().
3. When connection confirmation (CC) arrives, nfc_llcp_recv_cc() executes:

	nfc_llcp_sock_unlink(&local->connecting_sockets, sk);
	nfc_llcp_sock_link(&local->sockets, sk);

   Because sk was never unlinked from local->sockets, the head.first of
   local->sockets still points to &sk->sk_node. The second
   hlist_add_head() sets sk->sk_node.next = sk->sk_node, producing a
   self-referential loop. Subsequent traversals of local->sockets
   (e.g. nfc_llcp_sock_get(), nfc_llcp_socket_release()) enter an
   infinite loop with spinlocks held, resulting in kernel soft-lockups.
4. Furthermore, if connect() specifies a different NFC device index than
   bind(), the socket remains linked on device A's socket list while
   being assigned to device B, causing cross-device socket confusion.

Fix this by ensuring that llcp_sock_connect() only accepts sockets in the
LLCP_CLOSED state, returning -EBADFD otherwise, matching the state check
behavior in llcp_sock_bind().

Fixes: d646960f7986 ("NFC: Initial LLCP support")
Signed-off-by: Yuchao Zhang <ndaugoing@gmail.com>
---
 net/nfc/llcp_sock.c | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/net/nfc/llcp_sock.c b/net/nfc/llcp_sock.c
index 5558d8a4d48b..66f12e9af2fd 100644
--- a/net/nfc/llcp_sock.c
+++ b/net/nfc/llcp_sock.c
@@ -689,6 +689,10 @@ static int llcp_sock_connect(struct socket *sock, struct sockaddr_unsized *_addr
 		ret = -EINPROGRESS;
 		goto error;
 	}
+	if (sk->sk_state != LLCP_CLOSED) {
+		ret = -EBADFD;
+		goto error;
+	}
 
 	dev = nfc_get_device(addr->dev_idx);
 	if (dev == NULL) {
-- 
2.53.0


  reply	other threads:[~2026-09-18  3:39 UTC|newest]

Thread overview: 3+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-09-18  3:39 [PATCH 0/1] nfc: llcp: reject connect() on sockets not in LLCP_CLOSED state Yuchao Zhang
2026-09-18  3:39 ` Yuchao Zhang [this message]
2026-09-21 14:08   ` [PATCH 1/1] " Simon Horman

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260918033920.85025-2-ndaugoing@gmail.com \
    --to=ndaugoing@gmail.com \
    --cc=davem@davemloft.net \
    --cc=david@ixit.cz \
    --cc=edumazet@google.com \
    --cc=horms@kernel.org \
    --cc=kuba@kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=netdev@vger.kernel.org \
    --cc=oe-linux-nfc@lists.linux.dev \
    --cc=pabeni@redhat.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.