Bluetooth: hci_codec: validate vendor codec count length

The Read Local Supported Codecs parsers consume the variable-sized
standard codec array before parsing the vendor codec count.  Although the
initial reply-size check includes a vendor count byte in the fixed layout,
it does not guarantee that the byte remains after the standard codec array.

If a controller reply ends immediately after that array, calculating the
vendor codec array size reads vnd_codecs->num beyond the skb data.  Use
skb_pull_data() to validate and consume each codec header before using its
count in both command variants.

Fixes: 8961987f3f ("Bluetooth: Enumerate local supported codec and cache details")
Fixes: 9ae664028a ("Bluetooth: Add support for Read Local Supported Codecs V2")
Cc: stable@vger.kernel.org
Suggested-by: Luiz Augusto von Dentz <luiz.dentz@gmail.com>
Signed-off-by: Laxman Acharya Padhya <acharyalaxman8848@gmail.com>
Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
This commit is contained in:
Laxman Acharya Padhya 2026-08-24 21:42:36 +05:45 committed by Luiz Augusto von Dentz
parent 4914c49989
commit d0795cfd6f

View File

@ -145,11 +145,12 @@ void hci_read_supported_codecs(struct hci_dev *hdev)
skb_pull(skb, sizeof(rp->status));
std_codecs = (void *)skb->data;
std_codecs = skb_pull_data(skb, sizeof(*std_codecs));
if (!std_codecs)
goto error;
/* validate codecs length before accessing */
if (skb->len < flex_array_size(std_codecs, codec, std_codecs->num)
+ sizeof(std_codecs->num))
if (skb->len < flex_array_size(std_codecs, codec, std_codecs->num))
goto error;
/* enumerate codec capabilities of standard codecs */
@ -161,15 +162,14 @@ void hci_read_supported_codecs(struct hci_dev *hdev)
LOCAL_CODEC_ACL_MASK | LOCAL_CODEC_SCO_MASK, &caps);
}
skb_pull(skb, flex_array_size(std_codecs, codec, std_codecs->num)
+ sizeof(std_codecs->num));
skb_pull(skb, flex_array_size(std_codecs, codec, std_codecs->num));
vnd_codecs = (void *)skb->data;
vnd_codecs = skb_pull_data(skb, sizeof(*vnd_codecs));
if (!vnd_codecs)
goto error;
/* validate vendor codecs length before accessing */
if (skb->len <
flex_array_size(vnd_codecs, codec, vnd_codecs->num)
+ sizeof(vnd_codecs->num))
if (skb->len < flex_array_size(vnd_codecs, codec, vnd_codecs->num))
goto error;
/* enumerate vendor codec capabilities */
@ -214,11 +214,12 @@ void hci_read_supported_codecs_v2(struct hci_dev *hdev)
skb_pull(skb, sizeof(rp->status));
std_codecs = (void *)skb->data;
std_codecs = skb_pull_data(skb, sizeof(*std_codecs));
if (!std_codecs)
goto error;
/* check for payload data length before accessing */
if (skb->len < flex_array_size(std_codecs, codec, std_codecs->num)
+ sizeof(std_codecs->num))
if (skb->len < flex_array_size(std_codecs, codec, std_codecs->num))
goto error;
memset(&caps, 0, sizeof(caps));
@ -229,15 +230,14 @@ void hci_read_supported_codecs_v2(struct hci_dev *hdev)
&caps);
}
skb_pull(skb, flex_array_size(std_codecs, codec, std_codecs->num)
+ sizeof(std_codecs->num));
skb_pull(skb, flex_array_size(std_codecs, codec, std_codecs->num));
vnd_codecs = (void *)skb->data;
vnd_codecs = skb_pull_data(skb, sizeof(*vnd_codecs));
if (!vnd_codecs)
goto error;
/* check for payload data length before accessing */
if (skb->len <
flex_array_size(vnd_codecs, codec, vnd_codecs->num)
+ sizeof(vnd_codecs->num))
if (skb->len < flex_array_size(vnd_codecs, codec, vnd_codecs->num))
goto error;
for (i = 0; i < vnd_codecs->num; i++) {