Files
omarchy-pkgs/pkgbuilds/linux-omarchy-eevdf/0670-bluetooth-fixes.patch
T

486 lines
15 KiB
Diff

diff --git a/drivers/bluetooth/btintel.c b/drivers/bluetooth/btintel.c
--- a/drivers/bluetooth/btintel.c
+++ b/drivers/bluetooth/btintel.c
@@ -288,7 +288,8 @@ void btintel_hw_error(struct hci_dev *hdev, u8 code)
goto unlock;
}
- bt_dev_err(hdev, "Exception info %s", (char *)(skb->data + 1));
+ bt_dev_err(hdev, "Exception info %.*s", (int)(skb->len - 1),
+ (char *)(skb->data + 1));
kfree_skb(skb);
@@ -407,8 +408,16 @@ int btintel_load_ddc_config(struct hci_dev *hdev, const char *ddc_name)
/* DDC file contains one or more DDC structure which has
* Length (1 byte), DDC ID (2 bytes), and DDC value (Length - 2).
*/
- while (fw->size > fw_ptr - fw->data) {
- u8 cmd_plen = fw_ptr[0] + sizeof(u8);
+ while (fw->size > (size_t)(fw_ptr - fw->data)) {
+ size_t remaining = fw->size - (fw_ptr - fw->data);
+ unsigned int cmd_plen = fw_ptr[0] + 1U;
+
+ if (cmd_plen < 3 || cmd_plen > U8_MAX || cmd_plen > remaining) {
+ bt_dev_err(hdev, "Malformed DDC record (plen=%u, remaining=%zu)",
+ cmd_plen, remaining);
+ release_firmware(fw);
+ return -EINVAL;
+ }
skb = __hci_cmd_sync(hdev, 0xfc8b, cmd_plen, fw_ptr,
HCI_INIT_TIMEOUT);
diff --git a/drivers/bluetooth/btintel_pcie.c b/drivers/bluetooth/btintel_pcie.c
--- a/drivers/bluetooth/btintel_pcie.c
+++ b/drivers/bluetooth/btintel_pcie.c
@@ -1200,7 +1200,7 @@ static int btintel_pcie_recv_frame(struct btintel_pcie_data *data,
{
int ret;
u8 pkt_type;
- u16 plen;
+ u32 plen;
u32 pcie_pkt_type;
void *pdata;
struct hci_dev *hdev = data->hdev;
@@ -2149,6 +2149,16 @@ static int btintel_pcie_send_frame(struct hci_dev *hdev,
if (test_bit(BTINTEL_PCIE_RECOVERY_IN_PROGRESS, &data->flags))
return -ENODEV;
+ /* Account for the 4-byte PCIe type header prepended before the
+ * DMA copy. Written as a subtraction to avoid wrap-around on
+ * attacker-controlled skb->len.
+ */
+ if (skb->len > BTINTEL_PCIE_BUFFER_SIZE - BTINTEL_PCIE_HCI_TYPE_LEN) {
+ bt_dev_err(hdev, "Packet too large: %u > %u", skb->len,
+ BTINTEL_PCIE_BUFFER_SIZE - BTINTEL_PCIE_HCI_TYPE_LEN);
+ return -EMSGSIZE;
+ }
+
/* Due to the fw limitation, the type header of the packet should be
* 4 bytes unlike 1 byte for UART. In UART, the firmware can read
* the first byte to get the packet type and redirect the rest of data
diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -62,7 +62,7 @@ struct inquiry_entry {
NAME_PENDING,
NAME_KNOWN,
} name_state;
- __u32 timestamp;
+ unsigned long timestamp;
struct inquiry_data data;
};
@@ -78,7 +78,7 @@ struct discovery_state {
struct list_head all; /* All devices found during inquiry */
struct list_head unknown; /* Name state not known */
struct list_head resolve; /* Name needs to be resolved */
- __u32 timestamp;
+ unsigned long timestamp;
bdaddr_t last_adv_addr;
u8 last_adv_addr_type;
s8 last_adv_rssi;
@@ -561,6 +561,7 @@ struct hci_dev {
struct list_head link_keys;
struct list_head long_term_keys;
struct list_head identity_resolving_keys;
+ struct mutex remote_oob_lock;
struct list_head remote_oob_data;
struct list_head le_accept_list;
struct list_head le_resolv_list;
diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c
--- a/net/bluetooth/hci_conn.c
+++ b/net/bluetooth/hci_conn.c
@@ -302,11 +302,13 @@ static int hci_enhanced_setup_sync(struct hci_dev *hdev, void *data)
cp.tx_bandwidth = cpu_to_le32(0x00001f40);
cp.rx_bandwidth = cpu_to_le32(0x00001f40);
+ hci_dev_lock(hdev);
+
switch (conn->codec.id) {
case BT_CODEC_MSBC:
if (!find_next_esco_param(conn, esco_param_msbc,
ARRAY_SIZE(esco_param_msbc)))
- return -EINVAL;
+ goto unlock;
param = &esco_param_msbc[conn->attempt - 1];
cp.tx_coding_format.id = 0x05;
@@ -332,7 +334,7 @@ static int hci_enhanced_setup_sync(struct hci_dev *hdev, void *data)
case BT_CODEC_TRANSPARENT:
if (!find_next_esco_param(conn, esco_param_msbc,
ARRAY_SIZE(esco_param_msbc)))
- return -EINVAL;
+ goto unlock;
param = &esco_param_msbc[conn->attempt - 1];
cp.tx_coding_format.id = 0x03;
@@ -359,11 +361,11 @@ static int hci_enhanced_setup_sync(struct hci_dev *hdev, void *data)
if (conn->parent && lmp_esco_capable(conn->parent)) {
if (!find_next_esco_param(conn, esco_param_cvsd,
ARRAY_SIZE(esco_param_cvsd)))
- return -EINVAL;
+ goto unlock;
param = &esco_param_cvsd[conn->attempt - 1];
} else {
if (conn->attempt > ARRAY_SIZE(sco_param_cvsd))
- return -EINVAL;
+ goto unlock;
param = &sco_param_cvsd[conn->attempt - 1];
}
cp.tx_coding_format.id = 2;
@@ -386,9 +388,11 @@ static int hci_enhanced_setup_sync(struct hci_dev *hdev, void *data)
cp.out_transport_unit_size = 16;
break;
default:
- return -EINVAL;
+ goto unlock;
}
+ hci_dev_unlock(hdev);
+
cp.retrans_effort = param->retrans_effort;
cp.pkt_type = __cpu_to_le16(param->pkt_type);
cp.max_latency = __cpu_to_le16(param->max_latency);
@@ -397,6 +401,10 @@ static int hci_enhanced_setup_sync(struct hci_dev *hdev, void *data)
return -EIO;
return 0;
+
+unlock:
+ hci_dev_unlock(hdev);
+ return -EINVAL;
}
static bool hci_setup_sync_conn(struct hci_conn *conn, __u16 handle)
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -1486,8 +1486,10 @@ int hci_remove_remote_oob_data(struct hci_dev *hdev, bdaddr_t *bdaddr,
BT_DBG("%s removing %pMR (%u)", hdev->name, bdaddr, bdaddr_type);
+ mutex_lock(&hdev->remote_oob_lock);
list_del(&data->list);
kfree(data);
+ mutex_unlock(&hdev->remote_oob_lock);
return 0;
}
@@ -1496,10 +1498,12 @@ void hci_remote_oob_data_clear(struct hci_dev *hdev)
{
struct oob_data *data, *n;
+ mutex_lock(&hdev->remote_oob_lock);
list_for_each_entry_safe(data, n, &hdev->remote_oob_data, list) {
list_del(&data->list);
kfree(data);
}
+ mutex_unlock(&hdev->remote_oob_lock);
}
int hci_add_remote_oob_data(struct hci_dev *hdev, bdaddr_t *bdaddr,
@@ -1508,11 +1512,14 @@ int hci_add_remote_oob_data(struct hci_dev *hdev, bdaddr_t *bdaddr,
{
struct oob_data *data;
+ mutex_lock(&hdev->remote_oob_lock);
data = hci_find_remote_oob_data(hdev, bdaddr, bdaddr_type);
if (!data) {
data = kmalloc_obj(*data);
- if (!data)
+ if (!data) {
+ mutex_unlock(&hdev->remote_oob_lock);
return -ENOMEM;
+ }
bacpy(&data->bdaddr, bdaddr);
data->bdaddr_type = bdaddr_type;
@@ -1545,6 +1552,8 @@ int hci_add_remote_oob_data(struct hci_dev *hdev, bdaddr_t *bdaddr,
BT_DBG("%s for %pMR", hdev->name, bdaddr);
+ mutex_unlock(&hdev->remote_oob_lock);
+
return 0;
}
@@ -2482,6 +2491,7 @@ struct hci_dev *hci_alloc_dev_priv(int sizeof_priv)
mutex_init(&hdev->lock);
mutex_init(&hdev->req_lock);
mutex_init(&hdev->mgmt_pending_lock);
+ mutex_init(&hdev->remote_oob_lock);
ida_init(&hdev->unset_handle_ida);
@@ -2554,8 +2564,10 @@ int hci_register_dev(struct hci_dev *hdev)
return id;
error = dev_set_name(&hdev->dev, "hci%u", id);
- if (error)
+ if (error) {
+ ida_free(&hci_index_ida, id);
return error;
+ }
hdev->name = dev_name(&hdev->dev);
hdev->id = id;
@@ -3323,6 +3335,8 @@ static void hci_queue_iso(struct hci_conn *conn, struct sk_buff_head *queue,
skb_shinfo(skb)->frag_list = NULL;
+ spin_lock_bh(&queue->lock);
+
__skb_queue_tail(queue, skb);
do {
@@ -3337,6 +3351,8 @@ static void hci_queue_iso(struct hci_conn *conn, struct sk_buff_head *queue,
__skb_queue_tail(queue, skb);
} while (list);
+
+ spin_unlock_bh(&queue->lock);
}
bt_dev_dbg(hdev, "hcon %p queued %d", conn, skb_queue_len(queue));
@@ -3400,9 +3416,6 @@ static struct hci_conn *hci_low_sent(struct hci_dev *hdev, __u8 type,
struct hci_conn *conn = NULL, *c;
unsigned int num = 0, min = ~0;
- /* We don't have to lock device here. Connections are always
- * added and removed with TX task disabled. */
-
rcu_read_lock();
list_for_each_entry_rcu(c, &h->list, list) {
@@ -3607,13 +3620,15 @@ static void __check_timeout(struct hci_dev *hdev, unsigned int cnt, u8 type)
}
/* Schedule SCO */
-static void hci_sched_sco(struct hci_dev *hdev, __u8 type)
+static void __hci_sched_sco(struct hci_dev *hdev, __u8 type)
{
struct hci_conn *conn;
struct sk_buff *skb;
int quote, *cnt;
unsigned int pkts = hdev->sco_pkts;
+ lockdep_assert_held(&hdev->lock);
+
bt_dev_dbg(hdev, "type %u", type);
if (!hci_conn_num(hdev, type) || !pkts)
@@ -3648,6 +3663,13 @@ static void hci_sched_sco(struct hci_dev *hdev, __u8 type)
queue_work(hdev->workqueue, &hdev->tx_work);
}
+static void hci_sched_sco(struct hci_dev *hdev, __u8 type)
+{
+ hci_dev_lock(hdev);
+ __hci_sched_sco(hdev, type);
+ hci_dev_unlock(hdev);
+}
+
static void hci_sched_acl_pkt(struct hci_dev *hdev)
{
unsigned int cnt = hdev->acl_cnt;
@@ -3657,6 +3679,8 @@ static void hci_sched_acl_pkt(struct hci_dev *hdev)
__check_timeout(hdev, cnt, ACL_LINK);
+ hci_dev_lock(hdev);
+
while (hdev->acl_cnt &&
(chan = hci_chan_sent(hdev, ACL_LINK, &quote))) {
u32 priority = (skb_peek(&chan->data_q))->priority;
@@ -3681,13 +3705,15 @@ static void hci_sched_acl_pkt(struct hci_dev *hdev)
chan->conn->sent++;
/* Send pending SCO packets right away */
- hci_sched_sco(hdev, SCO_LINK);
- hci_sched_sco(hdev, ESCO_LINK);
+ __hci_sched_sco(hdev, SCO_LINK);
+ __hci_sched_sco(hdev, ESCO_LINK);
}
}
if (cnt != hdev->acl_cnt)
hci_prio_recalculate(hdev, ACL_LINK);
+
+ hci_dev_unlock(hdev);
}
static void hci_sched_acl(struct hci_dev *hdev)
@@ -3716,6 +3742,8 @@ static void hci_sched_le(struct hci_dev *hdev)
__check_timeout(hdev, *cnt, LE_LINK);
+ hci_dev_lock(hdev);
+
tmp = *cnt;
while (*cnt && (chan = hci_chan_sent(hdev, LE_LINK, &quote))) {
u32 priority = (skb_peek(&chan->data_q))->priority;
@@ -3737,13 +3765,15 @@ static void hci_sched_le(struct hci_dev *hdev)
chan->conn->sent++;
/* Send pending SCO packets right away */
- hci_sched_sco(hdev, SCO_LINK);
- hci_sched_sco(hdev, ESCO_LINK);
+ __hci_sched_sco(hdev, SCO_LINK);
+ __hci_sched_sco(hdev, ESCO_LINK);
}
}
if (*cnt != tmp)
hci_prio_recalculate(hdev, LE_LINK);
+
+ hci_dev_unlock(hdev);
}
/* Schedule iso */
@@ -3762,6 +3792,8 @@ static void hci_sched_iso(struct hci_dev *hdev, __u8 type)
__check_timeout(hdev, *cnt, type);
+ hci_dev_lock(hdev);
+
while (*cnt && (conn = hci_low_sent(hdev, type, &quote))) {
while (quote-- && (skb = skb_dequeue(&conn->data_q))) {
BT_DBG("skb %p len %d", skb, skb->len);
@@ -3775,6 +3807,8 @@ static void hci_sched_iso(struct hci_dev *hdev, __u8 type)
(*cnt)--;
}
}
+
+ hci_dev_unlock(hdev);
}
static void hci_tx_work(struct work_struct *work)
diff --git a/net/bluetooth/hci_debugfs.c b/net/bluetooth/hci_debugfs.c
--- a/net/bluetooth/hci_debugfs.c
+++ b/net/bluetooth/hci_debugfs.c
@@ -364,7 +364,7 @@ static int inquiry_cache_show(struct seq_file *f, void *p)
list_for_each_entry(e, &cache->all, all) {
struct inquiry_data *data = &e->data;
- seq_printf(f, "%pMR %d %d %d 0x%.2x%.2x%.2x 0x%.4x %d %d %u\n",
+ seq_printf(f, "%pMR %d %d %d 0x%.2x%.2x%.2x 0x%.4x %d %d %lu\n",
&data->bdaddr,
data->pscan_rep_mode, data->pscan_period_mode,
data->pscan_mode, data->dev_class[2],
diff --git a/net/bluetooth/hci_sync.c b/net/bluetooth/hci_sync.c
--- a/net/bluetooth/hci_sync.c
+++ b/net/bluetooth/hci_sync.c
@@ -312,6 +312,10 @@ static void hci_cmd_sync_work(struct work_struct *work)
while (1) {
struct hci_cmd_sync_work_entry *entry;
+ /* Leave the backlog to hci_cmd_sync_clear() */
+ if (hci_dev_test_flag(hdev, HCI_UNREGISTER))
+ break;
+
mutex_lock(&hdev->cmd_sync_work_lock);
entry = list_first_entry_or_null(&hdev->cmd_sync_work_list,
struct hci_cmd_sync_work_entry,
@@ -658,6 +662,8 @@ void hci_cmd_sync_clear(struct hci_dev *hdev)
{
struct hci_cmd_sync_work_entry *entry, *tmp;
+ /* cmd_work is disabled, the pending request can only time out */
+ hci_cmd_sync_cancel_sync(hdev, ENODEV);
cancel_work_sync(&hdev->cmd_sync_work);
cancel_work_sync(&hdev->reenable_adv_work);
@@ -5678,6 +5684,7 @@ int hci_stop_discovery_sync(struct hci_dev *hdev)
{
struct discovery_state *d = &hdev->discovery;
struct inquiry_entry *e;
+ bdaddr_t addr;
int err;
bt_dev_dbg(hdev, "state %u", hdev->discovery.state);
@@ -5713,15 +5720,21 @@ int hci_stop_discovery_sync(struct hci_dev *hdev)
return 0;
if (d->state == DISCOVERY_RESOLVING || d->state == DISCOVERY_STOPPING) {
+ hci_dev_lock(hdev);
e = hci_inquiry_cache_lookup_resolve(hdev, BDADDR_ANY,
NAME_PENDING);
- if (!e)
+ if (!e) {
+ hci_dev_unlock(hdev);
return 0;
+ }
+
+ bacpy(&addr, &e->data.bdaddr);
+ hci_dev_unlock(hdev);
/* Ignore cancel errors since it should interfere with stopping
* of the discovery.
*/
- hci_remote_name_cancel_sync(hdev, &e->data.bdaddr);
+ hci_remote_name_cancel_sync(hdev, &addr);
}
return 0;
@@ -7151,6 +7164,7 @@ static int hci_acl_create_conn_sync(struct hci_dev *hdev, void *data)
bacpy(&cp.bdaddr, &conn->dst);
cp.pscan_rep_mode = 0x02;
+ hci_dev_lock(hdev);
ie = hci_inquiry_cache_lookup(hdev, &conn->dst);
if (ie) {
if (inquiry_entry_age(ie) <= INQUIRY_ENTRY_AGE_MAX) {
@@ -7162,6 +7176,7 @@ static int hci_acl_create_conn_sync(struct hci_dev *hdev, void *data)
memcpy(conn->dev_class, ie->data.dev_class, 3);
}
+ hci_dev_unlock(hdev);
cp.pkt_type = cpu_to_le16(conn->pkt_type);
if (lmp_rswitch_capable(hdev) && !(hdev->link_mode & HCI_LM_MASTER))
diff --git a/net/bluetooth/rfcomm/tty.c b/net/bluetooth/rfcomm/tty.c
--- a/net/bluetooth/rfcomm/tty.c
+++ b/net/bluetooth/rfcomm/tty.c
@@ -462,7 +462,7 @@ static int __rfcomm_release_dev(void __user *arg)
/* Shut down TTY synchronously before freeing rfcomm_dev */
tty_port_tty_vhangup(&dev->port);
- if (!test_bit(RFCOMM_TTY_OWNED, &dev->status))
+ if (!test_and_set_bit(RFCOMM_TTY_OWNED, &dev->status))
tty_port_put(&dev->port);
tty_port_put(&dev->port);
@@ -724,10 +724,9 @@ static int rfcomm_tty_install(struct tty_driver *driver, struct tty_struct *tty)
* when the last process closes the tty. The behaviour is expected by
* userspace.
*/
- if (test_bit(RFCOMM_RELEASE_ONHUP, &dev->flags)) {
- set_bit(RFCOMM_TTY_OWNED, &dev->status);
+ if (test_bit(RFCOMM_RELEASE_ONHUP, &dev->flags) &&
+ !test_and_set_bit(RFCOMM_TTY_OWNED, &dev->status))
tty_port_put(&dev->port);
- }
return 0;
}
diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c
--- a/net/bluetooth/smp.c
+++ b/net/bluetooth/smp.c
@@ -661,6 +661,7 @@ static void build_pairing_cmd(struct l2cap_conn *conn,
else
bdaddr_type = BDADDR_LE_RANDOM;
+ mutex_lock(&hdev->remote_oob_lock);
oob_data = hci_find_remote_oob_data(hdev, &hcon->dst,
bdaddr_type);
if (oob_data && oob_data->present) {
@@ -671,6 +672,7 @@ static void build_pairing_cmd(struct l2cap_conn *conn,
SMP_DBG("OOB Remote Confirmation: %16phN", smp->pcnf);
SMP_DBG("OOB Remote Random: %16phN", smp->rr);
}
+ mutex_unlock(&hdev->remote_oob_lock);
} else {
authreq &= ~SMP_AUTH_SC;