Commit e66c456f authored by Jakub Kicinski's avatar Jakub Kicinski
Browse files

Merge tag 'nfc-7.1-rc6' of https://codeberg.org/linux-nfc/linux



David Heidelberg says:

====================
nfc pull request for net:

Code improvements
 - llcp: Fix use-after-free in llcp_sock_release()
 - llcp: Fix use-after-free race in nfc_llcp_recv_cc()
 - hci: fix out-of-bounds read in HCP header parsing
Regression fixes:
 - nxp-nci: i2c: use rising-edge IRQ on ACPI systems

Signed-off-by: default avatarDavid Heidelberg <david@ixit.cz>

* tag 'nfc-7.1-rc6' of https://codeberg.org/linux-nfc/linux:
  nfc: nxp-nci: i2c: use rising-edge IRQ on ACPI systems
  nfc: hci: fix out-of-bounds read in HCP header parsing
  nfc: llcp: Fix use-after-free race in nfc_llcp_recv_cc()
  nfc: llcp: Fix use-after-free in llcp_sock_release()
====================

Link: https://patch.msgid.link/217c0646-8a30-4037-b613-580c2b189729@ixit.cz


Signed-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parents 50932307 f23bf992
Loading
Loading
Loading
Loading
+20 −1
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@
#include <linux/delay.h>
#include <linux/i2c.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/module.h>
#include <linux/nfc.h>
#include <linux/gpio/consumer.h>
@@ -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");
+10 −0
Original line number Diff line number Diff line
@@ -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) {
+11 −0
Original line number Diff line number Diff line
@@ -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);
}

+2 −0
Original line number Diff line number Diff line
@@ -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);

+10 −0
Original line number Diff line number Diff line
@@ -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) {