From f4268b466190dae95a7585f69b4f1f8ad097632c Mon Sep 17 00:00:00 2001 From: Lee Jones Date: Wed, 29 Apr 2026 13:40:41 +0000 Subject: [PATCH 1/4] nfc: llcp: Fix use-after-free in llcp_sock_release() llcp_sock_release() unconditionally unlinks the socket from the local sockets list. However, if the socket is still in connecting state, it is on the connecting list. Fix this by checking the socket state and unlinking from the correct list. Fixes: b4011239a08e ("NFC: llcp: Fix non blocking sockets connections") Signed-off-by: Lee Jones Link: https://patch.msgid.link/20260429134115.3558604-1-lee@kernel.org Signed-off-by: David Heidelberg --- net/nfc/llcp_sock.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/net/nfc/llcp_sock.c b/net/nfc/llcp_sock.c index f1be1e84f665..feab29fc62f4 100644 --- a/net/nfc/llcp_sock.c +++ b/net/nfc/llcp_sock.c @@ -633,6 +633,8 @@ static int llcp_sock_release(struct socket *sock) if (sock->type == SOCK_RAW) nfc_llcp_sock_unlink(&local->raw_sockets, sk); + else if (sk->sk_state == LLCP_CONNECTING) + nfc_llcp_sock_unlink(&local->connecting_sockets, sk); else nfc_llcp_sock_unlink(&local->sockets, sk); From b493ea2765cc17cb8aa7e7544a4b6dcb05b6ed77 Mon Sep 17 00:00:00 2001 From: Lee Jones Date: Wed, 29 Apr 2026 13:40:42 +0000 Subject: [PATCH 2/4] nfc: llcp: Fix use-after-free race in nfc_llcp_recv_cc() A race condition exists in the NFC LLCP connection state machine where the connection acceptance packet (CC) can be processed concurrently with socket release. This can lead to a use-after-free of the socket object. When nfc_llcp_recv_cc() moves the socket from the connecting_sockets list to the sockets list, it does so without holding the socket lock. If llcp_sock_release() is executing concurrently, it might have already unlinked the socket and dropped its references, which can result in nfc_llcp_recv_cc() linking a freed socket into the live list. Fix this by holding lock_sock() during the state transition and list movement in nfc_llcp_recv_cc(). After acquiring the lock, check if the socket is still hashed to ensure it hasn't already been unlinked and marked for destruction by the release path. This aligns the locking pattern with recv_hdlc() and recv_disc(). Fixes: a69f32af86e3 ("NFC: Socket linked list") Signed-off-by: Lee Jones Reviewed-by: Simon Horman Link: https://patch.msgid.link/20260429134115.3558604-2-lee@kernel.org Signed-off-by: David Heidelberg --- net/nfc/llcp_core.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/net/nfc/llcp_core.c b/net/nfc/llcp_core.c index db5bc6a878dd..dc65c719f35f 100644 --- a/net/nfc/llcp_core.c +++ b/net/nfc/llcp_core.c @@ -1218,6 +1218,15 @@ static void nfc_llcp_recv_cc(struct nfc_llcp_local *local, sk = &llcp_sock->sk; + lock_sock(sk); + + /* Check if socket was destroyed whilst waiting for the lock */ + if (!sk_hashed(sk)) { + release_sock(sk); + nfc_llcp_sock_put(llcp_sock); + return; + } + /* Unlink from connecting and link to the client array */ nfc_llcp_sock_unlink(&local->connecting_sockets, sk); nfc_llcp_sock_link(&local->sockets, sk); @@ -1229,6 +1238,8 @@ static void nfc_llcp_recv_cc(struct nfc_llcp_local *local, sk->sk_state = LLCP_CONNECTED; sk->sk_state_change(sk); + release_sock(sk); + nfc_llcp_sock_put(llcp_sock); } From f040e590c035bfd9553fe79ee9585caf1b14d67b Mon Sep 17 00:00:00 2001 From: Ashutosh Desai Date: Tue, 5 May 2026 17:07:12 +0000 Subject: [PATCH 3/4] nfc: hci: fix out-of-bounds read in HCP header parsing Both nfc_hci_recv_from_llc() and nci_hci_data_received_cb() read packet->header from skb->data at function entry without first checking that the buffer holds at least one byte. A malicious NFC peer can send a 0-byte HCP frame that passes through the SHDLC layer and reaches these functions, causing an out-of-bounds heap read of packet->header. The same 0-byte frame, if queued as a non-final fragment, also causes the reassembly loop to underflow msg_len to UINT_MAX, triggering skb_over_panic() when the reassembled skb is written. Fix this by adding a pskb_may_pull() check at the entry of each function before packet->header is first accessed. The existing pskb_may_pull() checks before the reassembled hcp_skb is cast to struct hcp_packet remain in place to guard the 2-byte HCP message header. Fixes: 8b8d2e08bf0d ("NFC: HCI support") Fixes: 11f54f228643 ("NFC: nci: Add HCI over NCI protocol support") Cc: stable@vger.kernel.org Reviewed-by: Simon Horman Signed-off-by: Ashutosh Desai Link: https://patch.msgid.link/20260505170712.96560-1-ashutoshdesai993@gmail.com Signed-off-by: David Heidelberg --- net/nfc/hci/core.c | 10 ++++++++++ net/nfc/nci/hci.c | 10 ++++++++++ 2 files changed, 20 insertions(+) diff --git a/net/nfc/hci/core.c b/net/nfc/hci/core.c index 0d33c81a15fe..ba6f0310ffd7 100644 --- a/net/nfc/hci/core.c +++ b/net/nfc/hci/core.c @@ -861,6 +861,11 @@ static void nfc_hci_recv_from_llc(struct nfc_hci_dev *hdev, struct sk_buff *skb) struct sk_buff *frag_skb; int msg_len; + if (!pskb_may_pull(skb, NFC_HCI_HCP_PACKET_HEADER_LEN)) { + kfree_skb(skb); + return; + } + packet = (struct hcp_packet *)skb->data; if ((packet->header & ~NFC_HCI_FRAGMENT) == 0) { skb_queue_tail(&hdev->rx_hcp_frags, skb); @@ -904,6 +909,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..c03e8a0bd3bd 100644 --- a/net/nfc/nci/hci.c +++ b/net/nfc/nci/hci.c @@ -439,6 +439,11 @@ void nci_hci_data_received_cb(void *context, return; } + if (!pskb_may_pull(skb, NCI_HCI_HCP_PACKET_HEADER_LEN)) { + kfree_skb(skb); + return; + } + packet = (struct nci_hcp_packet *)skb->data; if ((packet->header & ~NCI_HCI_FRAGMENT) == 0) { skb_queue_tail(&ndev->hci_dev->rx_hcp_frags, skb); @@ -482,6 +487,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) { From f23bf992d65a42007c517b060ca35cebdea3525a Mon Sep 17 00:00:00 2001 From: Carl Lee Date: Sat, 16 May 2026 19:55:18 +0800 Subject: [PATCH 4/4] nfc: nxp-nci: i2c: use rising-edge IRQ on ACPI systems Some ACPI-based platforms report incorrect IRQ trigger types (e.g. IRQF_TRIGGER_HIGH), which can lead to interrupt storms. Use the historically working rising-edge trigger on ACPI systems to avoid this regression. Device Tree-based systems continue to use the firmware-provided trigger type. Fixes: 57be33f85e36 ("nfc: nxp-nci: remove interrupt trigger type") Signed-off-by: Carl Lee Tested-by: Bartosz Golaszewski Reviewed-by: Bartosz Golaszewski Reviewed-by: Mark Pearson Tested-by: Mark Pearson Tested-by: Luca Stefani Link: https://patch.msgid.link/20260516-nfc-nxp-nci-i2c-restore-irq-trigger-fallback-v3-1-37ba4b6e9086@amd.com Signed-off-by: David Heidelberg --- drivers/nfc/nxp-nci/i2c.c | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/drivers/nfc/nxp-nci/i2c.c b/drivers/nfc/nxp-nci/i2c.c index b3d34433bd14..a6c08175d9dd 100644 --- a/drivers/nfc/nxp-nci/i2c.c +++ b/drivers/nfc/nxp-nci/i2c.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -267,6 +268,7 @@ static int nxp_nci_i2c_probe(struct i2c_client *client) { struct device *dev = &client->dev; struct nxp_nci_i2c_phy *phy; + unsigned long irqflags; int r; if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { @@ -303,9 +305,26 @@ static int nxp_nci_i2c_probe(struct i2c_client *client) if (r < 0) return r; + /* + * ACPI platforms may report incorrect IRQ trigger types + * (e.g. level-high), which can lead to interrupt storms. + * + * Use the historically stable rising-edge trigger for ACPI devices. + * + * On non-ACPI systems (e.g. Device Tree), prefer the firmware- + * provided trigger type, falling back to rising-edge if not set. + */ + if (ACPI_COMPANION(dev)) { + irqflags = IRQF_TRIGGER_RISING; + } else { + irqflags = irq_get_trigger_type(client->irq); + if (!irqflags) + irqflags = IRQF_TRIGGER_RISING; + } + r = request_threaded_irq(client->irq, NULL, nxp_nci_i2c_irq_thread_fn, - IRQF_ONESHOT, + irqflags | IRQF_ONESHOT, NXP_NCI_I2C_DRIVER_NAME, phy); if (r < 0) nfc_err(&client->dev, "Unable to register IRQ handler\n");