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:
Jakub Kicinski 2026-09-21 18:20:07 -07:00
commit f0b88fade6
12 changed files with 128 additions and 25 deletions

View File

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

View File

@ -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 ===");

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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