[PATCH] Bluetooth: btintel_pcie: Fix array bounds check bugs

From: ZhaoJinming

Date: Thu Aug 13 2026 - 06:38:32 EST


Fix four array bounds issues in the Intel BT PCIe driver:

1. btintel_pcie_send_sync(): bounds check for tfd_index uses '>' instead
of '>='. When tfd_index == txq->count (32), the check passes and
btintel_pcie_prepare_tx() writes past the end of txq->tfds[] and
txq->bufs[].

2. btintel_pcie_submit_rx(): same off-by-one on frbd_index. When
frbd_index == rxq->count (64), the check passes and
btintel_pcie_prepare_rx() writes past the end of rxq->frbds[] and
rxq->bufs[].

3. btintel_pcie_msix_tx_handle(): cr_tia (device-controlled, from
shared DMA memory) is used to index txq->urbd0s[] before any bounds
check, and the urbd0->tfd_index check uses '>' instead of '>='.

4. btintel_pcie_msix_rx_handle(): cr_tia (device-controlled) indexes
rxq->urbd1s[] with no bounds check. urbd1->frbd_tag is a 16-bit
device-controlled field (0-65535) used directly as an index into
rxq->bufs[] (64 elements).

Fix all four by correcting the comparison operators and adding explicit
bounds checks on device-controlled indices before array access.

Fixes: c2b636b3f788 ("Bluetooth: btintel_pcie: Add support for PCIe transport")
Signed-off-by: ZhaoJinming <zhaojinming@xxxxxxxxxxxxx>
---
drivers/bluetooth/btintel_pcie.c | 21 ++++++++++++++++++---
1 file changed, 18 insertions(+), 3 deletions(-)

diff --git a/drivers/bluetooth/btintel_pcie.c b/drivers/bluetooth/btintel_pcie.c
index 2b7231be5973..32cfa0f5af1c 100644
--- a/drivers/bluetooth/btintel_pcie.c
+++ b/drivers/bluetooth/btintel_pcie.c
@@ -401,7 +401,7 @@ static int btintel_pcie_send_sync(struct btintel_pcie_data *data,

tfd_index = data->ia.tr_hia[BTINTEL_PCIE_TXQ_NUM];

- if (tfd_index > txq->count)
+ if (tfd_index >= txq->count)
return -ERANGE;

/* Firmware raises alive interrupt on HCI_OP_RESET or
@@ -502,7 +502,7 @@ static int btintel_pcie_submit_rx(struct btintel_pcie_data *data)

frbd_index = data->ia.tr_hia[BTINTEL_PCIE_RXQ_NUM];

- if (frbd_index > rxq->count)
+ if (frbd_index >= rxq->count)
return -ERANGE;

/* Prepare for RX submit. It updates the FRBD with the address of DMA
@@ -1094,12 +1094,15 @@ static void btintel_pcie_msix_tx_handle(struct btintel_pcie_data *data)
txq = &data->txq;

while (cr_tia != cr_hia) {
+ if (cr_tia >= txq->count)
+ return;
+
data->tx_wait_done = true;
wake_up(&data->tx_wait_q);

urbd0 = &txq->urbd0s[cr_tia];

- if (urbd0->tfd_index > txq->count)
+ if (urbd0->tfd_index >= txq->count)
return;

cr_tia = (cr_tia + 1) % txq->count;
@@ -1584,9 +1587,21 @@ static void btintel_pcie_msix_rx_handle(struct btintel_pcie_data *data)
* process all received CDs in this interrupt.
*/
while (cr_tia != cr_hia) {
+ if (cr_tia >= rxq->count) {
+ bt_dev_err(hdev, "RXQ: invalid cr_tia %u (count %u)",
+ cr_tia, rxq->count);
+ return;
+ }
+
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 (count %u)",
+ urbd1->frbd_tag, rxq->count);
+ return;
+ }
+
buf = &rxq->bufs[urbd1->frbd_tag];
if (!buf) {
bt_dev_err(hdev, "RXQ: failed to get the DMA buffer for %d",

base-commit: 3d6d817622b0a9721e3cc404df3469171582be13
--
2.51.0