[PATCH v4] nfc: hci: fix out-of-bounds read in HCP header parsing

Ashutosh Desai posted 1 patch 5 hours ago
net/nfc/hci/core.c | 5 +++++
net/nfc/nci/hci.c  | 5 +++++
2 files changed, 10 insertions(+)
[PATCH v4] nfc: hci: fix out-of-bounds read in HCP header parsing
Posted by Ashutosh Desai 5 hours ago
nfc_hci_recv_from_llc() and nci_hci_data_received_cb() cast skb->data
to struct hcp_packet and read the message header byte without checking
that enough data is present in the linear sk_buff area. A malicious NFC
peer can send a 1-byte HCP frame that passes through the SHDLC layer
and reaches these functions, causing an out-of-bounds heap read.

Fix this by adding pskb_may_pull() before each cast to ensure the full
2-byte HCP header is pulled into the linear area before it is accessed.

Fixes: 8b8d2e08bf0d ("NFC: HCI support")
Fixes: 11f54f228643 ("NFC: nci: Add HCI over NCI protocol support")
Cc: stable@vger.kernel.org
Signed-off-by: Ashutosh Desai <ashutoshdesai993@gmail.com>
---
V3 -> V4: add Fixes tags
V2 -> V3: drop redundant checks from nfc_hci_msg_rx_work/nci_hci_msg_rx_work,
          remove incorrect Suggested-by tag
V1 -> V2: switch skb->len check to pskb_may_pull

v3: https://lore.kernel.org/netdev/20260413024329.3293075-1-ashutoshdesai993@gmail.com/
v2: https://lore.kernel.org/netdev/20260409150825.2217133-1-ashutoshdesai993@gmail.com/
v1: https://lore.kernel.org/netdev/20260408223113.2009304-1-ashutoshdesai993@gmail.com/

 net/nfc/hci/core.c | 5 +++++
 net/nfc/nci/hci.c  | 5 +++++
 2 files changed, 10 insertions(+)

diff --git a/net/nfc/hci/core.c b/net/nfc/hci/core.c
index 0d33c81a15fe..cd9cf6c94a50 100644
--- a/net/nfc/hci/core.c
+++ b/net/nfc/hci/core.c
@@ -904,6 +904,11 @@ static void nfc_hci_recv_from_llc(struct nfc_hci_dev *hdev, struct sk_buff *skb)
          * unblock waiting cmd context. Otherwise, enqueue to dispatch
          * in separate context where handler can also execute command.
          */
+if (!pskb_may_pull(hcp_skb, NFC_HCI_HCP_HEADER_LEN)) {
+kfree_skb(hcp_skb);
+return;
+}
+
 packet = (struct hcp_packet *)hcp_skb->data;
 type = HCP_MSG_GET_TYPE(packet->message.header);
 if (type == NFC_HCI_HCP_RESPONSE) {
diff --git a/net/nfc/nci/hci.c b/net/nfc/nci/hci.c
index 40ae8e5a7ec7..6e633da257d1 100644
--- a/net/nfc/nci/hci.c
+++ b/net/nfc/nci/hci.c
@@ -482,6 +482,11 @@ void nci_hci_data_received_cb(void *context,
          * unblock waiting cmd context. Otherwise, enqueue to dispatch
          * in separate context where handler can also execute command.
          */
+if (!pskb_may_pull(hcp_skb, NCI_HCI_HCP_HEADER_LEN)) {
+kfree_skb(hcp_skb);
+return;
+}
+
 packet = (struct nci_hcp_packet *)hcp_skb->data;
 type = NCI_HCP_MSG_GET_TYPE(packet->message.header);
 if (type == NCI_HCI_HCP_RESPONSE) {
-- 
2.34.1