Commit 1876479d authored by Paolo Abeni's avatar Paolo Abeni
Browse files
Luiz Augusto von Dentz says:

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

 - hci_core: Disable works on hci_unregister_dev
 - SCO: Fix UAF on sco_sock_timeout
 - ISO: Fix UAF on iso_sock_timeout

* tag 'for-net-2024-10-23' of git://git.kernel.org/pub/scm/linux/kernel/git/bluetooth/bluetooth:
  Bluetooth: ISO: Fix UAF on iso_sock_timeout
  Bluetooth: SCO: Fix UAF on sco_sock_timeout
  Bluetooth: hci_core: Disable works on hci_unregister_dev
====================

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


Signed-off-by: default avatarPaolo Abeni <pabeni@redhat.com>
parents 1e424d08 246b435a
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -403,6 +403,7 @@ int bt_sock_register(int proto, const struct net_proto_family *ops);
void bt_sock_unregister(int proto);
void bt_sock_link(struct bt_sock_list *l, struct sock *s);
void bt_sock_unlink(struct bt_sock_list *l, struct sock *s);
bool bt_sock_linked(struct bt_sock_list *l, struct sock *s);
struct sock *bt_sock_alloc(struct net *net, struct socket *sock,
			   struct proto *prot, int proto, gfp_t prio, int kern);
int  bt_sock_recvmsg(struct socket *sock, struct msghdr *msg, size_t len,
+22 −0
Original line number Diff line number Diff line
@@ -185,6 +185,28 @@ void bt_sock_unlink(struct bt_sock_list *l, struct sock *sk)
}
EXPORT_SYMBOL(bt_sock_unlink);

bool bt_sock_linked(struct bt_sock_list *l, struct sock *s)
{
	struct sock *sk;

	if (!l || !s)
		return false;

	read_lock(&l->lock);

	sk_for_each(sk, &l->head) {
		if (s == sk) {
			read_unlock(&l->lock);
			return true;
		}
	}

	read_unlock(&l->lock);

	return false;
}
EXPORT_SYMBOL(bt_sock_linked);

void bt_accept_enqueue(struct sock *parent, struct sock *sk, bool bh)
{
	const struct cred *old_cred;
+15 −9
Original line number Diff line number Diff line
@@ -1644,12 +1644,12 @@ void hci_adv_instances_clear(struct hci_dev *hdev)
	struct adv_info *adv_instance, *n;

	if (hdev->adv_instance_timeout) {
		cancel_delayed_work(&hdev->adv_instance_expire);
		disable_delayed_work(&hdev->adv_instance_expire);
		hdev->adv_instance_timeout = 0;
	}

	list_for_each_entry_safe(adv_instance, n, &hdev->adv_instances, list) {
		cancel_delayed_work_sync(&adv_instance->rpa_expired_cb);
		disable_delayed_work_sync(&adv_instance->rpa_expired_cb);
		list_del(&adv_instance->list);
		kfree(adv_instance);
	}
@@ -2685,11 +2685,11 @@ void hci_unregister_dev(struct hci_dev *hdev)
	list_del(&hdev->list);
	write_unlock(&hci_dev_list_lock);

	cancel_work_sync(&hdev->rx_work);
	cancel_work_sync(&hdev->cmd_work);
	cancel_work_sync(&hdev->tx_work);
	cancel_work_sync(&hdev->power_on);
	cancel_work_sync(&hdev->error_reset);
	disable_work_sync(&hdev->rx_work);
	disable_work_sync(&hdev->cmd_work);
	disable_work_sync(&hdev->tx_work);
	disable_work_sync(&hdev->power_on);
	disable_work_sync(&hdev->error_reset);

	hci_cmd_sync_clear(hdev);

@@ -2796,8 +2796,14 @@ static void hci_cancel_cmd_sync(struct hci_dev *hdev, int err)
{
	bt_dev_dbg(hdev, "err 0x%2.2x", err);

	if (hci_dev_test_flag(hdev, HCI_UNREGISTER)) {
		disable_delayed_work_sync(&hdev->cmd_timer);
		disable_delayed_work_sync(&hdev->ncmd_timer);
	} else  {
		cancel_delayed_work_sync(&hdev->cmd_timer);
		cancel_delayed_work_sync(&hdev->ncmd_timer);
	}

	atomic_set(&hdev->cmd_cnt, 1);

	hci_cmd_sync_cancel_sync(hdev, err);
+9 −3
Original line number Diff line number Diff line
@@ -5131,9 +5131,15 @@ int hci_dev_close_sync(struct hci_dev *hdev)

	bt_dev_dbg(hdev, "");

	if (hci_dev_test_flag(hdev, HCI_UNREGISTER)) {
		disable_delayed_work(&hdev->power_off);
		disable_delayed_work(&hdev->ncmd_timer);
		disable_delayed_work(&hdev->le_scan_disable);
	} else {
		cancel_delayed_work(&hdev->power_off);
		cancel_delayed_work(&hdev->ncmd_timer);
		cancel_delayed_work(&hdev->le_scan_disable);
	}

	hci_cmd_sync_cancel_sync(hdev, ENODEV);

+12 −6
Original line number Diff line number Diff line
@@ -93,6 +93,16 @@ static struct sock *iso_get_sock(bdaddr_t *src, bdaddr_t *dst,
#define ISO_CONN_TIMEOUT	(HZ * 40)
#define ISO_DISCONN_TIMEOUT	(HZ * 2)

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_conn *conn = container_of(work, struct iso_conn,
@@ -100,9 +110,7 @@ static void iso_sock_timeout(struct work_struct *work)
	struct sock *sk;

	iso_conn_lock(conn);
	sk = conn->sk;
	if (sk)
		sock_hold(sk);
	sk = iso_sock_hold(conn);
	iso_conn_unlock(conn);

	if (!sk)
@@ -209,9 +217,7 @@ static void iso_conn_del(struct hci_conn *hcon, int err)

	/* Kill socket */
	iso_conn_lock(conn);
	sk = conn->sk;
	if (sk)
		sock_hold(sk);
	sk = iso_sock_hold(conn);
	iso_conn_unlock(conn);

	if (sk) {
Loading