mirror of
https://github.com/torvalds/linux.git
synced 2026-10-09 12:06:03 +02:00
bluetooth pull request for net:
Core: - hci_conn: fix CIS hold ownership on reuse - hci_sock: reject out-of-range OCF values - hci_sock: validate event length before filtering - L2CAP: validate frame length before control and FCS access - RFCOMM: fix NULL dereference of dlc->session in RFCOMM_CONNINFO - RFCOMM: Reject short EA=0 frames in rfcomm_recv_frame() - ISO: release unused CIS holds after channel attach - ISO: balance the parent hold in hci_bind_bis() - SMP: reject Security Request over BR/EDR - MGMT: fix race in read_unconf_index_list() - MGMT: Dequeue pending mesh_send_sync entries on cancel - BNEP: fix out-of-bounds reads on short RX/TX frames and control fallthrough Drivers: - btintel_pcie: validate device-supplied DMA indices - btnxpuart: Fix skb leak in nxp_process_fw_dump() -----BEGIN PGP SIGNATURE----- iQJNBAABCgA3FiEE7E6oRXp8w05ovYr/9JCA4xAyCykFAmqxN44ZHGx1aXoudm9u LmRlbnR6QGludGVsLmNvbQAKCRD0kIDjEDILKS7mD/43nt9IlCMp4fRi5eT3iV6J phP/zJTiikgOMv87kTI0Q9OXY8Xl1nhIGrTiypXQIJNJGTW/OTHtMF+N55pA7pF4 exD0US01bKUcuopztHeP1Yk08CMKAtE9VTPLi/PdAQz6KTo7wcH7yFwfsO6avIk4 T/IXi9b8iKPBMKizjgUe8Uo6wrFoByD/o2VwTSQwtZOgWppUkCvVKKx10Y8EYJRG UbDS8rpPtWN3t0fK5F4yVfkTP+9sA7uWb9bF2UoLcmov2ie33M50zf5giVofiNrX pT6RWTCPfjkPdDro66l6wV4M8prEUVok0QhlqeYOUXSZJSOTqqXBTOorioABSeHz i4QWH+KsqUFbaOJQuoF3v5jAccY8ZxKczRODK8Xt1+bY9O73lqpuWjQvoi98E/7i vNCSU/bDpRS0MjYDTgQTG9c0rv9qxKI0GBC8gDVI78/nAzUIxdJ09/wDBm17aUpt uxaBwYE1lhJwT0Lf+dwJrwVuTm5q5XotdRIsOwxZgfF25Ewk8ygUlEsQu/ioHmS+ q+9SL/mHb/wPI7j0YeVG2l7cHiHOZDEn0FW++WlgtF1Oj/HWUsz2UN/qdmpYZo1h rGX7D2DdZQo8IOEmZZn7wqLNOxjPjFVkxgQtgWd5OhE0O+7/e2H4mNeDJyWs6rJp lT1BJZnPQTFtwP41x7Hxng== =cLTc -----END PGP SIGNATURE----- Merge tag 'for-net-2026-09-21' of git://git.kernel.org/pub/scm/linux/kernel/git/bluetooth/bluetooth Luiz Augusto von Dentz says: ==================== bluetooth pull request for net: Core: - hci_conn: fix CIS hold ownership on reuse - hci_sock: reject out-of-range OCF values - hci_sock: validate event length before filtering - L2CAP: validate frame length before control and FCS access - RFCOMM: fix NULL dereference of dlc->session in RFCOMM_CONNINFO - RFCOMM: Reject short EA=0 frames in rfcomm_recv_frame() - ISO: release unused CIS holds after channel attach - ISO: balance the parent hold in hci_bind_bis() - SMP: reject Security Request over BR/EDR - MGMT: fix race in read_unconf_index_list() - MGMT: Dequeue pending mesh_send_sync entries on cancel - BNEP: fix out-of-bounds reads on short RX/TX frames and control fallthrough Drivers: - btintel_pcie: validate device-supplied DMA indices - btnxpuart: Fix skb leak in nxp_process_fw_dump() * tag 'for-net-2026-09-21' of git://git.kernel.org/pub/scm/linux/kernel/git/bluetooth/bluetooth: Bluetooth: RFCOMM: Reject short EA=0 frames in rfcomm_recv_frame() Bluetooth: RFCOMM: fix NULL dereference of dlc->session in RFCOMM_CONNINFO Bluetooth: btintel_pcie: validate device-supplied DMA indices Bluetooth: bnep: fix out-of-bounds reads on short RX/TX frames and control fallthrough Bluetooth: mgmt: fix race in read_unconf_index_list() Bluetooth: L2CAP: validate frame length before control and FCS access Bluetooth: ISO: balance the parent hold in hci_bind_bis() Bluetooth: hci_sock: validate event length before filtering Bluetooth: hci_sock: reject out-of-range OCF values Bluetooth: ISO: release unused CIS holds after channel attach Bluetooth: hci_conn: fix CIS hold ownership on reuse Bluetooth: mgmt: Dequeue pending mesh_send_sync entries on cancel Bluetooth: btnxpuart: Fix skb leak in nxp_process_fw_dump() Bluetooth: SMP: reject Security Request over BR/EDR ==================== Link: https://patch.msgid.link/20260921135807.3459373-1-luiz.dentz@gmail.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
commit
f0b88fade6
|
|
@ -1099,6 +1099,11 @@ static void btintel_pcie_msix_tx_handle(struct btintel_pcie_data *data)
|
|||
|
||||
txq = &data->txq;
|
||||
|
||||
if (cr_hia >= txq->count) {
|
||||
bt_dev_err(data->hdev, "TXQ: invalid cr_hia %u", cr_hia);
|
||||
return;
|
||||
}
|
||||
|
||||
while (cr_tia != cr_hia) {
|
||||
data->tx_wait_done = true;
|
||||
wake_up(&data->tx_wait_q);
|
||||
|
|
@ -1650,6 +1655,11 @@ static void btintel_pcie_msix_rx_handle(struct btintel_pcie_data *data)
|
|||
|
||||
rxq = &data->rxq;
|
||||
|
||||
if (cr_hia >= rxq->count) {
|
||||
bt_dev_err(hdev, "RXQ: invalid cr_hia %u", cr_hia);
|
||||
return;
|
||||
}
|
||||
|
||||
/* The firmware sends multiple CD in a single MSI-X and it needs to
|
||||
* process all received CDs in this interrupt.
|
||||
*/
|
||||
|
|
@ -1657,6 +1667,12 @@ static void btintel_pcie_msix_rx_handle(struct btintel_pcie_data *data)
|
|||
urbd1 = &rxq->urbd1s[cr_tia];
|
||||
ipc_print_urbd1(data->hdev, urbd1, cr_tia);
|
||||
|
||||
if (urbd1->frbd_tag >= rxq->count) {
|
||||
bt_dev_err(hdev, "RXQ: invalid frbd_tag %u",
|
||||
urbd1->frbd_tag);
|
||||
return;
|
||||
}
|
||||
|
||||
buf = &rxq->bufs[urbd1->frbd_tag];
|
||||
if (!buf) {
|
||||
bt_dev_err(hdev, "RXQ: failed to get the DMA buffer for %d",
|
||||
|
|
|
|||
|
|
@ -1388,9 +1388,11 @@ static int nxp_process_fw_dump(struct hci_dev *hdev, struct sk_buff *skb)
|
|||
msecs_to_jiffies(20000));
|
||||
}
|
||||
|
||||
err = hci_devcd_append(hdev, skb_clone(skb, GFP_ATOMIC));
|
||||
if (err < 0)
|
||||
goto free_skb;
|
||||
if (IS_ENABLED(CONFIG_DEV_COREDUMP)) {
|
||||
err = hci_devcd_append(hdev, skb_clone(skb, GFP_ATOMIC));
|
||||
if (err < 0)
|
||||
goto free_skb;
|
||||
}
|
||||
|
||||
if (buf_len == 0) {
|
||||
bt_dev_warn(hdev, "==== FW dump complete ===");
|
||||
|
|
|
|||
|
|
@ -270,9 +270,14 @@ static int bnep_rx_extension(struct bnep_session *s, struct sk_buff *skb)
|
|||
|
||||
BT_DBG("type 0x%x len %u", h->type, h->len);
|
||||
|
||||
if (skb->len < h->len) {
|
||||
err = -EILSEQ;
|
||||
break;
|
||||
}
|
||||
|
||||
switch (h->type & BNEP_TYPE_MASK) {
|
||||
case BNEP_EXT_CONTROL:
|
||||
bnep_rx_control(s, skb->data, skb->len);
|
||||
bnep_rx_control(s, skb->data, h->len);
|
||||
break;
|
||||
|
||||
default:
|
||||
|
|
@ -373,6 +378,11 @@ static int bnep_rx_frame(struct bnep_session *s, struct sk_buff *skb)
|
|||
goto badframe;
|
||||
}
|
||||
|
||||
if ((type & BNEP_TYPE_MASK) == BNEP_CONTROL) {
|
||||
kfree_skb(skb);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Strip 802.1p header */
|
||||
if (ntohs(s->eh.h_proto) == ETH_P_8021Q) {
|
||||
if (!skb_pull(skb, 4))
|
||||
|
|
@ -451,6 +461,11 @@ static int bnep_tx_frame(struct bnep_session *s, struct sk_buff *skb)
|
|||
goto send;
|
||||
}
|
||||
|
||||
if (skb->len < ETH_HLEN) {
|
||||
kfree_skb(skb);
|
||||
return 0;
|
||||
}
|
||||
|
||||
iv[il++] = (struct kvec) { &type, 1 };
|
||||
len++;
|
||||
|
||||
|
|
|
|||
|
|
@ -166,6 +166,12 @@ static netdev_tx_t bnep_net_xmit(struct sk_buff *skb,
|
|||
|
||||
BT_DBG("skb %p, dev %p", skb, dev);
|
||||
|
||||
if (!pskb_may_pull(skb, ETH_HLEN)) {
|
||||
dev->stats.tx_dropped++;
|
||||
kfree_skb(skb);
|
||||
return NETDEV_TX_OK;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_BT_BNEP_MC_FILTER
|
||||
if (bnep_net_mc_filter(skb, s)) {
|
||||
kfree_skb(skb);
|
||||
|
|
@ -218,7 +224,7 @@ void bnep_net_setup(struct net_device *dev)
|
|||
dev->addr_len = ETH_ALEN;
|
||||
|
||||
ether_setup(dev);
|
||||
dev->min_mtu = 0;
|
||||
dev->min_mtu = ETH_MIN_MTU;
|
||||
dev->max_mtu = ETH_MAX_MTU;
|
||||
dev->priv_flags &= ~IFF_TX_SKB_SHARING;
|
||||
dev->netdev_ops = &bnep_netdev_ops;
|
||||
|
|
|
|||
|
|
@ -2079,6 +2079,8 @@ struct hci_conn *hci_bind_cis(struct hci_dev *hdev, bdaddr_t *dst,
|
|||
cis->conn_timeout = timeout;
|
||||
}
|
||||
|
||||
hci_conn_hold(cis);
|
||||
|
||||
if (cis->state == BT_CONNECTED)
|
||||
return cis;
|
||||
|
||||
|
|
@ -2120,7 +2122,6 @@ struct hci_conn *hci_bind_cis(struct hci_dev *hdev, bdaddr_t *dst,
|
|||
return ERR_PTR(-EINVAL);
|
||||
}
|
||||
|
||||
hci_conn_hold(cis);
|
||||
cis->state = BT_BOUND;
|
||||
|
||||
return cis;
|
||||
|
|
@ -2374,10 +2375,13 @@ struct hci_conn *hci_bind_bis(struct hci_dev *hdev, bdaddr_t *dst, __u8 sid,
|
|||
parent = hci_conn_hash_lookup_big(hdev,
|
||||
conn->iso_qos.bcast.big);
|
||||
if (parent && parent != conn) {
|
||||
hci_conn_hold(parent);
|
||||
link = hci_conn_link(parent, conn);
|
||||
hci_conn_drop(conn);
|
||||
if (!link)
|
||||
if (!link) {
|
||||
hci_conn_drop(parent);
|
||||
return ERR_PTR(-ENOLINK);
|
||||
}
|
||||
}
|
||||
|
||||
return conn;
|
||||
|
|
@ -2497,6 +2501,12 @@ struct hci_conn *hci_connect_cis(struct hci_dev *hdev, bdaddr_t *dst,
|
|||
return cis;
|
||||
}
|
||||
|
||||
/* The existing link already owns the hold on its parent. */
|
||||
if (cis->link) {
|
||||
hci_conn_drop(le);
|
||||
return cis;
|
||||
}
|
||||
|
||||
link = hci_conn_link(le, cis);
|
||||
hci_conn_drop(cis);
|
||||
if (!link) {
|
||||
|
|
|
|||
|
|
@ -164,6 +164,7 @@ static bool is_filtered_packet(struct sock *sk, struct sk_buff *skb)
|
|||
{
|
||||
struct hci_filter *flt;
|
||||
int flt_type, flt_event;
|
||||
u8 event;
|
||||
|
||||
/* Apply filter */
|
||||
flt = &hci_pi(sk)->filter;
|
||||
|
|
@ -177,7 +178,11 @@ static bool is_filtered_packet(struct sock *sk, struct sk_buff *skb)
|
|||
if (hci_skb_pkt_type(skb) != HCI_EVENT_PKT)
|
||||
return false;
|
||||
|
||||
flt_event = (*(__u8 *)skb->data & HCI_FLT_EVENT_BITS);
|
||||
if (skb->len < 1)
|
||||
return true;
|
||||
|
||||
event = *(__u8 *)skb->data;
|
||||
flt_event = event & HCI_FLT_EVENT_BITS;
|
||||
|
||||
if (!hci_test_bit(flt_event, &flt->event_mask))
|
||||
return true;
|
||||
|
|
@ -186,11 +191,17 @@ static bool is_filtered_packet(struct sock *sk, struct sk_buff *skb)
|
|||
if (!flt->opcode)
|
||||
return false;
|
||||
|
||||
if (flt_event == HCI_EV_CMD_COMPLETE &&
|
||||
if (event == HCI_EV_CMD_COMPLETE && skb->len < 5)
|
||||
return true;
|
||||
|
||||
if (event == HCI_EV_CMD_COMPLETE &&
|
||||
flt->opcode != get_unaligned((__le16 *)(skb->data + 3)))
|
||||
return true;
|
||||
|
||||
if (flt_event == HCI_EV_CMD_STATUS &&
|
||||
if (event == HCI_EV_CMD_STATUS && skb->len < 6)
|
||||
return true;
|
||||
|
||||
if (event == HCI_EV_CMD_STATUS &&
|
||||
flt->opcode != get_unaligned((__le16 *)(skb->data + 4)))
|
||||
return true;
|
||||
|
||||
|
|
@ -1881,7 +1892,8 @@ static int hci_sock_sendmsg(struct socket *sock, struct msghdr *msg,
|
|||
u16 ocf = hci_opcode_ocf(opcode);
|
||||
|
||||
if (((ogf > HCI_SFLT_MAX_OGF) ||
|
||||
!hci_test_bit(ocf & HCI_FLT_OCF_BITS,
|
||||
(ocf > HCI_FLT_OCF_BITS) ||
|
||||
!hci_test_bit(ocf,
|
||||
&hci_sec_filter.ocf_mask[ogf])) &&
|
||||
!capable(CAP_NET_RAW)) {
|
||||
err = -EPERM;
|
||||
|
|
|
|||
|
|
@ -496,6 +496,7 @@ static int iso_connect_cis(struct sock *sk)
|
|||
struct hci_dev *hdev;
|
||||
bdaddr_t src, dst;
|
||||
u8 src_type;
|
||||
bool already_attached;
|
||||
int err;
|
||||
|
||||
lock_sock(sk);
|
||||
|
|
@ -568,8 +569,14 @@ static int iso_connect_cis(struct sock *sk)
|
|||
goto unlock;
|
||||
}
|
||||
|
||||
iso_conn_lock(conn);
|
||||
already_attached = iso_pi(sk)->conn == conn && conn->sk == sk;
|
||||
iso_conn_unlock(conn);
|
||||
|
||||
err = iso_chan_add(conn, sk, NULL);
|
||||
iso_conn_put(conn);
|
||||
if (already_attached || err == -EBUSY)
|
||||
hci_conn_drop(hcon);
|
||||
if (err)
|
||||
goto unlock;
|
||||
|
||||
|
|
|
|||
|
|
@ -6702,9 +6702,17 @@ static int l2cap_stream_rx(struct l2cap_chan *chan, struct l2cap_ctrl *control,
|
|||
static int l2cap_data_rcv(struct l2cap_chan *chan, struct sk_buff *skb)
|
||||
{
|
||||
struct l2cap_ctrl *control = &bt_cb(skb)->l2cap;
|
||||
u16 len;
|
||||
u16 len, min_len;
|
||||
u8 event;
|
||||
|
||||
min_len = test_bit(FLAG_EXT_CTRL, &chan->flags) ?
|
||||
L2CAP_EXT_CTRL_SIZE : L2CAP_ENH_CTRL_SIZE;
|
||||
if (chan->fcs == L2CAP_FCS_CRC16)
|
||||
min_len += L2CAP_FCS_SIZE;
|
||||
|
||||
if (skb->len < min_len)
|
||||
goto drop;
|
||||
|
||||
__unpack_control(chan, skb);
|
||||
|
||||
len = skb->len;
|
||||
|
|
|
|||
|
|
@ -496,13 +496,9 @@ static int read_unconf_index_list(struct sock *sk, struct hci_dev *hdev,
|
|||
|
||||
read_lock(&hci_dev_list_lock);
|
||||
|
||||
count = 0;
|
||||
list_for_each_entry(d, &hci_dev_list, list) {
|
||||
if (hci_dev_test_flag(d, HCI_UNCONFIGURED))
|
||||
count++;
|
||||
}
|
||||
count = list_count_nodes(&hci_dev_list);
|
||||
|
||||
rp_len = sizeof(*rp) + (2 * count);
|
||||
rp_len = sizeof(*rp) + (sizeof(__le16) * count);
|
||||
rp = kmalloc(rp_len, GFP_ATOMIC);
|
||||
if (!rp) {
|
||||
read_unlock(&hci_dev_list_lock);
|
||||
|
|
@ -2316,6 +2312,8 @@ static void mesh_send_start_complete(struct hci_dev *hdev, void *data, int err)
|
|||
hci_dev_clear_flag(hdev, HCI_MESH_SENDING);
|
||||
/* Send Complete Error Code for handle */
|
||||
mesh_send_complete(hdev, mesh_tx, false);
|
||||
if (err != -ECANCELED)
|
||||
mesh_next(hdev, NULL, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -2425,19 +2423,28 @@ static int send_cancel(struct hci_dev *hdev, void *data)
|
|||
do {
|
||||
mesh_tx = mgmt_mesh_next(hdev, cmd->sk);
|
||||
|
||||
if (mesh_tx)
|
||||
mesh_send_complete(hdev, mesh_tx, false);
|
||||
if (mesh_tx) {
|
||||
if (!hci_cmd_sync_dequeue(hdev, mesh_send_sync,
|
||||
mesh_tx, NULL))
|
||||
mesh_send_complete(hdev, mesh_tx, false);
|
||||
}
|
||||
} while (mesh_tx);
|
||||
} else {
|
||||
mesh_tx = mgmt_mesh_find(hdev, cancel->handle);
|
||||
|
||||
if (mesh_tx && mesh_tx->sk == cmd->sk)
|
||||
mesh_send_complete(hdev, mesh_tx, false);
|
||||
if (mesh_tx && mesh_tx->sk == cmd->sk) {
|
||||
if (!hci_cmd_sync_dequeue(hdev, mesh_send_sync,
|
||||
mesh_tx, NULL))
|
||||
mesh_send_complete(hdev, mesh_tx, false);
|
||||
}
|
||||
}
|
||||
|
||||
mgmt_cmd_complete(cmd->sk, hdev->id, MGMT_OP_MESH_SEND_CANCEL,
|
||||
0, NULL, 0);
|
||||
|
||||
if (!hci_dev_test_flag(hdev, HCI_MESH_SENDING))
|
||||
mesh_next(hdev, NULL, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1817,7 +1817,8 @@ static struct rfcomm_session *rfcomm_recv_frame(struct rfcomm_session *s,
|
|||
return s;
|
||||
}
|
||||
|
||||
if (skb->len < sizeof(*hdr) + 1) {
|
||||
if (skb->len < sizeof(*hdr) + 1 ||
|
||||
(!__test_ea(hdr->len) && skb->len < sizeof(*hdr) + 2)) {
|
||||
kfree_skb(skb);
|
||||
return s;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -786,8 +786,10 @@ static int rfcomm_sock_getsockopt_old(struct socket *sock, int optname,
|
|||
break;
|
||||
|
||||
case RFCOMM_CONNINFO:
|
||||
if (sk->sk_state != BT_CONNECTED &&
|
||||
!rfcomm_pi(sk)->dlc->defer_setup) {
|
||||
if ((sk->sk_state != BT_CONNECTED &&
|
||||
!(sk->sk_state == BT_CONNECT2 &&
|
||||
rfcomm_pi(sk)->dlc->defer_setup)) ||
|
||||
!rfcomm_pi(sk)->dlc->session) {
|
||||
err = -ENOTCONN;
|
||||
break;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2269,6 +2269,23 @@ static u8 smp_cmd_security_req(struct l2cap_conn *conn, struct sk_buff *skb)
|
|||
|
||||
bt_dev_dbg(hdev, "conn %p", conn);
|
||||
|
||||
/* SMP over BR/EDR only covers cross-transport key derivation; the
|
||||
* Security Request procedure has no BR/EDR counterpart. Reject it
|
||||
* here, otherwise smp_ltk_encrypt() finds the peer's LE LTK
|
||||
* (ADDR_LE_DEV_PUBLIC and BDADDR_BREDR are both 0) and issues
|
||||
* HCI_OP_LE_START_ENC on the ACL handle, which the controller
|
||||
* rejects and hci_cs_le_start_enc() turns into a disconnect. Reply
|
||||
* without smp_failure(): this is not an authentication failure, and
|
||||
* MGMT_EV_AUTH_FAILED would make bluetoothd drop the device.
|
||||
*/
|
||||
if (hcon->type != LE_LINK) {
|
||||
u8 reason = SMP_CMD_NOTSUPP;
|
||||
|
||||
smp_send_cmd(conn, SMP_CMD_PAIRING_FAIL, sizeof(reason),
|
||||
&reason);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (skb->len < sizeof(*rp))
|
||||
return SMP_INVALID_PARAMS;
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user