[PATCH v9 1/6] Bluetooth: btmtk: Add firmware size validation in btmtk_setup_firmware_79xx()
Chris Lu
chris.lu at mediatek.com
Thu Jul 2 03:14:31 PDT 2026
Add firmware size validation to prevent out-of-bounds access when loading
truncated or malicious firmware files.
Add three levels of validation:
1. Minimum size check for header and global descriptor
2. Section map bounds check with integer overflow protection using
check_mul_overflow() and check_add_overflow()
3. Section data bounds check before accessing each section
This matches the validation approach used in btmtk_load_cbmcu_firmware().
Signed-off-by: Chris Lu <chris.lu at mediatek.com>
Assisted-by: Claude:Sonnet-4.5
---
drivers/bluetooth/btmtk.c | 39 +++++++++++++++++++++++++++++++++++++++
1 file changed, 39 insertions(+)
diff --git a/drivers/bluetooth/btmtk.c b/drivers/bluetooth/btmtk.c
index 02a96342e964..3491060b3ae9 100644
--- a/drivers/bluetooth/btmtk.c
+++ b/drivers/bluetooth/btmtk.c
@@ -145,6 +145,7 @@ int btmtk_setup_firmware_79xx(struct hci_dev *hdev, const char *fwname,
int err, dlen, i, status;
u8 flag, first_block, retry;
u32 section_num, dl_size, section_offset;
+ size_t expected_size;
u8 cmd[64];
err = request_firmware(&fw, fwname, &hdev->dev);
@@ -153,12 +154,40 @@ int btmtk_setup_firmware_79xx(struct hci_dev *hdev, const char *fwname,
return err;
}
+ /* Validate minimum firmware size for header and global descriptor */
+ if (fw->size < MTK_FW_ROM_PATCH_HEADER_SIZE + MTK_FW_ROM_PATCH_GD_SIZE) {
+ bt_dev_err(hdev, "Firmware file too small: size=%zu, expected at least %u bytes",
+ fw->size, MTK_FW_ROM_PATCH_HEADER_SIZE + MTK_FW_ROM_PATCH_GD_SIZE);
+ err = -EINVAL;
+ goto err_release_fw;
+ }
+
fw_ptr = fw->data;
fw_bin_ptr = fw_ptr;
hdr = (struct btmtk_patch_header *)fw_ptr;
globaldesc = (struct btmtk_global_desc *)(fw_ptr + MTK_FW_ROM_PATCH_HEADER_SIZE);
section_num = le32_to_cpu(globaldesc->section_num);
+ /* Check for potential integer overflow in size calculation */
+ if (check_mul_overflow((size_t)MTK_FW_ROM_PATCH_SEC_MAP_SIZE,
+ (size_t)section_num, &expected_size) ||
+ check_add_overflow(expected_size,
+ (size_t)(MTK_FW_ROM_PATCH_HEADER_SIZE +
+ MTK_FW_ROM_PATCH_GD_SIZE),
+ &expected_size)) {
+ bt_dev_err(hdev, "Firmware size calculation overflow (section_num=%u)",
+ section_num);
+ err = -EINVAL;
+ goto err_release_fw;
+ }
+
+ if (fw->size < expected_size) {
+ bt_dev_err(hdev, "Firmware truncated: size=%zu, expected=%zu (section_num=%u)",
+ fw->size, expected_size, section_num);
+ err = -EINVAL;
+ goto err_release_fw;
+ }
+
bt_dev_info(hdev, "HW/SW Version: 0x%04x%04x, Build Time: %s",
le16_to_cpu(hdr->hwver), le16_to_cpu(hdr->swver), hdr->datetime);
@@ -171,6 +200,16 @@ int btmtk_setup_firmware_79xx(struct hci_dev *hdev, const char *fwname,
section_offset = le32_to_cpu(sectionmap->secoffset);
dl_size = le32_to_cpu(sectionmap->bin_info_spec.dlsize);
+ /* Validate section boundaries to prevent out-of-bounds access */
+ if (dl_size > 0 &&
+ (section_offset > fw->size ||
+ dl_size > fw->size - section_offset)) {
+ bt_dev_err(hdev, "Section %d out of bounds: offset=%u, size=%u, fw_size=%zu",
+ i, section_offset, dl_size, fw->size);
+ err = -EINVAL;
+ goto err_release_fw;
+ }
+
/* MT6639: only download sections where dlmode byte0 == 0x01,
* matching the Windows driver behavior which skips WiFi/other
* sections that would cause the chip to hang.
--
2.45.2
More information about the Linux-mediatek
mailing list