From nobody Sat Jul 25 06:09:17 2026 Received: from mail-ej1-f48.google.com (mail-ej1-f48.google.com [209.85.218.48]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 8ED9727466A for ; Thu, 16 Jul 2026 23:27:13 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.218.48 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784244435; cv=none; b=UIdEy9iiR/czSBzvDaejJjsA6rnuueLd9s6cI7iqwx2o1yNCO0XbMpudoyRUuJfivmB+CXGg/AeOjb52Ho71FKpEdNYT7bhQHtGa/PGMhdGxrnmbIV3Yb0OWoLHt6rbI0rc7lpa/ub/cikTAxzhle/Ffm38CdhlbieQkP9yFmvk= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784244435; c=relaxed/simple; bh=lu7YV5CCiyyOEgBNVeSsxlZkRV4pW1Z5+pf0FhhYiGM=; h=From:To:Cc:Subject:Date:Message-ID:MIME-Version; b=AJ2Cdacm8DsqJdl4nezkvuNnNQIRsBt03SRVxiLCbhGHh6gl08V0O38TQ7hyAbhXyBTpn5HXwgf4gmJY+rEhLiur2HQrKoivk2uRIXmOrZrtbjwTFJ+0uvxk+TxWWpjhmmtQ2deItoF/kxDhvxIVl6zEoSHInsDjFpwQrTpY7nQ= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=VmB6vs5j; arc=none smtp.client-ip=209.85.218.48 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="VmB6vs5j" Received: by mail-ej1-f48.google.com with SMTP id a640c23a62f3a-c165a41a52bso510228766b.3 for ; Thu, 16 Jul 2026 16:27:13 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1784244432; x=1784849232; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:message-id:date:subject:cc :to:from:from:to:cc:subject:date:message-id:reply-to:content-type; bh=WXuUFnyylEezjX3V9l0E0T/Ofv34IDOK/Bhil0kWQpA=; b=VmB6vs5jM57ysQUsDiFFcPQI9s+ZbXzQN20hqomrughJ9Ud8GlyZ0OGVuqD9qELtW3 Ps/2iCkmHjNp/R8Hy5HopqnyleavOJNUpUZzgVAVVBf52aGim6LSd3mwDTVuyPXf2Enr A/bosGHRd9cvYXh2r875s6LVhmXP8qbw9hf8i1jUMTYjDeA8yf8XtUHzBaQVcGUhar7/ OVztUjQsV5sSrNS0jSFcp4DOaeGHNA5OaKeRqpD6fkjUq8+zxjCfDhD/CFvckDRPyEfo 4iRD5ewtJuXD2sMMYPHSdxFy4Um5b7/P/xZlb+uCeYcfig5LhvaeP5r1KaqAmxGrtlPW f9aQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1784244432; x=1784849232; h=content-transfer-encoding:mime-version:message-id:date:subject:cc :to:from:x-gm-gg:x-gm-message-state:from:to:cc:subject:date :message-id:reply-to:content-type; bh=WXuUFnyylEezjX3V9l0E0T/Ofv34IDOK/Bhil0kWQpA=; b=YZfVdroI3knf0jBPhhplmD0H1GMDN6uMHEUIchLmussnCe9g7aIMCCGmujfuvy03ds CfnK219Jm83lQCHh1VDut83zOXjQWBAxSP/X0hnITtnwQLX8gWHMxwn3C9F90L0ARNYE JJaW0R369jeq4UCD05IdgOdM+fe9YXqvYrg7G35fFowsQf0o51LZuLDG+W+yi5xuc6PK oZsKe2ZYSuynRoE1hLYlrhdkBrTCNPizw2aoGcV901GXfrlec+Wf1nfiID6xnhajF/Vr LT0F+bq0ES0QyGA2XVFKzf635abBwHJzdQdWj23zwB+ZuXkkTezN/YX2cOt/3HTLANx1 iFXw== X-Forwarded-Encrypted: i=1; AHgh+RocC4iW3Dlh3XWt0xsNQmCj3wbBA1o8iEgA95vETeCI5vM+lVWYdNY88RcnE3asE5KFcx/+Bq9dDchG9PU=@vger.kernel.org X-Gm-Message-State: AOJu0YwnBRFgLk07224ipIzsimWLpDsmHHod7YHm3wWhVPch7DO/z7x0 pF/HCHI8+dC4rlWKw0iEPxXR6vTGV9wC2TrB1AfuHvUWfkGqcR0tYSap X-Gm-Gg: AfdE7cnCQbQi5FqTlwaS16tW3LaPvdjJ84Jnyg4gLGOokSZYfVh/lqpDWBPV8BJ/x2w 4bSEsWoG5eurnfe3IXTpKkAu1+2Ctmv9M7u3twRzXGa9tJAt3FYXCmTBWQWmkfzxm7EVA8qPpLk Zu0jr3zjkyPr+toLn4xNezgOEmhg7tfGEHo4r2neys3OL4lSOiPrTmRH8a8qKiPA91JpOk1kMCt 1OFuTjLZvc7OVim0wQHObPVGLAmHdECj6BJ0NjKi0atJzpzulokMxfY+rGYjkMyki6xBlAX7nvt IRwt1m+1ggUqLe2W0MVZGKJaD8t7hNVQLUNjeftSi06TeDlXButICMiKD4S3E53gahnhxL1NSMt znEsxpQv7zcHOJ6wFSxllYh3mNWEFwpuQQiuq+onC6MQFC+dVIdedrmsKq0DDHcWdI/Zo0Q== X-Received: by 2002:a17:907:6094:b0:c12:a16f:6864 with SMTP id a640c23a62f3a-c16b476b7b3mr599666b.48.1784244431513; Thu, 16 Jul 2026 16:27:11 -0700 (PDT) Received: from beelink.. ([164.5.253.70]) by smtp.gmail.com with ESMTPSA id a640c23a62f3a-c168744966asm295102766b.50.2026.07.16.16.27.06 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 16 Jul 2026 16:27:10 -0700 (PDT) From: Aldo Ariel Panzardo To: David Heidelberg , "David S . Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni Cc: Simon Horman , netdev@vger.kernel.org, oe-linux-nfc@lists.linux.dev, linux-kernel@vger.kernel.org, Aldo Ariel Panzardo Subject: [PATCH net] nfc: llcp: Fix list corruption / refcount desync in nfc_llcp_recv_dm() Date: Thu, 16 Jul 2026 20:26:57 -0300 Message-ID: <20260716232657.203145-1-qwe.aldo@gmail.com> X-Mailer: git-send-email 2.43.0 Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" nfc_llcp_recv_dm() handles DM(NOBOUND)/DM(REJ) for a socket that is still linked on local->connecting_sockets: it looks the socket up with nfc_llcp_connecting_sock_get(), sets sk->sk_state =3D LLCP_CLOSED and returns, without taking the socket lock and without unlinking the socket from the connecting_sockets list. llcp_sock_release() selects the list to unlink from by sk_state: a socket in LLCP_CONNECTING is unlinked from connecting_sockets, otherwise from the sockets list. Because recv_dm left the socket physically on connecting_sockets but in the LLCP_CLOSED state, release() takes the else branch and calls nfc_llcp_sock_unlink(&local->sockets, sk). That runs sk_del_node_init() while holding sockets.lock, i.e. it removes the socket from the connecting_sockets hlist under the wrong lock. A concurrent connect() linking another socket onto connecting_sockets under connecting_sockets.lock then mutates the same hlist unserialized, which corrupts the list and desyncs the sk_add_node()/sk_del_node_init() sock_hold()/__sock_put() pairing. An unprivileged local process holding LLCP sockets, with the DM supplied by the remote peer over an established LLCP link, can drive this to leak kernel sockets without bound (the mis-decrement goes through the non-freeing __sock_put() path, so the object is never released), leading to memory exhaustion / DoS. This is the same class of bug that was fixed in the sibling handler nfc_llcp_recv_cc() by commit b493ea2765cc ("nfc: llcp: Fix use-after-free race in nfc_llcp_recv_cc()"); recv_dm did not receive the equivalent fix. Fix it the same way: take lock_sock(), re-check that the socket is still hashed (release() may have won the race), and for the NOBOUND/REJ case unlink it from connecting_sockets before moving it to LLCP_CLOSED. The unlink drops the connecting_sockets membership reference via sk_del_node_init(), leaving the socket unhashed, so the later nfc_llcp_sock_unlink() in llcp_sock_release() becomes a no-op and no double put occurs. Fixes: a69f32af86e3 ("NFC: Socket linked list") Signed-off-by: Aldo Ariel Panzardo --- net/nfc/llcp_core.c | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/net/nfc/llcp_core.c b/net/nfc/llcp_core.c index dc65c719f35f..d8dbb1bb857b 100644 --- a/net/nfc/llcp_core.c +++ b/net/nfc/llcp_core.c @@ -1249,6 +1249,7 @@ static void nfc_llcp_recv_dm(struct nfc_llcp_local *l= ocal, struct nfc_llcp_sock *llcp_sock; struct sock *sk; u8 dsap, ssap, reason; + bool connecting =3D false; =20 dsap =3D nfc_llcp_dsap(skb); ssap =3D nfc_llcp_ssap(skb); @@ -1260,6 +1261,7 @@ static void nfc_llcp_recv_dm(struct nfc_llcp_local *l= ocal, case LLCP_DM_NOBOUND: case LLCP_DM_REJ: llcp_sock =3D nfc_llcp_connecting_sock_get(local, dsap); + connecting =3D true; break; =20 default: @@ -1274,10 +1276,33 @@ static void nfc_llcp_recv_dm(struct nfc_llcp_local = *local, =20 sk =3D &llcp_sock->sk; =20 + lock_sock(sk); + + /* Check if socket was destroyed whilst waiting for the lock */ + if (!sk_hashed(sk)) { + release_sock(sk); + nfc_llcp_sock_put(llcp_sock); + return; + } + + /* + * For DM(NOBOUND)/DM(REJ) the socket is still linked on the + * connecting_sockets list. Unlink it here, under the socket lock, + * before moving it to LLCP_CLOSED: llcp_sock_release() selects the + * list to unlink from by sk_state, so leaving a connecting socket + * in the CLOSED state would make it unlink from the wrong list and + * corrupt the connecting_sockets list / desync the socket refcount. + * This mirrors nfc_llcp_recv_cc(). + */ + if (connecting) + nfc_llcp_sock_unlink(&local->connecting_sockets, sk); + sk->sk_err =3D ENXIO; sk->sk_state =3D LLCP_CLOSED; sk->sk_state_change(sk); =20 + release_sock(sk); + nfc_llcp_sock_put(llcp_sock); } =20 base-commit: 3f1f755366687d051174739fb99f7d560202f60b --=20 2.43.0