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@vger.kernel.org Reported-by: Oleh Konko Signed-off-by: Oleh Konko --- 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