[PATCH net] nfc: llcp: fix tlv offset wrap and missing bounds checks

From: Oleh Konko

Date: Tue Mar 24 2026 - 17:26:18 EST


nfc_llcp_parse_gb_tlv() and nfc_llcp_parse_connection_tlv() iterate a
u16 tlv_array_len with a u8 offset. once cumulative TLV consumption
crosses 255 bytes, offset wraps and the loop may continue past the
declared TLV array bounds.

both parsers also read tlv[1] before checking that a full 2-byte TLV
header remains, and they advance by length + 2 without validating that
the declared payload still fits in the remaining array.

fix this by widening offset to u16 and by rejecting incomplete headers
or truncated TLVs before dereferencing or advancing the cursor.

Fixes: d646960f7986 ("NFC: Initial LLCP support")
Cc: stable@xxxxxxxxxxxxxxx
Reported-by: Oleh Konko <security@xxxxxxxxx>
Signed-off-by: Oleh Konko <security@xxxxxxxxx>
---
net/nfc/llcp_commands.c | 18 ++++++++++++++++--
1 file changed, 16 insertions(+), 2 deletions(-)

diff --git a/net/nfc/llcp_commands.c b/net/nfc/llcp_commands.c
index 291f26fac..157afd62f 100644
--- a/net/nfc/llcp_commands.c
+++ b/net/nfc/llcp_commands.c
@@ -193,7 +193,8 @@ int nfc_llcp_parse_gb_tlv(struct nfc_llcp_local *local,
const u8 *tlv_array, u16 tlv_array_len)
{
const u8 *tlv = tlv_array;
- u8 type, length, offset = 0;
+ u8 type, length;
+ u16 offset = 0;

pr_debug("TLV array length %d\n", tlv_array_len);

@@ -201,6 +202,9 @@ int nfc_llcp_parse_gb_tlv(struct nfc_llcp_local *local,
return -ENODEV;

while (offset < tlv_array_len) {
+ if (tlv_array_len - offset < 2)
+ return -EINVAL;
+
type = tlv[0];
length = tlv[1];

@@ -227,6 +231,9 @@ int nfc_llcp_parse_gb_tlv(struct nfc_llcp_local *local,
break;
}

+ if (tlv_array_len - offset < (u16)length + 2)
+ return -EINVAL;
+
offset += length + 2;
tlv += length + 2;
}
@@ -243,7 +250,8 @@ int nfc_llcp_parse_connection_tlv(struct nfc_llcp_sock *sock,
const u8 *tlv_array, u16 tlv_array_len)
{
const u8 *tlv = tlv_array;
- u8 type, length, offset = 0;
+ u8 type, length;
+ u16 offset = 0;

pr_debug("TLV array length %d\n", tlv_array_len);

@@ -251,6 +259,9 @@ int nfc_llcp_parse_connection_tlv(struct nfc_llcp_sock *sock,
return -ENOTCONN;

while (offset < tlv_array_len) {
+ if (tlv_array_len - offset < 2)
+ return -EINVAL;
+
type = tlv[0];
length = tlv[1];

@@ -270,6 +281,9 @@ int nfc_llcp_parse_connection_tlv(struct nfc_llcp_sock *sock,
break;
}

+ if (tlv_array_len - offset < (u16)length + 2)
+ return -EINVAL;
+
offset += length + 2;
tlv += length + 2;
}
--
2.50.0