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

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

 - Fix a buffer overflow in mgmt_mesh_add
 - Fix use HCI_OP_LE_READ_BUFFER_SIZE_V2
 - Fix hci_qca shutdown on closed serdev
 - Fix possible circular locking dependencies on ISO code
 - Fix possible deadlock in rfcomm_sk_state_change

* tag 'for-net-2023-01-17' of git://git.kernel.org/pub/scm/linux/kernel/git/bluetooth/bluetooth:
  Bluetooth: Fix possible deadlock in rfcomm_sk_state_change
  Bluetooth: ISO: Fix possible circular locking dependency
  Bluetooth: hci_event: Fix Invalid wait context
  Bluetooth: ISO: Fix possible circular locking dependency
  Bluetooth: hci_sync: fix memory leak in hci_update_adv_data()
  Bluetooth: hci_qca: Fix driver shutdown on closed serdev
  Bluetooth: hci_conn: Fix memory leaks
  Bluetooth: hci_sync: Fix use HCI_OP_LE_READ_BUFFER_SIZE_V2
  Bluetooth: Fix a buffer overflow in mgmt_mesh_add()
====================

Link: https://lore.kernel.org/r/20230118002944.1679845-1-luiz.dentz@gmail.com


Signed-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parents 423c1d36 1d80d57f
Loading
Loading
Loading
Loading
+7 −0
Original line number Diff line number Diff line
@@ -2164,10 +2164,17 @@ static void qca_serdev_shutdown(struct device *dev)
	int timeout = msecs_to_jiffies(CMD_TRANS_TIMEOUT_MS);
	struct serdev_device *serdev = to_serdev_device(dev);
	struct qca_serdev *qcadev = serdev_device_get_drvdata(serdev);
	struct hci_uart *hu = &qcadev->serdev_hu;
	struct hci_dev *hdev = hu->hdev;
	struct qca_data *qca = hu->priv;
	const u8 ibs_wake_cmd[] = { 0xFD };
	const u8 edl_reset_soc_cmd[] = { 0x01, 0x00, 0xFC, 0x01, 0x05 };

	if (qcadev->btsoc_type == QCA_QCA6390) {
		if (test_bit(QCA_BT_OFF, &qca->flags) ||
		    !test_bit(HCI_RUNNING, &hdev->flags))
			return;

		serdev_device_write_flush(serdev);
		ret = serdev_device_write_buf(serdev, ibs_wake_cmd,
					      sizeof(ibs_wake_cmd));
+14 −4
Original line number Diff line number Diff line
@@ -821,6 +821,7 @@ static void terminate_big_destroy(struct hci_dev *hdev, void *data, int err)
static int hci_le_terminate_big(struct hci_dev *hdev, u8 big, u8 bis)
{
	struct iso_list_data *d;
	int ret;

	bt_dev_dbg(hdev, "big 0x%2.2x bis 0x%2.2x", big, bis);

@@ -831,8 +832,12 @@ static int hci_le_terminate_big(struct hci_dev *hdev, u8 big, u8 bis)
	d->big = big;
	d->bis = bis;

	return hci_cmd_sync_queue(hdev, terminate_big_sync, d,
	ret = hci_cmd_sync_queue(hdev, terminate_big_sync, d,
				 terminate_big_destroy);
	if (ret)
		kfree(d);

	return ret;
}

static int big_terminate_sync(struct hci_dev *hdev, void *data)
@@ -857,6 +862,7 @@ static int big_terminate_sync(struct hci_dev *hdev, void *data)
static int hci_le_big_terminate(struct hci_dev *hdev, u8 big, u16 sync_handle)
{
	struct iso_list_data *d;
	int ret;

	bt_dev_dbg(hdev, "big 0x%2.2x sync_handle 0x%4.4x", big, sync_handle);

@@ -867,8 +873,12 @@ static int hci_le_big_terminate(struct hci_dev *hdev, u8 big, u16 sync_handle)
	d->big = big;
	d->sync_handle = sync_handle;

	return hci_cmd_sync_queue(hdev, big_terminate_sync, d,
	ret = hci_cmd_sync_queue(hdev, big_terminate_sync, d,
				 terminate_big_destroy);
	if (ret)
		kfree(d);

	return ret;
}

/* Cleanup BIS connection
+4 −1
Original line number Diff line number Diff line
@@ -3848,8 +3848,11 @@ static u8 hci_cc_le_set_cig_params(struct hci_dev *hdev, void *data,
			   conn->handle, conn->link);

		/* Create CIS if LE is already connected */
		if (conn->link && conn->link->state == BT_CONNECTED)
		if (conn->link && conn->link->state == BT_CONNECTED) {
			rcu_read_unlock();
			hci_le_create_cis(conn->link);
			rcu_read_lock();
		}

		if (i == rp->num_handles)
			break;
+6 −13
Original line number Diff line number Diff line
@@ -3572,7 +3572,7 @@ static const struct hci_init_stage hci_init2[] = {
static int hci_le_read_buffer_size_sync(struct hci_dev *hdev)
{
	/* Use Read LE Buffer Size V2 if supported */
	if (hdev->commands[41] & 0x20)
	if (iso_capable(hdev) && hdev->commands[41] & 0x20)
		return __hci_cmd_sync_status(hdev,
					     HCI_OP_LE_READ_BUFFER_SIZE_V2,
					     0, NULL, HCI_CMD_TIMEOUT);
@@ -3597,10 +3597,10 @@ static int hci_le_read_supported_states_sync(struct hci_dev *hdev)

/* LE Controller init stage 2 command sequence */
static const struct hci_init_stage le_init2[] = {
	/* HCI_OP_LE_READ_BUFFER_SIZE */
	HCI_INIT(hci_le_read_buffer_size_sync),
	/* HCI_OP_LE_READ_LOCAL_FEATURES */
	HCI_INIT(hci_le_read_local_features_sync),
	/* HCI_OP_LE_READ_BUFFER_SIZE */
	HCI_INIT(hci_le_read_buffer_size_sync),
	/* HCI_OP_LE_READ_SUPPORTED_STATES */
	HCI_INIT(hci_le_read_supported_states_sync),
	{}
@@ -6187,20 +6187,13 @@ int hci_get_random_address(struct hci_dev *hdev, bool require_privacy,

static int _update_adv_data_sync(struct hci_dev *hdev, void *data)
{
	u8 instance = *(u8 *)data;

	kfree(data);
	u8 instance = PTR_ERR(data);

	return hci_update_adv_data_sync(hdev, instance);
}

int hci_update_adv_data(struct hci_dev *hdev, u8 instance)
{
	u8 *inst_ptr = kmalloc(1, GFP_KERNEL);

	if (!inst_ptr)
		return -ENOMEM;

	*inst_ptr = instance;
	return hci_cmd_sync_queue(hdev, _update_adv_data_sync, inst_ptr, NULL);
	return hci_cmd_sync_queue(hdev, _update_adv_data_sync,
				  ERR_PTR(instance), NULL);
}
+26 −38
Original line number Diff line number Diff line
@@ -289,15 +289,15 @@ static int iso_connect_bis(struct sock *sk)
	hci_dev_unlock(hdev);
	hci_dev_put(hdev);

	err = iso_chan_add(conn, sk, NULL);
	if (err)
		return err;

	lock_sock(sk);

	/* Update source addr of the socket */
	bacpy(&iso_pi(sk)->src, &hcon->src);

	err = iso_chan_add(conn, sk, NULL);
	if (err)
		goto release;

	if (hcon->state == BT_CONNECTED) {
		iso_sock_clear_timer(sk);
		sk->sk_state = BT_CONNECTED;
@@ -306,7 +306,6 @@ static int iso_connect_bis(struct sock *sk)
		iso_sock_set_timer(sk, sk->sk_sndtimeo);
	}

release:
	release_sock(sk);
	return err;

@@ -372,15 +371,15 @@ static int iso_connect_cis(struct sock *sk)
	hci_dev_unlock(hdev);
	hci_dev_put(hdev);

	err = iso_chan_add(conn, sk, NULL);
	if (err)
		return err;

	lock_sock(sk);

	/* Update source addr of the socket */
	bacpy(&iso_pi(sk)->src, &hcon->src);

	err = iso_chan_add(conn, sk, NULL);
	if (err)
		goto release;

	if (hcon->state == BT_CONNECTED) {
		iso_sock_clear_timer(sk);
		sk->sk_state = BT_CONNECTED;
@@ -392,7 +391,6 @@ static int iso_connect_cis(struct sock *sk)
		iso_sock_set_timer(sk, sk->sk_sndtimeo);
	}

release:
	release_sock(sk);
	return err;

@@ -895,13 +893,10 @@ static int iso_listen_bis(struct sock *sk)
	if (!hdev)
		return -EHOSTUNREACH;

	hci_dev_lock(hdev);

	err = hci_pa_create_sync(hdev, &iso_pi(sk)->dst,
				 le_addr_type(iso_pi(sk)->dst_type),
				 iso_pi(sk)->bc_sid);

	hci_dev_unlock(hdev);
	hci_dev_put(hdev);

	return err;
@@ -1432,33 +1427,29 @@ static void iso_conn_ready(struct iso_conn *conn)
	struct sock *parent;
	struct sock *sk = conn->sk;
	struct hci_ev_le_big_sync_estabilished *ev;
	struct hci_conn *hcon;

	BT_DBG("conn %p", conn);

	if (sk) {
		iso_sock_ready(conn->sk);
	} else {
		iso_conn_lock(conn);

		if (!conn->hcon) {
			iso_conn_unlock(conn);
		hcon = conn->hcon;
		if (!hcon)
			return;
		}

		ev = hci_recv_event_data(conn->hcon->hdev,
		ev = hci_recv_event_data(hcon->hdev,
					 HCI_EVT_LE_BIG_SYNC_ESTABILISHED);
		if (ev)
			parent = iso_get_sock_listen(&conn->hcon->src,
						     &conn->hcon->dst,
			parent = iso_get_sock_listen(&hcon->src,
						     &hcon->dst,
						     iso_match_big, ev);
		else
			parent = iso_get_sock_listen(&conn->hcon->src,
			parent = iso_get_sock_listen(&hcon->src,
						     BDADDR_ANY, NULL, NULL);

		if (!parent) {
			iso_conn_unlock(conn);
		if (!parent)
			return;
		}

		lock_sock(parent);

@@ -1466,30 +1457,29 @@ static void iso_conn_ready(struct iso_conn *conn)
				    BTPROTO_ISO, GFP_ATOMIC, 0);
		if (!sk) {
			release_sock(parent);
			iso_conn_unlock(conn);
			return;
		}

		iso_sock_init(sk, parent);

		bacpy(&iso_pi(sk)->src, &conn->hcon->src);
		iso_pi(sk)->src_type = conn->hcon->src_type;
		bacpy(&iso_pi(sk)->src, &hcon->src);
		iso_pi(sk)->src_type = hcon->src_type;

		/* If hcon has no destination address (BDADDR_ANY) it means it
		 * was created by HCI_EV_LE_BIG_SYNC_ESTABILISHED so we need to
		 * initialize using the parent socket destination address.
		 */
		if (!bacmp(&conn->hcon->dst, BDADDR_ANY)) {
			bacpy(&conn->hcon->dst, &iso_pi(parent)->dst);
			conn->hcon->dst_type = iso_pi(parent)->dst_type;
			conn->hcon->sync_handle = iso_pi(parent)->sync_handle;
		if (!bacmp(&hcon->dst, BDADDR_ANY)) {
			bacpy(&hcon->dst, &iso_pi(parent)->dst);
			hcon->dst_type = iso_pi(parent)->dst_type;
			hcon->sync_handle = iso_pi(parent)->sync_handle;
		}

		bacpy(&iso_pi(sk)->dst, &conn->hcon->dst);
		iso_pi(sk)->dst_type = conn->hcon->dst_type;
		bacpy(&iso_pi(sk)->dst, &hcon->dst);
		iso_pi(sk)->dst_type = hcon->dst_type;

		hci_conn_hold(conn->hcon);
		__iso_chan_add(conn, sk, parent);
		hci_conn_hold(hcon);
		iso_chan_add(conn, sk, parent);

		if (test_bit(BT_SK_DEFER_SETUP, &bt_sk(parent)->flags))
			sk->sk_state = BT_CONNECT2;
@@ -1500,8 +1490,6 @@ static void iso_conn_ready(struct iso_conn *conn)
		parent->sk_data_ready(parent);

		release_sock(parent);

		iso_conn_unlock(conn);
	}
}

Loading