]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
Bluetooth: MGMT: validate advertising TLV before type checks
authorZhang Cen <rollkingzzc@gmail.com>
Thu, 28 May 2026 09:45:06 +0000 (17:45 +0800)
committerLuiz Augusto von Dentz <luiz.von.dentz@intel.com>
Wed, 3 Jun 2026 15:20:41 +0000 (11:20 -0400)
tlv_data_is_valid() reads each advertising data field length from
data[i], then inspects data[i + 1] for managed EIR types before
checking that the current field still fits inside the supplied buffer.

A malformed field whose length byte is the last byte of the buffer can
therefore make the parser read one byte past the advertising data.

KASAN reported the following when a malformed MGMT_OP_ADD_ADVERTISING
request reached that path:

  BUG: KASAN: vmalloc-out-of-bounds in tlv_data_is_valid()
  Read of size 1
  Call trace:
    tlv_data_is_valid()
    add_advertising()
    hci_mgmt_cmd()
    hci_sock_sendmsg()

Move the existing element-length check before any type-octet inspection
so each non-empty element is proven to contain its type byte before the
parser looks at data[i + 1].

Fixes: 2bb36870e8cb ("Bluetooth: Unify advertising instance flags check")
Reviewed-by: Paul Menzel <pmenzel@molgen.mpg.de>
Signed-off-by: Zhang Cen <rollkingzzc@gmail.com>
Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
net/bluetooth/mgmt.c

index de5bd6b637b2053904e95c5666e039658869f0ba..027b266ccc747c59917a07e956148a46acde3664 100644 (file)
@@ -8638,6 +8638,12 @@ static bool tlv_data_is_valid(struct hci_dev *hdev, u32 adv_flags, u8 *data,
                if (!cur_len)
                        continue;
 
+               /* If the current field length would exceed the total data
+                * length, then it's invalid.
+                */
+               if (i + cur_len >= len)
+                       return false;
+
                if (data[i + 1] == EIR_FLAGS &&
                    (!is_adv_data || flags_managed(adv_flags)))
                        return false;
@@ -8654,12 +8660,6 @@ static bool tlv_data_is_valid(struct hci_dev *hdev, u32 adv_flags, u8 *data,
                if (data[i + 1] == EIR_APPEARANCE &&
                    appearance_managed(adv_flags))
                        return false;
-
-               /* If the current field length would exceed the total data
-                * length, then it's invalid.
-                */
-               if (i + cur_len >= len)
-                       return false;
        }
 
        return true;