]> git.hungrycats.org Git - linux/commitdiff
Bluetooth: hci_aml: validate firmware segment lengths
authorLaxman Acharya Padhya <acharyalaxman8848@gmail.com>
Thu, 30 Jul 2026 12:20:28 +0000 (18:05 +0545)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 27 Aug 2026 12:32:55 +0000 (14:32 +0200)
commit 2bf6b9baca9372ea51b6d0f2820dc9bf29a83ef4 upstream.

aml_download_firmware() reads two lengths from the firmware header and
uses them to build pointers before checking that the header and segment
data are present. A truncated or inconsistent firmware image can make
the driver read past firmware->data while constructing TCI commands.

Reject images shorter than the header and ensure that the ICCM and DCCM
ranges fit within the loaded firmware before downloading either segment.

Fixes: 37bac77e4649 ("Bluetooth: hci_uart: Add support for Amlogic HCI UART")
Cc: stable@vger.kernel.org
Signed-off-by: Laxman Acharya Padhya <acharyalaxman8848@gmail.com>
Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/bluetooth/hci_aml.c

index b1f32c5a8a3f419650b29990a684bc1435e0bb08..0f227a0915b8cae4ba8f8ade8d16beda095c13cc 100644 (file)
@@ -247,7 +247,7 @@ static int aml_download_firmware(struct hci_dev *hdev, const char *fw_name)
        struct hci_uart *hu = hci_get_drvdata(hdev);
        struct aml_serdev *amldev = serdev_device_get_drvdata(hu->serdev);
        const struct firmware *firmware = NULL;
-       struct aml_fw_len *fw_len = NULL;
+       const struct aml_fw_len *fw_len = NULL;
        u8 *iccm_start = NULL, *dccm_start = NULL;
        u32 iccm_len, dccm_len;
        u32 value = 0;
@@ -281,7 +281,21 @@ static int aml_download_firmware(struct hci_dev *hdev, const char *fw_name)
                goto exit;
        }
 
-       fw_len = (struct aml_fw_len *)firmware->data;
+       if (firmware->size < sizeof(*fw_len)) {
+               bt_dev_err(hdev, "Firmware is too small for its header");
+               ret = -EINVAL;
+               goto exit;
+       }
+
+       fw_len = (const struct aml_fw_len *)firmware->data;
+       if (fw_len->iccm_len < amldev->aml_dev_data->iccm_offset ||
+           fw_len->iccm_len > firmware->size - sizeof(*fw_len) ||
+           fw_len->dccm_len > firmware->size - sizeof(*fw_len) -
+                       fw_len->iccm_len) {
+               bt_dev_err(hdev, "Invalid firmware segment lengths");
+               ret = -EINVAL;
+               goto exit;
+       }
 
        /* Download ICCM */
        iccm_start = (u8 *)(firmware->data) + sizeof(struct aml_fw_len)