Commit 57ce3b2e authored by Jakub Kicinski's avatar Jakub Kicinski
Browse files
Luiz Augusto von Dentz says:

====================
bluetooth pull request for net:

 - hci_ll: Fix firmware leak on error path
 - hci_sync: annotate data-races around hdev->req_status
 - L2CAP: Fix null-ptr-deref on l2cap_sock_ready_cb
 - L2CAP: Validate PDU length before reading SDU length in l2cap_ecred_data_rcv()
 - L2CAP: Fix regressions caused by reusing ident
 - L2CAP: Fix stack-out-of-bounds read in l2cap_ecred_conn_req
 - MGMT: Fix dangling pointer on mgmt_add_adv_patterns_monitor_complete
 - SCO: Fix use-after-free in sco_recv_frame() due to missing sock_hold

* tag 'for-net-2026-03-19' of git://git.kernel.org/pub/scm/linux/kernel/git/bluetooth/bluetooth:
  Bluetooth: L2CAP: Fix regressions caused by reusing ident
  Bluetooth: L2CAP: Fix null-ptr-deref on l2cap_sock_ready_cb
  Bluetooth: hci_ll: Fix firmware leak on error path
  Bluetooth: hci_sync: annotate data-races around hdev->req_status
  Bluetooth: MGMT: Fix dangling pointer on mgmt_add_adv_patterns_monitor_complete
  Bluetooth: SCO: Fix use-after-free in sco_recv_frame() due to missing sock_hold
  Bluetooth: L2CAP: Validate PDU length before reading SDU length in l2cap_ecred_data_rcv()
  Bluetooth: L2CAP: Fix stack-out-of-bounds read in l2cap_ecred_conn_req
====================

Link: https://patch.msgid.link/20260319190455.135302-1-luiz.dentz@gmail.com


Signed-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parents cbcb3cfc 761fb8ec
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -541,6 +541,8 @@ static int download_firmware(struct ll_device *lldev)
	if (err || !fw->data || !fw->size) {
		bt_dev_err(lldev->hu.hdev, "request_firmware failed(errno %d) for %s",
			   err, bts_scr_name);
		if (!err)
			release_firmware(fw);
		return -EINVAL;
	}
	ptr = (void *)fw->data;
+1 −0
Original line number Diff line number Diff line
@@ -658,6 +658,7 @@ struct l2cap_conn {
	struct sk_buff		*rx_skb;
	__u32			rx_len;
	struct ida		tx_ida;
	__u8			tx_ident;

	struct sk_buff_head	pending_rx;
	struct work_struct	pending_rx_work;
+1 −1
Original line number Diff line number Diff line
@@ -3095,7 +3095,7 @@ int hci_abort_conn(struct hci_conn *conn, u8 reason)
	 * hci_connect_le serializes the connection attempts so only one
	 * connection can be in BT_CONNECT at time.
	 */
	if (conn->state == BT_CONNECT && hdev->req_status == HCI_REQ_PEND) {
	if (conn->state == BT_CONNECT && READ_ONCE(hdev->req_status) == HCI_REQ_PEND) {
		switch (hci_skb_event(hdev->sent_cmd)) {
		case HCI_EV_CONN_COMPLETE:
		case HCI_EV_LE_CONN_COMPLETE:
+1 −1
Original line number Diff line number Diff line
@@ -4126,7 +4126,7 @@ static int hci_send_cmd_sync(struct hci_dev *hdev, struct sk_buff *skb)
		kfree_skb(skb);
	}

	if (hdev->req_status == HCI_REQ_PEND &&
	if (READ_ONCE(hdev->req_status) == HCI_REQ_PEND &&
	    !hci_dev_test_and_set_flag(hdev, HCI_CMD_PENDING)) {
		kfree_skb(hdev->req_skb);
		hdev->req_skb = skb_clone(hdev->sent_cmd, GFP_KERNEL);
+10 −10
Original line number Diff line number Diff line
@@ -25,11 +25,11 @@ static void hci_cmd_sync_complete(struct hci_dev *hdev, u8 result, u16 opcode,
{
	bt_dev_dbg(hdev, "result 0x%2.2x", result);

	if (hdev->req_status != HCI_REQ_PEND)
	if (READ_ONCE(hdev->req_status) != HCI_REQ_PEND)
		return;

	hdev->req_result = result;
	hdev->req_status = HCI_REQ_DONE;
	WRITE_ONCE(hdev->req_status, HCI_REQ_DONE);

	/* Free the request command so it is not used as response */
	kfree_skb(hdev->req_skb);
@@ -167,20 +167,20 @@ struct sk_buff *__hci_cmd_sync_sk(struct hci_dev *hdev, u16 opcode, u32 plen,

	hci_cmd_sync_add(&req, opcode, plen, param, event, sk);

	hdev->req_status = HCI_REQ_PEND;
	WRITE_ONCE(hdev->req_status, HCI_REQ_PEND);

	err = hci_req_sync_run(&req);
	if (err < 0)
		return ERR_PTR(err);

	err = wait_event_interruptible_timeout(hdev->req_wait_q,
					       hdev->req_status != HCI_REQ_PEND,
					       READ_ONCE(hdev->req_status) != HCI_REQ_PEND,
					       timeout);

	if (err == -ERESTARTSYS)
		return ERR_PTR(-EINTR);

	switch (hdev->req_status) {
	switch (READ_ONCE(hdev->req_status)) {
	case HCI_REQ_DONE:
		err = -bt_to_errno(hdev->req_result);
		break;
@@ -194,7 +194,7 @@ struct sk_buff *__hci_cmd_sync_sk(struct hci_dev *hdev, u16 opcode, u32 plen,
		break;
	}

	hdev->req_status = 0;
	WRITE_ONCE(hdev->req_status, 0);
	hdev->req_result = 0;
	skb = hdev->req_rsp;
	hdev->req_rsp = NULL;
@@ -665,9 +665,9 @@ void hci_cmd_sync_cancel(struct hci_dev *hdev, int err)
{
	bt_dev_dbg(hdev, "err 0x%2.2x", err);

	if (hdev->req_status == HCI_REQ_PEND) {
	if (READ_ONCE(hdev->req_status) == HCI_REQ_PEND) {
		hdev->req_result = err;
		hdev->req_status = HCI_REQ_CANCELED;
		WRITE_ONCE(hdev->req_status, HCI_REQ_CANCELED);

		queue_work(hdev->workqueue, &hdev->cmd_sync_cancel_work);
	}
@@ -683,12 +683,12 @@ void hci_cmd_sync_cancel_sync(struct hci_dev *hdev, int err)
{
	bt_dev_dbg(hdev, "err 0x%2.2x", err);

	if (hdev->req_status == HCI_REQ_PEND) {
	if (READ_ONCE(hdev->req_status) == HCI_REQ_PEND) {
		/* req_result is __u32 so error must be positive to be properly
		 * propagated.
		 */
		hdev->req_result = err < 0 ? -err : err;
		hdev->req_status = HCI_REQ_CANCELED;
		WRITE_ONCE(hdev->req_status, HCI_REQ_CANCELED);

		wake_up_interruptible(&hdev->req_wait_q);
	}
Loading