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
 -----BEGIN PGP SIGNATURE-----
 
 iQJNBAABCAA3FiEE7E6oRXp8w05ovYr/9JCA4xAyCykFAmcZB+0ZHGx1aXoudm9u
 LmRlbnR6QGludGVsLmNvbQAKCRD0kIDjEDILKWcfD/4j4Q3W01y1UotsTKa1et7V
 r6ydZfHBwU/ND8G8t7sfg4zJ6daYcYY6ERllj92JYCHdmrwILzt3WEgCAAC1Y8dj
 r6RUXFapGSwE3YMIdDstcKgsfYV+zzKL+IBt0VRjhEMeoEEczzRGldk8Y8Z9ePhm
 9Jyw1WDmid9DkIfIdrTKjnLH5HsjYZSvIJfkVuKKcfRshdolxfokHv9DpbPIbueO
 ya33a/mnHVKnLyZPT72uP2DANkP218+zHI+dCjE6279LzrXJkQKLKThf/3bTGO+o
 NohqGEj9NsIp8NqS/jr1yzvXOIqXkA5cG0Qrix+OyZuvBIohukTFyes1f2hcRHoh
 l41s+IorviUhrtEPZ2ki/AWyXTVpWJl2EQ6XPf6iUexF2PDCgTzILN4WIELBTZse
 cEWPVbMI+ZEq9FHX1P9Vfc+Yje4glTXcQzBSlfaljPmbW0CouxYCJ4kEj+5m4F6V
 xBUevpIz3dRUMST4tXaOrhso/Th2zCDDbWwp6ImEZQ8xBM5wm8sDrjkZOtWEWRNc
 miLEnkfqZxJmt6b8DfGzeM/p3FJ9i7OsCo6tUVEH4mGATViD8QOUaqMk/kxV5Wh0
 ORB3cWk4VYTvXGuPceEH7u8yBslbUzmad/eMOK52ErP4UrORhESZYoaDy3ALcr7A
 4z+9xBlOlezKTe5puR5ulw==
 =gOTr
 -----END PGP SIGNATURE-----

Merge tag 'for-net-2024-10-23' of git://git.kernel.org/pub/scm/linux/kernel/git/bluetooth/bluetooth

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: Paolo Abeni <pabeni@redhat.com>
This commit is contained in:
Paolo Abeni 2024-10-24 12:30:22 +02:00
commit 1876479d98
6 changed files with 71 additions and 24 deletions

View File

@ -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,

View File

@ -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;

View File

@ -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);
cancel_delayed_work_sync(&hdev->cmd_timer);
cancel_delayed_work_sync(&hdev->ncmd_timer);
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);

View File

@ -5131,9 +5131,15 @@ int hci_dev_close_sync(struct hci_dev *hdev)
bt_dev_dbg(hdev, "");
cancel_delayed_work(&hdev->power_off);
cancel_delayed_work(&hdev->ncmd_timer);
cancel_delayed_work(&hdev->le_scan_disable);
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);

View File

@ -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) {

View File

@ -76,6 +76,16 @@ struct sco_pinfo {
#define SCO_CONN_TIMEOUT (HZ * 40)
#define SCO_DISCONN_TIMEOUT (HZ * 2)
static struct sock *sco_sock_hold(struct sco_conn *conn)
{
if (!conn || !bt_sock_linked(&sco_sk_list, conn->sk))
return NULL;
sock_hold(conn->sk);
return conn->sk;
}
static void sco_sock_timeout(struct work_struct *work)
{
struct sco_conn *conn = container_of(work, struct sco_conn,
@ -87,9 +97,7 @@ static void sco_sock_timeout(struct work_struct *work)
sco_conn_unlock(conn);
return;
}
sk = conn->sk;
if (sk)
sock_hold(sk);
sk = sco_sock_hold(conn);
sco_conn_unlock(conn);
if (!sk)
@ -194,9 +202,7 @@ static void sco_conn_del(struct hci_conn *hcon, int err)
/* Kill socket */
sco_conn_lock(conn);
sk = conn->sk;
if (sk)
sock_hold(sk);
sk = sco_sock_hold(conn);
sco_conn_unlock(conn);
if (sk) {