Re: [PATCH] nfc: llcp: fix integer underflow and missing bounds checks in TLV parsing

David Heidelberg <[email protected]> Tue, 2 Jun 2026 13:12:52 +0200
Newsgroups dev.linux.lists.oe-linux-nfc,org.kernel.vger.netdev
Message-ID <[email protected]>
On 25/05/2026 22:24, Doruk Tan Ozturk wrote:
> Multiple out-of-bounds read vulnerabilities exist in the NFC LLCP TLV
> parsers:
> 
> 1. In nfc_llcp_recv_snl(), when an SDREQ TLV has length == 0,
>     service_name_len = length - 1 underflows to SIZE_MAX (size_t is
>     unsigned). The subsequent strncmp() and nfc_llcp_sock_from_sn()
>     calls then read unbounded kernel heap memory.
> 
> 2. All LLCP TLV parsing loops (nfc_llcp_recv_snl, nfc_llcp_connect_sn,
>     nfc_llcp_parse_gb_tlv, nfc_llcp_parse_connection_tlv) read tlv[0]
>     and tlv[1] without first verifying that at least 2 bytes remain in
>     the buffer.
> 
> A nearby malicious NFC device can trigger these without authentication --
> LLCP link activation happens automatically after NFC-DEP.
> 
> Fix by adding a minimum length check before the subtraction in the
> SDREQ case, and adding bounds validation at the top of each TLV loop
> iteration.
> 
> Found by pwnkit (https://github.com/0sec-labs/pwnkit), an automated
> kernel source review tool by 0sec (https://0sec.ai).
> 
> Signed-off-by: Doruk Tan Ozturk <[email protected]>
> ---
>   net/nfc/llcp_core.c | 6 ++++++
>   1 file changed, 6 insertions(+)
> 
> diff --git a/net/nfc/llcp_core.c b/net/nfc/llcp_core.c
> index XXXXXXX..YYYYYYY 100644

Hello Doruk,

thank you for your patch.

The patch won't apply cleanly, could you please resent patch based against 
recent https://codeberg.org/linux-nfc/linux/commits/branch/for-next ?


> --- a/net/nfc/llcp_core.c
> +++ b/net/nfc/llcp_core.c
> @@ -1300,6 +1300,9 @@ static void nfc_llcp_recv_snl(struct nfc_llcp_local *local,
>   
>   	while (offset < tlv_len) {
> +		if (offset + 2 > tlv_len)

I think it would be more descriptive use define, thus

(offset + LLCP_HEADER_SIZE > tlv_len)

David


> +			break;
> +
>   		type = tlv[0];
>   		length = tlv[1];
>   
> @@ -1307,6 +1310,9 @@ static void nfc_llcp_recv_snl(struct nfc_llcp_local *local,
>   		switch (type) {
>   		case LLCP_TLV_SDREQ:
> +			if (length < 1)
> +				break;
> +
>   			tid = tlv[2];
>   			service_name = (char *) &tlv[3];
>   			service_name_len = length - 1;

-- 
David Heidelberg