Unverified Commit d0d087dd authored by openeuler-ci-bot's avatar openeuler-ci-bot Committed by Gitee
Browse files

!14712 CVE-2024-56654

Merge Pull Request from: @ci-robot 
 
PR sync from: Yongqiang Liu <liuyongqiang13@huawei.com>
https://mailweb.openeuler.org/hyperkitty/list/kernel@openeuler.org/message/6MP4VCHEJSKHLEL2JADCFTOIX2M3KTF2/ 
Iulia Tanasescu (1):
  Bluetooth: ISO: Reassociate a socket with an active BIS

Luiz Augusto von Dentz (1):
  Bluetooth: hci_event: Fix using rcu_read_(un)lock while iterating


-- 
2.25.1
 
https://gitee.com/src-openeuler/kernel/issues/IBEAP1 
 
Link:https://gitee.com/openeuler/kernel/pulls/14712

 

Reviewed-by: default avatarYue Haibing <yuehaibing@huawei.com>
Signed-off-by: default avatarZhang Peng <zhangpeng362@huawei.com>
parents 00cfa1e6 9d1d6db4
Loading
Loading
Loading
Loading
+24 −0
Original line number Diff line number Diff line
@@ -1294,6 +1294,30 @@ static inline struct hci_conn *hci_conn_hash_lookup_big_any_dst(struct hci_dev *
	return NULL;
}

static inline struct hci_conn *
hci_conn_hash_lookup_big_state(struct hci_dev *hdev, __u8 handle,  __u16 state)
{
	struct hci_conn_hash *h = &hdev->conn_hash;
	struct hci_conn  *c;

	rcu_read_lock();

	list_for_each_entry_rcu(c, &h->list, list) {
		if (bacmp(&c->dst, BDADDR_ANY) || c->type != ISO_LINK ||
			c->state != state)
			continue;

		if (handle == c->iso_qos.bcast.big) {
			rcu_read_unlock();
			return c;
		}
	}

	rcu_read_unlock();

	return NULL;
}

static inline struct hci_conn *
hci_conn_hash_lookup_pa_sync_big_handle(struct hci_dev *hdev, __u8 big)
{
+30 −2
Original line number Diff line number Diff line
@@ -1054,8 +1054,9 @@ static void hci_conn_cleanup_child(struct hci_conn *conn, u8 reason)
			hci_conn_failed(conn, reason);
		break;
	case ISO_LINK:
		if (conn->state != BT_CONNECTED &&
		    !test_bit(HCI_CONN_CREATE_CIS, &conn->flags))
		if ((conn->state != BT_CONNECTED &&
		    !test_bit(HCI_CONN_CREATE_CIS, &conn->flags)) ||
		    test_bit(HCI_CONN_BIG_CREATED, &conn->flags))
			hci_conn_failed(conn, reason);
		break;
	}
@@ -2134,7 +2135,17 @@ struct hci_conn *hci_bind_bis(struct hci_dev *hdev, bdaddr_t *dst,
			      __u8 base_len, __u8 *base)
{
	struct hci_conn *conn;
	struct hci_conn *parent;
	__u8 eir[HCI_MAX_PER_AD_LENGTH];
	struct hci_link *link;

	/* Look for any BIS that is open for rebinding */
	conn = hci_conn_hash_lookup_big_state(hdev, qos->bcast.big, BT_OPEN);
	if (conn) {
		memcpy(qos, &conn->iso_qos, sizeof(*qos));
		conn->state = BT_CONNECTED;
		return conn;
	}

	if (base_len && base)
		base_len = eir_append_service_data(eir, 0,  0x1851,
@@ -2162,6 +2173,20 @@ struct hci_conn *hci_bind_bis(struct hci_dev *hdev, bdaddr_t *dst,
	conn->iso_qos = *qos;
	conn->state = BT_BOUND;

	/* Link BISes together */
	parent = hci_conn_hash_lookup_big(hdev,
					  conn->iso_qos.bcast.big);
	if (parent && parent != conn) {
		link = hci_conn_link(parent, conn);
		if (!link) {
			hci_conn_drop(conn);
			return ERR_PTR(-ENOLINK);
		}

		/* Link takes the refcount */
		hci_conn_drop(conn);
	}

	return conn;
}

@@ -2193,6 +2218,9 @@ struct hci_conn *hci_connect_bis(struct hci_dev *hdev, bdaddr_t *dst,
	if (IS_ERR(conn))
		return conn;

	if (conn->state == BT_CONNECTED)
		return conn;

	data.big = qos->bcast.big;
	data.bis = qos->bcast.bis;

+11 −22
Original line number Diff line number Diff line
@@ -6814,38 +6814,27 @@ static void hci_le_create_big_complete_evt(struct hci_dev *hdev, void *data,
		return;

	hci_dev_lock(hdev);
	rcu_read_lock();

	/* Connect all BISes that are bound to the BIG */
	list_for_each_entry_rcu(conn, &hdev->conn_hash.list, list) {
		if (bacmp(&conn->dst, BDADDR_ANY) ||
		    conn->type != ISO_LINK ||
		    conn->iso_qos.bcast.big != ev->handle)
	while ((conn = hci_conn_hash_lookup_big_state(hdev, ev->handle,
						      BT_BOUND))) {
		if (ev->status) {
			hci_connect_cfm(conn, ev->status);
			hci_conn_del(conn);
			continue;
		}

		if (hci_conn_set_handle(conn,
					__le16_to_cpu(ev->bis_handle[i++])))
			continue;

		if (!ev->status) {
		conn->state = BT_CONNECTED;
		set_bit(HCI_CONN_BIG_CREATED, &conn->flags);
			rcu_read_unlock();
		hci_debugfs_create_conn(conn);
		hci_conn_add_sysfs(conn);
		hci_iso_setup_path(conn);
			rcu_read_lock();
			continue;
	}

		hci_connect_cfm(conn, ev->status);
		rcu_read_unlock();
		hci_conn_del(conn);
		rcu_read_lock();
	}

	rcu_read_unlock();

	if (!ev->status && !i)
		/* If no BISes have been connected for the BIG,
		 * terminate. This is in case all bound connections
+77 −2
Original line number Diff line number Diff line
@@ -612,19 +612,68 @@ static struct sock *iso_get_sock_listen(bdaddr_t *src, bdaddr_t *dst,
			continue;

		/* Exact match. */
		if (!bacmp(&iso_pi(sk)->src, src))
		if (!bacmp(&iso_pi(sk)->src, src)) {
			sock_hold(sk);
			break;
		}

		/* Closest match */
		if (!bacmp(&iso_pi(sk)->src, BDADDR_ANY))
		if (!bacmp(&iso_pi(sk)->src, BDADDR_ANY)) {
			if (sk1)
				sock_put(sk1);

			sk1 = sk;
			sock_hold(sk1);
		}
	}

	if (sk && sk1)
		sock_put(sk1);

	read_unlock(&iso_sk_list.lock);

	return sk ? sk : sk1;
}

static struct sock *iso_get_sock_big(struct sock *match_sk, bdaddr_t *src,
				     bdaddr_t *dst, uint8_t big)
{
	struct sock *sk = NULL;

	read_lock(&iso_sk_list.lock);

	sk_for_each(sk, &iso_sk_list.head) {
		if (match_sk == sk)
			continue;

		/* Look for sockets that have already been
		 * connected to the BIG
		 */
		if (sk->sk_state != BT_CONNECTED &&
		    sk->sk_state != BT_CONNECT)
			continue;

		/* Match Broadcast destination */
		if (bacmp(&iso_pi(sk)->dst, dst))
			continue;

		/* Match BIG handle */
		if (iso_pi(sk)->qos.bcast.big != big)
			continue;

		/* Match source address */
		if (bacmp(&iso_pi(sk)->src, src))
			continue;

		sock_hold(sk);
		break;
	}

	read_unlock(&iso_sk_list.lock);

	return sk;
}

static void iso_sock_destruct(struct sock *sk)
{
	BT_DBG("sk %p", sk);
@@ -677,6 +726,28 @@ static void iso_sock_kill(struct sock *sk)

static void iso_sock_disconn(struct sock *sk)
{
	struct sock *bis_sk;
	struct hci_conn *hcon = iso_pi(sk)->conn->hcon;

	if (test_bit(HCI_CONN_BIG_CREATED, &hcon->flags)) {
		bis_sk = iso_get_sock_big(sk, &iso_pi(sk)->src,
					  &iso_pi(sk)->dst,
					  iso_pi(sk)->qos.bcast.big);

		/* If there are any other connected sockets for the
		 * same BIG, just delete the sk and leave the bis
		 * hcon active, in case later rebinding is needed.
		 */
		if (bis_sk) {
			hcon->state = BT_OPEN;
			iso_pi(sk)->conn->hcon = NULL;
			iso_sock_clear_timer(sk);
			iso_chan_del(sk, bt_to_errno(hcon->abort_reason));
			sock_put(bis_sk);
			return;
		}
	}

	sk->sk_state = BT_DISCONN;
	iso_sock_set_timer(sk, ISO_DISCONN_TIMEOUT);
	iso_conn_lock(iso_pi(sk)->conn);
@@ -1724,6 +1795,7 @@ static void iso_conn_ready(struct iso_conn *conn)
		parent->sk_data_ready(parent);

		release_sock(parent);
		sock_put(parent);
	}
}

@@ -1819,6 +1891,7 @@ int iso_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr, __u8 *flags)
				if (err) {
					bt_dev_err(hdev, "hci_le_big_create_sync: %d",
						   err);
					sock_put(sk);
					sk = NULL;
				}
			}
@@ -1847,6 +1920,8 @@ int iso_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr, __u8 *flags)
	if (test_bit(BT_SK_DEFER_SETUP, &bt_sk(sk)->flags))
		*flags |= HCI_PROTO_DEFER;

	sock_put(sk);

	return lm;
}