* [PATCH net v2 0/2] nfc: llcp: two fixes for nfc_llcp_getsockopt()
@ 2026-05-21 14:32 Breno Leitao
2026-05-21 14:32 ` [PATCH net v2 1/2] nfc: llcp: avoid userspace overflow on invalid optlen Breno Leitao
` (2 more replies)
0 siblings, 3 replies; 5+ messages in thread
From: Breno Leitao @ 2026-05-21 14:32 UTC (permalink / raw)
To: David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Simon Horman, Shuah Khan, David Heidelberg, Samuel Ortiz
Cc: linux-kernel, netdev, linux-kselftest, oe-linux-nfc, Breno Leitao,
kernel-team
While converting the NFC LLCP socket layer to the new getsockopt_iter()
API, I noticed that nfc_llcp_getsockopt() unconditionally stores four
bytes through a (u32 __user *) cast regardless of the caller-supplied
optlen, overflowing the user buffer when optlen < 4. Patch 1 adds an
explicit length check (with a signed-int guard so a negative optlen
cannot slip past it) and is what I originally sent as v1.
While reviewing v1, Simon/sashiko[1] pointed out that llcp_sock->local
is read outside lock_sock(sk) and can be freed by a concurrent
llcp_sock_bind() error path before getsockopt() dereferences it. Patch
2 moves the load and the NULL check inside the lock. Both fixes target
the same original commit, so they are now sent together as a two-patch
series.
Note: These fixes were compile-tested.
[1] https://lore.kernel.org/all/20260513-fix_llc-v1-1-33c76f931ff6@debian.org/
Signed-off-by: Breno Leitao <leitao@debian.org>
---
Changes in v2:
- Guard the length check against negative optlen (Simon Horman / sashiko).
- Add patch 2: move llcp_sock->local read inside lock_sock(sk) to close
a UAF race with llcp_sock_bind() (Simon Horman / sashiko).
- Link to v1: https://patch.msgid.link/20260513-fix_llc-v1-1-33c76f931ff6@debian.org
To: David Heidelberg <david+nfc@ixit.cz>
To: "David S. Miller" <davem@davemloft.net>
To: Eric Dumazet <edumazet@google.com>
To: Jakub Kicinski <kuba@kernel.org>
To: Paolo Abeni <pabeni@redhat.com>
To: Simon Horman <horms@kernel.org>
To: Samuel Ortiz <sameo@linux.intel.com>
Cc: oe-linux-nfc@lists.linux.dev
Cc: netdev@vger.kernel.org
Cc: linux-kernel@vger.kernel.org
---
Breno Leitao (2):
nfc: llcp: avoid userspace overflow on invalid optlen
nfc: llcp: read llcp_sock->local under the socket lock in getsockopt
net/nfc/llcp_sock.c | 14 +++++++++++---
1 file changed, 11 insertions(+), 3 deletions(-)
---
base-commit: 1d5dcaa3bd65f2e8c9baa14a393d3a2dc5db7524
change-id: 20260513-fix_llc-27f483568135
Best regards,
--
Breno Leitao <leitao@debian.org>
^ permalink raw reply [flat|nested] 5+ messages in thread
* [PATCH net v2 1/2] nfc: llcp: avoid userspace overflow on invalid optlen
2026-05-21 14:32 [PATCH net v2 0/2] nfc: llcp: two fixes for nfc_llcp_getsockopt() Breno Leitao
@ 2026-05-21 14:32 ` Breno Leitao
2026-05-21 14:32 ` [PATCH net v2 2/2] nfc: llcp: read llcp_sock->local under the socket lock in getsockopt Breno Leitao
2026-05-26 17:33 ` [PATCH net v2 0/2] nfc: llcp: two fixes for nfc_llcp_getsockopt() Simon Horman
2 siblings, 0 replies; 5+ messages in thread
From: Breno Leitao @ 2026-05-21 14:32 UTC (permalink / raw)
To: David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Simon Horman, Shuah Khan, David Heidelberg, Samuel Ortiz
Cc: linux-kernel, netdev, linux-kselftest, oe-linux-nfc, Breno Leitao,
kernel-team
nfc_llcp_getsockopt() casts optval to (u32 __user *) for put_user(), so
the kernel always stores 4 bytes regardless of the caller-supplied
optlen. The existing min_t(u32, len, sizeof(u32)) only clamps the length
reported back to userspace; it does not constrain the store. A call with
optlen < 4 therefore writes past the user buffer, violating the
getsockopt(2) contract for all five supported optnames.
Reject any call with optlen < sizeof(u32) up front. 'len' is int, so a
plain size comparison would promote a negative optlen to size_t and slip
past the check; an explicit 'len < 0' test is added first to catch
negative values before the size compare.
Fixes: 26fd76cab2e6 ("NFC: llcp: Implement socket options")
Signed-off-by: Breno Leitao <leitao@debian.org>
---
net/nfc/llcp_sock.c | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/net/nfc/llcp_sock.c b/net/nfc/llcp_sock.c
index f1be1e84f6653..aa9a78a671521 100644
--- a/net/nfc/llcp_sock.c
+++ b/net/nfc/llcp_sock.c
@@ -319,6 +319,12 @@ static int nfc_llcp_getsockopt(struct socket *sock, int level, int optname,
if (get_user(len, optlen))
return -EFAULT;
+ if (len < 0)
+ return -EINVAL;
+
+ if (len < sizeof(u32))
+ return -EINVAL;
+
local = llcp_sock->local;
if (!local)
return -ENODEV;
--
2.53.0-Meta
^ permalink raw reply related [flat|nested] 5+ messages in thread
* [PATCH net v2 2/2] nfc: llcp: read llcp_sock->local under the socket lock in getsockopt
2026-05-21 14:32 [PATCH net v2 0/2] nfc: llcp: two fixes for nfc_llcp_getsockopt() Breno Leitao
2026-05-21 14:32 ` [PATCH net v2 1/2] nfc: llcp: avoid userspace overflow on invalid optlen Breno Leitao
@ 2026-05-21 14:32 ` Breno Leitao
2026-05-26 17:33 ` [PATCH net v2 0/2] nfc: llcp: two fixes for nfc_llcp_getsockopt() Simon Horman
2 siblings, 0 replies; 5+ messages in thread
From: Breno Leitao @ 2026-05-21 14:32 UTC (permalink / raw)
To: David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Simon Horman, Shuah Khan, David Heidelberg, Samuel Ortiz
Cc: linux-kernel, netdev, linux-kselftest, oe-linux-nfc, Breno Leitao,
kernel-team
nfc_llcp_getsockopt() read llcp_sock->local before lock_sock(sk) and
then dereferenced the cached pointer inside the locked region.
llcp_sock_bind() assigns and clears llcp_sock->local under the same
socket lock, dropping the last reference on its error path. A
getsockopt() racing an in-flight bind() can observe the pointer, block
on lock_sock(), and then dereference a freed nfc_llcp_local once bind()
has unwound.
Move the llcp_sock->local read and the NULL check inside the
lock_sock(sk) region so bind() cannot mutate or free the pointer between
the load and the use.
Fixes: 26fd76cab2e6 ("NFC: llcp: Implement socket options")
Signed-off-by: Breno Leitao <leitao@debian.org>
---
net/nfc/llcp_sock.c | 10 ++++++----
1 file changed, 6 insertions(+), 4 deletions(-)
diff --git a/net/nfc/llcp_sock.c b/net/nfc/llcp_sock.c
index aa9a78a671521..266590d402664 100644
--- a/net/nfc/llcp_sock.c
+++ b/net/nfc/llcp_sock.c
@@ -325,14 +325,16 @@ static int nfc_llcp_getsockopt(struct socket *sock, int level, int optname,
if (len < sizeof(u32))
return -EINVAL;
- local = llcp_sock->local;
- if (!local)
- return -ENODEV;
-
len = min_t(u32, len, sizeof(u32));
lock_sock(sk);
+ local = llcp_sock->local;
+ if (!local) {
+ release_sock(sk);
+ return -ENODEV;
+ }
+
switch (optname) {
case NFC_LLCP_RW:
rw = llcp_sock->rw > LLCP_MAX_RW ? local->rw : llcp_sock->rw;
--
2.53.0-Meta
^ permalink raw reply related [flat|nested] 5+ messages in thread
* Re: [PATCH net v2 0/2] nfc: llcp: two fixes for nfc_llcp_getsockopt()
2026-05-21 14:32 [PATCH net v2 0/2] nfc: llcp: two fixes for nfc_llcp_getsockopt() Breno Leitao
2026-05-21 14:32 ` [PATCH net v2 1/2] nfc: llcp: avoid userspace overflow on invalid optlen Breno Leitao
2026-05-21 14:32 ` [PATCH net v2 2/2] nfc: llcp: read llcp_sock->local under the socket lock in getsockopt Breno Leitao
@ 2026-05-26 17:33 ` Simon Horman
2026-05-26 18:27 ` Breno Leitao
2 siblings, 1 reply; 5+ messages in thread
From: Simon Horman @ 2026-05-26 17:33 UTC (permalink / raw)
To: Breno Leitao
Cc: David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Shuah Khan, David Heidelberg, Samuel Ortiz, linux-kernel, netdev,
linux-kselftest, oe-linux-nfc, kernel-team
On Thu, May 21, 2026 at 07:32:08AM -0700, Breno Leitao wrote:
> While converting the NFC LLCP socket layer to the new getsockopt_iter()
> API, I noticed that nfc_llcp_getsockopt() unconditionally stores four
> bytes through a (u32 __user *) cast regardless of the caller-supplied
> optlen, overflowing the user buffer when optlen < 4. Patch 1 adds an
> explicit length check (with a signed-int guard so a negative optlen
> cannot slip past it) and is what I originally sent as v1.
>
> While reviewing v1, Simon/sashiko[1] pointed out that llcp_sock->local
> is read outside lock_sock(sk) and can be freed by a concurrent
> llcp_sock_bind() error path before getsockopt() dereferences it. Patch
> 2 moves the load and the NULL check inside the lock. Both fixes target
> the same original commit, so they are now sent together as a two-patch
> series.
>
> Note: These fixes were compile-tested.
>
> [1] https://lore.kernel.org/all/20260513-fix_llc-v1-1-33c76f931ff6@debian.org/
>
> Signed-off-by: Breno Leitao <leitao@debian.org>
> ---
> Changes in v2:
> - Guard the length check against negative optlen (Simon Horman / sashiko).
> - Add patch 2: move llcp_sock->local read inside lock_sock(sk) to close
> a UAF race with llcp_sock_bind() (Simon Horman / sashiko).
> - Link to v1: https://patch.msgid.link/20260513-fix_llc-v1-1-33c76f931ff6@debian.org
Thanks for the update.
There is an AI-generated review of this patch on sashiko.dev.
It looks like it flags pre-existing issue that doesn't directly
impact the intent of this patch-set. So I don't believe it should delay
progress of this patch-set.
Reviewed-by: Simon Horman <horms@kernel.org>
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH net v2 0/2] nfc: llcp: two fixes for nfc_llcp_getsockopt()
2026-05-26 17:33 ` [PATCH net v2 0/2] nfc: llcp: two fixes for nfc_llcp_getsockopt() Simon Horman
@ 2026-05-26 18:27 ` Breno Leitao
0 siblings, 0 replies; 5+ messages in thread
From: Breno Leitao @ 2026-05-26 18:27 UTC (permalink / raw)
To: Simon Horman
Cc: David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Shuah Khan, David Heidelberg, Samuel Ortiz, linux-kernel, netdev,
linux-kselftest, oe-linux-nfc, kernel-team
Hello Simon,
On Tue, May 26, 2026 at 06:33:51PM +0000, Simon Horman wrote:
> > Changes in v2:
> > - Guard the length check against negative optlen (Simon Horman / sashiko).
> > - Add patch 2: move llcp_sock->local read inside lock_sock(sk) to close
> > a UAF race with llcp_sock_bind() (Simon Horman / sashiko).
> > - Link to v1: https://patch.msgid.link/20260513-fix_llc-v1-1-33c76f931ff6@debian.org
>
> Thanks for the update.
>
> There is an AI-generated review of this patch on sashiko.dev.
> It looks like it flags pre-existing issue that doesn't directly
> impact the intent of this patch-set. So I don't believe it should delay
> progress of this patch-set.
Agree, and looking at what sashiko raised, it seems reasonable, I would
say the state check in llcp_sock_connect() is incomplete, and
llcp_sock_connect() should refuse non-LLCP_CLOSED states.
I will send an independent patch later, if we don't hear any concern
from anyone else.
Thanks for the review,
--breno
^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2026-05-26 18:27 UTC | newest]
Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-05-21 14:32 [PATCH net v2 0/2] nfc: llcp: two fixes for nfc_llcp_getsockopt() Breno Leitao
2026-05-21 14:32 ` [PATCH net v2 1/2] nfc: llcp: avoid userspace overflow on invalid optlen Breno Leitao
2026-05-21 14:32 ` [PATCH net v2 2/2] nfc: llcp: read llcp_sock->local under the socket lock in getsockopt Breno Leitao
2026-05-26 17:33 ` [PATCH net v2 0/2] nfc: llcp: two fixes for nfc_llcp_getsockopt() Simon Horman
2026-05-26 18:27 ` Breno Leitao
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox