Bluetooth: btintel: validate version TLV value lengths

btintel_parse_version_tlv() verifies that a complete TLV is present in
the response, but it does not ensure that the value is long enough for
the specific TLV type. A short value can therefore cause an
out-of-bounds read through get_unaligned_le16(), get_unaligned_le32(),
or memcpy().

Reject values shorter than the minimum required by each known TLV type.
Also reject responses that do not contain the Command Complete Status
field.

Fixes: 57375beef7 ("Bluetooth: btintel: Add infrastructure to read controller information")
Reviewed-by: Ali Ahmet Memis <ali@iusegentoo.com>
Signed-off-by: Laxman Acharya Padhya <acharyalaxman8848@gmail.com>
Tested-by: Kiran K <kiran.k@intel.com>
Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
This commit is contained in:
Laxman Acharya Padhya 2026-08-31 15:44:21 +05:45 committed by Luiz Augusto von Dentz
parent ea2ee8b222
commit a086c08929

View File

@ -571,12 +571,44 @@ int btintel_version_info_tlv(struct hci_dev *hdev,
}
EXPORT_SYMBOL_GPL(btintel_version_info_tlv);
static u8 btintel_version_tlv_min_len(u8 type)
{
switch (type) {
case INTEL_TLV_CNVI_TOP:
case INTEL_TLV_CNVR_TOP:
case INTEL_TLV_CNVI_BT:
case INTEL_TLV_CNVR_BT:
case INTEL_TLV_BUILD_NUM:
case INTEL_TLV_GIT_SHA1:
return sizeof(u32);
case INTEL_TLV_DEV_REV_ID:
case INTEL_TLV_TIME_STAMP:
return sizeof(u16);
case INTEL_TLV_IMAGE_TYPE:
case INTEL_TLV_BUILD_TYPE:
case INTEL_TLV_SECURE_BOOT:
case INTEL_TLV_OTP_LOCK:
case INTEL_TLV_API_LOCK:
case INTEL_TLV_DEBUG_LOCK:
case INTEL_TLV_LIMITED_CCE:
case INTEL_TLV_SBE_TYPE:
return sizeof(u8);
case INTEL_TLV_MIN_FW:
return 3;
case INTEL_TLV_OTP_BDADDR:
return sizeof(bdaddr_t);
default:
return 0;
}
}
int btintel_parse_version_tlv(struct hci_dev *hdev,
struct intel_version_tlv *version,
struct sk_buff *skb)
{
/* Consume Command Complete Status field */
skb_pull(skb, 1);
if (!skb_pull(skb, 1))
return -EINVAL;
/* Event parameters contain multiple TLVs. Read each of them
* and only keep the required data. Also, it use existing legacy
@ -596,6 +628,9 @@ int btintel_parse_version_tlv(struct hci_dev *hdev,
if (skb->len < tlv->len + sizeof(*tlv))
return -EINVAL;
if (tlv->len < btintel_version_tlv_min_len(tlv->type))
return -EINVAL;
switch (tlv->type) {
case INTEL_TLV_CNVI_TOP:
version->cnvi_top = get_unaligned_le32(tlv->val);