* [PATCH v2 1/3] Bluetooth: btintel: validate version TLV value lengths
2026-08-14 17:15 [PATCH v2 0/3] Bluetooth: btintel: harden version TLV parsing Laxman Acharya Padhya
@ 2026-08-14 17:15 ` Laxman Acharya Padhya
2026-08-14 18:29 ` Bluetooth: btintel: harden version TLV parsing bluez.test.bot
2026-08-14 17:15 ` [PATCH v2 2/3] Bluetooth: btintel: bound firmware ID by TLV length Laxman Acharya Padhya
2026-08-14 17:15 ` [PATCH v2 3/3] Bluetooth: btintel: propagate version TLV parsing errors Laxman Acharya Padhya
2 siblings, 1 reply; 6+ messages in thread
From: Laxman Acharya Padhya @ 2026-08-14 17:15 UTC (permalink / raw)
To: linux-bluetooth
Cc: marcel, luiz.dentz, linux-kernel, ali, raghuram.hegde, kiraank,
kiran.k, ravishankar.srivatsa, amit.k.bag
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: 57375beef71a ("Bluetooth: btintel: Add infrastructure to read controller information")
Reviewed-by: Ali Ahmet Memis <ali@iusegentoo.com>
Assisted-by: Codex:gpt-5 sparse
Signed-off-by: Laxman Acharya Padhya <acharyalaxman8848@gmail.com>
---
drivers/bluetooth/btintel.c | 37 ++++++++++++++++++++++++++++++++++++-
1 file changed, 36 insertions(+), 1 deletion(-)
diff --git a/drivers/bluetooth/btintel.c b/drivers/bluetooth/btintel.c
index bf567b7c5f00..26435e41f1ce 100644
--- a/drivers/bluetooth/btintel.c
+++ b/drivers/bluetooth/btintel.c
@@ -570,12 +570,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
@@ -595,6 +627,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);
--
2.51.2
^ permalink raw reply related [flat|nested] 6+ messages in thread* [PATCH v2 2/3] Bluetooth: btintel: bound firmware ID by TLV length
2026-08-14 17:15 [PATCH v2 0/3] Bluetooth: btintel: harden version TLV parsing Laxman Acharya Padhya
2026-08-14 17:15 ` [PATCH v2 1/3] Bluetooth: btintel: validate version TLV value lengths Laxman Acharya Padhya
@ 2026-08-14 17:15 ` Laxman Acharya Padhya
2026-08-14 17:15 ` [PATCH v2 3/3] Bluetooth: btintel: propagate version TLV parsing errors Laxman Acharya Padhya
2 siblings, 0 replies; 6+ messages in thread
From: Laxman Acharya Padhya @ 2026-08-14 17:15 UTC (permalink / raw)
To: linux-bluetooth
Cc: marcel, luiz.dentz, linux-kernel, ali, raghuram.hegde, kiraank,
kiran.k, ravishankar.srivatsa, amit.k.bag
The firmware ID is treated as a NUL-terminated string even though the
TLV length is its only boundary. If the value does not contain a NUL
terminator, snprintf() can read beyond the received response.
Limit the conversion to the advertised TLV value length.
Fixes: 164c62f958f8 ("Bluetooth: btintel: Add firmware ID to firmware name")
Reviewed-by: Ali Ahmet Memis <ali@iusegentoo.com>
Assisted-by: Codex:gpt-5 sparse
Signed-off-by: Laxman Acharya Padhya <acharyalaxman8848@gmail.com>
---
drivers/bluetooth/btintel.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/bluetooth/btintel.c b/drivers/bluetooth/btintel.c
index 26435e41f1ce..c204e9a1cd0f 100644
--- a/drivers/bluetooth/btintel.c
+++ b/drivers/bluetooth/btintel.c
@@ -701,7 +701,7 @@ int btintel_parse_version_tlv(struct hci_dev *hdev,
break;
case INTEL_TLV_FW_ID:
snprintf(version->fw_id, sizeof(version->fw_id),
- "%s", tlv->val);
+ "%.*s", tlv->len, tlv->val);
break;
default:
/* Ignore rest of information */
--
2.51.2
^ permalink raw reply related [flat|nested] 6+ messages in thread* [PATCH v2 3/3] Bluetooth: btintel: propagate version TLV parsing errors
2026-08-14 17:15 [PATCH v2 0/3] Bluetooth: btintel: harden version TLV parsing Laxman Acharya Padhya
2026-08-14 17:15 ` [PATCH v2 1/3] Bluetooth: btintel: validate version TLV value lengths Laxman Acharya Padhya
2026-08-14 17:15 ` [PATCH v2 2/3] Bluetooth: btintel: bound firmware ID by TLV length Laxman Acharya Padhya
@ 2026-08-14 17:15 ` Laxman Acharya Padhya
2026-08-14 18:46 ` Ali Ahmet Memis
2 siblings, 1 reply; 6+ messages in thread
From: Laxman Acharya Padhya @ 2026-08-14 17:15 UTC (permalink / raw)
To: linux-bluetooth
Cc: marcel, luiz.dentz, linux-kernel, ali, raghuram.hegde, kiraank,
kiran.k, ravishankar.srivatsa, amit.k.bag
btintel_read_version_tlv() ignores the parser return value, so setup
continues with partially initialized version data after a malformed TLV
causes parsing to stop.
Return the parser error to the caller so an invalid response fails setup
instead of being treated as successful. Keep this behavioral change
separate from the bounds checks so it can be reverted independently if
an existing controller sends malformed data.
Assisted-by: Codex:gpt-5 sparse
Signed-off-by: Laxman Acharya Padhya <acharyalaxman8848@gmail.com>
---
drivers/bluetooth/btintel.c | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/drivers/bluetooth/btintel.c b/drivers/bluetooth/btintel.c
index c204e9a1cd0f..934775e449db 100644
--- a/drivers/bluetooth/btintel.c
+++ b/drivers/bluetooth/btintel.c
@@ -720,6 +720,7 @@ static int btintel_read_version_tlv(struct hci_dev *hdev,
{
struct sk_buff *skb;
const u8 param[1] = { 0xFF };
+ int err;
if (!version)
return -EINVAL;
@@ -738,10 +739,10 @@ static int btintel_read_version_tlv(struct hci_dev *hdev,
return -EIO;
}
- btintel_parse_version_tlv(hdev, version, skb);
+ err = btintel_parse_version_tlv(hdev, version, skb);
kfree_skb(skb);
- return 0;
+ return err;
}
/* ------- REGMAP IBT SUPPORT ------- */
--
2.51.2
^ permalink raw reply related [flat|nested] 6+ messages in thread