Re: [PATCH] Bluetooth: hci_codec: validate vendor codec count length

Luiz Augusto von Dentz <[email protected]>
Newsgroups org.kernel.vger.linux-bluetooth,org.kernel.vger.linux-kernel,org.kernel.vger.stable
Message-ID <CABBYNZJxXFt3N-hNQ-RPSe379uw9qfwvKL9yncQ4a034_9d6hQ@mail.gmail.com>
Hi Laxman,

On Mon, Aug 24, 2026 at 11:20 AM Laxman Acharya Padhya
<[email protected]> wrote:
>
> Hi Luiz,
>
> Thanks for looking at this.  Sorry that my earlier wording was unclear.
> I agree that the uses of p inside sizeof() and __must_be_array() are
> unevaluated, and that sizeof(vnd_codecs->num) is a compile-time value of
> one.
>
> The runtime access comes from the third macro argument, count.  Here that
> argument is the expression vnd_codecs->num.  Since it is not a constant
> expression, __builtin_choose_expr() selects the size_mul() branch, which
> effectively evaluates:
>
>         size_mul(vnd_codecs->num, sizeof(*vnd_codecs->codec))

Opps, yeah that indeed access the ->num.

> Evaluating the first argument reads vnd_codecs->num before the result is
> compared with skb->len.  Therefore, if no byte remains after the standard
> codec array, the read is already out of bounds.  The issue is this count
> load, rather than any evaluation of the sizeof() operands.
>
> I also verified this with a minimal reproducer using the same macro
> expansion: the compiler emits a byte load from vnd_codecs, and ASan
> reports a one-byte out-of-bounds read when the pointer is at the end of
> the buffer.
>
> Changing the trailing sizeof(vnd_codecs->num) to sizeof(*vnd_codecs)
> would give the same size, but it would not prevent the earlier count
> load.  The added check ensures that the count byte is present before
> flex_array_size() uses it.

That said I rather use skb_pull_data then:

diff --git a/net/bluetooth/hci_codec.c b/net/bluetooth/hci_codec.c
index 5bc5003c387c..fdc9652dad29 100644
--- a/net/bluetooth/hci_codec.c
+++ b/net/bluetooth/hci_codec.c
@@ -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 */


-- 
Luiz Augusto von Dentz
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.