2934 lines · 63.3 KB · C
RawDownload
// SPDX-License-Identifier: GPL-2.0/* * BlueZ - Bluetooth protocol stack for Linux * * Copyright (C) 2022 Intel Corporation * Copyright 2023-2024 NXP */ #include <linux/module.h>#include <linux/debugfs.h>#include <linux/seq_file.h>#include <linux/sched/signal.h>#include <linux/uio.h> #include <net/bluetooth/bluetooth.h>#include <net/bluetooth/hci_core.h>#include <net/bluetooth/iso.h>#include "eir.h" static const struct proto_ops iso_sock_ops; static struct bt_sock_list iso_sk_list = {	.lock = __RW_LOCK_UNLOCKED(iso_sk_list.lock)}; /* ---- ISO connections ---- */enum {	ISO_CONN_DROPPED,	__ISO_CONN_NUM_FLAGS}; struct iso_conn {	struct hci_conn	*hcon;	DECLARE_BITMAP(flags, __ISO_CONN_NUM_FLAGS); 	/* @lock: spinlock protecting changes to iso_conn fields */	spinlock_t	lock;	struct sock	*sk; 	struct sk_buff	*rx_skb;	__u32		rx_len;	__u16		tx_sn;	struct kref	ref;}; #define iso_conn_lock(c)	spin_lock(&(c)->lock)#define iso_conn_unlock(c)	spin_unlock(&(c)->lock) static void iso_sock_close(struct sock *sk);static void iso_sock_kill(struct sock *sk); /* ----- ISO socket info ----- */#define iso_pi(sk) ((struct iso_pinfo *)sk) #define EIR_SERVICE_DATA_LENGTH 4#define BASE_MAX_LENGTH (HCI_MAX_PER_AD_LENGTH - EIR_SERVICE_DATA_LENGTH)#define EIR_BAA_SERVICE_UUID	0x1851 /* iso_pinfo flags values */enum {	BT_SK_BIG_SYNC,	BT_SK_PA_SYNC,	BT_SK_KILLED,}; struct iso_pinfo {	struct bt_sock		bt;	bdaddr_t		src;	__u8			src_type;	bdaddr_t		dst;	__u8			dst_type;	__u8			bc_sid;	__u8			bc_num_bis;	__u8			bc_bis[ISO_MAX_NUM_BIS];	__u16			sync_handle;	unsigned long		flags;	struct bt_iso_qos	qos;	bool			qos_user_set;	__u8			base_len;	__u8			base[BASE_MAX_LENGTH];	struct iso_conn		*conn;	struct delayed_work	timeout_work;}; static struct bt_iso_qos default_qos; static bool check_ucast_qos(struct bt_iso_qos *qos);static bool check_bcast_qos(struct bt_iso_qos *qos);static bool iso_match_sid(struct sock *sk, void *data);static bool iso_match_sid_past(struct sock *sk, void *data);static bool iso_match_sync_handle(struct sock *sk, void *data);static bool iso_match_sync_handle_pa_report(struct sock *sk, void *data);static void iso_sock_disconn(struct sock *sk); typedef bool (*iso_sock_match_t)(struct sock *sk, void *data); static struct sock *iso_get_sock(struct hci_dev *hdev, bdaddr_t *src,				 bdaddr_t *dst, enum bt_sock_state state,				 iso_sock_match_t match, void *data); /* ---- ISO timers ---- */#define ISO_CONN_TIMEOUT	secs_to_jiffies(20)#define ISO_DISCONN_TIMEOUT	secs_to_jiffies(2) static void iso_conn_free(struct kref *ref){	struct iso_conn *conn = container_of(ref, struct iso_conn, ref); 	BT_DBG("conn %p", conn); 	if (conn->hcon) {		spin_lock(&conn->hcon->proto_lock); 		/* Check we are not racing with iso_conn_add */		if (conn->hcon->iso_data == conn) {			conn->hcon->iso_data = NULL;			if (!test_and_set_bit(ISO_CONN_DROPPED, conn->flags))				hci_conn_drop(conn->hcon);		} 		spin_unlock(&conn->hcon->proto_lock);	} 	kfree_skb(conn->rx_skb); 	kfree(conn);} static void iso_conn_put(struct iso_conn *conn){	if (!conn)		return; 	BT_DBG("conn %p refcnt %d", conn, kref_read(&conn->ref)); 	/* The following race vs. iso_conn_del() is possible:	 *	 * 1. conn->hcon != NULL here	 * 2. kref_put puts the last reference	 * 3. concurrent iso_conn_del() gets iso_conn_hold_unless_zero() -> NULL	 *    and returns immediately, so conn->hcon is not cleared	 * 4. iso_conn_free() dereferences conn->hcon	 *	 * To avoid UAF in step 4, take RCU before decrementing the refcount.	 */	rcu_read_lock(); 	kref_put(&conn->ref, iso_conn_free); 	rcu_read_unlock();} static struct iso_conn *iso_conn_hold_unless_zero(struct iso_conn *conn){	if (!conn)		return NULL; 	BT_DBG("conn %p refcnt %u", conn, kref_read(&conn->ref)); 	if (!kref_get_unless_zero(&conn->ref))		return NULL; 	return conn;} static struct iso_conn *iso_conn_hold(struct iso_conn *conn){	BT_DBG("conn %p refcnt %u", conn, kref_read(&conn->ref)); 	kref_get(&conn->ref);	return conn;} static struct sock *iso_sock_hold(struct iso_conn *conn){	if (!conn || !bt_sock_linked(&iso_sk_list, conn->sk))		return NULL; 	sock_hold(conn->sk); 	return conn->sk;} static void iso_sock_timeout(struct work_struct *work){	struct iso_pinfo *pi = container_of(work, struct iso_pinfo,					    timeout_work.work);	struct sock *sk = &pi->bt.sk; 	BT_DBG("sock %p state %d", sk, sk->sk_state); 	lock_sock(sk);	if (!sock_flag(sk, SOCK_ZAPPED)) {		sk->sk_err = ETIMEDOUT;		sk->sk_state_change(sk);	}	release_sock(sk);} static void iso_sock_set_timer(struct sock *sk, long timeout){	lockdep_assert(lockdep_sock_is_held(sk)); 	cancel_delayed_work(&iso_pi(sk)->timeout_work); 	if (!iso_pi(sk)->conn)		return; 	BT_DBG("sock %p state %d timeout %ld", sk, sk->sk_state, timeout);	schedule_delayed_work(&iso_pi(sk)->timeout_work, timeout);} static void iso_sock_clear_timer(struct sock *sk){	BT_DBG("sock %p state %d", sk, sk->sk_state);	cancel_delayed_work(&iso_pi(sk)->timeout_work);} static void iso_sock_disable_timer(struct sock *sk){	lockdep_assert(!lockdep_sock_is_held(sk)); 	BT_DBG("sock %p state %d", sk, sk->sk_state);	disable_delayed_work_sync(&iso_pi(sk)->timeout_work);} /* ---- ISO connections ---- */static struct iso_conn *iso_conn_add(struct hci_conn *hcon)	__must_hold(&hcon->hdev->lock){	struct iso_conn *conn; 	spin_lock(&hcon->proto_lock); 	conn = iso_conn_hold_unless_zero(hcon->iso_data);	if (conn) {		if (!conn->hcon) {			iso_conn_lock(conn);			conn->hcon = hcon;			iso_conn_unlock(conn);		}		spin_unlock(&hcon->proto_lock);		return conn;	} 	conn = kzalloc_obj(*conn, GFP_ATOMIC);	if (!conn) {		spin_unlock(&hcon->proto_lock);		return NULL;	} 	kref_init(&conn->ref);	spin_lock_init(&conn->lock); 	hcon->iso_data = conn;	conn->hcon = hcon;	conn->tx_sn = 0; 	spin_unlock(&hcon->proto_lock); 	BT_DBG("hcon %p conn %p", hcon, conn); 	return conn;} /* Delete channel. Must be called on the locked socket. */static void iso_chan_del(struct sock *sk, int err){	struct iso_conn *conn;	struct sock *parent; 	conn = iso_pi(sk)->conn;	iso_pi(sk)->conn = NULL; 	BT_DBG("sk %p, conn %p, err %d", sk, conn, err); 	if (conn) {		iso_conn_lock(conn);		conn->sk = NULL;		iso_conn_unlock(conn);		iso_conn_put(conn);	} 	sk->sk_state = BT_CLOSED;	sk->sk_err   = err; 	parent = bt_sk(sk)->parent;	if (parent) {		bt_accept_unlink(sk);		parent->sk_data_ready(parent);	} else {		sk->sk_state_change(sk);	} 	sock_set_flag(sk, SOCK_ZAPPED);} static void iso_conn_del(struct hci_conn *hcon, int err)	__must_hold(&hcon->hdev->lock){	struct iso_conn *conn;	struct sock *sk; 	spin_lock(&hcon->proto_lock);	conn = iso_conn_hold_unless_zero(hcon->iso_data);	spin_unlock(&hcon->proto_lock);	if (!conn)		return; 	BT_DBG("hcon %p conn %p, err %d", hcon, conn, err); 	/* Kill socket */	iso_conn_lock(conn);	sk = iso_sock_hold(conn);	iso_conn_unlock(conn); 	if (!sk)		goto done; 	iso_sock_disable_timer(sk); 	lock_sock(sk);	iso_chan_del(sk, err);	release_sock(sk);	iso_sock_kill(sk);	sock_put(sk); done:	/* No sk access to conn->hcon any more (lock_sock + hdev->lock) */	spin_lock(&hcon->proto_lock);	iso_conn_lock(conn);	conn->hcon = NULL;	hcon->iso_data = NULL;	iso_conn_unlock(conn);	spin_unlock(&hcon->proto_lock); 	iso_conn_put(conn);} static int __iso_chan_add(struct iso_conn *conn, struct sock *sk,			  struct sock *parent){	BT_DBG("conn %p", conn); 	if (iso_pi(sk)->conn == conn && conn->sk == sk)		return 0; 	if (conn->sk) {		BT_ERR("conn->sk already set");		return -EBUSY;	} 	if (!conn->hcon) {		BT_ERR("conn->hcon missing");		return -EIO;	} 	iso_pi(sk)->conn = iso_conn_hold(conn);	conn->sk = sk;	clear_bit(ISO_CONN_DROPPED, conn->flags); 	if (parent)		bt_accept_enqueue(parent, sk, true); 	return 0;} static int iso_chan_add(struct iso_conn *conn, struct sock *sk,			struct sock *parent){	int err; 	iso_conn_lock(conn);	err = __iso_chan_add(conn, sk, parent);	iso_conn_unlock(conn); 	return err;} static inline u8 le_addr_type(u8 bdaddr_type){	if (bdaddr_type == BDADDR_LE_PUBLIC)		return ADDR_LE_DEV_PUBLIC;	else		return ADDR_LE_DEV_RANDOM;} static int iso_connect_bis(struct sock *sk){	struct iso_conn *conn;	struct hci_conn *hcon;	struct hci_dev  *hdev;	bdaddr_t src, dst;	u8 src_type, bc_sid;	int err; 	lock_sock(sk);	bacpy(&src, &iso_pi(sk)->src);	bacpy(&dst, &iso_pi(sk)->dst);	src_type = iso_pi(sk)->src_type;	bc_sid = iso_pi(sk)->bc_sid;	release_sock(sk); 	BT_DBG("%pMR (SID 0x%2.2x)", &src, bc_sid); 	hdev = hci_get_route(&dst, &src, src_type);	if (!hdev)		return -EHOSTUNREACH; 	hci_dev_lock(hdev);	lock_sock(sk); 	if (!bis_capable(hdev)) {		err = -EOPNOTSUPP;		goto unlock;	} 	/* Fail if user set invalid QoS */	if (iso_pi(sk)->qos_user_set && !check_bcast_qos(&iso_pi(sk)->qos)) {		iso_pi(sk)->qos = default_qos;		err = -EINVAL;		goto unlock;	} 	/* Fail if out PHYs are marked as disabled */	if (!iso_pi(sk)->qos.bcast.out.phys) {		err = -EINVAL;		goto unlock;	} 	/* Just bind if DEFER_SETUP has been set */	if (test_bit(BT_SK_DEFER_SETUP, &bt_sk(sk)->flags)) {		hcon = hci_bind_bis(hdev, &iso_pi(sk)->dst, iso_pi(sk)->bc_sid,				    &iso_pi(sk)->qos, iso_pi(sk)->base_len,				    iso_pi(sk)->base,				    READ_ONCE(sk->sk_sndtimeo));		if (IS_ERR(hcon)) {			err = PTR_ERR(hcon);			goto unlock;		}	} else {		hcon = hci_connect_bis(hdev, &iso_pi(sk)->dst,				       le_addr_type(iso_pi(sk)->dst_type),				       iso_pi(sk)->bc_sid, &iso_pi(sk)->qos,				       iso_pi(sk)->base_len, iso_pi(sk)->base,				       READ_ONCE(sk->sk_sndtimeo));		if (IS_ERR(hcon)) {			err = PTR_ERR(hcon);			goto unlock;		} 		/* Update SID if it was not set */		if (iso_pi(sk)->bc_sid == HCI_SID_INVALID)			iso_pi(sk)->bc_sid = hcon->sid;	} 	lockdep_assert_held(&hcon->hdev->lock); 	conn = iso_conn_add(hcon);	if (!conn) {		hci_conn_drop(hcon);		err = -ENOMEM;		goto unlock;	} 	err = iso_chan_add(conn, sk, NULL);	iso_conn_put(conn);	if (err)		goto unlock; 	/* Update source addr of the socket */	bacpy(&iso_pi(sk)->src, &hcon->src); 	if (hcon->state == BT_CONNECTED) {		iso_sock_clear_timer(sk);		sk->sk_state = BT_CONNECTED;	} else if (test_bit(BT_SK_DEFER_SETUP, &bt_sk(sk)->flags)) {		iso_sock_clear_timer(sk);		sk->sk_state = BT_CONNECT;	} else {		sk->sk_state = BT_CONNECT;		iso_sock_set_timer(sk, READ_ONCE(sk->sk_sndtimeo));	} unlock:	release_sock(sk);	hci_dev_unlock(hdev);	hci_dev_put(hdev);	return err;} static int iso_connect_cis(struct sock *sk){	struct iso_conn *conn;	struct hci_conn *hcon;	struct hci_dev  *hdev;	bdaddr_t src, dst;	u8 src_type;	int err; 

Lines 1–500 of 2934.