bluetooth pull request for net:
- hci_sync: Fix hci_le_create_conn_sync - MGMT: Fix list corruption and UAF in command complete handlers - L2CAP: Disconnect if received packet's SDU exceeds IMTU - L2CAP: Disconnect if sum of payload sizes exceed SDU - L2CAP: Fix accepting multiple L2CAP_ECRED_CONN_REQ - L2CAP: Fix type confusion in l2cap_ecred_reconf_rsp() - L2CAP: Validate L2CAP_INFO_RSP payload length before access - L2CAP: Fix use-after-free in l2cap_unregister_user - ISO: Fix defer tests being unstable - HIDP: Fix possible UAF - SMP: make SM/PER/KDU/BI-04-C happy - qca: fix ROM version reading on WCN3998 chips -----BEGIN PGP SIGNATURE----- iQJNBAABCgA3FiEE7E6oRXp8w05ovYr/9JCA4xAyCykFAmmzHI8ZHGx1aXoudm9u LmRlbnR6QGludGVsLmNvbQAKCRD0kIDjEDILKXtGD/4zaZVcPMT54ucmItF4rRVJ XX3abRfOi1/Z/xFPlG5eSiMiBEBjsXXikP66UI3/qLPdNwxTn+Psv1EY5Z8UYUNZ uPVv3LVUH/tmlney5wGZc92prZoiuBxfJ2rXoFFiyZWwQp/asJnmSnurE383r/Vp 9GEQVQvXtQ2HJ5xFxN0RMDZWAm0gijqFfYVy7+vlUDEpCM9Zmh3QAK04wyCNGFVV qLYSIeQ9HGoQ3IRP6JWBzYwfVp0v365a6MKGR8TkKWHfoLUuabXm8GlWOZ/8Sdkr xJIUvqC2UHycBHSCF/IWauxh6nbODzFCAvOWXlL/z1GJrQZX50M+OIYfGDgUjYOp oFMl1r77ueDHBiifSXXKLjV8TJPPwFzxMPfh6Q+uk2U6wM/bqzulkfsGMBD9SwC9 M+fiU13KIQpqjE6yOeqNz0Hhld8tQMQ8FhVhqfwm5LZqR9qavAtP1FJ6UWwrZPd5 1K1pBp6/IENyELv+pE8DkfiYyJTNaBpqx/eGfJvMyJ9FePDdG8PXMDs9x20S1PHT otk+qljfOtXBM6nVsgItB7l1me1y8RjBI2Iuk/kv9T1xJd+NQyVIn3hooBwcREG3 1h3iX2wlou12Fpb3EAek7HvAYXvUKhTyDpSrPQgx8RsDbBgpvKVf6XrODewa/oct VDyb+TqsOO8iYzz4ExUG6w== =RKEF -----END PGP SIGNATURE----- Merge tag 'for-net-2026-03-12' of git://git.kernel.org/pub/scm/linux/kernel/git/bluetooth/bluetooth Luiz Augusto von Dentz says: ==================== bluetooth pull request for net: - hci_sync: Fix hci_le_create_conn_sync - MGMT: Fix list corruption and UAF in command complete handlers - L2CAP: Disconnect if received packet's SDU exceeds IMTU - L2CAP: Disconnect if sum of payload sizes exceed SDU - L2CAP: Fix accepting multiple L2CAP_ECRED_CONN_REQ - L2CAP: Fix type confusion in l2cap_ecred_reconf_rsp() - L2CAP: Validate L2CAP_INFO_RSP payload length before access - L2CAP: Fix use-after-free in l2cap_unregister_user - ISO: Fix defer tests being unstable - HIDP: Fix possible UAF - SMP: make SM/PER/KDU/BI-04-C happy - qca: fix ROM version reading on WCN3998 chips * tag 'for-net-2026-03-12' of git://git.kernel.org/pub/scm/linux/kernel/git/bluetooth/bluetooth: Bluetooth: qca: fix ROM version reading on WCN3998 chips Bluetooth: L2CAP: Validate L2CAP_INFO_RSP payload length before access Bluetooth: L2CAP: Fix type confusion in l2cap_ecred_reconf_rsp() Bluetooth: L2CAP: Fix accepting multiple L2CAP_ECRED_CONN_REQ Bluetooth: L2CAP: Fix use-after-free in l2cap_unregister_user Bluetooth: HIDP: Fix possible UAF Bluetooth: MGMT: Fix list corruption and UAF in command complete handlers Bluetooth: hci_sync: Fix hci_le_create_conn_sync Bluetooth: ISO: Fix defer tests being unstable Bluetooth: SMP: make SM/PER/KDU/BI-04-C happy Bluetooth: LE L2CAP: Disconnect if sum of payload sizes exceed SDU Bluetooth: LE L2CAP: Disconnect if received packet's SDU exceeds IMTU ==================== Link: https://patch.msgid.link/20260312200655.1215688-1-luiz.dentz@gmail.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
commit
74c1e2737b
|
|
@ -787,6 +787,8 @@ int qca_uart_setup(struct hci_dev *hdev, uint8_t baudrate,
|
|||
*/
|
||||
if (soc_type == QCA_WCN3988)
|
||||
rom_ver = ((soc_ver & 0x00000f00) >> 0x05) | (soc_ver & 0x0000000f);
|
||||
else if (soc_type == QCA_WCN3998)
|
||||
rom_ver = ((soc_ver & 0x0000f000) >> 0x07) | (soc_ver & 0x0000000f);
|
||||
else
|
||||
rom_ver = ((soc_ver & 0x00000f00) >> 0x04) | (soc_ver & 0x0000000f);
|
||||
|
||||
|
|
|
|||
|
|
@ -1944,6 +1944,8 @@ static bool hci_le_set_cig_params(struct hci_conn *conn, struct bt_iso_qos *qos)
|
|||
return false;
|
||||
|
||||
done:
|
||||
conn->iso_qos = *qos;
|
||||
|
||||
if (hci_cmd_sync_queue(hdev, set_cig_params_sync,
|
||||
UINT_PTR(qos->ucast.cig), NULL) < 0)
|
||||
return false;
|
||||
|
|
@ -2013,8 +2015,6 @@ struct hci_conn *hci_bind_cis(struct hci_dev *hdev, bdaddr_t *dst,
|
|||
}
|
||||
|
||||
hci_conn_hold(cis);
|
||||
|
||||
cis->iso_qos = *qos;
|
||||
cis->state = BT_BOUND;
|
||||
|
||||
return cis;
|
||||
|
|
|
|||
|
|
@ -6627,8 +6627,8 @@ static int hci_le_create_conn_sync(struct hci_dev *hdev, void *data)
|
|||
* state.
|
||||
*/
|
||||
if (hci_dev_test_flag(hdev, HCI_LE_SCAN)) {
|
||||
hci_scan_disable_sync(hdev);
|
||||
hci_dev_set_flag(hdev, HCI_LE_SCAN_INTERRUPTED);
|
||||
hci_scan_disable_sync(hdev);
|
||||
}
|
||||
|
||||
/* Update random address, but set require_privacy to false so
|
||||
|
|
|
|||
|
|
@ -986,7 +986,8 @@ static void session_free(struct kref *ref)
|
|||
skb_queue_purge(&session->intr_transmit);
|
||||
fput(session->intr_sock->file);
|
||||
fput(session->ctrl_sock->file);
|
||||
l2cap_conn_put(session->conn);
|
||||
if (session->conn)
|
||||
l2cap_conn_put(session->conn);
|
||||
kfree(session);
|
||||
}
|
||||
|
||||
|
|
@ -1164,6 +1165,15 @@ static void hidp_session_remove(struct l2cap_conn *conn,
|
|||
|
||||
down_write(&hidp_session_sem);
|
||||
|
||||
/* Drop L2CAP reference immediately to indicate that
|
||||
* l2cap_unregister_user() shall not be called as it is already
|
||||
* considered removed.
|
||||
*/
|
||||
if (session->conn) {
|
||||
l2cap_conn_put(session->conn);
|
||||
session->conn = NULL;
|
||||
}
|
||||
|
||||
hidp_session_terminate(session);
|
||||
|
||||
cancel_work_sync(&session->dev_init);
|
||||
|
|
@ -1301,7 +1311,9 @@ static int hidp_session_thread(void *arg)
|
|||
* Instead, this call has the same semantics as if user-space tried to
|
||||
* delete the session.
|
||||
*/
|
||||
l2cap_unregister_user(session->conn, &session->user);
|
||||
if (session->conn)
|
||||
l2cap_unregister_user(session->conn, &session->user);
|
||||
|
||||
hidp_session_put(session);
|
||||
|
||||
module_put_and_kthread_exit(0);
|
||||
|
|
|
|||
|
|
@ -1678,17 +1678,15 @@ static void l2cap_info_timeout(struct work_struct *work)
|
|||
|
||||
int l2cap_register_user(struct l2cap_conn *conn, struct l2cap_user *user)
|
||||
{
|
||||
struct hci_dev *hdev = conn->hcon->hdev;
|
||||
int ret;
|
||||
|
||||
/* We need to check whether l2cap_conn is registered. If it is not, we
|
||||
* must not register the l2cap_user. l2cap_conn_del() is unregisters
|
||||
* l2cap_conn objects, but doesn't provide its own locking. Instead, it
|
||||
* relies on the parent hci_conn object to be locked. This itself relies
|
||||
* on the hci_dev object to be locked. So we must lock the hci device
|
||||
* here, too. */
|
||||
* must not register the l2cap_user. l2cap_conn_del() unregisters
|
||||
* l2cap_conn objects under conn->lock, and we use the same lock here
|
||||
* to protect access to conn->users and conn->hchan.
|
||||
*/
|
||||
|
||||
hci_dev_lock(hdev);
|
||||
mutex_lock(&conn->lock);
|
||||
|
||||
if (!list_empty(&user->list)) {
|
||||
ret = -EINVAL;
|
||||
|
|
@ -1709,16 +1707,14 @@ int l2cap_register_user(struct l2cap_conn *conn, struct l2cap_user *user)
|
|||
ret = 0;
|
||||
|
||||
out_unlock:
|
||||
hci_dev_unlock(hdev);
|
||||
mutex_unlock(&conn->lock);
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(l2cap_register_user);
|
||||
|
||||
void l2cap_unregister_user(struct l2cap_conn *conn, struct l2cap_user *user)
|
||||
{
|
||||
struct hci_dev *hdev = conn->hcon->hdev;
|
||||
|
||||
hci_dev_lock(hdev);
|
||||
mutex_lock(&conn->lock);
|
||||
|
||||
if (list_empty(&user->list))
|
||||
goto out_unlock;
|
||||
|
|
@ -1727,7 +1723,7 @@ void l2cap_unregister_user(struct l2cap_conn *conn, struct l2cap_user *user)
|
|||
user->remove(conn, user);
|
||||
|
||||
out_unlock:
|
||||
hci_dev_unlock(hdev);
|
||||
mutex_unlock(&conn->lock);
|
||||
}
|
||||
EXPORT_SYMBOL(l2cap_unregister_user);
|
||||
|
||||
|
|
@ -4616,7 +4612,8 @@ static inline int l2cap_information_rsp(struct l2cap_conn *conn,
|
|||
|
||||
switch (type) {
|
||||
case L2CAP_IT_FEAT_MASK:
|
||||
conn->feat_mask = get_unaligned_le32(rsp->data);
|
||||
if (cmd_len >= sizeof(*rsp) + sizeof(u32))
|
||||
conn->feat_mask = get_unaligned_le32(rsp->data);
|
||||
|
||||
if (conn->feat_mask & L2CAP_FEAT_FIXED_CHAN) {
|
||||
struct l2cap_info_req req;
|
||||
|
|
@ -4635,7 +4632,8 @@ static inline int l2cap_information_rsp(struct l2cap_conn *conn,
|
|||
break;
|
||||
|
||||
case L2CAP_IT_FIXED_CHAN:
|
||||
conn->remote_fixed_chan = rsp->data[0];
|
||||
if (cmd_len >= sizeof(*rsp) + sizeof(rsp->data[0]))
|
||||
conn->remote_fixed_chan = rsp->data[0];
|
||||
conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_DONE;
|
||||
conn->info_ident = 0;
|
||||
|
||||
|
|
@ -5059,7 +5057,7 @@ static inline int l2cap_ecred_conn_req(struct l2cap_conn *conn,
|
|||
u16 mtu, mps;
|
||||
__le16 psm;
|
||||
u8 result, rsp_len = 0;
|
||||
int i, num_scid;
|
||||
int i, num_scid = 0;
|
||||
bool defer = false;
|
||||
|
||||
if (!enable_ecred)
|
||||
|
|
@ -5072,6 +5070,14 @@ static inline int l2cap_ecred_conn_req(struct l2cap_conn *conn,
|
|||
goto response;
|
||||
}
|
||||
|
||||
/* Check if there are no pending channels with the same ident */
|
||||
__l2cap_chan_list_id(conn, cmd->ident, l2cap_ecred_list_defer,
|
||||
&num_scid);
|
||||
if (num_scid) {
|
||||
result = L2CAP_CR_LE_INVALID_PARAMS;
|
||||
goto response;
|
||||
}
|
||||
|
||||
cmd_len -= sizeof(*req);
|
||||
num_scid = cmd_len / sizeof(u16);
|
||||
|
||||
|
|
@ -5424,7 +5430,7 @@ static inline int l2cap_ecred_reconf_rsp(struct l2cap_conn *conn,
|
|||
u8 *data)
|
||||
{
|
||||
struct l2cap_chan *chan, *tmp;
|
||||
struct l2cap_ecred_conn_rsp *rsp = (void *) data;
|
||||
struct l2cap_ecred_reconf_rsp *rsp = (void *)data;
|
||||
u16 result;
|
||||
|
||||
if (cmd_len < sizeof(*rsp))
|
||||
|
|
@ -5432,7 +5438,7 @@ static inline int l2cap_ecred_reconf_rsp(struct l2cap_conn *conn,
|
|||
|
||||
result = __le16_to_cpu(rsp->result);
|
||||
|
||||
BT_DBG("result 0x%4.4x", rsp->result);
|
||||
BT_DBG("result 0x%4.4x", result);
|
||||
|
||||
if (!result)
|
||||
return 0;
|
||||
|
|
@ -6662,8 +6668,10 @@ static int l2cap_ecred_data_rcv(struct l2cap_chan *chan, struct sk_buff *skb)
|
|||
return -ENOBUFS;
|
||||
}
|
||||
|
||||
if (chan->imtu < skb->len) {
|
||||
BT_ERR("Too big LE L2CAP PDU");
|
||||
if (skb->len > chan->imtu) {
|
||||
BT_ERR("Too big LE L2CAP PDU: len %u > %u", skb->len,
|
||||
chan->imtu);
|
||||
l2cap_send_disconn_req(chan, ECONNRESET);
|
||||
return -ENOBUFS;
|
||||
}
|
||||
|
||||
|
|
@ -6689,7 +6697,9 @@ static int l2cap_ecred_data_rcv(struct l2cap_chan *chan, struct sk_buff *skb)
|
|||
sdu_len, skb->len, chan->imtu);
|
||||
|
||||
if (sdu_len > chan->imtu) {
|
||||
BT_ERR("Too big LE L2CAP SDU length received");
|
||||
BT_ERR("Too big LE L2CAP SDU length: len %u > %u",
|
||||
skb->len, sdu_len);
|
||||
l2cap_send_disconn_req(chan, ECONNRESET);
|
||||
err = -EMSGSIZE;
|
||||
goto failed;
|
||||
}
|
||||
|
|
@ -6725,6 +6735,7 @@ static int l2cap_ecred_data_rcv(struct l2cap_chan *chan, struct sk_buff *skb)
|
|||
|
||||
if (chan->sdu->len + skb->len > chan->sdu_len) {
|
||||
BT_ERR("Too much LE L2CAP data received");
|
||||
l2cap_send_disconn_req(chan, ECONNRESET);
|
||||
err = -EINVAL;
|
||||
goto failed;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2195,10 +2195,7 @@ static void set_mesh_complete(struct hci_dev *hdev, void *data, int err)
|
|||
sk = cmd->sk;
|
||||
|
||||
if (status) {
|
||||
mgmt_cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_MESH_RECEIVER,
|
||||
status);
|
||||
mgmt_pending_foreach(MGMT_OP_SET_MESH_RECEIVER, hdev, true,
|
||||
cmd_status_rsp, &status);
|
||||
mgmt_cmd_status(cmd->sk, hdev->id, cmd->opcode, status);
|
||||
goto done;
|
||||
}
|
||||
|
||||
|
|
@ -5377,7 +5374,7 @@ static void mgmt_add_adv_patterns_monitor_complete(struct hci_dev *hdev,
|
|||
|
||||
mgmt_cmd_complete(cmd->sk, cmd->hdev->id, cmd->opcode,
|
||||
mgmt_status(status), &rp, sizeof(rp));
|
||||
mgmt_pending_remove(cmd);
|
||||
mgmt_pending_free(cmd);
|
||||
|
||||
hci_dev_unlock(hdev);
|
||||
bt_dev_dbg(hdev, "add monitor %d complete, status %d",
|
||||
|
|
|
|||
|
|
@ -2743,7 +2743,7 @@ static int smp_cmd_public_key(struct l2cap_conn *conn, struct sk_buff *skb)
|
|||
if (!test_bit(SMP_FLAG_DEBUG_KEY, &smp->flags) &&
|
||||
!crypto_memneq(key, smp->local_pk, 64)) {
|
||||
bt_dev_err(hdev, "Remote and local public keys are identical");
|
||||
return SMP_UNSPECIFIED;
|
||||
return SMP_DHKEY_CHECK_FAILED;
|
||||
}
|
||||
|
||||
memcpy(smp->remote_pk, key, 64);
|
||||
|
|
|
|||
Loading…
Reference in New Issue