diff options
| author | Doruk Tan Ozturk <doruk@0sec.ai> | 2026-07-14 18:46:31 +0200 |
|---|---|---|
| committer | David Heidelberg <david@ixit.cz> | 2026-07-26 21:26:07 +0200 |
| commit | e8c39b06ebd66fcb18c25b8917b07f201b858718 (patch) | |
| tree | 8ed68b454b1787e2e091eccf8af09fc13c0a9e4d | |
| parent | 9e9831d3cfcff2dbace18b8f4e440657c4d5c89b (diff) | |
| download | linux-next-e8c39b06ebd66fcb18c25b8917b07f201b858718.tar.gz linux-next-e8c39b06ebd66fcb18c25b8917b07f201b858718.zip | |
nfc: llcp: reject PDUs shorter than the LLCP header
Every LLCP PDU begins with a two-byte header (DSAP/SSAP + PTYPE), but the
receive path never checked that a frame is at least LLCP_HEADER_SIZE bytes
before parsing it.
nfc_llcp_rx_skb() reads the header via nfc_llcp_ptype()/nfc_llcp_dsap()/
nfc_llcp_ssap(), which dereference pdu->data[0] and pdu->data[1], and a
CONNECT or CC PDU then computes
tlv_array_len = skb->len - LLCP_HEADER_SIZE;
as a size_t and hands it to the TLV walk. When the frame is shorter than
the header the subtraction wraps to a huge value and the walk runs far
past the buffer, an out-of-bounds read.
A nearby NFC device can reach this without authentication; LLCP link
activation happens automatically after NFC-DEP.
Guard the common receive choke point __nfc_llcp_recv(), shared by both the
target (nfc_llcp_data_received()) and initiator (nfc_llcp_recv()) paths, so
a short skb is dropped before the rx_work worker parses it. Use
pskb_may_pull() rather than a skb->len test so the two header bytes are
guaranteed to sit in the skb linear area even for a non-linear skb,
matching how the sibling NCI and HCI receive paths validate their headers.
Reproduced with a KFENCE out-of-bounds read via /dev/virtual_nci on
linux-next.
Found by 0sec automated security-research tooling (https://0sec.ai).
Fixes: d646960f7986 ("NFC: Initial LLCP support")
Cc: stable@vger.kernel.org
Suggested-by: David Laight <david.laight.linux@gmail.com>
Signed-off-by: Doruk Tan Ozturk <doruk@0sec.ai>
Reviewed-by: Vadim Fedorenko <vadim.fedorenko@linux.dev>
Link: https://patch.msgid.link/20260714164631.75068-1-doruk@0sec.ai
Signed-off-by: David Heidelberg <david@ixit.cz>
| -rw-r--r-- | net/nfc/llcp_core.c | 5 |
1 files changed, 5 insertions, 0 deletions
diff --git a/net/nfc/llcp_core.c b/net/nfc/llcp_core.c index aed5fe1afef0..e3b2627cb089 100644 --- a/net/nfc/llcp_core.c +++ b/net/nfc/llcp_core.c @@ -1565,6 +1565,11 @@ static void nfc_llcp_rx_work(struct work_struct *work) static void __nfc_llcp_recv(struct nfc_llcp_local *local, struct sk_buff *skb) { + if (!pskb_may_pull(skb, LLCP_HEADER_SIZE)) { + kfree_skb(skb); + return; + } + local->rx_pending = skb; timer_delete(&local->link_timer); schedule_work(&local->rx_work); |
