Commit 417adf54 authored by Johan Hovold's avatar Johan Hovold Committed by Yi Yang
Browse files

Bluetooth: qca: add missing firmware sanity checks

stable inclusion
from stable-v5.15.159
commit ed53949cc92e28aaa3463d246942bda1fbb7f307
category: bugfix
bugzilla: https://gitee.com/src-openeuler/kernel/issues/I9U3C7
CVE: CVE-2024-36880

Reference: https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/?id=ed53949cc92e28aaa3463d246942bda1fbb7f307



---------------------------

commit 2e4edfa1e2bd821a317e7d006517dcf2f3fac68d upstream.

Add the missing sanity checks when parsing the firmware files before
downloading them to avoid accessing and corrupting memory beyond the
vmalloced buffer.

Fixes: 83e81961 ("Bluetooth: btqca: Introduce generic QCA ROME support")
Cc: stable@vger.kernel.org	# 4.10
Signed-off-by: default avatarJohan Hovold <johan+linaro@kernel.org>
Signed-off-by: default avatarLuiz Augusto von Dentz <luiz.von.dentz@intel.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Conflicts:
	drivers/bluetooth/btqca.c
[ecf6b2d9 not merged so the case ELF_TYPE_PATCH is not contained,
and b91390f4e828f is not merged too, so they lead to context conflicts]
Signed-off-by: default avatarYi Yang <yiyang13@huawei.com>
parent 10361bdc
Loading
Loading
Loading
Loading
+30 −6
Original line number Diff line number Diff line
@@ -142,8 +142,10 @@ int qca_send_pre_shutdown_cmd(struct hci_dev *hdev)
}
EXPORT_SYMBOL_GPL(qca_send_pre_shutdown_cmd);

static void qca_tlv_check_data(struct qca_fw_config *config,
		u8 *fw_data, enum qca_btsoc_type soc_type)
static int qca_tlv_check_data(struct hci_dev *hdev,
			       struct qca_fw_config *config,
			       u8 *fw_data, size_t fw_size,
			       enum qca_btsoc_type soc_type)
{
	const u8 *data;
	u32 type_len;
@@ -167,6 +169,9 @@ static void qca_tlv_check_data(struct qca_fw_config *config,

	switch (config->type) {
	case TLV_TYPE_PATCH:
		if (fw_size < sizeof(struct tlv_type_hdr) + sizeof(struct tlv_type_patch))
			return -EINVAL;

		tlv_patch = (struct tlv_type_patch *)tlv->data;

		/* For Rome version 1.1 to 3.1, all segment commands
@@ -203,17 +208,29 @@ static void qca_tlv_check_data(struct qca_fw_config *config,
		break;

	case TLV_TYPE_NVM:
		if (fw_size < sizeof(struct tlv_type_hdr))
			return -EINVAL;

		if (fw_size < length + (tlv->data - fw_data))
			return -EINVAL;

		idx = 0;
		data = tlv->data;
		while (idx < length) {
		while (idx < length - sizeof(struct tlv_type_nvm)) {
			tlv_nvm = (struct tlv_type_nvm *)(data + idx);

			tag_id = le16_to_cpu(tlv_nvm->tag_id);
			tag_len = le16_to_cpu(tlv_nvm->tag_len);

			if (length < idx + sizeof(struct tlv_type_nvm) + tag_len)
				return -EINVAL;

			/* Update NVM tags as needed */
			switch (tag_id) {
			case EDL_TAG_ID_HCI:
				if (tag_len < 3)
					return -EINVAL;

				/* HCI transport layer parameters
				 * enabling software inband sleep
				 * onto controller side.
@@ -229,6 +246,9 @@ static void qca_tlv_check_data(struct qca_fw_config *config,
				break;

			case EDL_TAG_ID_DEEP_SLEEP:
				if (tag_len < 1)
					return -EINVAL;

				/* Sleep enable mask
				 * enabling deep sleep feature on controller.
				 */
@@ -237,14 +257,16 @@ static void qca_tlv_check_data(struct qca_fw_config *config,
				break;
			}

			idx += (sizeof(u16) + sizeof(u16) + 8 + tag_len);
			idx += sizeof(struct tlv_type_nvm) + tag_len;
		}
		break;

	default:
		BT_ERR("Unknown TLV type %d", config->type);
		break;
		return -EINVAL;
	}

	return 0;
}

static int qca_tlv_send_segment(struct hci_dev *hdev, int seg_size,
@@ -375,7 +397,9 @@ static int qca_download_firmware(struct hci_dev *hdev,
	memcpy(data, fw->data, size);
	release_firmware(fw);

	qca_tlv_check_data(config, data, soc_type);
	ret = qca_tlv_check_data(hdev, config, data, size, soc_type);
	if (ret)
		return ret;

	segment = data;
	remain = size;