* [PATCH v1] Bluetooth: btintel_pcie: cap device debug regions at 1 MB
@ 2026-09-08 13:34 Kiran K
2026-09-08 15:56 ` [v1] " bluez.test.bot
2026-09-08 16:30 ` [PATCH v1] " patchwork-bot+bluetooth
0 siblings, 2 replies; 3+ messages in thread
From: Kiran K @ 2026-09-08 13:34 UTC (permalink / raw)
To: linux-bluetooth
Cc: ravishankar.srivatsa, chethan.tumkur.narayan,
chandrashekar.devegowda, Kiran K
Validate device-supplied debug-region boundaries during mailbox TLV
parsing and convert start/end values to a validated region size. Cap
debug-region sizes to 1 MB to prevent out-of-bounds reads if firmware
reports oversized memory ranges. Skip invalid or oversized regions
prior to coredump capture.
This issue was reported by Claude Mythos.
Fixes: 755cf7adf8dd ("Bluetooth: btintel_pcie: unified decoder coredump format")
Assisted-by: Copilot:claude-opus-4.7
Signed-off-by: Kiran K <kiran.k@intel.com>
---
drivers/bluetooth/btintel_pcie.c | 229 ++++++++++++++++---------------
drivers/bluetooth/btintel_pcie.h | 16 +--
2 files changed, 128 insertions(+), 117 deletions(-)
diff --git a/drivers/bluetooth/btintel_pcie.c b/drivers/bluetooth/btintel_pcie.c
index 04f5b0273977..652777d1026f 100644
--- a/drivers/bluetooth/btintel_pcie.c
+++ b/drivers/bluetooth/btintel_pcie.c
@@ -960,13 +960,6 @@ static int btintel_pcie_dump_target_region(struct btintel_pcie_data *data,
return 1;
}
- if (size > BTINTEL_PCIE_REGION_MAX_SIZE) {
- bt_dev_warn(data->hdev,
- "Skipping dump region %s: size %u exceeds max %u",
- name, size, BTINTEL_PCIE_REGION_MAX_SIZE);
- return 1;
- }
-
if (addr_start > U32_MAX - size) {
bt_dev_warn(data->hdev,
"Skipping dump region %s: addr_start 0x%08x + size %u would overflow",
@@ -1196,28 +1189,10 @@ static bool btintel_pcie_is_mdbgc_supported(struct btintel_pcie_data *data)
static void btintel_pcie_dump_mem_range(struct btintel_pcie_data *data,
struct list_head *list, u32 region_id,
const char *name, u32 addr_start,
- u32 addr_end, u64 *regions_mask)
+ u32 region_size, u64 *regions_mask)
{
- u32 region_size;
-
- if (!addr_start || !addr_end || addr_end < addr_start)
- return;
-
- if (addr_end > U32_MAX - 0x04) {
- bt_dev_warn(data->hdev,
- "Skipping dump region %s: addr_end 0x%08x would overflow",
- name, addr_end);
- return;
- }
-
- region_size = (addr_end + 0x04) - addr_start;
- if (region_size > BTINTEL_PCIE_REGION_MAX_SIZE) {
- bt_dev_warn(data->hdev,
- "Skipping dump region %s: size %u exceeds max %u",
- name, region_size,
- BTINTEL_PCIE_REGION_MAX_SIZE);
+ if (!region_size)
return;
- }
if (!btintel_pcie_dump_target_region(data, list, region_id, name,
addr_start, region_size))
@@ -1228,16 +1203,14 @@ static int btintel_pcie_read_debug_regions(struct btintel_pcie_data *data)
{
struct btintel_pcie_dbgc *dbgc = NULL;
struct btintel_pcie_mdbgc *mdbgc = NULL;
+ struct btintel_pcie_dump_mem_info *dump_info = &data->dump_info;
struct hci_dev *hdev = data->hdev;
struct btintel_pcie_dump_entry *entry;
struct btintel_pcie_dump_file_hdr *file_hdr;
struct scatterlist *sg_dump_data;
u32 status_reg, wrap_reg;
- u32 exception_dump_len;
- u32 exc_addr;
u64 regions_mask = 0;
u8 hw_variant;
- u32 smem_rd_addr = 0, smem_rd_size = 0;
u32 file_len;
u8 count;
int ret;
@@ -1270,35 +1243,6 @@ static int btintel_pcie_read_debug_regions(struct btintel_pcie_data *data)
return -EINVAL;
}
- smem_rd_addr = data->dump_info.smem_addr_start;
- smem_rd_size = 0;
-
- if (!smem_rd_addr && !data->dump_info.smem_addr_end) {
- bt_dev_dbg(hdev, "smem region not advertised by firmware");
- } else if (data->dump_info.smem_addr_end < smem_rd_addr ||
- data->dump_info.smem_addr_end > U32_MAX - 0x04) {
- bt_dev_err(hdev,
- "Invalid smem region: start=0x%08x end=0x%08x",
- smem_rd_addr, data->dump_info.smem_addr_end);
- } else {
- smem_rd_size = (data->dump_info.smem_addr_end + 0x04) -
- smem_rd_addr;
-
- bt_dev_dbg(hdev,
- "smem_region: smem_start_addr=0x%08x smem_end_addr=0x%08x smem_rd_size=%u",
- smem_rd_addr, data->dump_info.smem_addr_end,
- smem_rd_size);
-
- if (smem_rd_size == 0 ||
- smem_rd_size > BTINTEL_PCIE_SMEM_MAX_SIZE) {
- bt_dev_err(hdev,
- "Invalid smem region: smem_rd_addr 0x%08x size %u (max %u)",
- smem_rd_addr, smem_rd_size,
- BTINTEL_PCIE_SMEM_MAX_SIZE);
- smem_rd_size = 0;
- }
- }
-
if (btintel_pcie_is_mdbgc_supported(data)) {
ret = btintel_pcie_dump_dram_monitor(data, &dump_list, count,
mdbgc->buf1, status_reg,
@@ -1350,47 +1294,46 @@ static int btintel_pcie_read_debug_regions(struct btintel_pcie_data *data)
"Failed to dump DRAM region: %d", ret);
}
- if (smem_rd_size &&
+ if (dump_info->smem_size &&
!btintel_pcie_dump_smem_monitor_region(data, &dump_list,
BTINTEL_PCIE_INI_ID_SMEM,
"monitor_smem",
- smem_rd_addr,
- smem_rd_size))
+ dump_info->smem_addr_start,
+ dump_info->smem_size))
regions_mask |= BIT_ULL(BTINTEL_PCIE_INI_ID_SMEM);
- exc_addr = data->dump_info.exception_dump_addr;
- exception_dump_len = data->dump_info.exception_dump_len;
- if (exc_addr && exception_dump_len) {
+ if (dump_info->exception_dump_addr && dump_info->exception_dump_len) {
ret = btintel_pcie_dump_target_region(data, &dump_list,
BTINTEL_PCIE_INI_ID_EXCEPTION_EVT,
- "EXCEPTION_EVT_BUFFER", exc_addr,
- exception_dump_len);
+ "EXCEPTION_EVT_BUFFER",
+ dump_info->exception_dump_addr,
+ dump_info->exception_dump_len);
if (!ret)
regions_mask |= BIT_ULL(BTINTEL_PCIE_INI_ID_EXCEPTION_EVT);
}
btintel_pcie_dump_mem_range(data, &dump_list,
BTINTEL_PCIE_INI_ID_DCCM, "DCCM",
- data->dump_info.dccm_addr_start,
- data->dump_info.dccm_addr_end,
+ dump_info->dccm_addr_start,
+ dump_info->dccm_size,
®ions_mask);
btintel_pcie_dump_mem_range(data, &dump_list,
BTINTEL_PCIE_INI_ID_SDS, "SDS",
- data->dump_info.sds_start_addr_start,
- data->dump_info.sds_start_addr_end,
+ dump_info->sds_start_addr_start,
+ dump_info->sds_start_size,
®ions_mask);
btintel_pcie_dump_mem_range(data, &dump_list,
BTINTEL_PCIE_INI_ID_SDS_IOSF, "SDS_IOSF",
- data->dump_info.sds_iosf_data_addr_start,
- data->dump_info.sds_iosf_data_addr_end,
+ dump_info->sds_iosf_data_addr_start,
+ dump_info->sds_iosf_data_size,
®ions_mask);
btintel_pcie_dump_mem_range(data, &dump_list,
BTINTEL_PCIE_INI_ID_ECL, "ECL_REGION",
- data->dump_info.ecl_addr_start,
- data->dump_info.ecl_addr_end,
+ dump_info->ecl_addr_start,
+ dump_info->ecl_size,
®ions_mask);
ret = btintel_pcie_dump_info(data, &dump_list, regions_mask);
@@ -1593,6 +1536,34 @@ static inline bool btintel_pcie_in_error(struct btintel_pcie_data *data)
return data->boot_stage_cache & BTINTEL_PCIE_CSR_BOOT_STAGE_ABORT_HANDLER;
}
+static u32 btintel_pcie_region_size(struct hci_dev *hdev, const char *name,
+ u32 start, u32 end)
+{
+ u64 size;
+
+ if (!start || !end)
+ return 0;
+
+ if (end < start) {
+ bt_dev_warn(hdev, "%s region invalid: start=0x%08x end=0x%08x",
+ name, start, end);
+ return 0;
+ }
+
+ size = (u64)end + 0x04 - start;
+ if (size % sizeof(u32))
+ bt_dev_warn(hdev, "%s region size %llu is not 4-byte aligned",
+ name, size);
+
+ if (size > BTINTEL_PCIE_REGION_MAX_SIZE) {
+ bt_dev_warn(hdev, "%s region size %llu exceeds cap %u, ignoring",
+ name, size, BTINTEL_PCIE_REGION_MAX_SIZE);
+ return 0;
+ }
+
+ return (u32)size;
+}
+
static const char *btintel_pcie_tlv_str(u8 tlv_type)
{
switch (tlv_type) {
@@ -1720,6 +1691,15 @@ static int btintel_parse_mbox_tlv(struct btintel_pcie_data *data)
get_unaligned_le32(&tlv->val[0]);
data->dump_info.exception_dump_len =
get_unaligned_le32(&tlv->val[4]);
+ if (data->dump_info.exception_dump_len >
+ BTINTEL_PCIE_REGION_MAX_SIZE) {
+ bt_dev_warn(data->hdev,
+ "EXCEPTION_EVT_BUFFER size %u exceeds cap %u, ignoring",
+ data->dump_info.exception_dump_len,
+ BTINTEL_PCIE_REGION_MAX_SIZE);
+ data->dump_info.exception_dump_addr = 0;
+ data->dump_info.exception_dump_len = 0;
+ }
break;
case BTINTEL_PCIE_TLV_TYPE_DCCM_MEM_ADDRESS:
if (tlv_len < 8) {
@@ -1731,10 +1711,16 @@ static int btintel_parse_mbox_tlv(struct btintel_pcie_data *data)
}
data->dump_info.dccm_addr_start =
get_unaligned_le32(&tlv->val[0]);
- data->dump_info.dccm_addr_end =
- get_unaligned_le32(&tlv->val[4]);
+ data->dump_info.dccm_size =
+ btintel_pcie_region_size(data->hdev, "DCCM",
+ data->dump_info.dccm_addr_start,
+ get_unaligned_le32(&tlv->val[4]));
+ if (!data->dump_info.dccm_size)
+ data->dump_info.dccm_addr_start = 0;
break;
- case BTINTEL_PCIE_TLV_TYPE_SDS_MEM_ADDRESS:
+ case BTINTEL_PCIE_TLV_TYPE_SDS_MEM_ADDRESS: {
+ struct btintel_pcie_dump_mem_info *di = &data->dump_info;
+
/* hw_variant comes from cnvi_bt which is set during
* setup. If mailbox fires before setup completes,
* hw_variant is 0. Skip SDS parsing in that case.
@@ -1744,35 +1730,52 @@ static int btintel_parse_mbox_tlv(struct btintel_pcie_data *data)
break;
}
if (tlv_len == 16 && hw_variant > BTINTEL_HWID_BZRI) {
- data->dump_info.sds_start_addr_start =
+ di->sds_start_addr_start =
get_unaligned_le32(&tlv->val[0]);
- data->dump_info.sds_start_addr_end =
- get_unaligned_le32(&tlv->val[4]);
- data->dump_info.sds_iosf_data_addr_start =
+ di->sds_start_size =
+ btintel_pcie_region_size(data->hdev, "SDS",
+ di->sds_start_addr_start,
+ get_unaligned_le32(&tlv->val[4]));
+ di->sds_iosf_data_addr_start =
get_unaligned_le32(&tlv->val[8]);
- data->dump_info.sds_iosf_data_addr_end =
- get_unaligned_le32(&tlv->val[12]);
+ di->sds_iosf_data_size =
+ btintel_pcie_region_size(data->hdev, "SDS_IOSF",
+ di->sds_iosf_data_addr_start,
+ get_unaligned_le32(&tlv->val[12]));
} else if (tlv_len == 24 &&
(hw_variant == BTINTEL_HWID_BZRI ||
hw_variant == BTINTEL_HWID_BZRIW)) {
- data->dump_info.sds_fixed_rom_addr_start =
+ di->sds_fixed_rom_addr_start =
get_unaligned_le32(&tlv->val[0]);
- data->dump_info.sds_fixed_rom_addr_end =
- get_unaligned_le32(&tlv->val[4]);
- data->dump_info.sds_start_addr_start =
+ di->sds_fixed_rom_size =
+ btintel_pcie_region_size(data->hdev, "SDS_FIXED_ROM",
+ di->sds_fixed_rom_addr_start,
+ get_unaligned_le32(&tlv->val[4]));
+ di->sds_start_addr_start =
get_unaligned_le32(&tlv->val[8]);
- data->dump_info.sds_start_addr_end =
- get_unaligned_le32(&tlv->val[12]);
- data->dump_info.sds_iosf_data_addr_start =
+ di->sds_start_size =
+ btintel_pcie_region_size(data->hdev, "SDS",
+ di->sds_start_addr_start,
+ get_unaligned_le32(&tlv->val[12]));
+ di->sds_iosf_data_addr_start =
get_unaligned_le32(&tlv->val[16]);
- data->dump_info.sds_iosf_data_addr_end =
- get_unaligned_le32(&tlv->val[20]);
+ di->sds_iosf_data_size =
+ btintel_pcie_region_size(data->hdev, "SDS_IOSF",
+ di->sds_iosf_data_addr_start,
+ get_unaligned_le32(&tlv->val[20]));
} else {
bt_dev_err(data->hdev,
"SDS TLV: hw=0x%2.2x len=%u",
hw_variant, tlv_len);
}
+ if (!di->sds_start_size)
+ di->sds_start_addr_start = 0;
+ if (!di->sds_iosf_data_size)
+ di->sds_iosf_data_addr_start = 0;
+ if (!di->sds_fixed_rom_size)
+ di->sds_fixed_rom_addr_start = 0;
break;
+ }
case BTINTEL_PCIE_TLV_TYPE_ECL_MEM_ADDRESS:
if (tlv_len < 8) {
bt_dev_err(data->hdev,
@@ -1783,8 +1786,12 @@ static int btintel_parse_mbox_tlv(struct btintel_pcie_data *data)
}
data->dump_info.ecl_addr_start =
get_unaligned_le32(&tlv->val[0]);
- data->dump_info.ecl_addr_end =
- get_unaligned_le32(&tlv->val[4]);
+ data->dump_info.ecl_size =
+ btintel_pcie_region_size(data->hdev, "ECL",
+ data->dump_info.ecl_addr_start,
+ get_unaligned_le32(&tlv->val[4]));
+ if (!data->dump_info.ecl_size)
+ data->dump_info.ecl_addr_start = 0;
break;
case BTINTEL_PCIE_TLV_TYPE_SMEM_ADDRESS:
if (tlv_len < 8) {
@@ -1796,8 +1803,12 @@ static int btintel_parse_mbox_tlv(struct btintel_pcie_data *data)
}
data->dump_info.smem_addr_start =
get_unaligned_le32(&tlv->val[0]);
- data->dump_info.smem_addr_end =
- get_unaligned_le32(&tlv->val[4]);
+ data->dump_info.smem_size =
+ btintel_pcie_region_size(data->hdev, "SMEM",
+ data->dump_info.smem_addr_start,
+ get_unaligned_le32(&tlv->val[4]));
+ if (!data->dump_info.smem_size)
+ data->dump_info.smem_addr_start = 0;
break;
default:
bt_dev_dbg(data->hdev, "Unknown TLV type: %u length: %u",
@@ -1815,29 +1826,29 @@ static int btintel_parse_mbox_tlv(struct btintel_pcie_data *data)
data->dump_info.exception_dump_addr,
data->dump_info.exception_dump_len);
bt_dev_info(data->hdev,
- "dccm: start:0x%08x end:0x%08x",
+ "dccm: start:0x%8.8x size:%u",
data->dump_info.dccm_addr_start,
- data->dump_info.dccm_addr_end);
+ data->dump_info.dccm_size);
bt_dev_info(data->hdev,
- "sds_fixed_rom: start:0x%08x end:0x%08x",
+ "sds_fixed_rom: start:0x%8.8x size:%u",
data->dump_info.sds_fixed_rom_addr_start,
- data->dump_info.sds_fixed_rom_addr_end);
+ data->dump_info.sds_fixed_rom_size);
bt_dev_info(data->hdev,
- "sds: start:0x%08x end:0x%08x",
+ "sds: start:0x%8.8x size:%u",
data->dump_info.sds_start_addr_start,
- data->dump_info.sds_start_addr_end);
+ data->dump_info.sds_start_size);
bt_dev_info(data->hdev,
- "sds_iosf: start:0x%08x end:0x%08x",
+ "sds_iosf: start:0x%8.8x size:%u",
data->dump_info.sds_iosf_data_addr_start,
- data->dump_info.sds_iosf_data_addr_end);
+ data->dump_info.sds_iosf_data_size);
bt_dev_info(data->hdev,
- "ecl: start:0x%08x end:0x%08x",
+ "ecl: start:0x%8.8x size:%u",
data->dump_info.ecl_addr_start,
- data->dump_info.ecl_addr_end);
+ data->dump_info.ecl_size);
bt_dev_info(data->hdev,
- "smem: start:0x%08x end:0x%08x",
+ "smem: start:0x%8.8x size:%u",
data->dump_info.smem_addr_start,
- data->dump_info.smem_addr_end);
+ data->dump_info.smem_size);
vfree(buffer);
return 0;
diff --git a/drivers/bluetooth/btintel_pcie.h b/drivers/bluetooth/btintel_pcie.h
index 9d84db48a8e5..f35f80f800ed 100644
--- a/drivers/bluetooth/btintel_pcie.h
+++ b/drivers/bluetooth/btintel_pcie.h
@@ -76,8 +76,8 @@
#define BTINTEL_PCIE_DBGC_DBGBUFF_WRAP_ARND_SCP (BTINTEL_PCIE_DBGC_BASE_ADDR_SCP + 0x2C)
#define BTINTEL_PCIE_DBGC_ALLOCATION_OFFSET 0x100
-#define BTINTEL_PCIE_SMEM_MAX_SIZE (16 * 1024)
-#define BTINTEL_PCIE_REGION_MAX_SIZE (16 * 1024 * 1024)
+/* Upper bound for device-supplied debug-region sizes. */
+#define BTINTEL_PCIE_REGION_MAX_SIZE (1 * 1024 * 1024)
#define BTINTEL_PCIE_DBG_IDX_BIT_MASK 0x0F
#define BTINTEL_PCIE_DBGC_DBG_BUF_IDX(data) (((data) >> 24) & BTINTEL_PCIE_DBG_IDX_BIT_MASK)
#define BTINTEL_PCIE_DBG_OFFSET_BIT_MASK 0xFFFFFF
@@ -497,17 +497,17 @@ struct btintel_pcie_dump_mem_info {
u32 exception_dump_addr;
u32 exception_dump_len;
u32 dccm_addr_start;
- u32 dccm_addr_end;
+ u32 dccm_size;
u32 sds_fixed_rom_addr_start;
- u32 sds_fixed_rom_addr_end;
+ u32 sds_fixed_rom_size;
u32 sds_start_addr_start;
- u32 sds_start_addr_end;
+ u32 sds_start_size;
u32 sds_iosf_data_addr_start;
- u32 sds_iosf_data_addr_end;
+ u32 sds_iosf_data_size;
u32 ecl_addr_start;
- u32 ecl_addr_end;
+ u32 ecl_size;
u32 smem_addr_start;
- u32 smem_addr_end;
+ u32 smem_size;
};
struct btintel_pcie_mbox {
--
2.54.0
^ permalink raw reply related [flat|nested] 3+ messages in thread* RE: [v1] Bluetooth: btintel_pcie: cap device debug regions at 1 MB
2026-09-08 13:34 [PATCH v1] Bluetooth: btintel_pcie: cap device debug regions at 1 MB Kiran K
@ 2026-09-08 15:56 ` bluez.test.bot
2026-09-08 16:30 ` [PATCH v1] " patchwork-bot+bluetooth
1 sibling, 0 replies; 3+ messages in thread
From: bluez.test.bot @ 2026-09-08 15:56 UTC (permalink / raw)
To: linux-bluetooth, kiran.k
[-- Attachment #1: Type: text/plain, Size: 1158 bytes --]
This is automated email and please do not reply to this email!
Dear submitter,
Thank you for submitting the patches to the linux bluetooth mailing list.
This is a CI test results with your patch series:
PW Link:https://patchwork.kernel.org/series/1160490/
---Test result---
Test Summary:
CheckPatch PASS 1.73 seconds
VerifyFixes PASS 0.12 seconds
VerifySignedoff PASS 0.14 seconds
GitLint PASS 0.34 seconds
SubjectPrefix PASS 0.12 seconds
BuildKernel PASS 27.44 seconds
CheckAllWarning PASS 30.00 seconds
CheckSparse PASS 28.91 seconds
BuildKernel32 PASS 26.76 seconds
CheckKernelLLVM SKIP 0.00 seconds
TestRunnerSetup PASS 482.75 seconds
IncrementalBuild PASS 25.78 seconds
Details
##############################
Test: CheckKernelLLVM - SKIP
Desc: Build kernel with LLVM + context analysis
Output:
Clang not found
https://github.com/bluez/bluetooth-next/pull/723
---
Regards,
Linux Bluetooth
^ permalink raw reply [flat|nested] 3+ messages in thread
* Re: [PATCH v1] Bluetooth: btintel_pcie: cap device debug regions at 1 MB
2026-09-08 13:34 [PATCH v1] Bluetooth: btintel_pcie: cap device debug regions at 1 MB Kiran K
2026-09-08 15:56 ` [v1] " bluez.test.bot
@ 2026-09-08 16:30 ` patchwork-bot+bluetooth
1 sibling, 0 replies; 3+ messages in thread
From: patchwork-bot+bluetooth @ 2026-09-08 16:30 UTC (permalink / raw)
To: K, Kiran
Cc: linux-bluetooth, ravishankar.srivatsa, chethan.tumkur.narayan,
chandrashekar.devegowda
Hello:
This patch was applied to bluetooth/bluetooth-next.git (master)
by Luiz Augusto von Dentz <luiz.von.dentz@intel.com>:
On Tue, 8 Sep 2026 19:04:21 +0530 you wrote:
> Validate device-supplied debug-region boundaries during mailbox TLV
> parsing and convert start/end values to a validated region size. Cap
> debug-region sizes to 1 MB to prevent out-of-bounds reads if firmware
> reports oversized memory ranges. Skip invalid or oversized regions
> prior to coredump capture.
>
> This issue was reported by Claude Mythos.
>
> [...]
Here is the summary with links:
- [v1] Bluetooth: btintel_pcie: cap device debug regions at 1 MB
https://git.kernel.org/bluetooth/bluetooth-next/c/ea6d8993c910
You are awesome, thank you!
--
Deet-doot-dot, I am a bot.
https://korg.docs.kernel.org/patchwork/pwbot.html
^ permalink raw reply [flat|nested] 3+ messages in thread
end of thread, other threads:[~2026-09-08 16:31 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-09-08 13:34 [PATCH v1] Bluetooth: btintel_pcie: cap device debug regions at 1 MB Kiran K
2026-09-08 15:56 ` [v1] " bluez.test.bot
2026-09-08 16:30 ` [PATCH v1] " patchwork-bot+bluetooth
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.