* Re: [PATCH BlueZ v5 08/16] test-runner: use virtio-serial for implementing -u device forwarding
From: Pauli Virtanen @ 2026-06-02 20:03 UTC (permalink / raw)
To: Luiz Augusto von Dentz; +Cc: linux-bluetooth
In-Reply-To: <132073b9a61db8dcd9c85f0b5787200a63a50604.camel@iki.fi>
ti, 2026-06-02 kello 19:51 +0000, Pauli Virtanen kirjoitti:
> Hi Luiz,
>
> ti, 2026-06-02 kello 15:35 -0400, Luiz Augusto von Dentz kirjoitti:
> > Hi Pauli,
> >
> > On Wed, May 13, 2026 at 12:48 PM Pauli Virtanen <pav@iki.fi> wrote:
> > >
> > > Using pci-serial to forward eg. btvirt sockets is unreliable, as
> > > qemu or
> > > kernel seems to be sometimes dropping part of the sent data or
> > > insert
> > > spurious \0 bytes, leading to sporadic errors like:
> > >
> > > kernel: Bluetooth: hci0: command 0x0c52 tx timeout
> > > kernel: Bluetooth: hci0: Opcode 0x0c52 failed: -110
> > > btvirt: packet error, unknown type: 0
> > >
> > > This appears to occur most often when host system is under load,
> > > e.g.
> > > due to multiple test-runners running at the same time. The
> > > problem
> > > is
> > > not specific to btvirt, but seems to be in the qemu serial device
> > > layer
> > > vs. kernel interaction.
> > >
> > > Change test-runner to use virtserialport to forward the btvirt
> > > connection inside the VM, as virtio-serial doesn't appear to have
> > > these
> > > problems.
> > > ---
> > > tools/test-runner.c | 13 +++++++++----
> > > 1 file changed, 9 insertions(+), 4 deletions(-)
> > >
> > > diff --git a/tools/test-runner.c b/tools/test-runner.c
> > > index b3e0b0cfe..0e3bfb8b7 100644
> > > --- a/tools/test-runner.c
> > > +++ b/tools/test-runner.c
> > > @@ -306,7 +306,7 @@ static void start_qemu(void)
> > > testargs);
> > >
> > > argv = alloca(sizeof(qemu_argv) +
> > > - (sizeof(char *) * (6 + (num_devs * 4))) +
> > > + (sizeof(char *) * (8 + (num_devs * 4))) +
> > > (sizeof(char *) * (usb_dev ? 4 : 0)) +
> > > (sizeof(char *) * num_extra_opts));
> > > memcpy(argv, qemu_argv, sizeof(qemu_argv));
> > > @@ -330,14 +330,19 @@ static void start_qemu(void)
> > > argv[pos++] = "-append";
> > > argv[pos++] = (char *) cmdline;
> > >
> > > + if (num_devs) {
> > > + argv[pos++] = "-device";
> > > + argv[pos++] = "virtio-serial";
> > > + }
> > > +
> > > for (i = 0; i < num_devs; i++) {
> > > char *chrdev, *serdev;
> > >
> > > chrdev = alloca(48 + strlen(device_path));
> > > sprintf(chrdev, "socket,path=%s,id=bt%d",
> > > device_path, i);
> > >
> > > - serdev = alloca(48);
> > > - sprintf(serdev, "pci-serial,chardev=bt%d", i);
> > > + serdev = alloca(64);
> > > + sprintf(serdev,
> > > "virtconsole,chardev=bt%d,name=bt.%d", i, i);
> > >
> > > argv[pos++] = "-chardev";
> > > argv[pos++] = chrdev;
> > > @@ -910,7 +915,7 @@ static void run_command(char *cmdname, char
> > > *home)
> > > }
> > >
> > > if (num_devs) {
> > > - const char *node = "/dev/ttyS1";
> > > + const char *node = "/dev/hvc0";
> >
> > Im getting and error with these changes:
> >
> > Attaching BR/EDR controller to /dev/hvc0
> > Failed to open serial port: No such file or directory
> >
> > I tried adding the kernel config options but it didn't make any
> > difference.
>
> We have test-runner with this patch in Pipewire CI, and it is working
>
> https://gitlab.freedesktop.org/pipewire/pipewire/-/jobs/101256448
>
> on Fedora 44 + Qemu 10.2.2. Kernel configuration is here:
>
> https://github.com/pv/bluez-test-functional-kernel/blob/main/tester.config
>
> I've also used with this for USB redirection.
Also, the exact kernel image we are using built from that config is
here:
https://github.com/pv/bluez-test-functional-kernel/releases/tag/2026-05-08.1
at bluez 07b6fc156348bb515ac0a876d49644312c9476d6 I can then do
$ ./emulator/btvirt -s &
$ ./tools/test-runner -u/tmp/bt-server-bredrle -k bzImage -- bash
...
Attachment of devices requested
Attaching BR/EDR controller to /dev/hvc0
Switched line discipline from 0 to 15
Device index 0 attached
Running command bash
>
> Not sure what is different for you, do you get any virtio serial
> devices from the virtconsole?
>
> >
> > > unsigned int basic_flags, extra_flags;
> > >
> > > printf("Attaching BR/EDR controller to %s\n",
> > > node);
> > > --
> > > 2.54.0
> > >
> > >
> >
^ permalink raw reply
* Re: [PATCH BlueZ v5 08/16] test-runner: use virtio-serial for implementing -u device forwarding
From: Pauli Virtanen @ 2026-06-02 19:51 UTC (permalink / raw)
To: Luiz Augusto von Dentz; +Cc: linux-bluetooth
In-Reply-To: <CABBYNZL42S2FKP9EF33i=P5p5ggD4fg2qFkg-NaKAF4h8wD_iw@mail.gmail.com>
Hi Luiz,
ti, 2026-06-02 kello 15:35 -0400, Luiz Augusto von Dentz kirjoitti:
> Hi Pauli,
>
> On Wed, May 13, 2026 at 12:48 PM Pauli Virtanen <pav@iki.fi> wrote:
> >
> > Using pci-serial to forward eg. btvirt sockets is unreliable, as
> > qemu or
> > kernel seems to be sometimes dropping part of the sent data or
> > insert
> > spurious \0 bytes, leading to sporadic errors like:
> >
> > kernel: Bluetooth: hci0: command 0x0c52 tx timeout
> > kernel: Bluetooth: hci0: Opcode 0x0c52 failed: -110
> > btvirt: packet error, unknown type: 0
> >
> > This appears to occur most often when host system is under load,
> > e.g.
> > due to multiple test-runners running at the same time. The problem
> > is
> > not specific to btvirt, but seems to be in the qemu serial device
> > layer
> > vs. kernel interaction.
> >
> > Change test-runner to use virtserialport to forward the btvirt
> > connection inside the VM, as virtio-serial doesn't appear to have
> > these
> > problems.
> > ---
> > tools/test-runner.c | 13 +++++++++----
> > 1 file changed, 9 insertions(+), 4 deletions(-)
> >
> > diff --git a/tools/test-runner.c b/tools/test-runner.c
> > index b3e0b0cfe..0e3bfb8b7 100644
> > --- a/tools/test-runner.c
> > +++ b/tools/test-runner.c
> > @@ -306,7 +306,7 @@ static void start_qemu(void)
> > testargs);
> >
> > argv = alloca(sizeof(qemu_argv) +
> > - (sizeof(char *) * (6 + (num_devs * 4))) +
> > + (sizeof(char *) * (8 + (num_devs * 4))) +
> > (sizeof(char *) * (usb_dev ? 4 : 0)) +
> > (sizeof(char *) * num_extra_opts));
> > memcpy(argv, qemu_argv, sizeof(qemu_argv));
> > @@ -330,14 +330,19 @@ static void start_qemu(void)
> > argv[pos++] = "-append";
> > argv[pos++] = (char *) cmdline;
> >
> > + if (num_devs) {
> > + argv[pos++] = "-device";
> > + argv[pos++] = "virtio-serial";
> > + }
> > +
> > for (i = 0; i < num_devs; i++) {
> > char *chrdev, *serdev;
> >
> > chrdev = alloca(48 + strlen(device_path));
> > sprintf(chrdev, "socket,path=%s,id=bt%d",
> > device_path, i);
> >
> > - serdev = alloca(48);
> > - sprintf(serdev, "pci-serial,chardev=bt%d", i);
> > + serdev = alloca(64);
> > + sprintf(serdev,
> > "virtconsole,chardev=bt%d,name=bt.%d", i, i);
> >
> > argv[pos++] = "-chardev";
> > argv[pos++] = chrdev;
> > @@ -910,7 +915,7 @@ static void run_command(char *cmdname, char
> > *home)
> > }
> >
> > if (num_devs) {
> > - const char *node = "/dev/ttyS1";
> > + const char *node = "/dev/hvc0";
>
> Im getting and error with these changes:
>
> Attaching BR/EDR controller to /dev/hvc0
> Failed to open serial port: No such file or directory
>
> I tried adding the kernel config options but it didn't make any
> difference.
We have test-runner with this patch in Pipewire CI, and it is working
https://gitlab.freedesktop.org/pipewire/pipewire/-/jobs/101256448
on Fedora 44 + Qemu 10.2.2. Kernel configuration is here:
https://github.com/pv/bluez-test-functional-kernel/blob/main/tester.config
I've also used with this for USB redirection.
Not sure what is different for you, do you get any virtio serial
devices from the virtconsole?
>
> > unsigned int basic_flags, extra_flags;
> >
> > printf("Attaching BR/EDR controller to %s\n",
> > node);
> > --
> > 2.54.0
> >
> >
>
--
Pauli Virtanen
^ permalink raw reply
* Re: [PATCH BlueZ v5 08/16] test-runner: use virtio-serial for implementing -u device forwarding
From: Luiz Augusto von Dentz @ 2026-06-02 19:35 UTC (permalink / raw)
To: Pauli Virtanen; +Cc: linux-bluetooth
In-Reply-To: <5d818c768189b6d0a8e5a4b90eb41cc7b9932624.1778688966.git.pav@iki.fi>
Hi Pauli,
On Wed, May 13, 2026 at 12:48 PM Pauli Virtanen <pav@iki.fi> wrote:
>
> Using pci-serial to forward eg. btvirt sockets is unreliable, as qemu or
> kernel seems to be sometimes dropping part of the sent data or insert
> spurious \0 bytes, leading to sporadic errors like:
>
> kernel: Bluetooth: hci0: command 0x0c52 tx timeout
> kernel: Bluetooth: hci0: Opcode 0x0c52 failed: -110
> btvirt: packet error, unknown type: 0
>
> This appears to occur most often when host system is under load, e.g.
> due to multiple test-runners running at the same time. The problem is
> not specific to btvirt, but seems to be in the qemu serial device layer
> vs. kernel interaction.
>
> Change test-runner to use virtserialport to forward the btvirt
> connection inside the VM, as virtio-serial doesn't appear to have these
> problems.
> ---
> tools/test-runner.c | 13 +++++++++----
> 1 file changed, 9 insertions(+), 4 deletions(-)
>
> diff --git a/tools/test-runner.c b/tools/test-runner.c
> index b3e0b0cfe..0e3bfb8b7 100644
> --- a/tools/test-runner.c
> +++ b/tools/test-runner.c
> @@ -306,7 +306,7 @@ static void start_qemu(void)
> testargs);
>
> argv = alloca(sizeof(qemu_argv) +
> - (sizeof(char *) * (6 + (num_devs * 4))) +
> + (sizeof(char *) * (8 + (num_devs * 4))) +
> (sizeof(char *) * (usb_dev ? 4 : 0)) +
> (sizeof(char *) * num_extra_opts));
> memcpy(argv, qemu_argv, sizeof(qemu_argv));
> @@ -330,14 +330,19 @@ static void start_qemu(void)
> argv[pos++] = "-append";
> argv[pos++] = (char *) cmdline;
>
> + if (num_devs) {
> + argv[pos++] = "-device";
> + argv[pos++] = "virtio-serial";
> + }
> +
> for (i = 0; i < num_devs; i++) {
> char *chrdev, *serdev;
>
> chrdev = alloca(48 + strlen(device_path));
> sprintf(chrdev, "socket,path=%s,id=bt%d", device_path, i);
>
> - serdev = alloca(48);
> - sprintf(serdev, "pci-serial,chardev=bt%d", i);
> + serdev = alloca(64);
> + sprintf(serdev, "virtconsole,chardev=bt%d,name=bt.%d", i, i);
>
> argv[pos++] = "-chardev";
> argv[pos++] = chrdev;
> @@ -910,7 +915,7 @@ static void run_command(char *cmdname, char *home)
> }
>
> if (num_devs) {
> - const char *node = "/dev/ttyS1";
> + const char *node = "/dev/hvc0";
Im getting and error with these changes:
Attaching BR/EDR controller to /dev/hvc0
Failed to open serial port: No such file or directory
I tried adding the kernel config options but it didn't make any difference.
> unsigned int basic_flags, extra_flags;
>
> printf("Attaching BR/EDR controller to %s\n", node);
> --
> 2.54.0
>
>
--
Luiz Augusto von Dentz
^ permalink raw reply
* RE: [v2] Bluetooth: eir: Fix stack OOB write when prepending the Flags AD
From: bluez.test.bot @ 2026-06-02 19:14 UTC (permalink / raw)
To: linux-bluetooth, bestswngs
In-Reply-To: <20260602170621.1454711-2-bestswngs@gmail.com>
[-- Attachment #1: Type: text/plain, Size: 3488 bytes --]
This is automated email and please do not reply to this email!
Dear submitter,
Thank you for submitting the patches to the linux bluetooth mailing list.
This is a CI test results with your patch series:
PW Link:https://patchwork.kernel.org/project/bluetooth/list/?series=1104768
---Test result---
Test Summary:
CheckPatch FAIL 0.69 seconds
VerifyFixes PASS 0.11 seconds
VerifySignedoff PASS 0.11 seconds
GitLint FAIL 0.28 seconds
SubjectPrefix PASS 0.11 seconds
BuildKernel PASS 24.67 seconds
CheckAllWarning PASS 27.02 seconds
CheckSparse PASS 26.04 seconds
BuildKernel32 PASS 24.01 seconds
TestRunnerSetup PASS 529.67 seconds
TestRunner_l2cap-tester PASS 60.82 seconds
TestRunner_iso-tester PASS 80.07 seconds
TestRunner_bnep-tester PASS 18.82 seconds
TestRunner_mgmt-tester FAIL 215.41 seconds
TestRunner_rfcomm-tester PASS 25.46 seconds
TestRunner_sco-tester PASS 32.57 seconds
TestRunner_ioctl-tester PASS 26.03 seconds
TestRunner_mesh-tester FAIL 25.87 seconds
TestRunner_smp-tester PASS 27.08 seconds
TestRunner_userchan-tester PASS 19.66 seconds
TestRunner_6lowpan-tester PASS 22.53 seconds
IncrementalBuild PASS 23.19 seconds
Details
##############################
Test: CheckPatch - FAIL
Desc: Run checkpatch.pl script
Output:
[v2] Bluetooth: eir: Fix stack OOB write when prepending the Flags AD
WARNING: Reported-by: should be immediately followed by Closes: with a URL to the report
#136:
Reported-by: Xiang Mei <xmei5@asu.edu>
Assisted-by: Claude:claude-opus-4-8
total: 0 errors, 1 warnings, 0 checks, 15 lines checked
NOTE: For some of the reported defects, checkpatch may be able to
mechanically convert to the typical style using --fix or --fix-inplace.
/github/workspace/src/patch/14607518.patch has style problems, please review.
NOTE: Ignored message types: UNKNOWN_COMMIT_ID
NOTE: If any of the errors are false positives, please report
them to the maintainer, see CHECKPATCH in MAINTAINERS.
##############################
Test: GitLint - FAIL
Desc: Run gitlint
Output:
[v2] Bluetooth: eir: Fix stack OOB write when prepending the Flags AD
8: B3 Line contains hard tab characters (\t): " memcpy(ptr, adv->adv_data, adv->adv_data_len);"
16: B1 Line exceeds max length (82>80): " BUG: KASAN: stack-out-of-bounds in eir_create_adv_data (net/bluetooth/eir.c:301)"
39: B1 Line exceeds max length (81>80): "v2: drop the kernel-added "Flags" AD when it does not fit with the instance data,"
##############################
Test: TestRunner_mgmt-tester - FAIL
Desc: Run mgmt-tester with test-runner
Output:
Total: 494, Passed: 489 (99.0%), Failed: 1, Not Run: 4
Failed Test Cases
Read Exp Feature - Success Failed 0.247 seconds
##############################
Test: TestRunner_mesh-tester - FAIL
Desc: Run mesh-tester with test-runner
Output:
Total: 10, Passed: 8 (80.0%), Failed: 2, Not Run: 0
Failed Test Cases
Mesh - Send cancel - 1 Timed out 2.452 seconds
Mesh - Send cancel - 2 Timed out 1.990 seconds
https://github.com/bluez/bluetooth-next/pull/275
---
Regards,
Linux Bluetooth
^ permalink raw reply
* [PATCH] Bluetooth: btmtk: Disable remote wakeup for MT7922/MT7925
From: Rong Zhang @ 2026-06-02 18:38 UTC (permalink / raw)
To: Marcel Holtmann, Luiz Augusto von Dentz, Matthias Brugger,
AngeloGioacchino Del Regno
Cc: linux-bluetooth, linux-kernel, linux-arm-kernel, linux-mediatek,
Rong Zhang
These NICs are often reported to lose their Bluetooth interfaces, i.e,
their USB interfaces suddenly become completely unresponsive, causing
the USB core to reset them, only to find that they are no longer
accessible. A power cycle is required to make the Bluetooth interfaces
recover.
After some investigations, I found that their USB autosuspend remote
wakeup capabilities are so broken that they are precisely the culprit
behind the issue:
[27452.608056] hub 3-0:1.0: state 7 ports 5 chg 0000 evt 0020
[27452.702018] usb 3-5: usb wakeup-resume
[27452.716038] usb 3-5: Waited 0ms for CONNECT
[27452.716642] usb 3-5: finish resume
/* usbmon showed that the device was completely unresponsive to any
URBs after the remote wakeup */
[27457.836030] usb 3-5: retry with reset-resume
[27457.956046] usb 3-5: reset high-speed USB device number 4 using xhci_hcd
[27463.332047] usb 3-5: device descriptor read/64, error -110
[27478.948117] usb 3-5: device descriptor read/64, error -110
[27479.172430] usb 3-5: reset high-speed USB device number 4 using xhci_hcd
[27484.332035] usb 3-5: device descriptor read/64, error -110
[27499.940039] usb 3-5: device descriptor read/64, error -110
[27500.164060] usb 3-5: reset high-speed USB device number 4 using xhci_hcd
[27505.196142] xhci_hcd 0000:67:00.0: Timeout while waiting for setup device command
[27510.576045] xhci_hcd 0000:67:00.0: Timeout while waiting for setup device command
[27510.784038] usb 3-5: device not accepting address 4, error -62
[27510.912215] usb 3-5: reset high-speed USB device number 4 using xhci_hcd
[27515.948307] xhci_hcd 0000:67:00.0: Timeout while waiting for setup device command
[27521.324380] xhci_hcd 0000:67:00.0: Timeout while waiting for setup device command
[27521.525107] usb 3-5: device not accepting address 4, error -62
[27521.525928] usb usb3-port5: logical disconnect
[27521.525996] usb 3-5: gone after usb resume? status -19
[27521.526230] usb 3-5: can't resume, status -19
[27521.526434] usb usb3-port5: logical disconnect
[27521.526469] usb usb3-port5: resume, status -19
[27521.526493] usb usb3-port5: status 0503, change 0004, 480 Mb/s
[27521.526528] usb 3-5: USB disconnect, device number 4
[27521.526736] usb 3-5: unregistering device
[27521.804029] usb 3-5: new high-speed USB device number 5 using xhci_hcd
[27527.076067] usb 3-5: device descriptor read/64, error -110
[27542.692027] usb 3-5: device descriptor read/64, error -110
[27542.916047] usb 3-5: new high-speed USB device number 6 using xhci_hcd
[27548.068043] usb 3-5: device descriptor read/64, error -110
[27563.684073] usb 3-5: device descriptor read/64, error -110
[27563.792133] usb usb3-port5: attempt power cycle
[27563.924381] hub 3-0:1.0: port_wait_reset: err = -11
[27563.925213] usb usb3-port5: not enabled, trying reset again...
[27564.184398] usb 3-5: new high-speed USB device number 7 using xhci_hcd
[27569.196322] xhci_hcd 0000:67:00.0: Timeout while waiting for setup device command
[27574.572040] xhci_hcd 0000:67:00.0: Timeout while waiting for setup device command
[27574.776053] usb 3-5: device not accepting address 7, error -62
[27574.900165] usb 3-5: new high-speed USB device number 8 using xhci_hcd
[27579.948039] xhci_hcd 0000:67:00.0: Timeout while waiting for setup device command
[27585.324331] xhci_hcd 0000:67:00.0: Timeout while waiting for setup device command
[27585.528040] usb 3-5: device not accepting address 8, error -62
[27585.528389] usb usb3-port5: unable to enumerate USB device
[27585.528424] hub 3-0:1.0: state 7 ports 5 chg 0000 evt 0020
To reproduce the issue, these conditions must be met:
- a noisy radio environment (cafe or office) to cause frequent remote
wakeup events
- no Bluetooth device is connected, so autosuspend is not prohibited
- the Bluetooth interface is opened, so remote wakeup is enabled when
the device runs into autosuspend
Then I can reproduce the issue within sereval hours each time.
Increasing TRSMRCY or setting USB_QUIRK_RESET doesn't help at all.
Since the remote wakeup capability is super broken, just disable it to
get rid of the troubles. The device can still be autosuspended when
the bluetooth interface is closed, which won't break the device as
remote wakeup is unneeded in this case.
Link: https://bbs.archlinux.org/viewtopic.php?id=308169
Link: https://bbs.bee-link.com/d/7694-gtr9-pro-ai-max-395-usb-issues
Signed-off-by: Rong Zhang <i@rong.moe>
---
drivers/bluetooth/btmtk.c | 10 ++++++++++
1 file changed, 10 insertions(+)
diff --git a/drivers/bluetooth/btmtk.c b/drivers/bluetooth/btmtk.c
index 8ff66b276af0..3d2a8598892b 100644
--- a/drivers/bluetooth/btmtk.c
+++ b/drivers/bluetooth/btmtk.c
@@ -1379,6 +1379,16 @@ int btmtk_usb_setup(struct hci_dev *hdev)
break;
case 0x7922:
case 0x7925:
+ /*
+ * A remote wakeup could cause the device completely unresponsive, and
+ * recovering from such a state needs a power cycle.
+ *
+ * Since the remote wakeup capability is super broken, just disable it
+ * to get rid of the troubles. The device can still be autosuspended
+ * when the bluetooth interface is closed.
+ */
+ device_set_wakeup_capable(&btmtk_data->udev->dev, false);
+ fallthrough;
case 0x7961:
case 0x7902:
case 0x6639:
---
base-commit: e43ffb69e0438cddd72aaa30898b4dc446f664f8
change-id: a4222333-btmtk-remote-wakeup-494f4c97af88
Thanks,
Rong
^ permalink raw reply related
* [bluez/bluez]
From: BluezTestBot @ 2026-06-02 18:24 UTC (permalink / raw)
To: linux-bluetooth
Branch: refs/heads/1097183
Home: https://github.com/bluez/bluez
To unsubscribe from these emails, change your notification settings at https://github.com/bluez/bluez/settings/notifications
^ permalink raw reply
* [bluez/bluez] 96a51d: client/btpclient: Fix GAP unpair command
From: fdanis-oss @ 2026-06-02 18:23 UTC (permalink / raw)
To: linux-bluetooth
Branch: refs/heads/master
Home: https://github.com/bluez/bluez
Commit: 96a51d53ccf3f3e443c524478c8c697d1a2dd799
https://github.com/bluez/bluez/commit/96a51d53ccf3f3e443c524478c8c697d1a2dd799
Author: Frédéric Danis <frederic.danis@collabora.com>
Date: 2026-06-02 (Tue, 02 Jun 2026)
Changed paths:
M client/btpclient/gap.c
Log Message:
-----------
client/btpclient: Fix GAP unpair command
Fix unpair_reply() because the device is no more available on
RemoveDevice reply.
Commit: 07b6fc156348bb515ac0a876d49644312c9476d6
https://github.com/bluez/bluez/commit/07b6fc156348bb515ac0a876d49644312c9476d6
Author: Frédéric Danis <frederic.danis@collabora.com>
Date: 2026-06-02 (Tue, 02 Jun 2026)
Changed paths:
M client/btpclient/gap.c
Log Message:
-----------
client/btpclient: Don't remove all devices on GAP Reset command
Currently running auto-pts remove all paired devices, instead of just
removing the PTS devices.
This removes this behavior, expecting auto-pts to explicitly remove the
PTS devices using Unpair command.
Compare: https://github.com/bluez/bluez/compare/e2874db00a40...07b6fc156348
To unsubscribe from these emails, change your notification settings at https://github.com/bluez/bluez/settings/notifications
^ permalink raw reply
* Re: [PATCH BlueZ v2 1/2] client/btpclient: Fix GAP unpair command
From: patchwork-bot+bluetooth @ 2026-06-02 17:30 UTC (permalink / raw)
To: =?utf-8?b?RnLDqWTDqXJpYyBEYW5pcyA8ZnJlZGVyaWMuZGFuaXNAY29sbGFib3JhLmNvbT4=?=
Cc: linux-bluetooth
In-Reply-To: <20260519085016.188744-1-frederic.danis@collabora.com>
Hello:
This series was applied to bluetooth/bluez.git (master)
by Luiz Augusto von Dentz <luiz.von.dentz@intel.com>:
On Tue, 19 May 2026 10:50:15 +0200 you wrote:
> Fix unpair_reply() because the device is no more available on
> RemoveDevice reply.
> ---
> client/btpclient/gap.c | 40 +++++++++++++++++++++++-----------------
> 1 file changed, 23 insertions(+), 17 deletions(-)
Here is the summary with links:
- [BlueZ,v2,1/2] client/btpclient: Fix GAP unpair command
https://git.kernel.org/pub/scm/bluetooth/bluez.git/?id=96a51d53ccf3
- [BlueZ,v2,2/2] client/btpclient: Don't remove all devices on GAP Reset command
https://git.kernel.org/pub/scm/bluetooth/bluez.git/?id=07b6fc156348
You are awesome, thank you!
--
Deet-doot-dot, I am a bot.
https://korg.docs.kernel.org/patchwork/pwbot.html
^ permalink raw reply
* Re: [PATCH v2 0/2] Bluetooth: Fix data-races in SCO/ISO connect paths
From: patchwork-bot+bluetooth @ 2026-06-02 17:20 UTC (permalink / raw)
To: SeungJu Cheon
Cc: marcel, luiz.dentz, linux-bluetooth, linux-kernel, me, skhan,
linux-kernel-mentees
In-Reply-To: <20260601111908.232707-1-suunj1331@gmail.com>
Hello:
This series was applied to bluetooth/bluetooth-next.git (master)
by Luiz Augusto von Dentz <luiz.von.dentz@intel.com>:
On Mon, 1 Jun 2026 20:19:06 +0900 you wrote:
> The connect paths read socket address and config fields without
> lock_sock() and pass them to hci_get_route() and hci_connect_*(),
> while connect()/bind()/setsockopt() can update them concurrently.
>
> Patch 1 covers ISO (iso_connect_bis/cis, iso_listen_bis,
> iso_conn_big_sync), patch 2 covers SCO (sco_connect).
>
> [...]
Here is the summary with links:
- [v2,1/2] Bluetooth: ISO: Fix data-race on iso_pi fields in hci_get_route calls
https://git.kernel.org/bluetooth/bluetooth-next/c/961ea93b3ceb
- [v2,2/2] Bluetooth: SCO: Fix data-race on sco_pi fields in sco_connect
https://git.kernel.org/bluetooth/bluetooth-next/c/4a17208f1b99
You are awesome, thank you!
--
Deet-doot-dot, I am a bot.
https://korg.docs.kernel.org/patchwork/pwbot.html
^ permalink raw reply
* Re: [PATCH v2 1/2] Bluetooth: ISO: Fix not releasing hdev reference on iso_conn_big_sync
From: patchwork-bot+bluetooth @ 2026-06-02 17:20 UTC (permalink / raw)
To: Luiz Augusto von Dentz; +Cc: linux-bluetooth
In-Reply-To: <20260601204157.13923-1-luiz.dentz@gmail.com>
Hello:
This series was applied to bluetooth/bluetooth-next.git (master)
by Luiz Augusto von Dentz <luiz.von.dentz@intel.com>:
On Mon, 1 Jun 2026 16:41:56 -0400 you wrote:
> From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
>
> hci_get_route() returns a reference-counted hci_dev pointer via
> hci_dev_hold(). The function exits normally or with an error without ever
> releasing it.
>
> Fixes: 07a9342b94a9 ("Bluetooth: ISO: Send BIG Create Sync via hci_sync")
> Reported-by: Sashiko <sashiko-bot@kernel.org>
> Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
>
> [...]
Here is the summary with links:
- [v2,1/2] Bluetooth: ISO: Fix not releasing hdev reference on iso_conn_big_sync
https://git.kernel.org/bluetooth/bluetooth-next/c/59e3efb116d4
- [v2,2/2] Bluetooth: ISO: Fix a use-after-free of the hci_conn pointer
https://git.kernel.org/bluetooth/bluetooth-next/c/e13696f42ec9
You are awesome, thank you!
--
Deet-doot-dot, I am a bot.
https://korg.docs.kernel.org/patchwork/pwbot.html
^ permalink raw reply
* [PATCH v2] Bluetooth: eir: Fix stack OOB write when prepending the Flags AD
From: Weiming Shi @ 2026-06-02 17:06 UTC (permalink / raw)
To: Marcel Holtmann, Luiz Augusto von Dentz
Cc: Arman Uguray, linux-bluetooth, linux-kernel, Xiang Mei,
Weiming Shi
eir_create_adv_data() builds the advertising data into a fixed-size
buffer ("size", 31 for the legacy path). It may prepend a 3-byte "Flags"
AD structure (LE_AD_NO_BREDR on an LE-only controller) and then copies
the per-instance data without checking that it still fits:
memcpy(ptr, adv->adv_data, adv->adv_data_len);
tlv_data_max_len() only reserves those 3 bytes when the user-supplied
flags carry a managed-flags bit, so an instance added with flags == 0 is
accepted with adv_data_len up to the full buffer. At advertise time the
flags are still prepended, and the memcpy() writes 3 + adv_data_len
bytes into the size-byte buffer:
BUG: KASAN: stack-out-of-bounds in eir_create_adv_data (net/bluetooth/eir.c:301)
Write of size 31 at addr ffff88800a547bdc by task kworker/u9:0/65
Workqueue: hci0 hci_cmd_sync_work
__asan_memcpy (mm/kasan/shadow.c:106)
eir_create_adv_data (net/bluetooth/eir.c:301)
hci_update_adv_data_sync (net/bluetooth/hci_sync.c:1310)
hci_schedule_adv_instance_sync (net/bluetooth/hci_sync.c:1817)
hci_cmd_sync_work (net/bluetooth/hci_sync.c:332)
This frame has 1 object:
[32, 64) 'cp'
The "Flags" structure is added by the kernel, not requested by
userspace, so only prepend it when it fits together with the instance
advertising data; when there is no room for both, drop the flags rather
than the user-provided data.
Reachable by a local user with CAP_NET_ADMIN owning an LE-only
controller on the legacy advertising path.
Fixes: b44133ff03be ("Bluetooth: Support the "discoverable" adv flag")
Reported-by: Xiang Mei <xmei5@asu.edu>
Assisted-by: Claude:claude-opus-4-8
Signed-off-by: Weiming Shi <bestswngs@gmail.com>
---
v2: drop the kernel-added "Flags" AD when it does not fit with the instance data,
instead of dropping the user data .
net/bluetooth/eir.c | 8 +++++---
1 file changed, 5 insertions(+), 3 deletions(-)
diff --git a/net/bluetooth/eir.c b/net/bluetooth/eir.c
index 3f72111ba651..1de5f9df6eec 100644
--- a/net/bluetooth/eir.c
+++ b/net/bluetooth/eir.c
@@ -283,10 +283,12 @@ u8 eir_create_adv_data(struct hci_dev *hdev, u8 instance, u8 *ptr, u8 size)
if (!flags)
flags |= mgmt_get_adv_discov_flags(hdev);
- /* If flags would still be empty, then there is no need to
- * include the "Flags" AD field".
+ /* 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) <= size)) {
+ if (flags &&
+ (ad_len + eir_precalc_len(1) +
+ (adv ? adv->adv_data_len : 0) <= size)) {
ptr[0] = 0x02;
ptr[1] = EIR_FLAGS;
ptr[2] = flags;
--
2.43.0
^ permalink raw reply related
* Re: [PATCH v2] Bluetooth: hci_event: fix simultaneous discovery stuck in FINDING
From: Luiz Augusto von Dentz @ 2026-06-02 16:43 UTC (permalink / raw)
To: Paul Menzel
Cc: Jiajia Liu, Marcel Holtmann, Brian Gix, linux-bluetooth,
linux-kernel, Jiajia Liu
In-Reply-To: <fc5c142e-3187-42a2-af4d-9103858da93e@molgen.mpg.de>
Hi Paul,
On Tue, Jun 2, 2026 at 10:41 AM Paul Menzel <pmenzel@molgen.mpg.de> wrote:
>
> Dear Jiajia,
>
>
> Thank you for your patch.
>
> Am 02.06.26 um 09:00 schrieb Jiajia Liu:
> > When hci_inquiry_complete_evt is called between le_scan_disable and
> > le_set_scan_enable_complete and no remote name needs to be resolved,
> > the interleaved discovery with SIMULTANEOUS quirk gets stuck in
> > DISCOVERY_FINDING. le_set_scan_enable_complete does not check inquiry
> > state. No one sets DISCOVERY_STOPPED in this process.
> >
> > Add state check in le_set_scan_enable_complete and change state if
> > the state is DISCOVERY_FINDING. Tested with AX201 (8087:0026) in Dell
>
> … change state to DISCOVERY_STOPPED …
>
> I’d add a new paragraph for the Tested part.
>
> > Vostro 13. Discovering disabled MGMT Event below is reported when
> > running into the above condition.
>
> Thank you for sharing the test device. Could you please document how to
> get into this state exactly? Some Xiaomi device?
What are you talking about here by saying Xiaom devicei? He literally
said Dell Vostro 13, a laptop, and this is a local only procedure,
there is no remote device involved here.
> > @ MGMT Command: Start Discovery (0x0023) {0x0001} [hci0] 10885.970873
> > Address type: 0x07
> > BR/EDR
> > LE Public
> > LE Random
> > ...
> > < HCI Command: LE Set Extended Scan Enable #38205 [hci0] 10886.131438
> > Extended scan: Enabled (0x01)
> > Filter duplicates: Enabled (0x01)
> > Duration: 0 msec (0x0000)
> > Period: 0.00 sec (0x0000)
> > > HCI Event: Command Complete (0x0e) plen 4 #38206 [hci0] 10886.133295
> > LE Set Extended Scan Enable (0x08|0x0042) ncmd 2
> > Status: Success (0x00)
> > @ MGMT Event: Discovering (0x0013) plen 2 {0x0001} [hci0] 10886.133414
> > Address type: 0x07
> > BR/EDR
> > LE Public
> > LE Random
> > Discovery: Enabled (0x01)
> > < HCI Command: Inquiry (0x01|0x0001) plen 5 #38207 [hci0] 10886.133528
> > Access code: 0x9e8b33 (General Inquiry)
> > Length: 10.24s (0x08)
> > Num responses: 0
> > > HCI Event: Command Status (0x0f) plen 4 #38208 [hci0] 10886.141333
> > Inquiry (0x01|0x0001) ncmd 2
> > Status: Success (0x00)
> > ...
> > < HCI Command: LE Set Extended Scan Enable #38242 [hci0] 10896.381802
> > Extended scan: Disabled (0x00)
> > Filter duplicates: Disabled (0x00)
> > Duration: 0 msec (0x0000)
> > Period: 0.00 sec (0x0000)
> > > HCI Event: Inquiry Complete (0x01) plen 1 #38243 [hci0] 10896.383419
> > Status: Success (0x00)
> > > HCI Event: Command Complete (0x0e) plen 4 #38244 [hci0] 10896.394378
> > LE Set Extended Scan Enable (0x08|0x0042) ncmd 2
> > Status: Success (0x00)
> > @ MGMT Event: Device Found (0x0012) plen 22 {0x0001} [hci0] 10896.394497
> > LE Address: 88:12:AC:92:43:69
> > RSSI: -101 dBm (0x9b)
> > Flags: 0x00000004
> > Not Connectable
> > Data length: 8
> > Company: Xiaomi Inc. (911)
> > Data[0]:
> > 16-bit Service UUIDs (complete): 1 entry
> > Xiaomi Inc. (0xfdaa)
> > @ MGMT Event: Discovering (0x0013) plen 2 {0x0001} [hci0] 10896.394506
> > Address type: 0x07
> > BR/EDR
> > LE Public
> > LE Random
> > Discovery: Disabled (0x00)
> >
> > Fixes: 8ffde2a73f2c ("Bluetooth: Convert le_scan_disable timeout to hci_sync")
> > Signed-off-by: Jiajia Liu <liujiajia@kylinos.cn>
> > ---
> >
> > Changes in v2:
> > - move the handler to hci_event.c
> > - remove unnecessary bt_dev_dbg
> > - update commit message
> >
> > ---
> > net/bluetooth/hci_event.c | 7 +++++++
> > 1 file changed, 7 insertions(+)
> >
> > diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
> > index eea2f810aafa..1cd5f97daafe 100644
> > --- a/net/bluetooth/hci_event.c
> > +++ b/net/bluetooth/hci_event.c
> > @@ -1769,6 +1769,13 @@ static void le_set_scan_enable_complete(struct hci_dev *hdev, u8 enable)
> >
> > hci_dev_clear_flag(hdev, HCI_LE_SCAN);
> >
> > + if (hdev->discovery.type == DISCOV_TYPE_INTERLEAVED &&
> > + hci_test_quirk(hdev, HCI_QUIRK_SIMULTANEOUS_DISCOVERY) &&
> > + !test_bit(HCI_INQUIRY, &hdev->flags) &&
> > + hdev->discovery.state == DISCOVERY_FINDING) {
> > + hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
> > + }
> > +
> > /* The HCI_LE_SCAN_INTERRUPTED flag indicates that we
> > * interrupted scanning due to a connect request. Mark
> > * therefore discovery as stopped.
>
>
> Kind regards,
>
> Paul
--
Luiz Augusto von Dentz
^ permalink raw reply
* Re: [PATCH v8 1/1] Bluetooth: L2CAP: Fix use-after-free in l2cap_sock_new_connection_cb()
From: Luiz Augusto von Dentz @ 2026-06-02 16:33 UTC (permalink / raw)
To: Siwei Zhang; +Cc: Marcel Holtmann, linux-bluetooth
In-Reply-To: <20260602125618.2520506-2-oss@fourdim.xyz>
Hi Siwei,
On Tue, Jun 2, 2026 at 8:56 AM Siwei Zhang <oss@fourdim.xyz> wrote:
>
> l2cap_sock_new_connection_cb() accesses l2cap_pi(sk)->chan after
> release_sock(parent). Once the parent lock is released, the child
> socket sk can be freed by another task.
>
> Allocate the channel outside the func to prevent this.
>
> Fixes: 8ffb929098a5 ("Bluetooth: Remove parent socket usage from l2cap_core.c")
> Cc: stable@kernel.org
> Assisted-by: Claude:claude-opus-4-6
> Signed-off-by: Siwei Zhang <oss@fourdim.xyz>
> ---
> include/net/bluetooth/l2cap.h | 8 ++--
> net/bluetooth/6lowpan.c | 32 +++++++++------
> net/bluetooth/l2cap_core.c | 60 ++++++++++++++++++++-------
> net/bluetooth/l2cap_sock.c | 76 ++++++++++++++++++++++-------------
> net/bluetooth/smp.c | 18 ++++-----
> 5 files changed, 126 insertions(+), 68 deletions(-)
>
> diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h
> index e0a1f2293679..ffd006187324 100644
> --- a/include/net/bluetooth/l2cap.h
> +++ b/include/net/bluetooth/l2cap.h
> @@ -620,7 +620,8 @@ struct l2cap_chan {
> struct l2cap_ops {
> char *name;
>
> - struct l2cap_chan *(*new_connection) (struct l2cap_chan *chan);
> + int (*new_connection)(struct l2cap_chan *chan,
> + struct l2cap_chan *new_chan);
> int (*recv) (struct l2cap_chan * chan,
> struct sk_buff *skb);
> void (*teardown) (struct l2cap_chan *chan, int err);
> @@ -884,9 +885,10 @@ static inline __u16 __next_seq(struct l2cap_chan *chan, __u16 seq)
> return (seq + 1) % (chan->tx_win_max + 1);
> }
>
> -static inline struct l2cap_chan *l2cap_chan_no_new_connection(struct l2cap_chan *chan)
> +static inline int l2cap_chan_no_new_connection(struct l2cap_chan *chan,
> + struct l2cap_chan *new_chan)
> {
> - return NULL;
> + return -EOPNOTSUPP;
> }
>
> static inline int l2cap_chan_no_recv(struct l2cap_chan *chan, struct sk_buff *skb)
> diff --git a/net/bluetooth/6lowpan.c b/net/bluetooth/6lowpan.c
> index cb1e329d66fd..40f118168015 100644
> --- a/net/bluetooth/6lowpan.c
> +++ b/net/bluetooth/6lowpan.c
> @@ -624,6 +624,15 @@ static bool is_bt_6lowpan(struct hci_conn *hcon)
> return true;
> }
>
> +static void chan_init(struct l2cap_chan *chan)
> +{
> + l2cap_chan_set_defaults(chan);
> +
> + chan->chan_type = L2CAP_CHAN_CONN_ORIENTED;
> + chan->mode = L2CAP_MODE_LE_FLOWCTL;
> + chan->imtu = 1280;
> +}
> +
> static struct l2cap_chan *chan_create(void)
> {
> struct l2cap_chan *chan;
> @@ -632,11 +641,7 @@ static struct l2cap_chan *chan_create(void)
> if (!chan)
> return NULL;
>
> - l2cap_chan_set_defaults(chan);
> -
> - chan->chan_type = L2CAP_CHAN_CONN_ORIENTED;
> - chan->mode = L2CAP_MODE_LE_FLOWCTL;
> - chan->imtu = 1280;
> + chan_init(chan);
>
> return chan;
> }
> @@ -745,19 +750,20 @@ static inline void chan_ready_cb(struct l2cap_chan *chan)
> ifup(dev->netdev);
> }
>
> -static inline struct l2cap_chan *chan_new_conn_cb(struct l2cap_chan *pchan)
> +static inline int chan_new_conn_cb(struct l2cap_chan *pchan,
> + struct l2cap_chan *chan)
> {
> - struct l2cap_chan *chan;
> -
> - chan = chan_create();
> - if (!chan)
> - return NULL;
> -
> + chan_init(chan);
> chan->ops = pchan->ops;
>
> + /* Take a reference to match the put in chan_close_cb(). The caller
> + * drops its own local reference after __l2cap_chan_add().
> + */
> + l2cap_chan_hold(chan);
If we are not going to assign to any variable here, I'm not sure I
agree that taking a reference is the best thing to do.
> BT_DBG("chan %p pchan %p", chan, pchan);
>
> - return chan;
> + return 0;
> }
>
> static void unregister_dev(struct lowpan_btle_dev *dev)
> diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
> index c4ccfbda9d78..31fb715fd830 100644
> --- a/net/bluetooth/l2cap_core.c
> +++ b/net/bluetooth/l2cap_core.c
> @@ -4007,6 +4007,36 @@ static inline int l2cap_command_rej(struct l2cap_conn *conn,
> return 0;
> }
>
> +/* Allocate and initialise a channel for an incoming connection. The returned
> + * channel carries the caller's local reference, which must be dropped once
> + * __l2cap_chan_add() has pinned it via the conn list.
> + */
> +static struct l2cap_chan *l2cap_new_connection(struct l2cap_chan *pchan)
> +{
> + struct l2cap_chan *chan;
> +
> + chan = l2cap_chan_create();
> + if (!chan)
> + return NULL;
> +
> + if (pchan->ops->new_connection(pchan, chan) < 0) {
> + l2cap_chan_put(chan);
> + return NULL;
> + }
> +
> + return chan;
> +}
> +
> +/* Link a channel from l2cap_new_connection() into conn and release the local
> + * reference it carried. __l2cap_chan_add() pins the channel via the conn list,
> + * so it remains valid after this returns.
> + */
> +static void l2cap_chan_add_new(struct l2cap_conn *conn, struct l2cap_chan *chan)
> +{
> + __l2cap_chan_add(conn, chan);
> + l2cap_chan_put(chan);
> +}
Couldn't we just make __l2cap_chan_add take ownership of the
reference, instead of doing multiple calls to
l2cap_chan_hold/l2cap_chan_put?
> static void l2cap_connect(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd,
> u8 *data, u8 rsp_code)
> {
> @@ -4053,7 +4083,7 @@ static void l2cap_connect(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd,
> goto response;
> }
>
> - chan = pchan->ops->new_connection(pchan);
> + chan = l2cap_new_connection(pchan);
> if (!chan)
> goto response;
>
> @@ -4071,7 +4101,7 @@ static void l2cap_connect(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd,
> chan->psm = psm;
> chan->dcid = scid;
>
> - __l2cap_chan_add(conn, chan);
> + l2cap_chan_add_new(conn, chan);
>
> dcid = chan->scid;
>
> @@ -4883,6 +4913,7 @@ static int l2cap_le_connect_req(struct l2cap_conn *conn,
> struct l2cap_le_conn_rsp rsp;
> struct l2cap_chan *chan, *pchan;
> u16 dcid, scid, credits, mtu, mps;
> + u16 rsp_mtu, rsp_mps;
> __le16 psm;
> u8 result;
>
> @@ -4895,6 +4926,8 @@ static int l2cap_le_connect_req(struct l2cap_conn *conn,
> psm = req->psm;
> dcid = 0;
> credits = 0;
> + rsp_mtu = 0;
> + rsp_mps = 0;
>
> if (mtu < 23 || mps < 23)
> return -EPROTO;
> @@ -4955,7 +4988,7 @@ static int l2cap_le_connect_req(struct l2cap_conn *conn,
> goto response_unlock;
> }
>
> - chan = pchan->ops->new_connection(pchan);
> + chan = l2cap_new_connection(pchan);
> if (!chan) {
> result = L2CAP_CR_LE_NO_MEM;
> goto response_unlock;
> @@ -4970,12 +5003,14 @@ static int l2cap_le_connect_req(struct l2cap_conn *conn,
> chan->omtu = mtu;
> chan->remote_mps = mps;
>
> - __l2cap_chan_add(conn, chan);
> + l2cap_chan_add_new(conn, chan);
>
> l2cap_le_flowctl_init(chan, __le16_to_cpu(req->credits));
>
> dcid = chan->scid;
> credits = chan->rx_credits;
> + rsp_mtu = chan->imtu;
> + rsp_mps = chan->mps;
>
> __set_chan_timer(chan, chan->ops->get_sndtimeo(chan));
>
> @@ -5003,13 +5038,8 @@ static int l2cap_le_connect_req(struct l2cap_conn *conn,
> return 0;
>
> response:
> - if (chan) {
> - rsp.mtu = cpu_to_le16(chan->imtu);
> - rsp.mps = cpu_to_le16(chan->mps);
> - } else {
> - rsp.mtu = 0;
> - rsp.mps = 0;
> - }
> + rsp.mtu = cpu_to_le16(rsp_mtu);
> + rsp.mps = cpu_to_le16(rsp_mps);
>
> rsp.dcid = cpu_to_le16(dcid);
> rsp.credits = cpu_to_le16(credits);
> @@ -5179,7 +5209,7 @@ static inline int l2cap_ecred_conn_req(struct l2cap_conn *conn,
> continue;
> }
>
> - chan = pchan->ops->new_connection(pchan);
> + chan = l2cap_new_connection(pchan);
> if (!chan) {
> result = L2CAP_CR_LE_NO_MEM;
> continue;
> @@ -5194,7 +5224,7 @@ static inline int l2cap_ecred_conn_req(struct l2cap_conn *conn,
> chan->omtu = mtu;
> chan->remote_mps = mps;
>
> - __l2cap_chan_add(conn, chan);
> + l2cap_chan_add_new(conn, chan);
>
> l2cap_ecred_init(chan, __le16_to_cpu(req->credits));
>
> @@ -7470,14 +7500,14 @@ static void l2cap_connect_cfm(struct hci_conn *hcon, u8 status)
> goto next;
>
> l2cap_chan_lock(pchan);
> - chan = pchan->ops->new_connection(pchan);
> + chan = l2cap_new_connection(pchan);
> if (chan) {
> bacpy(&chan->src, &hcon->src);
> bacpy(&chan->dst, &hcon->dst);
> chan->src_type = bdaddr_src_type(hcon);
> chan->dst_type = dst_type;
>
> - __l2cap_chan_add(conn, chan);
> + l2cap_chan_add_new(conn, chan);
> }
>
> l2cap_chan_unlock(pchan);
> diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c
> index 025329636353..745b012890ee 100644
> --- a/net/bluetooth/l2cap_sock.c
> +++ b/net/bluetooth/l2cap_sock.c
> @@ -46,7 +46,8 @@ static struct bt_sock_list l2cap_sk_list = {
> static const struct proto_ops l2cap_sock_ops;
> static void l2cap_sock_init(struct sock *sk, struct sock *parent);
> static struct sock *l2cap_sock_alloc(struct net *net, struct socket *sock,
> - int proto, gfp_t prio, int kern);
> + int proto, gfp_t prio, int kern,
> + struct l2cap_chan *chan);
> static void l2cap_sock_cleanup_listen(struct sock *parent);
>
> bool l2cap_is_socket(struct socket *sock)
> @@ -1292,18 +1293,25 @@ static int l2cap_sock_recvmsg(struct socket *sock, struct msghdr *msg,
> */
> static void l2cap_sock_kill(struct sock *sk)
> {
> + struct l2cap_chan *chan = l2cap_pi(sk)->chan;
> +
> if (!sock_flag(sk, SOCK_ZAPPED) || sk->sk_socket)
> return;
>
> BT_DBG("sk %p state %s", sk, state_to_string(sk->sk_state));
>
> - /* Sock is dead, so set chan data to NULL, avoid other task use invalid
> - * sock pointer.
> + /* Release the sock's ref on chan and clear the pointer so that
> + * l2cap_sock_destruct() does not drop it a second time. Setting
> + * chan->data to NULL first stops any other task from dereferencing
> + * the now-dead sock pointer.
> */
> - l2cap_pi(sk)->chan->data = NULL;
> - /* Kill poor orphan */
> + if (chan) {
> + chan->data = NULL;
> + l2cap_pi(sk)->chan = NULL;
> + l2cap_chan_put(chan);
> + }
>
> - l2cap_chan_put(l2cap_pi(sk)->chan);
> + /* Kill poor orphan */
> sock_set_flag(sk, SOCK_DEAD);
> sock_put(sk);
> }
> @@ -1383,7 +1391,9 @@ static int l2cap_sock_shutdown(struct socket *sock, int how)
> sock_hold(sk);
>
> /* prevent chan structure from being freed whilst unlocked */
> - chan = l2cap_chan_hold_unless_zero(l2cap_pi(sk)->chan);
> + chan = l2cap_pi(sk)->chan;
> + if (chan)
> + chan = l2cap_chan_hold_unless_zero(chan);
l2cap_chan_hold_unless_zero already handles !chan so no need to change
anything here.
> if (!chan)
> goto shutdown_already;
>
> @@ -1546,12 +1556,13 @@ static void l2cap_sock_cleanup_listen(struct sock *parent)
> }
> }
>
> -static struct l2cap_chan *l2cap_sock_new_connection_cb(struct l2cap_chan *chan)
> +static int l2cap_sock_new_connection_cb(struct l2cap_chan *chan,
> + struct l2cap_chan *new_chan)
> {
> struct sock *sk, *parent = chan->data;
>
> if (!parent)
> - return NULL;
> + return -EINVAL;
>
> lock_sock(parent);
>
> @@ -1559,15 +1570,15 @@ static struct l2cap_chan *l2cap_sock_new_connection_cb(struct l2cap_chan *chan)
> if (sk_acceptq_is_full(parent)) {
> BT_DBG("backlog full %d", parent->sk_ack_backlog);
> release_sock(parent);
> - return NULL;
> + return -ENOBUFS;
> }
>
> sk = l2cap_sock_alloc(sock_net(parent), NULL, BTPROTO_L2CAP,
> - GFP_ATOMIC, 0);
> + GFP_ATOMIC, 0, new_chan);
> if (!sk) {
> release_sock(parent);
> - return NULL;
> - }
> + return -ENOMEM;
> + }
>
> bt_sock_reclassify_lock(sk, BTPROTO_L2CAP);
>
> @@ -1577,7 +1588,7 @@ static struct l2cap_chan *l2cap_sock_new_connection_cb(struct l2cap_chan *chan)
>
> release_sock(parent);
>
> - return l2cap_pi(sk)->chan;
> + return 0;
> }
>
> static int l2cap_sock_recv_cb(struct l2cap_chan *chan, struct sk_buff *skb)
> @@ -1875,8 +1886,11 @@ static void l2cap_sock_destruct(struct sock *sk)
> BT_DBG("sk %p", sk);
>
> if (l2cap_pi(sk)->chan) {
> - l2cap_pi(sk)->chan->data = NULL;
> - l2cap_chan_put(l2cap_pi(sk)->chan);
> + struct l2cap_chan *chan = l2cap_pi(sk)->chan;
> +
> + chan->data = NULL;
> + l2cap_pi(sk)->chan = NULL;
> + l2cap_chan_put(chan);
> }
>
> list_for_each_entry_safe(rx_busy, next, &l2cap_pi(sk)->rx_busy, list) {
> @@ -1978,10 +1992,10 @@ static struct proto l2cap_proto = {
> };
>
> static struct sock *l2cap_sock_alloc(struct net *net, struct socket *sock,
> - int proto, gfp_t prio, int kern)
> + int proto, gfp_t prio, int kern,
> + struct l2cap_chan *chan)
> {
> struct sock *sk;
> - struct l2cap_chan *chan;
>
> sk = bt_sock_alloc(net, sock, &l2cap_proto, proto, prio, kern);
> if (!sk)
> @@ -1992,14 +2006,11 @@ static struct sock *l2cap_sock_alloc(struct net *net, struct socket *sock,
>
> INIT_LIST_HEAD(&l2cap_pi(sk)->rx_busy);
>
> - chan = l2cap_chan_create();
> - if (!chan) {
> - sk_free(sk);
> - if (sock)
> - sock->sk = NULL;
> - return NULL;
> - }
> -
> + /* The sock owns a single ref on chan. It is released by whichever of
> + * l2cap_sock_kill() or l2cap_sock_destruct() runs first; that path
> + * clears l2cap_pi(sk)->chan so the ref is dropped exactly once. The
> + * caller keeps its own ref independent of this one.
> + */
> l2cap_chan_hold(chan);
>
> l2cap_pi(sk)->chan = chan;
> @@ -2011,6 +2022,7 @@ static int l2cap_sock_create(struct net *net, struct socket *sock, int protocol,
> int kern)
> {
> struct sock *sk;
> + struct l2cap_chan *chan;
>
> BT_DBG("sock %p", sock);
>
> @@ -2025,9 +2037,17 @@ static int l2cap_sock_create(struct net *net, struct socket *sock, int protocol,
>
> sock->ops = &l2cap_sock_ops;
>
> - sk = l2cap_sock_alloc(net, sock, protocol, GFP_ATOMIC, kern);
> - if (!sk)
> + chan = l2cap_chan_create();
> + if (!chan)
> + return -ENOMEM;
> +
> + sk = l2cap_sock_alloc(net, sock, protocol, GFP_ATOMIC, kern, chan);
> + if (!sk) {
> + l2cap_chan_put(chan);
> return -ENOMEM;
> + }
> + /* Sock has taken its own refs on chan; drop the chan_create() ref. */
> + l2cap_chan_put(chan);
We can probably eliminate another pair of
l2cap_chan_hold/l2cap_chan_put here as well, just take the ownership
when doing l2cap_pi(sk)->chan = chan;, except if we are trying to
prevent use after free but until l2cap_chan is attached to a sk that
should be probably safe.
>
> l2cap_sock_init(sk, NULL);
> bt_sock_link(&l2cap_sk_list, sk);
> diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c
> index 1739c1989dbd..887a2fc34391 100644
> --- a/net/bluetooth/smp.c
> +++ b/net/bluetooth/smp.c
> @@ -3204,16 +3204,11 @@ static const struct l2cap_ops smp_chan_ops = {
> .get_sndtimeo = l2cap_chan_no_get_sndtimeo,
> };
>
> -static inline struct l2cap_chan *smp_new_conn_cb(struct l2cap_chan *pchan)
> +static inline int smp_new_conn_cb(struct l2cap_chan *pchan,
> + struct l2cap_chan *chan)
> {
> - struct l2cap_chan *chan;
> -
> BT_DBG("pchan %p", pchan);
>
> - chan = l2cap_chan_create();
> - if (!chan)
> - return NULL;
> -
> chan->chan_type = pchan->chan_type;
> chan->ops = &smp_chan_ops;
> chan->scid = pchan->scid;
> @@ -3229,9 +3224,14 @@ static inline struct l2cap_chan *smp_new_conn_cb(struct l2cap_chan *pchan)
> */
> atomic_set(&chan->nesting, L2CAP_NESTING_SMP);
>
> - BT_DBG("created chan %p", chan);
> + /* Take a reference to match the put in smp_teardown_cb(). The caller
> + * drops its own local reference after __l2cap_chan_add().
> + */
> + l2cap_chan_hold(chan);
Ditto, if we are not attaching to a field of the sk then we shouldn't
need to hold a reference.
> - return chan;
> + BT_DBG("initialised chan %p", chan);
> +
> + return 0;
> }
>
> static const struct l2cap_ops smp_root_chan_ops = {
> --
> 2.54.0
>
--
Luiz Augusto von Dentz
^ permalink raw reply
* Re: [PATCH bluetooth] Bluetooth: eir: Fix stack OOB write in eir_create_adv_data()
From: Weiming Shi @ 2026-06-02 16:14 UTC (permalink / raw)
To: Luiz Augusto von Dentz
Cc: linux-bluetooth, Marcel Holtmann, linux-kernel, Xiang Mei
In-Reply-To: <CABBYNZKmodLjPqOCtmY9R-4OccC2vBV=pDQfwY9vCFbwZo+LtQ@mail.gmail.com>
On 26-06-01 13:38, Luiz Augusto von Dentz wrote:
> Hi Xiang,
>
> On Mon, Jun 1, 2026 at 12:22 PM Xiang Mei <bestswngs@gmail.com> wrote:
> >
> > From: Weiming Shi <bestswngs@gmail.com>
> >
> > eir_create_adv_data() builds the advertising data into a fixed-size
> > buffer of "size" bytes (31 for the legacy path in hci_set_adv_data_sync()).
> > It may prepend a 3-byte "Flags" AD structure, but the per-instance
> > advertising data is then copied without checking that it still fits:
> >
> > skip_flags:
> > if (adv) {
> > memcpy(ptr, adv->adv_data, adv->adv_data_len);
> >
> > The "Flags" structure is added whenever BR/EDR is disabled
> > (LE_AD_NO_BREDR), which is the normal state for an LE-only controller.
> > However, the mgmt length validator tlv_data_max_len() only reserves
> > those 3 bytes when the user-supplied adv_flags carries a managed-flags
> > bit (DISCOV / LIMITED_DISCOV / MANAGED_FLAGS). Adding an instance with
> > flags == 0 reserves nothing, so adv_data_len is accepted up to the full
> > buffer size. At advertise time the 3 flag bytes are still prepended,
> > and the subsequent memcpy() writes 3 + adv_data_len bytes into the
> > size-byte buffer, overflowing it by the attacker-controlled tail of
> > adv_data:
> >
> > BUG: KASAN: stack-out-of-bounds in eir_create_adv_data (net/bluetooth/eir.c:302)
> > Write of size 31 at addr ffff88800b7e7bac by task kworker/u9:0/51
> > Workqueue: hci0 hci_cmd_sync_work
> > __asan_memcpy (mm/kasan/shadow.c:106)
> > eir_create_adv_data (net/bluetooth/eir.c:302)
> > hci_update_adv_data_sync (net/bluetooth/hci_sync.c:1689)
> > hci_schedule_adv_instance_sync (net/bluetooth/hci_sync.c:2015)
> > hci_cmd_sync_work (net/bluetooth/hci_sync.c:332)
> > This frame has 1 object:
> > [32, 64) 'cp'
>
> Add the btmon trace of the MGMT command when this is triggered, and
> explaing how the advertisement was created, as with bluetoothd?
>
> > The inconsistency dates back to when the managed "Flags" field was first
> > added to the Add Advertising path: the prepended LE_AD_NO_BREDR flag does
> > not depend on the user-supplied adv_flags, but tlv_data_is_valid() only
> > reserved room when MGMT_ADV_FLAG_DISCOV was set. Commit 47c03902269a
> > ("Bluetooth: eir: Fix possible crashes on eir_create_adv_data") later
> > added the "size" argument and bounds-checked the "Flags" and "Tx Power"
> > AD structures, but left this copy unguarded. Guard it the same way so
> > the data is only copied when it fits.
> >
> > The bug is reachable by a local user with CAP_NET_ADMIN that owns an
> > LE-only controller using the legacy advertising path.
> >
> > Fixes: b44133ff03be ("Bluetooth: Support the "discoverable" adv flag")
> > Reported-by: Xiang Mei <xmei5@asu.edu>
> > Assisted-by: Claude:claude-opus-4-8
> > Signed-off-by: Weiming Shi <bestswngs@gmail.com>
> > ---
> > net/bluetooth/eir.c | 2 +-
> > 1 file changed, 1 insertion(+), 1 deletion(-)
> >
> > diff --git a/net/bluetooth/eir.c b/net/bluetooth/eir.c
> > index 3f72111ba651..e574f8f61e16 100644
> > --- a/net/bluetooth/eir.c
> > +++ b/net/bluetooth/eir.c
> > @@ -297,7 +297,7 @@ u8 eir_create_adv_data(struct hci_dev *hdev, u8 instance, u8 *ptr, u8 size)
> > }
> >
> > skip_flags:
> > - if (adv) {
> > + if (adv && ad_len + adv->adv_data_len <= size) {
>
> So we have 2 options: 1) Don't add flags if there is no space, or 2)
> Don't add the user provided data. We should probably choose option 1,
> not option 2 since option 2 probably means the advertisement is
> useless.
>
> > memcpy(ptr, adv->adv_data, adv->adv_data_len);
> > ad_len += adv->adv_data_len;
> > ptr += adv->adv_data_len;
> > --
> > 2.43.0
> >
>
>
> --
> Luiz Augusto von Dentz
Thanks. Agreed on option 1. I'll send v2 implementing that shortly.
^ permalink raw reply
* RE: Bluetooth: L2CAP: Fix use-after-free in l2cap_sock_new_connection_cb()
From: bluez.test.bot @ 2026-06-02 15:27 UTC (permalink / raw)
To: linux-bluetooth, oss
In-Reply-To: <20260602125618.2520506-2-oss@fourdim.xyz>
[-- Attachment #1: Type: text/plain, Size: 1150 bytes --]
This is automated email and please do not reply to this email!
Dear submitter,
Thank you for submitting the patches to the linux bluetooth mailing list.
This is a CI test results with your patch series:
PW Link:https://patchwork.kernel.org/project/bluetooth/list/?series=1104625
---Test result---
Test Summary:
CheckPatch PASS 2.73 seconds
VerifyFixes PASS 0.12 seconds
VerifySignedoff PASS 0.12 seconds
GitLint PASS 0.30 seconds
SubjectPrefix PASS 0.11 seconds
BuildKernel PASS 25.05 seconds
CheckAllWarning PASS 27.86 seconds
CheckSparse PASS 26.23 seconds
BuildKernel32 PASS 24.55 seconds
TestRunnerSetup PASS 535.77 seconds
TestRunner_l2cap-tester PASS 59.84 seconds
TestRunner_smp-tester PASS 23.74 seconds
TestRunner_6lowpan-tester PASS 23.40 seconds
IncrementalBuild PASS 24.33 seconds
https://github.com/bluez/bluetooth-next/pull/273
---
Regards,
Linux Bluetooth
^ permalink raw reply
* RE: Bluetooth: btusb: Add support for TP-Link TL-UB250
From: bluez.test.bot @ 2026-06-02 15:24 UTC (permalink / raw)
To: linux-bluetooth, cxs1494089474
In-Reply-To: <20260602135419.3092500-1-cxs1494089474@gmail.com>
[-- Attachment #1: Type: text/plain, Size: 1666 bytes --]
This is automated email and please do not reply to this email!
Dear submitter,
Thank you for submitting the patches to the linux bluetooth mailing list.
This is a CI test results with your patch series:
PW Link:https://patchwork.kernel.org/project/bluetooth/list/?series=1104655
---Test result---
Test Summary:
CheckPatch FAIL 1.09 seconds
VerifyFixes PASS 0.12 seconds
VerifySignedoff PASS 0.12 seconds
GitLint PASS 0.31 seconds
SubjectPrefix PASS 0.12 seconds
BuildKernel PASS 25.93 seconds
CheckAllWarning PASS 28.33 seconds
CheckSparse PASS 26.99 seconds
BuildKernel32 PASS 24.85 seconds
TestRunnerSetup PASS 527.95 seconds
IncrementalBuild PASS 24.62 seconds
Details
##############################
Test: CheckPatch - FAIL
Desc: Run checkpatch.pl script
Output:
Bluetooth: btusb: Add support for TP-Link TL-UB250
WARNING: The commit message has 'stable@', perhaps it also needs a 'Fixes:' tag?
total: 0 errors, 1 warnings, 8 lines checked
NOTE: For some of the reported defects, checkpatch may be able to
mechanically convert to the typical style using --fix or --fix-inplace.
/github/workspace/src/patch/14607133.patch has style problems, please review.
NOTE: Ignored message types: UNKNOWN_COMMIT_ID
NOTE: If any of the errors are false positives, please report
them to the maintainer, see CHECKPATCH in MAINTAINERS.
https://github.com/bluez/bluetooth-next/pull/274
---
Regards,
Linux Bluetooth
^ permalink raw reply
* Re: [BlueZ PATCH 1/1] shared/bap: add ASE Control Point error responses
From: Luiz Augusto von Dentz @ 2026-06-02 15:01 UTC (permalink / raw)
To: raghu447; +Cc: linux-bluetooth
In-Reply-To: <20260602082925.7061-2-raghavendra.rao@collabora.com>
Hi Raghu,
On Tue, Jun 2, 2026 at 4:35 AM raghu447 <raghavendra.rao@collabora.com> wrote:
>
> From: raghavendra <raghavendra.rao@collabora.com>
>
> These changes are required to Pass BAP/USR/SPE/BI-01[5]-C tests.
> ---
> src/shared/bap.c | 78 ++++++++++++++++++++++++++++++++++++++++++++++--
> 1 file changed, 76 insertions(+), 2 deletions(-)
>
> diff --git a/src/shared/bap.c b/src/shared/bap.c
> index 8fc2fb14d..ce56efbb2 100644
> --- a/src/shared/bap.c
> +++ b/src/shared/bap.c
> @@ -3304,6 +3304,33 @@ static uint8_t stream_enable(struct bt_bap_stream *stream, struct iovec *meta,
> return 0;
> }
>
> +static bool ascs_metadata_rsp(struct bt_bap_endpoint *ep, struct iovec *meta,
> + struct iovec *rsp)
> +{
> + struct bt_ltv *ltv;
> + uint16_t context;
> +
> + ltv = meta->iov_base;
> + if (meta->iov_len >= sizeof(*ltv) && ltv->type == 0xfc) {
What is this for? Why is it checking for type 0xfc?
> + ascs_ase_rsp_add(rsp, ep->id,
> + BT_ASCS_RSP_METADATA_UNSUPPORTED, ltv->type);
> + return true;
> + }
> +
> + if (meta->iov_len >= sizeof(*ltv) + sizeof(context) &&
> + ltv->type == 0x02 && ltv->len == 0x03) {
> + context = get_le16(ltv->value);
> + if (!context || (context & 0xf000)) {
> + ascs_ase_rsp_add(rsp, ep->id,
> + BT_ASCS_RSP_METADATA_INVALID,
> + ltv->type);
This seems to check if the metadata is a context and then checks if
it's setting undefined bits. I'm not sure if this will age well,
though, because the moment any of those bits are defined, this check
will become invalid. Perhaps the intent is to check if the context is
set to a value outside the supported contexts, in which case it should
be rejected? But then we shouldn't hardcode 0xf000, instead we should
probably use something like: ~supported_context.
> + return true;
> + }
> + }
> +
> + return false;
> +}
> +
> static uint8_t ep_enable(struct bt_bap_endpoint *ep, struct bt_bap *bap,
> struct bt_ascs_enable *req, struct iovec *iov,
> struct iovec *rsp)
> @@ -3335,6 +3362,9 @@ static uint8_t ep_enable(struct bt_bap_endpoint *ep, struct bt_bap *bap,
> return 0;
> }
>
> + if (ascs_metadata_rsp(ep, &meta, rsp))
> + return 0;
> +
> if (!ep->stream) {
> DBG(bap, "No stream found");
> ascs_ase_rsp_add(rsp, ep->id,
> @@ -3568,6 +3598,9 @@ static uint8_t ep_metadata(struct bt_bap_endpoint *ep,
> meta.iov_base = util_iov_pull_mem(iov, req->len);
> meta.iov_len = req->len;
>
> + if (ascs_metadata_rsp(ep, &meta, rsp))
> + return 0;
> +
> return stream_metadata(ep->stream, &meta, rsp);
> }
>
> @@ -3673,6 +3706,23 @@ static struct iovec *ascs_ase_cp_rsp_new(uint8_t op)
> return iov;
> }
>
> +static void ascs_ase_cp_rsp_add_truncated(struct iovec *rsp)
> +{
> + ascs_ase_rsp_add_errno(rsp, 0x00, -ENOMSG);
> +}
> +
> +static bool ascs_ase_cp_rsp_invalid_len(uint8_t op, size_t len, uint8_t num)
> +{
> + switch (op) {
> + case BT_ASCS_METADATA:
> + return len == num;
> + case BT_ASCS_RELEASE:
> + return true;
> + default:
> + return false;
> + }
> +}
> +
> static void ascs_ase_cp_write(struct gatt_db_attribute *attrib,
> unsigned int id, uint16_t offset,
> const uint8_t *value, size_t len,
> @@ -3697,7 +3747,7 @@ static void ascs_ase_cp_write(struct gatt_db_attribute *attrib,
> return;
> }
>
> - if (len < sizeof(*hdr)) {
> + if (!len) {
> DBG(bap, "invalid len %u < %u sizeof(*hdr)", len,
> sizeof(*hdr));
> gatt_db_attribute_write_result(attrib, id,
> @@ -3705,9 +3755,26 @@ static void ascs_ase_cp_write(struct gatt_db_attribute *attrib,
> return;
> }
>
> + if (len < sizeof(*hdr)) {
> + DBG(bap, "invalid len %u < %u sizeof(*hdr)", len,
> + sizeof(*hdr));
> +
> + rsp = ascs_ase_cp_rsp_new(value[0]);
> + ascs_ase_cp_rsp_add_truncated(rsp);
> + ret = 0;
> + goto respond;
> + }
> +
> hdr = util_iov_pull_mem(&iov, sizeof(*hdr));
> rsp = ascs_ase_cp_rsp_new(hdr->op);
>
> + if (!hdr->num) {
> + DBG(bap, "invalid Number_of_ASEs 0");
> + ascs_ase_cp_rsp_add_truncated(rsp);
> + ret = 0;
> + goto respond;
> + }
> +
> for (handler = handlers; handler && handler->str; handler++) {
> if (handler->op != hdr->op)
> continue;
> @@ -3716,7 +3783,14 @@ static void ascs_ase_cp_write(struct gatt_db_attribute *attrib,
> DBG(bap, "invalid len %u < %u "
> "hdr->num * handler->size", len,
> hdr->num * handler->size);
> - ret = BT_ATT_ERROR_INVALID_ATTRIBUTE_VALUE_LEN;
> +
> + if (ascs_ase_cp_rsp_invalid_len(hdr->op, iov.iov_len,
> + hdr->num)) {
> + ascs_ase_cp_rsp_add_truncated(rsp);
> + ret = 0;
> + } else
> + ret = BT_ATT_ERROR_INVALID_ATTRIBUTE_VALUE_LEN;
> +
> goto respond;
> }
>
>
--
Luiz Augusto von Dentz
^ permalink raw reply
* Re: [BlueZ PATCH 0/1] shared/bap: add ASE Control Point error responses
From: Luiz Augusto von Dentz @ 2026-06-02 14:53 UTC (permalink / raw)
To: raghu447; +Cc: linux-bluetooth
In-Reply-To: <20260602082925.7061-1-raghavendra.rao@collabora.com>
Hi Raghu,
On Tue, Jun 2, 2026 at 4:35 AM raghu447 <raghavendra.rao@collabora.com> wrote:
>
> This patch adds the responses that are expected by PTS.
> These changes are requited to Pass PTS tests BAP/USR/SPE/BI-01[5]-C.
Hmm, it doesn't look like we have any SPE test case captured in
unit/test-bap.c, maybe we should start with that.
> raghavendra (1):
> shared/bap: add ASE Control Point error responses
>
> src/shared/bap.c | 78 ++++++++++++++++++++++++++++++++++++++++++++++--
> 1 file changed, 76 insertions(+), 2 deletions(-)
>
>
--
Luiz Augusto von Dentz
^ permalink raw reply
* Re: [PATCH v2] Bluetooth: hci_event: fix simultaneous discovery stuck in FINDING
From: Paul Menzel @ 2026-06-02 14:40 UTC (permalink / raw)
To: Jiajia Liu
Cc: Marcel Holtmann, Luiz Augusto von Dentz, Brian Gix,
linux-bluetooth, linux-kernel, Jiajia Liu
In-Reply-To: <20260602070032.51248-1-liujiajia@kylinos.cn>
Dear Jiajia,
Thank you for your patch.
Am 02.06.26 um 09:00 schrieb Jiajia Liu:
> When hci_inquiry_complete_evt is called between le_scan_disable and
> le_set_scan_enable_complete and no remote name needs to be resolved,
> the interleaved discovery with SIMULTANEOUS quirk gets stuck in
> DISCOVERY_FINDING. le_set_scan_enable_complete does not check inquiry
> state. No one sets DISCOVERY_STOPPED in this process.
>
> Add state check in le_set_scan_enable_complete and change state if
> the state is DISCOVERY_FINDING. Tested with AX201 (8087:0026) in Dell
… change state to DISCOVERY_STOPPED …
I’d add a new paragraph for the Tested part.
> Vostro 13. Discovering disabled MGMT Event below is reported when
> running into the above condition.
Thank you for sharing the test device. Could you please document how to
get into this state exactly? Some Xiaomi device?
> @ MGMT Command: Start Discovery (0x0023) {0x0001} [hci0] 10885.970873
> Address type: 0x07
> BR/EDR
> LE Public
> LE Random
> ...
> < HCI Command: LE Set Extended Scan Enable #38205 [hci0] 10886.131438
> Extended scan: Enabled (0x01)
> Filter duplicates: Enabled (0x01)
> Duration: 0 msec (0x0000)
> Period: 0.00 sec (0x0000)
> > HCI Event: Command Complete (0x0e) plen 4 #38206 [hci0] 10886.133295
> LE Set Extended Scan Enable (0x08|0x0042) ncmd 2
> Status: Success (0x00)
> @ MGMT Event: Discovering (0x0013) plen 2 {0x0001} [hci0] 10886.133414
> Address type: 0x07
> BR/EDR
> LE Public
> LE Random
> Discovery: Enabled (0x01)
> < HCI Command: Inquiry (0x01|0x0001) plen 5 #38207 [hci0] 10886.133528
> Access code: 0x9e8b33 (General Inquiry)
> Length: 10.24s (0x08)
> Num responses: 0
> > HCI Event: Command Status (0x0f) plen 4 #38208 [hci0] 10886.141333
> Inquiry (0x01|0x0001) ncmd 2
> Status: Success (0x00)
> ...
> < HCI Command: LE Set Extended Scan Enable #38242 [hci0] 10896.381802
> Extended scan: Disabled (0x00)
> Filter duplicates: Disabled (0x00)
> Duration: 0 msec (0x0000)
> Period: 0.00 sec (0x0000)
> > HCI Event: Inquiry Complete (0x01) plen 1 #38243 [hci0] 10896.383419
> Status: Success (0x00)
> > HCI Event: Command Complete (0x0e) plen 4 #38244 [hci0] 10896.394378
> LE Set Extended Scan Enable (0x08|0x0042) ncmd 2
> Status: Success (0x00)
> @ MGMT Event: Device Found (0x0012) plen 22 {0x0001} [hci0] 10896.394497
> LE Address: 88:12:AC:92:43:69
> RSSI: -101 dBm (0x9b)
> Flags: 0x00000004
> Not Connectable
> Data length: 8
> Company: Xiaomi Inc. (911)
> Data[0]:
> 16-bit Service UUIDs (complete): 1 entry
> Xiaomi Inc. (0xfdaa)
> @ MGMT Event: Discovering (0x0013) plen 2 {0x0001} [hci0] 10896.394506
> Address type: 0x07
> BR/EDR
> LE Public
> LE Random
> Discovery: Disabled (0x00)
>
> Fixes: 8ffde2a73f2c ("Bluetooth: Convert le_scan_disable timeout to hci_sync")
> Signed-off-by: Jiajia Liu <liujiajia@kylinos.cn>
> ---
>
> Changes in v2:
> - move the handler to hci_event.c
> - remove unnecessary bt_dev_dbg
> - update commit message
>
> ---
> net/bluetooth/hci_event.c | 7 +++++++
> 1 file changed, 7 insertions(+)
>
> diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
> index eea2f810aafa..1cd5f97daafe 100644
> --- a/net/bluetooth/hci_event.c
> +++ b/net/bluetooth/hci_event.c
> @@ -1769,6 +1769,13 @@ static void le_set_scan_enable_complete(struct hci_dev *hdev, u8 enable)
>
> hci_dev_clear_flag(hdev, HCI_LE_SCAN);
>
> + if (hdev->discovery.type == DISCOV_TYPE_INTERLEAVED &&
> + hci_test_quirk(hdev, HCI_QUIRK_SIMULTANEOUS_DISCOVERY) &&
> + !test_bit(HCI_INQUIRY, &hdev->flags) &&
> + hdev->discovery.state == DISCOVERY_FINDING) {
> + hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
> + }
> +
> /* The HCI_LE_SCAN_INTERRUPTED flag indicates that we
> * interrupted scanning due to a connect request. Mark
> * therefore discovery as stopped.
Kind regards,
Paul
^ permalink raw reply
* Re: [PATCH v2] profile: Set L2CAP IMTU for external profile listeners
From: Luiz Augusto von Dentz @ 2026-06-02 14:42 UTC (permalink / raw)
To: Wei Deng; +Cc: linux-bluetooth
In-Reply-To: <CABBYNZ+vSQWjJyajPxoBs3endFOkU2JGOFoBKvePu8YvZSMEXQ@mail.gmail.com>
Hi,
On Tue, Jun 2, 2026 at 10:21 AM Luiz Augusto von Dentz
<luiz.dentz@gmail.com> wrote:
>
> Hi,
>
> On Mon, Jun 1, 2026 at 11:18 PM Wei Deng <wei.deng@oss.qualcomm.com> wrote:
> >
> > bt_io_listen() in ext_start_servers() creates the L2CAP listening
> > socket for external profiles without an explicit IMTU. This causes
> > the socket to use the L2CAP minimum of 672 bytes, which is advertised
> > to the peer in L2CAP_CONFIGURATION_RSP.
> >
> > As a result, when acting as a server (receiver), the peer limits its
> > outgoing PDU size to our advertised 672 bytes. This leads to small
> > OBEX body chunks (~669 bytes) and severely degraded Rx throughput,
> > while Tx throughput is unaffected since the peer's IMTU is not
> > constrained by our setting.
> >
> > The obexd client side (obexd/client/bluetooth.c) already sets IMTU to
> > BT_RX_MTU (32767) for outgoing connections. Mirror that on the server
> > side by setting BT_IO_OPT_IMTU to BT_RX_MTU in ext_start_servers(),
> > so incoming connections advertise the same maximum receive capability.
> >
> > Signed-off-by: Wei Deng <wei.deng@oss.qualcomm.com>
> > ---
> > src/profile.c | 3 +++
> > 1 file changed, 3 insertions(+)
> >
> > diff --git a/src/profile.c b/src/profile.c
> > index dfc5f7161..297959f3c 100644
> > --- a/src/profile.c
> > +++ b/src/profile.c
> > @@ -55,6 +55,8 @@
> > #define MAS_DEFAULT_CHANNEL 16
> > #define MNS_DEFAULT_CHANNEL 17
> >
> > +#define BT_RX_MTU 32767
> > +
> > #define BTD_PROFILE_PSM_AUTO -1
> > #define BTD_PROFILE_CHAN_AUTO -1
> >
> > @@ -1411,6 +1413,7 @@ static uint32_t ext_start_servers(struct ext_profile *ext,
> > BT_IO_OPT_MODE, ext->mode,
> > BT_IO_OPT_PSM, psm,
> > BT_IO_OPT_SEC_LEVEL, ext->sec_level,
> > + BT_IO_OPT_IMTU, BT_RX_MTU,
>
> This is doing it for all service registered via ProfileManager which
> is not going to fly, instead we probably need to add a MTU option so
> the profile entity can pass it instead of getting the default.
Actually there are no options, it's built from `default_setting`,
which doesn't set any MTU for some reason. For the OBEX profiles it
probably makes sense to add an MTU field so it gets properly set.
^ permalink raw reply
* Re: [PATCH v2] profile: Set L2CAP IMTU for external profile listeners
From: Luiz Augusto von Dentz @ 2026-06-02 14:21 UTC (permalink / raw)
To: Wei Deng; +Cc: linux-bluetooth
In-Reply-To: <20260602031719.679979-1-wei.deng@oss.qualcomm.com>
Hi,
On Mon, Jun 1, 2026 at 11:18 PM Wei Deng <wei.deng@oss.qualcomm.com> wrote:
>
> bt_io_listen() in ext_start_servers() creates the L2CAP listening
> socket for external profiles without an explicit IMTU. This causes
> the socket to use the L2CAP minimum of 672 bytes, which is advertised
> to the peer in L2CAP_CONFIGURATION_RSP.
>
> As a result, when acting as a server (receiver), the peer limits its
> outgoing PDU size to our advertised 672 bytes. This leads to small
> OBEX body chunks (~669 bytes) and severely degraded Rx throughput,
> while Tx throughput is unaffected since the peer's IMTU is not
> constrained by our setting.
>
> The obexd client side (obexd/client/bluetooth.c) already sets IMTU to
> BT_RX_MTU (32767) for outgoing connections. Mirror that on the server
> side by setting BT_IO_OPT_IMTU to BT_RX_MTU in ext_start_servers(),
> so incoming connections advertise the same maximum receive capability.
>
> Signed-off-by: Wei Deng <wei.deng@oss.qualcomm.com>
> ---
> src/profile.c | 3 +++
> 1 file changed, 3 insertions(+)
>
> diff --git a/src/profile.c b/src/profile.c
> index dfc5f7161..297959f3c 100644
> --- a/src/profile.c
> +++ b/src/profile.c
> @@ -55,6 +55,8 @@
> #define MAS_DEFAULT_CHANNEL 16
> #define MNS_DEFAULT_CHANNEL 17
>
> +#define BT_RX_MTU 32767
> +
> #define BTD_PROFILE_PSM_AUTO -1
> #define BTD_PROFILE_CHAN_AUTO -1
>
> @@ -1411,6 +1413,7 @@ static uint32_t ext_start_servers(struct ext_profile *ext,
> BT_IO_OPT_MODE, ext->mode,
> BT_IO_OPT_PSM, psm,
> BT_IO_OPT_SEC_LEVEL, ext->sec_level,
> + BT_IO_OPT_IMTU, BT_RX_MTU,
This is doing it for all service registered via ProfileManager which
is not going to fly, instead we probably need to add a MTU option so
the profile entity can pass it instead of getting the default.
> BT_IO_OPT_INVALID);
> if (err != NULL) {
> error("L2CAP server failed for %s: %s",
> --
> 2.34.1
>
>
--
Luiz Augusto von Dentz
^ permalink raw reply
* [PATCH] Bluetooth: btusb: Add support for TP-Link TL-UB250
From: Cris @ 2026-06-02 13:54 UTC (permalink / raw)
To: linux-bluetooth; +Cc: marcel, luiz.dentz, linux-kernel, Cris
Add USB ID 2357:0607 for TP-Link TL-UB250.
This is a Realtek RTL8761BUV based Bluetooth adapter.
Without this entry the device is picked up by the generic Bluetooth USB
class match and exposes hci0, but the Realtek setup path is not used and
rtl8761bu firmware/config are not loaded.
The controller reports Realtek Semiconductor Corporation as the
manufacturer and LMP subversion 0x8761. With this entry added, btusb
loads rtl_bt/rtl8761bu_fw.bin and rtl_bt/rtl8761bu_config.bin
successfully.
Use the same flags as the existing TP-Link 2357:0604 entry.
Cc: stable@vger.kernel.org
Signed-off-by: Cris <cxs1494089474@gmail.com>
---
drivers/bluetooth/btusb.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c
index 3aef21d4c..3cbb3c22e 100644
--- a/drivers/bluetooth/btusb.c
+++ b/drivers/bluetooth/btusb.c
@@ -831,6 +831,8 @@ static const struct usb_device_id quirks_table[] = {
BTUSB_WIDEBAND_SPEECH },
{ USB_DEVICE(0x2357, 0x0604), .driver_info = BTUSB_REALTEK |
BTUSB_WIDEBAND_SPEECH },
+ { USB_DEVICE(0x2357, 0x0607), .driver_info = BTUSB_REALTEK |
+ BTUSB_WIDEBAND_SPEECH },
{ USB_DEVICE(0x0b05, 0x190e), .driver_info = BTUSB_REALTEK |
BTUSB_WIDEBAND_SPEECH },
{ USB_DEVICE(0x2550, 0x8761), .driver_info = BTUSB_REALTEK |
--
2.34.1
^ permalink raw reply related
* [PATCH v8 1/1] Bluetooth: L2CAP: Fix use-after-free in l2cap_sock_new_connection_cb()
From: Siwei Zhang @ 2026-06-02 12:55 UTC (permalink / raw)
To: Marcel Holtmann, Luiz Augusto von Dentz; +Cc: linux-bluetooth, Siwei Zhang
In-Reply-To: <20260602125618.2520506-1-oss@fourdim.xyz>
l2cap_sock_new_connection_cb() accesses l2cap_pi(sk)->chan after
release_sock(parent). Once the parent lock is released, the child
socket sk can be freed by another task.
Allocate the channel outside the func to prevent this.
Fixes: 8ffb929098a5 ("Bluetooth: Remove parent socket usage from l2cap_core.c")
Cc: stable@kernel.org
Assisted-by: Claude:claude-opus-4-6
Signed-off-by: Siwei Zhang <oss@fourdim.xyz>
---
include/net/bluetooth/l2cap.h | 8 ++--
net/bluetooth/6lowpan.c | 32 +++++++++------
net/bluetooth/l2cap_core.c | 60 ++++++++++++++++++++-------
net/bluetooth/l2cap_sock.c | 76 ++++++++++++++++++++++-------------
net/bluetooth/smp.c | 18 ++++-----
5 files changed, 126 insertions(+), 68 deletions(-)
diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h
index e0a1f2293679..ffd006187324 100644
--- a/include/net/bluetooth/l2cap.h
+++ b/include/net/bluetooth/l2cap.h
@@ -620,7 +620,8 @@ struct l2cap_chan {
struct l2cap_ops {
char *name;
- struct l2cap_chan *(*new_connection) (struct l2cap_chan *chan);
+ int (*new_connection)(struct l2cap_chan *chan,
+ struct l2cap_chan *new_chan);
int (*recv) (struct l2cap_chan * chan,
struct sk_buff *skb);
void (*teardown) (struct l2cap_chan *chan, int err);
@@ -884,9 +885,10 @@ static inline __u16 __next_seq(struct l2cap_chan *chan, __u16 seq)
return (seq + 1) % (chan->tx_win_max + 1);
}
-static inline struct l2cap_chan *l2cap_chan_no_new_connection(struct l2cap_chan *chan)
+static inline int l2cap_chan_no_new_connection(struct l2cap_chan *chan,
+ struct l2cap_chan *new_chan)
{
- return NULL;
+ return -EOPNOTSUPP;
}
static inline int l2cap_chan_no_recv(struct l2cap_chan *chan, struct sk_buff *skb)
diff --git a/net/bluetooth/6lowpan.c b/net/bluetooth/6lowpan.c
index cb1e329d66fd..40f118168015 100644
--- a/net/bluetooth/6lowpan.c
+++ b/net/bluetooth/6lowpan.c
@@ -624,6 +624,15 @@ static bool is_bt_6lowpan(struct hci_conn *hcon)
return true;
}
+static void chan_init(struct l2cap_chan *chan)
+{
+ l2cap_chan_set_defaults(chan);
+
+ chan->chan_type = L2CAP_CHAN_CONN_ORIENTED;
+ chan->mode = L2CAP_MODE_LE_FLOWCTL;
+ chan->imtu = 1280;
+}
+
static struct l2cap_chan *chan_create(void)
{
struct l2cap_chan *chan;
@@ -632,11 +641,7 @@ static struct l2cap_chan *chan_create(void)
if (!chan)
return NULL;
- l2cap_chan_set_defaults(chan);
-
- chan->chan_type = L2CAP_CHAN_CONN_ORIENTED;
- chan->mode = L2CAP_MODE_LE_FLOWCTL;
- chan->imtu = 1280;
+ chan_init(chan);
return chan;
}
@@ -745,19 +750,20 @@ static inline void chan_ready_cb(struct l2cap_chan *chan)
ifup(dev->netdev);
}
-static inline struct l2cap_chan *chan_new_conn_cb(struct l2cap_chan *pchan)
+static inline int chan_new_conn_cb(struct l2cap_chan *pchan,
+ struct l2cap_chan *chan)
{
- struct l2cap_chan *chan;
-
- chan = chan_create();
- if (!chan)
- return NULL;
-
+ chan_init(chan);
chan->ops = pchan->ops;
+ /* Take a reference to match the put in chan_close_cb(). The caller
+ * drops its own local reference after __l2cap_chan_add().
+ */
+ l2cap_chan_hold(chan);
+
BT_DBG("chan %p pchan %p", chan, pchan);
- return chan;
+ return 0;
}
static void unregister_dev(struct lowpan_btle_dev *dev)
diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
index c4ccfbda9d78..31fb715fd830 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -4007,6 +4007,36 @@ static inline int l2cap_command_rej(struct l2cap_conn *conn,
return 0;
}
+/* Allocate and initialise a channel for an incoming connection. The returned
+ * channel carries the caller's local reference, which must be dropped once
+ * __l2cap_chan_add() has pinned it via the conn list.
+ */
+static struct l2cap_chan *l2cap_new_connection(struct l2cap_chan *pchan)
+{
+ struct l2cap_chan *chan;
+
+ chan = l2cap_chan_create();
+ if (!chan)
+ return NULL;
+
+ if (pchan->ops->new_connection(pchan, chan) < 0) {
+ l2cap_chan_put(chan);
+ return NULL;
+ }
+
+ return chan;
+}
+
+/* Link a channel from l2cap_new_connection() into conn and release the local
+ * reference it carried. __l2cap_chan_add() pins the channel via the conn list,
+ * so it remains valid after this returns.
+ */
+static void l2cap_chan_add_new(struct l2cap_conn *conn, struct l2cap_chan *chan)
+{
+ __l2cap_chan_add(conn, chan);
+ l2cap_chan_put(chan);
+}
+
static void l2cap_connect(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd,
u8 *data, u8 rsp_code)
{
@@ -4053,7 +4083,7 @@ static void l2cap_connect(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd,
goto response;
}
- chan = pchan->ops->new_connection(pchan);
+ chan = l2cap_new_connection(pchan);
if (!chan)
goto response;
@@ -4071,7 +4101,7 @@ static void l2cap_connect(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd,
chan->psm = psm;
chan->dcid = scid;
- __l2cap_chan_add(conn, chan);
+ l2cap_chan_add_new(conn, chan);
dcid = chan->scid;
@@ -4883,6 +4913,7 @@ static int l2cap_le_connect_req(struct l2cap_conn *conn,
struct l2cap_le_conn_rsp rsp;
struct l2cap_chan *chan, *pchan;
u16 dcid, scid, credits, mtu, mps;
+ u16 rsp_mtu, rsp_mps;
__le16 psm;
u8 result;
@@ -4895,6 +4926,8 @@ static int l2cap_le_connect_req(struct l2cap_conn *conn,
psm = req->psm;
dcid = 0;
credits = 0;
+ rsp_mtu = 0;
+ rsp_mps = 0;
if (mtu < 23 || mps < 23)
return -EPROTO;
@@ -4955,7 +4988,7 @@ static int l2cap_le_connect_req(struct l2cap_conn *conn,
goto response_unlock;
}
- chan = pchan->ops->new_connection(pchan);
+ chan = l2cap_new_connection(pchan);
if (!chan) {
result = L2CAP_CR_LE_NO_MEM;
goto response_unlock;
@@ -4970,12 +5003,14 @@ static int l2cap_le_connect_req(struct l2cap_conn *conn,
chan->omtu = mtu;
chan->remote_mps = mps;
- __l2cap_chan_add(conn, chan);
+ l2cap_chan_add_new(conn, chan);
l2cap_le_flowctl_init(chan, __le16_to_cpu(req->credits));
dcid = chan->scid;
credits = chan->rx_credits;
+ rsp_mtu = chan->imtu;
+ rsp_mps = chan->mps;
__set_chan_timer(chan, chan->ops->get_sndtimeo(chan));
@@ -5003,13 +5038,8 @@ static int l2cap_le_connect_req(struct l2cap_conn *conn,
return 0;
response:
- if (chan) {
- rsp.mtu = cpu_to_le16(chan->imtu);
- rsp.mps = cpu_to_le16(chan->mps);
- } else {
- rsp.mtu = 0;
- rsp.mps = 0;
- }
+ rsp.mtu = cpu_to_le16(rsp_mtu);
+ rsp.mps = cpu_to_le16(rsp_mps);
rsp.dcid = cpu_to_le16(dcid);
rsp.credits = cpu_to_le16(credits);
@@ -5179,7 +5209,7 @@ static inline int l2cap_ecred_conn_req(struct l2cap_conn *conn,
continue;
}
- chan = pchan->ops->new_connection(pchan);
+ chan = l2cap_new_connection(pchan);
if (!chan) {
result = L2CAP_CR_LE_NO_MEM;
continue;
@@ -5194,7 +5224,7 @@ static inline int l2cap_ecred_conn_req(struct l2cap_conn *conn,
chan->omtu = mtu;
chan->remote_mps = mps;
- __l2cap_chan_add(conn, chan);
+ l2cap_chan_add_new(conn, chan);
l2cap_ecred_init(chan, __le16_to_cpu(req->credits));
@@ -7470,14 +7500,14 @@ static void l2cap_connect_cfm(struct hci_conn *hcon, u8 status)
goto next;
l2cap_chan_lock(pchan);
- chan = pchan->ops->new_connection(pchan);
+ chan = l2cap_new_connection(pchan);
if (chan) {
bacpy(&chan->src, &hcon->src);
bacpy(&chan->dst, &hcon->dst);
chan->src_type = bdaddr_src_type(hcon);
chan->dst_type = dst_type;
- __l2cap_chan_add(conn, chan);
+ l2cap_chan_add_new(conn, chan);
}
l2cap_chan_unlock(pchan);
diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c
index 025329636353..745b012890ee 100644
--- a/net/bluetooth/l2cap_sock.c
+++ b/net/bluetooth/l2cap_sock.c
@@ -46,7 +46,8 @@ static struct bt_sock_list l2cap_sk_list = {
static const struct proto_ops l2cap_sock_ops;
static void l2cap_sock_init(struct sock *sk, struct sock *parent);
static struct sock *l2cap_sock_alloc(struct net *net, struct socket *sock,
- int proto, gfp_t prio, int kern);
+ int proto, gfp_t prio, int kern,
+ struct l2cap_chan *chan);
static void l2cap_sock_cleanup_listen(struct sock *parent);
bool l2cap_is_socket(struct socket *sock)
@@ -1292,18 +1293,25 @@ static int l2cap_sock_recvmsg(struct socket *sock, struct msghdr *msg,
*/
static void l2cap_sock_kill(struct sock *sk)
{
+ struct l2cap_chan *chan = l2cap_pi(sk)->chan;
+
if (!sock_flag(sk, SOCK_ZAPPED) || sk->sk_socket)
return;
BT_DBG("sk %p state %s", sk, state_to_string(sk->sk_state));
- /* Sock is dead, so set chan data to NULL, avoid other task use invalid
- * sock pointer.
+ /* Release the sock's ref on chan and clear the pointer so that
+ * l2cap_sock_destruct() does not drop it a second time. Setting
+ * chan->data to NULL first stops any other task from dereferencing
+ * the now-dead sock pointer.
*/
- l2cap_pi(sk)->chan->data = NULL;
- /* Kill poor orphan */
+ if (chan) {
+ chan->data = NULL;
+ l2cap_pi(sk)->chan = NULL;
+ l2cap_chan_put(chan);
+ }
- l2cap_chan_put(l2cap_pi(sk)->chan);
+ /* Kill poor orphan */
sock_set_flag(sk, SOCK_DEAD);
sock_put(sk);
}
@@ -1383,7 +1391,9 @@ static int l2cap_sock_shutdown(struct socket *sock, int how)
sock_hold(sk);
/* prevent chan structure from being freed whilst unlocked */
- chan = l2cap_chan_hold_unless_zero(l2cap_pi(sk)->chan);
+ chan = l2cap_pi(sk)->chan;
+ if (chan)
+ chan = l2cap_chan_hold_unless_zero(chan);
if (!chan)
goto shutdown_already;
@@ -1546,12 +1556,13 @@ static void l2cap_sock_cleanup_listen(struct sock *parent)
}
}
-static struct l2cap_chan *l2cap_sock_new_connection_cb(struct l2cap_chan *chan)
+static int l2cap_sock_new_connection_cb(struct l2cap_chan *chan,
+ struct l2cap_chan *new_chan)
{
struct sock *sk, *parent = chan->data;
if (!parent)
- return NULL;
+ return -EINVAL;
lock_sock(parent);
@@ -1559,15 +1570,15 @@ static struct l2cap_chan *l2cap_sock_new_connection_cb(struct l2cap_chan *chan)
if (sk_acceptq_is_full(parent)) {
BT_DBG("backlog full %d", parent->sk_ack_backlog);
release_sock(parent);
- return NULL;
+ return -ENOBUFS;
}
sk = l2cap_sock_alloc(sock_net(parent), NULL, BTPROTO_L2CAP,
- GFP_ATOMIC, 0);
+ GFP_ATOMIC, 0, new_chan);
if (!sk) {
release_sock(parent);
- return NULL;
- }
+ return -ENOMEM;
+ }
bt_sock_reclassify_lock(sk, BTPROTO_L2CAP);
@@ -1577,7 +1588,7 @@ static struct l2cap_chan *l2cap_sock_new_connection_cb(struct l2cap_chan *chan)
release_sock(parent);
- return l2cap_pi(sk)->chan;
+ return 0;
}
static int l2cap_sock_recv_cb(struct l2cap_chan *chan, struct sk_buff *skb)
@@ -1875,8 +1886,11 @@ static void l2cap_sock_destruct(struct sock *sk)
BT_DBG("sk %p", sk);
if (l2cap_pi(sk)->chan) {
- l2cap_pi(sk)->chan->data = NULL;
- l2cap_chan_put(l2cap_pi(sk)->chan);
+ struct l2cap_chan *chan = l2cap_pi(sk)->chan;
+
+ chan->data = NULL;
+ l2cap_pi(sk)->chan = NULL;
+ l2cap_chan_put(chan);
}
list_for_each_entry_safe(rx_busy, next, &l2cap_pi(sk)->rx_busy, list) {
@@ -1978,10 +1992,10 @@ static struct proto l2cap_proto = {
};
static struct sock *l2cap_sock_alloc(struct net *net, struct socket *sock,
- int proto, gfp_t prio, int kern)
+ int proto, gfp_t prio, int kern,
+ struct l2cap_chan *chan)
{
struct sock *sk;
- struct l2cap_chan *chan;
sk = bt_sock_alloc(net, sock, &l2cap_proto, proto, prio, kern);
if (!sk)
@@ -1992,14 +2006,11 @@ static struct sock *l2cap_sock_alloc(struct net *net, struct socket *sock,
INIT_LIST_HEAD(&l2cap_pi(sk)->rx_busy);
- chan = l2cap_chan_create();
- if (!chan) {
- sk_free(sk);
- if (sock)
- sock->sk = NULL;
- return NULL;
- }
-
+ /* The sock owns a single ref on chan. It is released by whichever of
+ * l2cap_sock_kill() or l2cap_sock_destruct() runs first; that path
+ * clears l2cap_pi(sk)->chan so the ref is dropped exactly once. The
+ * caller keeps its own ref independent of this one.
+ */
l2cap_chan_hold(chan);
l2cap_pi(sk)->chan = chan;
@@ -2011,6 +2022,7 @@ static int l2cap_sock_create(struct net *net, struct socket *sock, int protocol,
int kern)
{
struct sock *sk;
+ struct l2cap_chan *chan;
BT_DBG("sock %p", sock);
@@ -2025,9 +2037,17 @@ static int l2cap_sock_create(struct net *net, struct socket *sock, int protocol,
sock->ops = &l2cap_sock_ops;
- sk = l2cap_sock_alloc(net, sock, protocol, GFP_ATOMIC, kern);
- if (!sk)
+ chan = l2cap_chan_create();
+ if (!chan)
+ return -ENOMEM;
+
+ sk = l2cap_sock_alloc(net, sock, protocol, GFP_ATOMIC, kern, chan);
+ if (!sk) {
+ l2cap_chan_put(chan);
return -ENOMEM;
+ }
+ /* Sock has taken its own refs on chan; drop the chan_create() ref. */
+ l2cap_chan_put(chan);
l2cap_sock_init(sk, NULL);
bt_sock_link(&l2cap_sk_list, sk);
diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c
index 1739c1989dbd..887a2fc34391 100644
--- a/net/bluetooth/smp.c
+++ b/net/bluetooth/smp.c
@@ -3204,16 +3204,11 @@ static const struct l2cap_ops smp_chan_ops = {
.get_sndtimeo = l2cap_chan_no_get_sndtimeo,
};
-static inline struct l2cap_chan *smp_new_conn_cb(struct l2cap_chan *pchan)
+static inline int smp_new_conn_cb(struct l2cap_chan *pchan,
+ struct l2cap_chan *chan)
{
- struct l2cap_chan *chan;
-
BT_DBG("pchan %p", pchan);
- chan = l2cap_chan_create();
- if (!chan)
- return NULL;
-
chan->chan_type = pchan->chan_type;
chan->ops = &smp_chan_ops;
chan->scid = pchan->scid;
@@ -3229,9 +3224,14 @@ static inline struct l2cap_chan *smp_new_conn_cb(struct l2cap_chan *pchan)
*/
atomic_set(&chan->nesting, L2CAP_NESTING_SMP);
- BT_DBG("created chan %p", chan);
+ /* Take a reference to match the put in smp_teardown_cb(). The caller
+ * drops its own local reference after __l2cap_chan_add().
+ */
+ l2cap_chan_hold(chan);
- return chan;
+ BT_DBG("initialised chan %p", chan);
+
+ return 0;
}
static const struct l2cap_ops smp_root_chan_ops = {
--
2.54.0
^ permalink raw reply related
* [PATCH v8 0/1] Bluetooth: L2CAP: Fix use-after-free in l2cap_sock_new_connection_cb()
From: Siwei Zhang @ 2026-06-02 12:55 UTC (permalink / raw)
To: Marcel Holtmann, Luiz Augusto von Dentz; +Cc: linux-bluetooth, Siwei Zhang
Compared to v2, addresses comments on https://sashiko.dev/#/patchset/20260415204842.2363950-1-oss%40fourdim.xyz .
Compared to v3, rebase against bluetooth-next.
Compared to v4, allocate the channel outside the function and pass it in as an argument to avoid the use-after-free.
Compared to v5, extract the channel init to a separate function.
Compared to v6, balance puts and holds on chans.
Compared to v7, rebase against bluetooth-next and refactor the chan refcounting.
Siwei Zhang (1):
Bluetooth: L2CAP: Fix use-after-free in l2cap_sock_new_connection_cb()
include/net/bluetooth/l2cap.h | 8 ++--
net/bluetooth/6lowpan.c | 32 +++++++++------
net/bluetooth/l2cap_core.c | 60 ++++++++++++++++++++-------
net/bluetooth/l2cap_sock.c | 76 ++++++++++++++++++++++-------------
net/bluetooth/smp.c | 18 ++++-----
5 files changed, 126 insertions(+), 68 deletions(-)
--
2.54.0
^ permalink raw reply
* Re: [REGRESSION] RIP: 0010:hidinput_setup_battery.isra.0+0x6d/0x370 [hid]
From: Rafael Passos @ 2026-06-02 12:39 UTC (permalink / raw)
To: regressions; +Cc: linux-input, linux-kernel, linux-bluetooth, Rafael Passos
In-Reply-To: <b84a408c-b12c-40e5-b44b-62aa072cb285@leemhuis.info>
I'm really happy it helped!
Cheers!
Rafael Passos,
Software Engineer
São Paulo, Brasil
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox