Linux bluetooth development
 help / color / mirror / Atom feed
* [bluez/bluez]
From: BluezTestBot @ 2026-06-10 19:22 UTC (permalink / raw)
  To: linux-bluetooth

  Branch: refs/heads/1108786
  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]
From: BluezTestBot @ 2026-06-10 19:22 UTC (permalink / raw)
  To: linux-bluetooth

  Branch: refs/heads/1108823
  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]
From: BluezTestBot @ 2026-06-10 19:22 UTC (permalink / raw)
  To: linux-bluetooth

  Branch: refs/heads/1108826
  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]
From: BluezTestBot @ 2026-06-10 19:22 UTC (permalink / raw)
  To: linux-bluetooth

  Branch: refs/heads/1108830
  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]
From: BluezTestBot @ 2026-06-10 19:22 UTC (permalink / raw)
  To: linux-bluetooth

  Branch: refs/heads/1108834
  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]
From: BluezTestBot @ 2026-06-10 19:22 UTC (permalink / raw)
  To: linux-bluetooth

  Branch: refs/heads/1109089
  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] ea4b49: btio: handle error from broadcast ISO socket
From: Šimon Mikuda @ 2026-06-10 19:21 UTC (permalink / raw)
  To: linux-bluetooth

  Branch: refs/heads/master
  Home:   https://github.com/bluez/bluez
  Commit: ea4b494414f60beda3cf69aef9278354c07b74f1
      https://github.com/bluez/bluez/commit/ea4b494414f60beda3cf69aef9278354c07b74f1
  Author: Michal Dzik <michal.dzik@streamunlimited.com>
  Date:   2026-06-09 (Tue, 09 Jun 2026)

  Changed paths:
    M btio/btio.c

  Log Message:
  -----------
  btio: handle error from broadcast ISO socket

If not handled, server_cb() will be stuck in endless loop of calling
accept() on the socket.


  Commit: 6ea27ab0dcfc1ac38467d8e88ceccb5784494cb5
      https://github.com/bluez/bluez/commit/6ea27ab0dcfc1ac38467d8e88ceccb5784494cb5
  Author: Michal Dzik <michal.dzik@streamunlimited.com>
  Date:   2026-06-09 (Tue, 09 Jun 2026)

  Changed paths:
    M profiles/audio/bap.c

  Log Message:
  -----------
  bap: log errors in BIG sync


  Commit: 8c580d30d2655f75796c31ca0d496ffd1578cb46
      https://github.com/bluez/bluez/commit/8c580d30d2655f75796c31ca0d496ffd1578cb46
  Author: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
  Date:   2026-06-10 (Wed, 10 Jun 2026)

  Changed paths:
    M btio/btio.c

  Log Message:
  -----------
  btio: Handle EOPNOTSUPP from accept() to prevent busy loop

When accept() returns EOPNOTSUPP on an L2CAP SEQPACKET server socket
(e.g. AVCTP browsing channel, PSM 0x1b), the error is permanent and
retrying will never succeed. Previously, only EBADFD was treated as
fatal, causing server_cb to return TRUE for EOPNOTSUPP. Since the fd
remains readable, this creates an infinite busy loop that hangs
bluetoothd.

Treat EOPNOTSUPP the same as EBADFD by returning FALSE to remove the
GLib IO watch and stop the loop.


  Commit: abf0911e25ef414f06b895b22a6a9aa05c03360e
      https://github.com/bluez/bluez/commit/abf0911e25ef414f06b895b22a6a9aa05c03360e
  Author: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
  Date:   2026-06-10 (Wed, 10 Jun 2026)

  Changed paths:
    M src/profile.c

  Log Message:
  -----------
  profile: Check if bearer is enabled on registration

btd_profile_register now verifies that the profile's bearer type is
compatible with btd_opts.mode before registering. If the required bearer
is not enabled (e.g. LE-only profile when mode is BR/EDR, or BR/EDR-only
profile when mode is LE), registration is rejected with -ENOTSUP.


  Commit: 7b5895d8063505798ec5988a4b3bb545834afb1a
      https://github.com/bluez/bluez/commit/7b5895d8063505798ec5988a4b3bb545834afb1a
  Author: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
  Date:   2026-06-10 (Wed, 10 Jun 2026)

  Changed paths:
    M profiles/audio/a2dp.c
    M profiles/audio/avrcp.c
    M profiles/audio/hfp-hf.c
    M profiles/audio/micp.c
    M profiles/input/manager.c
    M profiles/network/manager.c
    M src/gatt-database.c

  Log Message:
  -----------
  plugins: Check btd_profile_register return value

Ensure all plugin init functions check the return value of
btd_profile_register. If registration fails (e.g. bearer not enabled),
the plugin init propagates the error instead of continuing with an
unregistered profile.


  Commit: 8c821a150b8f5319b8201b5e7d8fdaa6a67d3bd1
      https://github.com/bluez/bluez/commit/8c821a150b8f5319b8201b5e7d8fdaa6a67d3bd1
  Author: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
  Date:   2026-06-10 (Wed, 10 Jun 2026)

  Changed paths:
    M src/bearer.c

  Log Message:
  -----------
  bearer: Check btd_opts.mode on btd_bearer_new

Only create the bearer interface if the corresponding transport is
enabled. Return NULL if BREDR bearer is requested in LE-only mode or
LE bearer in BREDR-only mode, so the D-Bus interface is never
registered for unsupported bearers.


  Commit: 39ad431de60b896a03904887a0f1d0285b719edd
      https://github.com/bluez/bluez/commit/39ad431de60b896a03904887a0f1d0285b719edd
  Author: Simon Mikuda <simon.mikuda@streamunlimited.com>
  Date:   2026-06-10 (Wed, 10 Jun 2026)

  Changed paths:
    M profiles/audio/avdtp.c

  Log Message:
  -----------
  avdtp: Return correct error when SEP is inuse

This fixes AVDTP/SNK/ACP/SIG/SMG/BI-08-C


  Commit: 249e2bedfacf51fc6c89f43a0adb9a12d761c2b7
      https://github.com/bluez/bluez/commit/249e2bedfacf51fc6c89f43a0adb9a12d761c2b7
  Author: Simon Mikuda <simon.mikuda@streamunlimited.com>
  Date:   2026-06-10 (Wed, 10 Jun 2026)

  Changed paths:
    M profiles/audio/avrcp.c

  Log Message:
  -----------
  avrcp: Abort continuing response on fragmented CT replies

Send AbortContinuingResponse when a Get Element Attributes reply
arrives fragmented, as the CT side does not reassemble fragments.

Fixes PTS test AVRCP/CT/RCR/BV-03-C


  Commit: 2e00b83c07885f960fc0d53568b4ab0091ffb09c
      https://github.com/bluez/bluez/commit/2e00b83c07885f960fc0d53568b4ab0091ffb09c
  Author: Simon Mikuda <simon.mikuda@streamunlimited.com>
  Date:   2026-06-10 (Wed, 10 Jun 2026)

  Changed paths:
    M src/shared/bap.c

  Log Message:
  -----------
  shared/bap: Report invalid-length ASE CP write via notification

A zero-length write to the ASE Control Point returned an ATT error, but
ASCS requires the write to succeed at ATT level and the failure to be
carried by a CP notification. Build a response with the truncated error
code and return success instead.

Fixes PTS tests ASCS/SR/SPE/BI-01-C and BI-02-C


  Commit: 3047c2a4c5ea8313bcf5a9edbb18f9c9a187a7fd
      https://github.com/bluez/bluez/commit/3047c2a4c5ea8313bcf5a9edbb18f9c9a187a7fd
  Author: Simon Mikuda <simon.mikuda@streamunlimited.com>
  Date:   2026-06-10 (Wed, 10 Jun 2026)

  Changed paths:
    M profiles/audio/transport.c
    M src/shared/bap.c

  Log Message:
  -----------
  transport: Complete Acquire for Sink ASE entering Enabling

On the QoS to Enabling transition the IO is not yet available because
the CIS is not established, so the handler returns early and a pending
Acquire is left unanswered once the IO later arrives.

Notify the connecting callbacks once the fd is attached so the
transport can re-run the Enabling handling and complete the Acquire.


  Commit: 5d836f1c697cde166981d31276e2dd828996f3e7
      https://github.com/bluez/bluez/commit/5d836f1c697cde166981d31276e2dd828996f3e7
  Author: Simon Mikuda <simon.mikuda@streamunlimited.com>
  Date:   2026-06-10 (Wed, 10 Jun 2026)

  Changed paths:
    M src/adapter.c

  Log Message:
  -----------
  adapter: Fix failed bonding attempt after LE link disconnection

What happens when issue occurs:
- device is connected to both bearers BR/EDR and LE
- bonding is requested
- LE link disconnects
- pairing keys arrive

BlueZ would finish bonding request with error and mark device as
temporary. Then it would be disconnected+removed after default
temporary timeout (30 seconds).


Compare: https://github.com/bluez/bluez/compare/912d67d1d3a4...5d836f1c697c

To unsubscribe from these emails, change your notification settings at https://github.com/bluez/bluez/settings/notifications

^ permalink raw reply

* Re: [PATCH BlueZ] transport: Complete Acquire for Sink ASE entering Enabling
From: patchwork-bot+bluetooth @ 2026-06-10 18:40 UTC (permalink / raw)
  To: Simon Mikuda; +Cc: linux-bluetooth
In-Reply-To: <20260609211130.3887817-1-simon.mikuda@streamunlimited.com>

Hello:

This patch was applied to bluetooth/bluez.git (master)
by Luiz Augusto von Dentz <luiz.von.dentz@intel.com>:

On Tue,  9 Jun 2026 23:11:29 +0200 you wrote:
> On the QoS to Enabling transition the IO is not yet available because
> the CIS is not established, so the handler returns early and a pending
> Acquire is left unanswered once the IO later arrives.
> 
> Notify the connecting callbacks once the fd is attached so the
> transport can re-run the Enabling handling and complete the Acquire.
> 
> [...]

Here is the summary with links:
  - [BlueZ] transport: Complete Acquire for Sink ASE entering Enabling
    https://git.kernel.org/pub/scm/bluetooth/bluez.git/?id=3047c2a4c5ea

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 BlueZ] shared/bap: Report invalid-length ASE CP write via notification
From: patchwork-bot+bluetooth @ 2026-06-10 18:40 UTC (permalink / raw)
  To: Simon Mikuda; +Cc: linux-bluetooth
In-Reply-To: <20260609211104.3887577-1-simon.mikuda@streamunlimited.com>

Hello:

This patch was applied to bluetooth/bluez.git (master)
by Luiz Augusto von Dentz <luiz.von.dentz@intel.com>:

On Tue,  9 Jun 2026 23:11:04 +0200 you wrote:
> A zero-length write to the ASE Control Point returned an ATT error, but
> ASCS requires the write to succeed at ATT level and the failure to be
> carried by a CP notification. Build a response with the truncated error
> code and return success instead.
> 
> Fixes PTS tests ASCS/SR/SPE/BI-01-C and BI-02-C
> 
> [...]

Here is the summary with links:
  - [BlueZ] shared/bap: Report invalid-length ASE CP write via notification
    https://git.kernel.org/pub/scm/bluetooth/bluez.git/?id=2e00b83c0788

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 BlueZ] avrcp: Abort continuing response on fragmented CT replies
From: patchwork-bot+bluetooth @ 2026-06-10 18:40 UTC (permalink / raw)
  To: Simon Mikuda; +Cc: linux-bluetooth
In-Reply-To: <20260609212656.3900190-1-simon.mikuda@streamunlimited.com>

Hello:

This patch was applied to bluetooth/bluez.git (master)
by Luiz Augusto von Dentz <luiz.von.dentz@intel.com>:

On Tue,  9 Jun 2026 23:26:56 +0200 you wrote:
> Send AbortContinuingResponse when a Get Element Attributes reply
> arrives fragmented, as the CT side does not reassemble fragments.
> 
> Fixes PTS test AVRCP/CT/RCR/BV-03-C
> ---
>  profiles/audio/avrcp.c | 25 +++++++++++++++++++++++++
>  1 file changed, 25 insertions(+)

Here is the summary with links:
  - [BlueZ] avrcp: Abort continuing response on fragmented CT replies
    https://git.kernel.org/pub/scm/bluetooth/bluez.git/?id=249e2bedfacf

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 BlueZ] avdtp: Return correct error when SEP is inuse
From: patchwork-bot+bluetooth @ 2026-06-10 18:40 UTC (permalink / raw)
  To: Simon Mikuda; +Cc: linux-bluetooth
In-Reply-To: <20260609213013.3900808-1-simon.mikuda@streamunlimited.com>

Hello:

This patch was applied to bluetooth/bluez.git (master)
by Luiz Augusto von Dentz <luiz.von.dentz@intel.com>:

On Tue,  9 Jun 2026 23:30:13 +0200 you wrote:
> This fixes AVDTP/SNK/ACP/SIG/SMG/BI-08-C
> ---
>  profiles/audio/avdtp.c | 6 ++++++
>  1 file changed, 6 insertions(+)

Here is the summary with links:
  - [BlueZ] avdtp: Return correct error when SEP is inuse
    https://git.kernel.org/pub/scm/bluetooth/bluez.git/?id=39ad431de60b

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 BlueZ v2] adapter: Fix failed bonding attempt after LE link disconnection
From: patchwork-bot+bluetooth @ 2026-06-10 18:40 UTC (permalink / raw)
  To: Simon Mikuda; +Cc: linux-bluetooth
In-Reply-To: <20260610082054.3915366-1-simon.mikuda@streamunlimited.com>

Hello:

This patch was applied to bluetooth/bluez.git (master)
by Luiz Augusto von Dentz <luiz.von.dentz@intel.com>:

On Wed, 10 Jun 2026 10:20:54 +0200 you wrote:
> What happens when issue occurs:
> - device is connected to both bearers BR/EDR and LE
> - bonding is requested
> - LE link disconnects
> - pairing keys arrive
> 
> BlueZ would finish bonding request with error and mark device as
> temporary. Then it would be disconnected+removed after default
> temporary timeout (30 seconds).
> 
> [...]

Here is the summary with links:
  - [BlueZ,v2] adapter: Fix failed bonding attempt after LE link disconnection
    https://git.kernel.org/pub/scm/bluetooth/bluez.git/?id=5d836f1c697c

You are awesome, thank you!
-- 
Deet-doot-dot, I am a bot.
https://korg.docs.kernel.org/patchwork/pwbot.html



^ permalink raw reply

* Re: RTL8922A (0bda:d922): BLE HID disconnects with supervision timeout (0x08) during active HFP/SCO call
From: Benjamin Mirko Blume @ 2026-06-10 18:38 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Max Chou
In-Reply-To: <20d6a474-18c9-439b-8b01-a3ef5e8310cd@posteo.de>

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

Gentle ping on this one — still reproducing reliably, now on kernel
7.0.11-1-cachyos-bore.
Quoting the core of the original report for context:

 > a BLE-only HID device (mouse) is disconnected with link supervision
 > timeout whenever an HFP voice call (SCO) is active on the same
 > controller. The SCO audio link itself stays up; only the LE HID link
 > starves.
 >
 >     HCI Event: Disconnect Complete (0x05)  Handle: 16
 >         Reason: Connection Timeout (0x08)
 >     MGMT Event: Device Disconnected
 >         LE Address: DB:5C:42:57:1E:1E   (the mouse)

As offered in the original report, I'm attaching the short,
payload-scrubbed btmon reproducer (btmon-rtl8922-repro-scrubbed.snoop).
The raw SCO payload (call audio) has been stripped; the HCI/MGMT command
and event flow — the LE connection events, the eSCO setup, and the
Disconnect Complete with reason 0x08 — is intact, so the starvation of
the LE link during the active SCO call is fully visible in the capture.

To recap the open questions:
- Is this a known coexistence/scheduling limitation of the RTL8922A
   firmware, or is the SCO/LE arbitration firmware-tunable?
- Can the host side mitigate it (e.g. via LE connection parameters)?
- Could it have regressed between linux-firmware versions? I'm happy to
   bisect linux-firmware, and happy to test any debug patch.

Thanks,
Benjamin

[-- Attachment #2: btmon-rtl8922-repro-scrubbed.snoop --]
[-- Type: application/octet-stream, Size: 232107 bytes --]

^ permalink raw reply

* Re: [PATCH BlueZ v2 1/4] btio: Handle EOPNOTSUPP from accept() to prevent busy loop
From: patchwork-bot+bluetooth @ 2026-06-10 18:30 UTC (permalink / raw)
  To: Luiz Augusto von Dentz; +Cc: linux-bluetooth
In-Reply-To: <20260609185313.155105-1-luiz.dentz@gmail.com>

Hello:

This series was applied to bluetooth/bluez.git (master)
by Luiz Augusto von Dentz <luiz.von.dentz@intel.com>:

On Tue,  9 Jun 2026 14:53:10 -0400 you wrote:
> From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
> 
> When accept() returns EOPNOTSUPP on an L2CAP SEQPACKET server socket
> (e.g. AVCTP browsing channel, PSM 0x1b), the error is permanent and
> retrying will never succeed. Previously, only EBADFD was treated as
> fatal, causing server_cb to return TRUE for EOPNOTSUPP. Since the fd
> remains readable, this creates an infinite busy loop that hangs
> bluetoothd.
> 
> [...]

Here is the summary with links:
  - [BlueZ,v2,1/4] btio: Handle EOPNOTSUPP from accept() to prevent busy loop
    https://git.kernel.org/pub/scm/bluetooth/bluez.git/?id=8c580d30d265
  - [BlueZ,v2,2/4] profile: Check if bearer is enabled on registration
    https://git.kernel.org/pub/scm/bluetooth/bluez.git/?id=abf0911e25ef
  - [BlueZ,v2,3/4] plugins: Check btd_profile_register return value
    https://git.kernel.org/pub/scm/bluetooth/bluez.git/?id=7b5895d80635
  - [BlueZ,v2,4/4] bearer: Check btd_opts.mode on btd_bearer_new
    https://git.kernel.org/pub/scm/bluetooth/bluez.git/?id=8c821a150b8f

You are awesome, thank you!
-- 
Deet-doot-dot, I am a bot.
https://korg.docs.kernel.org/patchwork/pwbot.html



^ permalink raw reply

* RE: [v2] Bluetooth: hci_conn: Fix null ptr deref in hci_abort_conn()
From: bluez.test.bot @ 2026-06-10 18:28 UTC (permalink / raw)
  To: linux-bluetooth, oss
In-Reply-To: <20260610150704.1234558-1-oss@fourdim.xyz>

[-- Attachment #1: Type: text/plain, Size: 2204 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=1109363

---Test result---

Test Summary:
CheckPatch                    PASS      1.14 seconds
VerifyFixes                   PASS      0.11 seconds
VerifySignedoff               PASS      0.11 seconds
GitLint                       PASS      0.29 seconds
SubjectPrefix                 PASS      0.11 seconds
BuildKernel                   PASS      27.22 seconds
CheckAllWarning               PASS      29.76 seconds
CheckSparse                   PASS      28.66 seconds
BuildKernel32                 PASS      26.45 seconds
TestRunnerSetup               PASS      579.03 seconds
TestRunner_l2cap-tester       PASS      60.13 seconds
TestRunner_iso-tester         PASS      74.99 seconds
TestRunner_bnep-tester        PASS      19.60 seconds
TestRunner_mgmt-tester        FAIL      214.34 seconds
TestRunner_rfcomm-tester      PASS      25.55 seconds
TestRunner_sco-tester         PASS      32.90 seconds
TestRunner_ioctl-tester       PASS      26.59 seconds
TestRunner_mesh-tester        FAIL      26.13 seconds
TestRunner_smp-tester         PASS      23.46 seconds
TestRunner_userchan-tester    PASS      20.07 seconds
TestRunner_6lowpan-tester     PASS      23.57 seconds
IncrementalBuild              PASS      26.07 seconds

Details
##############################
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.248 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.228 seconds
Mesh - Send cancel - 2                               Timed out    1.988 seconds


https://github.com/bluez/bluetooth-next/pull/302

---
Regards,
Linux Bluetooth


^ permalink raw reply

* Re: [PATCH BlueZ 0/2] btio: handle error from broadcast ISO socket
From: patchwork-bot+bluetooth @ 2026-06-10 18:20 UTC (permalink / raw)
  To: Michal Dzik; +Cc: linux-bluetooth
In-Reply-To: <20260606060348.2240980-1-michal.dzik@streamunlimited.com>

Hello:

This series was applied to bluetooth/bluez.git (master)
by Luiz Augusto von Dentz <luiz.von.dentz@intel.com>:

On Sat,  6 Jun 2026 08:03:46 +0200 you wrote:
> If not handled, server_cb() will be stuck in endless loop of calling
> accept() on the socket.
> 
> Michal Dzik (2):
>   btio: handle error from broadcast ISO socket
>   bap: log errors in BIG sync
> 
> [...]

Here is the summary with links:
  - [BlueZ,1/2] btio: handle error from broadcast ISO socket
    https://git.kernel.org/pub/scm/bluetooth/bluez.git/?id=ea4b494414f6
  - [BlueZ,2/2] bap: log errors in BIG sync
    https://git.kernel.org/pub/scm/bluetooth/bluez.git/?id=6ea27ab0dcfc

You are awesome, thank you!
-- 
Deet-doot-dot, I am a bot.
https://korg.docs.kernel.org/patchwork/pwbot.html



^ permalink raw reply

* [GIT PULL] bluetooth 2026-06-10
From: Luiz Augusto von Dentz @ 2026-06-10 18:00 UTC (permalink / raw)
  To: davem, kuba; +Cc: linux-bluetooth, netdev

The following changes since commit 149324fc762c2a7acef9c26790566f81f475e51f:

  Bluetooth: MGMT: Fix backward compatibility with userspace (2026-06-03 11:24:12 -0400)

are available in the Git repository at:

  git://git.kernel.org/pub/scm/linux/kernel/git/bluetooth/bluetooth.git tags/for-net-2026-06-10

for you to fetch changes up to f98220e190507d3eb3e02f9a2f20c418c30d04ae:

  Bluetooth: vhci: validate devcoredump state before side effects (2026-06-10 13:51:15 -0400)

----------------------------------------------------------------
bluetooth pull request for net:

 - hci_core: Fix UAF in hci_unregister_dev()
 - hci_event: fix simultaneous discovery stuck in FINDING
 - hci: validate codec capability element length
 - eir: Fix stack OOB write when prepending the Flags AD
 - L2CAP: Fix UAF in channel timeout by holding conn ref
 - btusb: fix use-after-free on registration failure
 - btusb: fix use-after-free on marvell probe failure
 - btusb: fix wakeup source leak on probe failure
 - btusb: fix wakeup irq devres lifetime
 - btmtk: fix URB leak in alloc_mtk_intr_urb error path
 - vhci: validate devcoredump state before side effects

----------------------------------------------------------------
Jiajia Liu (1):
      Bluetooth: hci_event: fix simultaneous discovery stuck in FINDING

Johan Hovold (4):
      Bluetooth: btusb: fix use-after-free on registration failure
      Bluetooth: btusb: fix use-after-free on marvell probe failure
      Bluetooth: btusb: fix wakeup source leak on probe failure
      Bluetooth: btusb: fix wakeup irq devres lifetime

Jordan Walters (1):
      Bluetooth: hci_core: Fix UAF in hci_unregister_dev()

Marco Elver (1):
      Bluetooth: L2CAP: Fix UAF in channel timeout by holding conn ref

Samuel Moelius (2):
      Bluetooth: hci: validate codec capability element length
      Bluetooth: vhci: validate devcoredump state before side effects

Weiming Shi (1):
      Bluetooth: eir: Fix stack OOB write when prepending the Flags AD

Zhao Dongdong (1):
      Bluetooth: btmtk: fix URB leak in alloc_mtk_intr_urb error path

 drivers/bluetooth/btmtk.c     |  4 +++-
 drivers/bluetooth/btusb.c     | 55 ++++++++++++++++++++++++++++++++++---------
 drivers/bluetooth/hci_vhci.c  | 10 ++++++++
 include/net/bluetooth/l2cap.h |  1 +
 net/bluetooth/eir.c           |  8 ++++---
 net/bluetooth/hci_codec.c     |  2 +-
 net/bluetooth/hci_core.c      |  2 ++
 net/bluetooth/hci_event.c     |  7 ++++++
 net/bluetooth/l2cap_core.c    | 34 +++++++++++++++-----------
 9 files changed, 93 insertions(+), 30 deletions(-)

^ permalink raw reply

* RE: [v2] Bluetooth: btintel_pcie: Separate coredump work from RX work
From: bluez.test.bot @ 2026-06-10 17:53 UTC (permalink / raw)
  To: linux-bluetooth, kiran.k
In-Reply-To: <20260610162544.240444-1-kiran.k@intel.com>

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

This is an automated email and please do not reply to this email.

Dear Submitter,

Thank you for submitting the patches to the linux bluetooth mailing list.
While preparing the CI tests, the patches you submitted couldn't be applied to the current HEAD of the repository.

----- Output -----

error: patch failed: drivers/bluetooth/btintel_pcie.c:1457
error: drivers/bluetooth/btintel_pcie.c: patch does not apply
hint: Use 'git am --show-current-patch' to see the failed patch

Please resolve the issue and submit the patches again.


---
Regards,
Linux Bluetooth


^ permalink raw reply

* Re: [PATCH v9 1/1] Bluetooth: L2CAP: Fix use-after-free in l2cap_sock_new_connection_cb()
From: Siwei Zhang @ 2026-06-10 17:13 UTC (permalink / raw)
  To: Luiz Augusto von Dentz; +Cc: linux-bluetooth
In-Reply-To: <CABBYNZKuKSs938J6Pt_gqJzj4s1vz3wTGzJsfowS7H_n6mPd4A@mail.gmail.com>



On Wed, Jun 10, 2026, at 1:12 PM, Luiz Augusto von Dentz wrote:
> Hi Siwei,
>
> On Wed, Jun 10, 2026 at 1:03 PM Siwei Zhang <oss@fourdim.xyz> wrote:
>>
>>
>> On Wed, Jun 10, 2026, at 12:59 PM, Luiz Augusto von Dentz wrote:
>> > Hi Siwei,
>> >
>> > On Wed, Jun 10, 2026 at 12:33 PM Siwei Zhang <oss@fourdim.xyz> wrote:
>> >>
>> >>
>> >>
>> >> On Wed, Jun 10, 2026, at 11:57 AM, Luiz Augusto von Dentz wrote:
>> >> > Hi Siwei,
>> >> >
>> >> > On Mon, Jun 8, 2026 at 9:29 AM Siwei Zhang <oss@fourdim.xyz> wrote:
>> >> >>
>> >> >> Hi Luiz,
>> >> >>
>> >> >> On Thu, Jun 4, 2026, at 11:52 AM, Siwei Zhang wrote:
>> >> >> > Hi Luiz,
>> >> >> >
>> >> >> > On Wed, Jun 3, 2026, at 2:17 PM, Luiz Augusto von Dentz wrote:
>> >> >> >> Hi Siwei,
>> >> >> >>
>> >> >> >> On Wed, Jun 3, 2026 at 11:09 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-8
>> >> >> >>> Signed-off-by: Siwei Zhang <oss@fourdim.xyz>
>> >> >> >>> ---
>> >> >> >>>  include/net/bluetooth/l2cap.h | 10 +++--
>> >> >> >>>  net/bluetooth/6lowpan.c       | 31 +++++++------
>> >> >> >>>  net/bluetooth/l2cap_core.c    | 41 ++++++++++++-----
>> >> >> >>>  net/bluetooth/l2cap_sock.c    | 83 +++++++++++++++++++++--------------
>> >> >> >>>  net/bluetooth/smp.c           | 17 ++++---
>> >> >> >>>  5 files changed, 113 insertions(+), 69 deletions(-)
>> >> >> >>>
>> >> >> >>> diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h
>> >> >> >>> index e0a1f2293679..7f5e4647f6e0 100644
>> >> >> >>> --- a/include/net/bluetooth/l2cap.h
>> >> >> >>> +++ b/include/net/bluetooth/l2cap.h
>> >> >> >>> @@ -620,7 +620,9 @@ struct l2cap_chan {
>> >> >> >>>  struct l2cap_ops {
>> >> >> >>>         char                    *name;
>> >> >> >>>
>> >> >> >>> -       struct l2cap_chan       *(*new_connection) (struct l2cap_chan *chan);
>> >> >> >>> +       int                     (*new_connection)(struct l2cap_conn *conn,
>> >> >> >>> +                                                 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 +886,11 @@ 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_conn *conn,
>> >> >> >>> +                                              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..94863af97a44 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,19 @@ 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_conn *conn,
>> >> >> >>> +                                  struct l2cap_chan *pchan,
>> >> >> >>> +                                  struct l2cap_chan *chan)
>> >> >> >>>  {
>> >> >> >>> -       struct l2cap_chan *chan;
>> >> >> >>> -
>> >> >> >>> -       chan = chan_create();
>> >> >> >>> -       if (!chan)
>> >> >> >>> -               return NULL;
>> >> >> >>> -
>> >> >> >>> +       chan_init(chan);
>> >>
>> >> ref1: chan->chan_type = L2CAP_CHAN_CONN_ORIENTED; set
>> >> in chan_init.
>> >>
>> >> >> >>>         chan->ops = pchan->ops;
>> >> >> >>>
>> >> >> >>> +       /* Take the conn list reference; see l2cap_new_connection(). */
>> >> >> >>> +       __l2cap_chan_add(conn, 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..62acf90837fb 100644
>> >> >> >>> --- a/net/bluetooth/l2cap_core.c
>> >> >> >>> +++ b/net/bluetooth/l2cap_core.c
>> >> >> >>> @@ -4007,6 +4007,31 @@ static inline int l2cap_command_rej(struct l2cap_conn *conn,
>> >> >> >>>         return 0;
>> >> >> >>>  }
>> >> >> >>>
>> >> >> >>> +/* Allocate and initialise a channel for an incoming connection.
>> >> >> >>> + *
>> >> >> >>> + * ->new_connection() initialises the channel and links it into @conn with
>> >> >> >>> + * __l2cap_chan_add(). The l2cap_chan_create() reference becomes the one owned
>> >> >> >>> + * by the parent subsystem (l2cap_pi(sk)->chan, conn->smp or peer->chan) and is
>> >> >> >>> + * released by its teardown callback; the conn list reference is released by
>> >> >> >>> + * l2cap_chan_del().
>> >> >> >>> + */
>> >> >> >>> +static struct l2cap_chan *l2cap_new_connection(struct l2cap_conn *conn,
>> >> >> >>> +                                              struct l2cap_chan *pchan)
>> >> >> >>> +{
>> >> >> >>> +       struct l2cap_chan *chan;
>> >> >> >>> +
>> >> >> >>> +       chan = l2cap_chan_create();
>> >> >> >>> +       if (!chan)
>> >> >> >>> +               return NULL;
>> >> >> >>> +
>> >> >> >>> +       if (pchan->ops->new_connection(conn, pchan, chan) < 0) {
>> >> >> >>> +               l2cap_chan_put(chan);
>> >> >> >>> +               return NULL;
>> >> >> >>> +       }
>> >> >> >>
>> >> >> >> I don't quite get why we can't just place __l2cap_chan_add here
>> >> >> >> instead of having it called by new_connection callbacks?
>> >> >> >>
>> >> >> >
>> >> >> > It's specifically the l2cap_sock_new_connection_cb() case - the very
>> >> >> > use-after-free this patch fixes. The __l2cap_chan_add() has to happen while
>> >> >> > the parent lock is still held, and only the callback holds that lock.
>> >> >> >
>> >> >> > The reference counting on the new child chan starts at one ref,
>> >> >> > owned by the new socket:
>> >> >> >
>> >> >> >       /* l2cap_new_connection() */
>> >> >> >       chan = l2cap_chan_create();             /* refcount = 1 */
>> >> >> >       if (!chan)
>> >> >> >               return NULL;
>> >> >> >
>> >> >> >       pchan->ops->new_connection(conn, pchan, chan);
>> >> >> >
>> >> >> > and inside the socket callback:
>> >> >> >
>> >> >> >       /* l2cap_sock_new_connection_cb() */
>> >> >> >       lock_sock(parent);
>> >> >> >       ...
>> >> >> >       sk = l2cap_sock_alloc(..., new_chan);   /* sk owns the chan_create ref */
>> >> >> >       ...
>> >> >> >       l2cap_sock_init(sk, parent);
>> >> >> >
>> >> >> >       __l2cap_chan_add(conn, new_chan);       /* (A) conn list takes a ref */
>> >> >> >       bt_accept_enqueue(parent, sk, false);   /* (B) sk now on accept queue */
>> >> >> >
>> >> >> >       release_sock(parent);                   /* (C) parent lock dropped */
>> >> >> >       return 0;
>> >> >> >
>> >> >> > The moment we hit (C), sk is reachable through the parent's accept queue, so
>> >> >> > another task can grab and tear it down:
>> >> >> >
>> >> >> >       accept() -> l2cap_sock_kill() -> l2cap_sock_put_chan()
>> >> >> >               chan->data = NULL;
>> >> >> >               l2cap_chan_put(chan);           /* drops the sk's chan ref */
>> >> >> >
>> >> >> > If __l2cap_chan_add() at (A) hadn't already taken the conn list reference,
>> >> >> > that put would drop the last ref and free new_chan. Control then returns up
>> >> >> > to l2cap_new_connection(), which hands the now-freed chan back to
>> >> >> > l2cap_connect():
>> >> >> >
>> >> >> >       /* l2cap_connect() - runs after the callback returns */
>> >> >> >       chan = l2cap_new_connection(conn, pchan);
>> >> >> >       if (!chan)
>> >> >> >               goto response;
>> >> >> >       ...
>> >> >> >       bacpy(&chan->src, &conn->hcon->src);    /* <-- UAF on freed chan */
>> >> >> >       chan->psm  = psm;
>> >> >> >       chan->dcid = scid;
>> >> >> >
>> >> >> > The conn list reference taken at (A), before (C), is what keeps new_chan
>> >> >> > alive across the release_sock() window so l2cap_connect() can keep using it.
>> >> >> >
>> >> >> > So __l2cap_chan_add() can't move out to l2cap_new_connection(): by the time
>> >> >> > the callback returns, the parent lock is already dropped and chan may already
>> >> >> > be freed - which is exactly the race. It has to be taken inside the callback,
>> >> >> > under the parent lock, before the socket is exposed.
>> >> >
>> >> > If you do after l2cap_new_connection, yes, but what if you do before
>> >> > you call ->new_connect:
>> >> >
>> >> > diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
>> >> > index 3991c179b98f..cd864f400985 100644
>> >> > --- a/net/bluetooth/l2cap_core.c
>> >> > +++ b/net/bluetooth/l2cap_core.c
>> >> > @@ -4027,8 +4027,10 @@ static struct l2cap_chan
>> >> > *l2cap_new_connection(struct l2cap_conn *conn,
>> >> >         if (!chan)
>> >> >                 return NULL;
>> >> >
>> >> > +       __l2cap_chan_add(conn, chan);
>> >> > +
>> >> >         if (pchan->ops->new_connection(conn, pchan, chan) < 0) {
>> >> > -               l2cap_chan_put(chan);
>> >> > +               l2cap_chan_del(chan, 0);
>> >> >                 return NULL;
>> >> >         }
>> >> >
>> >> > This means we have to call l2cap_chan_del if new_connection fails, but
>> >> > we can eliminate other functions having to call __l2cap_chan_add with
>> >> > this. If the issue is then having l2cap_chan_del called concurrently,
>> >> > we can add a l2cap_chan_hold; actually, we may need a reference anyway
>> >> > since sk can be released and call l2cap_chan_del, releasing both
>> >> > references.
>> >> >
>> >>
>> >> In:
>> >>
>> >> void __l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan)
>> >> {
>> >>         ...
>> >>         switch (chan->chan_type) {
>> >>         case L2CAP_CHAN_CONN_ORIENTED:
>> >>                 ...
>> >>                 break;
>> >>         case L2CAP_CHAN_CONN_LESS:
>> >>                 ...
>> >>                 break;
>> >>         case L2CAP_CHAN_FIXED:
>> >>                 ...
>> >>                 break;
>> >>         default:
>> >>                 ...
>> >>         }
>> >> }
>> >>
>> >> Apparently it depends on chan->chan_type and it is set by ref1.
>> >> It is only set in cb function.
>> >
>> > Ok, this probably needs fixing in 6lowpan. These defaults should come
>> > from the parent channel, similar to how it's done in l2cap_sock_init.
>> > Perhaps we should promote that logic to l2cap_chan_set_defaults
>> > passing pchan so it can initialize the channel before calling
>> > __l2cap_chan_add.
>>
>> I can fix that in a separate patch.
>> Could you please merge it first?
>
> Merge it first, and then rework the order? Not sure what is the
> benefit of doing that, it is a somewhat substatial change either way
> so I don't think it will make it much easier to lets say backport.
>

Will do a patch v10.

>> Best,
>> Siwei
>
>
>
> -- 
> Luiz Augusto von Dentz

Best,
Siwei

^ permalink raw reply

* Re: [PATCH] Bluetooth: hci_bcm4377: Use named initializers for pci_device_id array
From: Luiz Augusto von Dentz @ 2026-06-10 17:13 UTC (permalink / raw)
  To: Uwe Kleine-König (The Capable Hub)
  Cc: Sven Peter, Janne Grunau, Neal Gompa, Marcel Holtmann,
	Markus Schneider-Pargmann, asahi, linux-arm-kernel,
	linux-bluetooth, linux-kernel
In-Reply-To: <aimXkX4FC4JVxt6q@monoceros>

Hi Uwe,

On Wed, Jun 10, 2026 at 12:59 PM Uwe Kleine-König (The Capable Hub)
<u.kleine-koenig@baylibre.com> wrote:
>
> On Mon, May 04, 2026 at 06:09:40PM +0200, Uwe Kleine-König (The Capable Hub) wrote:
> > Initializing a struct using list initializers is hard to read, compared
> > to that using named initializers is more ideomatic. Convert the macro
> > used to assign values in the driver's pci_device_id array accordingly.
> >
> > This change doesn't introduce any changes to the compiled array on an
> > x86 and an arm64 build.
> >
> > Signed-off-by: Uwe Kleine-König (The Capable Hub) <u.kleine-koenig@baylibre.com>
> > ---
> > Hello,
> >
> > this is a preparing change for making struct pci_device_id::driver_data an
> > anonymous union (similar to
> > https://lore.kernel.org/all/cover.1776579304.git.u.kleine-koenig@baylibre.com/).
> > This requires named initializers for .driver_data. But even without that
> > this is a nice cleanup making the macro better readable.
> >
> > Gcc is happy with simplifying the assignment further using
> > PCI_VDEVICE(BROADCOM, BCM ## id ## _DEVICE_ID), but this is a bit fishy
> > because PCI_VDEVICE also assigns .class and .class_mask (using list
> > initializers), so I didn't convert that.
>
> In the meantime I learned that doing that would break W=1 builds, so it
> was a good choice to not go that path.
>
> > Once all pci_device_id use
> > named initializers, the two zeros can be dropped from PCI_VDEVICE and
> > this entry simplified accordingly.
>
> Is this patch still on someone's radar? Ideally for application in time
> for 7.2-rc1?

It is no longer in patchwork so if you really want to get in please resend.

> Best regards
> Uwe



-- 
Luiz Augusto von Dentz

^ permalink raw reply

* Re: [PATCH v9 1/1] Bluetooth: L2CAP: Fix use-after-free in l2cap_sock_new_connection_cb()
From: Luiz Augusto von Dentz @ 2026-06-10 17:12 UTC (permalink / raw)
  To: Siwei Zhang; +Cc: linux-bluetooth
In-Reply-To: <e9720437-0673-4428-9be2-203404e5cbec@app.fastmail.com>

Hi Siwei,

On Wed, Jun 10, 2026 at 1:03 PM Siwei Zhang <oss@fourdim.xyz> wrote:
>
>
> On Wed, Jun 10, 2026, at 12:59 PM, Luiz Augusto von Dentz wrote:
> > Hi Siwei,
> >
> > On Wed, Jun 10, 2026 at 12:33 PM Siwei Zhang <oss@fourdim.xyz> wrote:
> >>
> >>
> >>
> >> On Wed, Jun 10, 2026, at 11:57 AM, Luiz Augusto von Dentz wrote:
> >> > Hi Siwei,
> >> >
> >> > On Mon, Jun 8, 2026 at 9:29 AM Siwei Zhang <oss@fourdim.xyz> wrote:
> >> >>
> >> >> Hi Luiz,
> >> >>
> >> >> On Thu, Jun 4, 2026, at 11:52 AM, Siwei Zhang wrote:
> >> >> > Hi Luiz,
> >> >> >
> >> >> > On Wed, Jun 3, 2026, at 2:17 PM, Luiz Augusto von Dentz wrote:
> >> >> >> Hi Siwei,
> >> >> >>
> >> >> >> On Wed, Jun 3, 2026 at 11:09 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-8
> >> >> >>> Signed-off-by: Siwei Zhang <oss@fourdim.xyz>
> >> >> >>> ---
> >> >> >>>  include/net/bluetooth/l2cap.h | 10 +++--
> >> >> >>>  net/bluetooth/6lowpan.c       | 31 +++++++------
> >> >> >>>  net/bluetooth/l2cap_core.c    | 41 ++++++++++++-----
> >> >> >>>  net/bluetooth/l2cap_sock.c    | 83 +++++++++++++++++++++--------------
> >> >> >>>  net/bluetooth/smp.c           | 17 ++++---
> >> >> >>>  5 files changed, 113 insertions(+), 69 deletions(-)
> >> >> >>>
> >> >> >>> diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h
> >> >> >>> index e0a1f2293679..7f5e4647f6e0 100644
> >> >> >>> --- a/include/net/bluetooth/l2cap.h
> >> >> >>> +++ b/include/net/bluetooth/l2cap.h
> >> >> >>> @@ -620,7 +620,9 @@ struct l2cap_chan {
> >> >> >>>  struct l2cap_ops {
> >> >> >>>         char                    *name;
> >> >> >>>
> >> >> >>> -       struct l2cap_chan       *(*new_connection) (struct l2cap_chan *chan);
> >> >> >>> +       int                     (*new_connection)(struct l2cap_conn *conn,
> >> >> >>> +                                                 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 +886,11 @@ 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_conn *conn,
> >> >> >>> +                                              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..94863af97a44 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,19 @@ 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_conn *conn,
> >> >> >>> +                                  struct l2cap_chan *pchan,
> >> >> >>> +                                  struct l2cap_chan *chan)
> >> >> >>>  {
> >> >> >>> -       struct l2cap_chan *chan;
> >> >> >>> -
> >> >> >>> -       chan = chan_create();
> >> >> >>> -       if (!chan)
> >> >> >>> -               return NULL;
> >> >> >>> -
> >> >> >>> +       chan_init(chan);
> >>
> >> ref1: chan->chan_type = L2CAP_CHAN_CONN_ORIENTED; set
> >> in chan_init.
> >>
> >> >> >>>         chan->ops = pchan->ops;
> >> >> >>>
> >> >> >>> +       /* Take the conn list reference; see l2cap_new_connection(). */
> >> >> >>> +       __l2cap_chan_add(conn, 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..62acf90837fb 100644
> >> >> >>> --- a/net/bluetooth/l2cap_core.c
> >> >> >>> +++ b/net/bluetooth/l2cap_core.c
> >> >> >>> @@ -4007,6 +4007,31 @@ static inline int l2cap_command_rej(struct l2cap_conn *conn,
> >> >> >>>         return 0;
> >> >> >>>  }
> >> >> >>>
> >> >> >>> +/* Allocate and initialise a channel for an incoming connection.
> >> >> >>> + *
> >> >> >>> + * ->new_connection() initialises the channel and links it into @conn with
> >> >> >>> + * __l2cap_chan_add(). The l2cap_chan_create() reference becomes the one owned
> >> >> >>> + * by the parent subsystem (l2cap_pi(sk)->chan, conn->smp or peer->chan) and is
> >> >> >>> + * released by its teardown callback; the conn list reference is released by
> >> >> >>> + * l2cap_chan_del().
> >> >> >>> + */
> >> >> >>> +static struct l2cap_chan *l2cap_new_connection(struct l2cap_conn *conn,
> >> >> >>> +                                              struct l2cap_chan *pchan)
> >> >> >>> +{
> >> >> >>> +       struct l2cap_chan *chan;
> >> >> >>> +
> >> >> >>> +       chan = l2cap_chan_create();
> >> >> >>> +       if (!chan)
> >> >> >>> +               return NULL;
> >> >> >>> +
> >> >> >>> +       if (pchan->ops->new_connection(conn, pchan, chan) < 0) {
> >> >> >>> +               l2cap_chan_put(chan);
> >> >> >>> +               return NULL;
> >> >> >>> +       }
> >> >> >>
> >> >> >> I don't quite get why we can't just place __l2cap_chan_add here
> >> >> >> instead of having it called by new_connection callbacks?
> >> >> >>
> >> >> >
> >> >> > It's specifically the l2cap_sock_new_connection_cb() case - the very
> >> >> > use-after-free this patch fixes. The __l2cap_chan_add() has to happen while
> >> >> > the parent lock is still held, and only the callback holds that lock.
> >> >> >
> >> >> > The reference counting on the new child chan starts at one ref,
> >> >> > owned by the new socket:
> >> >> >
> >> >> >       /* l2cap_new_connection() */
> >> >> >       chan = l2cap_chan_create();             /* refcount = 1 */
> >> >> >       if (!chan)
> >> >> >               return NULL;
> >> >> >
> >> >> >       pchan->ops->new_connection(conn, pchan, chan);
> >> >> >
> >> >> > and inside the socket callback:
> >> >> >
> >> >> >       /* l2cap_sock_new_connection_cb() */
> >> >> >       lock_sock(parent);
> >> >> >       ...
> >> >> >       sk = l2cap_sock_alloc(..., new_chan);   /* sk owns the chan_create ref */
> >> >> >       ...
> >> >> >       l2cap_sock_init(sk, parent);
> >> >> >
> >> >> >       __l2cap_chan_add(conn, new_chan);       /* (A) conn list takes a ref */
> >> >> >       bt_accept_enqueue(parent, sk, false);   /* (B) sk now on accept queue */
> >> >> >
> >> >> >       release_sock(parent);                   /* (C) parent lock dropped */
> >> >> >       return 0;
> >> >> >
> >> >> > The moment we hit (C), sk is reachable through the parent's accept queue, so
> >> >> > another task can grab and tear it down:
> >> >> >
> >> >> >       accept() -> l2cap_sock_kill() -> l2cap_sock_put_chan()
> >> >> >               chan->data = NULL;
> >> >> >               l2cap_chan_put(chan);           /* drops the sk's chan ref */
> >> >> >
> >> >> > If __l2cap_chan_add() at (A) hadn't already taken the conn list reference,
> >> >> > that put would drop the last ref and free new_chan. Control then returns up
> >> >> > to l2cap_new_connection(), which hands the now-freed chan back to
> >> >> > l2cap_connect():
> >> >> >
> >> >> >       /* l2cap_connect() - runs after the callback returns */
> >> >> >       chan = l2cap_new_connection(conn, pchan);
> >> >> >       if (!chan)
> >> >> >               goto response;
> >> >> >       ...
> >> >> >       bacpy(&chan->src, &conn->hcon->src);    /* <-- UAF on freed chan */
> >> >> >       chan->psm  = psm;
> >> >> >       chan->dcid = scid;
> >> >> >
> >> >> > The conn list reference taken at (A), before (C), is what keeps new_chan
> >> >> > alive across the release_sock() window so l2cap_connect() can keep using it.
> >> >> >
> >> >> > So __l2cap_chan_add() can't move out to l2cap_new_connection(): by the time
> >> >> > the callback returns, the parent lock is already dropped and chan may already
> >> >> > be freed - which is exactly the race. It has to be taken inside the callback,
> >> >> > under the parent lock, before the socket is exposed.
> >> >
> >> > If you do after l2cap_new_connection, yes, but what if you do before
> >> > you call ->new_connect:
> >> >
> >> > diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
> >> > index 3991c179b98f..cd864f400985 100644
> >> > --- a/net/bluetooth/l2cap_core.c
> >> > +++ b/net/bluetooth/l2cap_core.c
> >> > @@ -4027,8 +4027,10 @@ static struct l2cap_chan
> >> > *l2cap_new_connection(struct l2cap_conn *conn,
> >> >         if (!chan)
> >> >                 return NULL;
> >> >
> >> > +       __l2cap_chan_add(conn, chan);
> >> > +
> >> >         if (pchan->ops->new_connection(conn, pchan, chan) < 0) {
> >> > -               l2cap_chan_put(chan);
> >> > +               l2cap_chan_del(chan, 0);
> >> >                 return NULL;
> >> >         }
> >> >
> >> > This means we have to call l2cap_chan_del if new_connection fails, but
> >> > we can eliminate other functions having to call __l2cap_chan_add with
> >> > this. If the issue is then having l2cap_chan_del called concurrently,
> >> > we can add a l2cap_chan_hold; actually, we may need a reference anyway
> >> > since sk can be released and call l2cap_chan_del, releasing both
> >> > references.
> >> >
> >>
> >> In:
> >>
> >> void __l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan)
> >> {
> >>         ...
> >>         switch (chan->chan_type) {
> >>         case L2CAP_CHAN_CONN_ORIENTED:
> >>                 ...
> >>                 break;
> >>         case L2CAP_CHAN_CONN_LESS:
> >>                 ...
> >>                 break;
> >>         case L2CAP_CHAN_FIXED:
> >>                 ...
> >>                 break;
> >>         default:
> >>                 ...
> >>         }
> >> }
> >>
> >> Apparently it depends on chan->chan_type and it is set by ref1.
> >> It is only set in cb function.
> >
> > Ok, this probably needs fixing in 6lowpan. These defaults should come
> > from the parent channel, similar to how it's done in l2cap_sock_init.
> > Perhaps we should promote that logic to l2cap_chan_set_defaults
> > passing pchan so it can initialize the channel before calling
> > __l2cap_chan_add.
>
> I can fix that in a separate patch.
> Could you please merge it first?

Merge it first, and then rework the order? Not sure what is the
benefit of doing that, it is a somewhat substatial change either way
so I don't think it will make it much easier to lets say backport.

> Best,
> Siwei



-- 
Luiz Augusto von Dentz

^ permalink raw reply

* Re: [PATCH v9 1/1] Bluetooth: L2CAP: Fix use-after-free in l2cap_sock_new_connection_cb()
From: Siwei Zhang @ 2026-06-10 17:02 UTC (permalink / raw)
  To: Luiz Augusto von Dentz; +Cc: linux-bluetooth
In-Reply-To: <CABBYNZJsyPU5wr4T32Ej9Vj0=Nco=PjtQn4aiC=NqUGbgP3zBw@mail.gmail.com>


On Wed, Jun 10, 2026, at 12:59 PM, Luiz Augusto von Dentz wrote:
> Hi Siwei,
>
> On Wed, Jun 10, 2026 at 12:33 PM Siwei Zhang <oss@fourdim.xyz> wrote:
>>
>>
>>
>> On Wed, Jun 10, 2026, at 11:57 AM, Luiz Augusto von Dentz wrote:
>> > Hi Siwei,
>> >
>> > On Mon, Jun 8, 2026 at 9:29 AM Siwei Zhang <oss@fourdim.xyz> wrote:
>> >>
>> >> Hi Luiz,
>> >>
>> >> On Thu, Jun 4, 2026, at 11:52 AM, Siwei Zhang wrote:
>> >> > Hi Luiz,
>> >> >
>> >> > On Wed, Jun 3, 2026, at 2:17 PM, Luiz Augusto von Dentz wrote:
>> >> >> Hi Siwei,
>> >> >>
>> >> >> On Wed, Jun 3, 2026 at 11:09 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-8
>> >> >>> Signed-off-by: Siwei Zhang <oss@fourdim.xyz>
>> >> >>> ---
>> >> >>>  include/net/bluetooth/l2cap.h | 10 +++--
>> >> >>>  net/bluetooth/6lowpan.c       | 31 +++++++------
>> >> >>>  net/bluetooth/l2cap_core.c    | 41 ++++++++++++-----
>> >> >>>  net/bluetooth/l2cap_sock.c    | 83 +++++++++++++++++++++--------------
>> >> >>>  net/bluetooth/smp.c           | 17 ++++---
>> >> >>>  5 files changed, 113 insertions(+), 69 deletions(-)
>> >> >>>
>> >> >>> diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h
>> >> >>> index e0a1f2293679..7f5e4647f6e0 100644
>> >> >>> --- a/include/net/bluetooth/l2cap.h
>> >> >>> +++ b/include/net/bluetooth/l2cap.h
>> >> >>> @@ -620,7 +620,9 @@ struct l2cap_chan {
>> >> >>>  struct l2cap_ops {
>> >> >>>         char                    *name;
>> >> >>>
>> >> >>> -       struct l2cap_chan       *(*new_connection) (struct l2cap_chan *chan);
>> >> >>> +       int                     (*new_connection)(struct l2cap_conn *conn,
>> >> >>> +                                                 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 +886,11 @@ 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_conn *conn,
>> >> >>> +                                              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..94863af97a44 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,19 @@ 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_conn *conn,
>> >> >>> +                                  struct l2cap_chan *pchan,
>> >> >>> +                                  struct l2cap_chan *chan)
>> >> >>>  {
>> >> >>> -       struct l2cap_chan *chan;
>> >> >>> -
>> >> >>> -       chan = chan_create();
>> >> >>> -       if (!chan)
>> >> >>> -               return NULL;
>> >> >>> -
>> >> >>> +       chan_init(chan);
>>
>> ref1: chan->chan_type = L2CAP_CHAN_CONN_ORIENTED; set
>> in chan_init.
>>
>> >> >>>         chan->ops = pchan->ops;
>> >> >>>
>> >> >>> +       /* Take the conn list reference; see l2cap_new_connection(). */
>> >> >>> +       __l2cap_chan_add(conn, 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..62acf90837fb 100644
>> >> >>> --- a/net/bluetooth/l2cap_core.c
>> >> >>> +++ b/net/bluetooth/l2cap_core.c
>> >> >>> @@ -4007,6 +4007,31 @@ static inline int l2cap_command_rej(struct l2cap_conn *conn,
>> >> >>>         return 0;
>> >> >>>  }
>> >> >>>
>> >> >>> +/* Allocate and initialise a channel for an incoming connection.
>> >> >>> + *
>> >> >>> + * ->new_connection() initialises the channel and links it into @conn with
>> >> >>> + * __l2cap_chan_add(). The l2cap_chan_create() reference becomes the one owned
>> >> >>> + * by the parent subsystem (l2cap_pi(sk)->chan, conn->smp or peer->chan) and is
>> >> >>> + * released by its teardown callback; the conn list reference is released by
>> >> >>> + * l2cap_chan_del().
>> >> >>> + */
>> >> >>> +static struct l2cap_chan *l2cap_new_connection(struct l2cap_conn *conn,
>> >> >>> +                                              struct l2cap_chan *pchan)
>> >> >>> +{
>> >> >>> +       struct l2cap_chan *chan;
>> >> >>> +
>> >> >>> +       chan = l2cap_chan_create();
>> >> >>> +       if (!chan)
>> >> >>> +               return NULL;
>> >> >>> +
>> >> >>> +       if (pchan->ops->new_connection(conn, pchan, chan) < 0) {
>> >> >>> +               l2cap_chan_put(chan);
>> >> >>> +               return NULL;
>> >> >>> +       }
>> >> >>
>> >> >> I don't quite get why we can't just place __l2cap_chan_add here
>> >> >> instead of having it called by new_connection callbacks?
>> >> >>
>> >> >
>> >> > It's specifically the l2cap_sock_new_connection_cb() case - the very
>> >> > use-after-free this patch fixes. The __l2cap_chan_add() has to happen while
>> >> > the parent lock is still held, and only the callback holds that lock.
>> >> >
>> >> > The reference counting on the new child chan starts at one ref,
>> >> > owned by the new socket:
>> >> >
>> >> >       /* l2cap_new_connection() */
>> >> >       chan = l2cap_chan_create();             /* refcount = 1 */
>> >> >       if (!chan)
>> >> >               return NULL;
>> >> >
>> >> >       pchan->ops->new_connection(conn, pchan, chan);
>> >> >
>> >> > and inside the socket callback:
>> >> >
>> >> >       /* l2cap_sock_new_connection_cb() */
>> >> >       lock_sock(parent);
>> >> >       ...
>> >> >       sk = l2cap_sock_alloc(..., new_chan);   /* sk owns the chan_create ref */
>> >> >       ...
>> >> >       l2cap_sock_init(sk, parent);
>> >> >
>> >> >       __l2cap_chan_add(conn, new_chan);       /* (A) conn list takes a ref */
>> >> >       bt_accept_enqueue(parent, sk, false);   /* (B) sk now on accept queue */
>> >> >
>> >> >       release_sock(parent);                   /* (C) parent lock dropped */
>> >> >       return 0;
>> >> >
>> >> > The moment we hit (C), sk is reachable through the parent's accept queue, so
>> >> > another task can grab and tear it down:
>> >> >
>> >> >       accept() -> l2cap_sock_kill() -> l2cap_sock_put_chan()
>> >> >               chan->data = NULL;
>> >> >               l2cap_chan_put(chan);           /* drops the sk's chan ref */
>> >> >
>> >> > If __l2cap_chan_add() at (A) hadn't already taken the conn list reference,
>> >> > that put would drop the last ref and free new_chan. Control then returns up
>> >> > to l2cap_new_connection(), which hands the now-freed chan back to
>> >> > l2cap_connect():
>> >> >
>> >> >       /* l2cap_connect() - runs after the callback returns */
>> >> >       chan = l2cap_new_connection(conn, pchan);
>> >> >       if (!chan)
>> >> >               goto response;
>> >> >       ...
>> >> >       bacpy(&chan->src, &conn->hcon->src);    /* <-- UAF on freed chan */
>> >> >       chan->psm  = psm;
>> >> >       chan->dcid = scid;
>> >> >
>> >> > The conn list reference taken at (A), before (C), is what keeps new_chan
>> >> > alive across the release_sock() window so l2cap_connect() can keep using it.
>> >> >
>> >> > So __l2cap_chan_add() can't move out to l2cap_new_connection(): by the time
>> >> > the callback returns, the parent lock is already dropped and chan may already
>> >> > be freed - which is exactly the race. It has to be taken inside the callback,
>> >> > under the parent lock, before the socket is exposed.
>> >
>> > If you do after l2cap_new_connection, yes, but what if you do before
>> > you call ->new_connect:
>> >
>> > diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
>> > index 3991c179b98f..cd864f400985 100644
>> > --- a/net/bluetooth/l2cap_core.c
>> > +++ b/net/bluetooth/l2cap_core.c
>> > @@ -4027,8 +4027,10 @@ static struct l2cap_chan
>> > *l2cap_new_connection(struct l2cap_conn *conn,
>> >         if (!chan)
>> >                 return NULL;
>> >
>> > +       __l2cap_chan_add(conn, chan);
>> > +
>> >         if (pchan->ops->new_connection(conn, pchan, chan) < 0) {
>> > -               l2cap_chan_put(chan);
>> > +               l2cap_chan_del(chan, 0);
>> >                 return NULL;
>> >         }
>> >
>> > This means we have to call l2cap_chan_del if new_connection fails, but
>> > we can eliminate other functions having to call __l2cap_chan_add with
>> > this. If the issue is then having l2cap_chan_del called concurrently,
>> > we can add a l2cap_chan_hold; actually, we may need a reference anyway
>> > since sk can be released and call l2cap_chan_del, releasing both
>> > references.
>> >
>>
>> In:
>>
>> void __l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan)
>> {
>>         ...
>>         switch (chan->chan_type) {
>>         case L2CAP_CHAN_CONN_ORIENTED:
>>                 ...
>>                 break;
>>         case L2CAP_CHAN_CONN_LESS:
>>                 ...
>>                 break;
>>         case L2CAP_CHAN_FIXED:
>>                 ...
>>                 break;
>>         default:
>>                 ...
>>         }
>> }
>>
>> Apparently it depends on chan->chan_type and it is set by ref1.
>> It is only set in cb function.
>
> Ok, this probably needs fixing in 6lowpan. These defaults should come
> from the parent channel, similar to how it's done in l2cap_sock_init.
> Perhaps we should promote that logic to l2cap_chan_set_defaults
> passing pchan so it can initialize the channel before calling
> __l2cap_chan_add.

I can fix that in a separate patch.
Could you please merge it first?

Best,
Siwei

^ permalink raw reply

* Re: [PATCH v9 1/1] Bluetooth: L2CAP: Fix use-after-free in l2cap_sock_new_connection_cb()
From: Luiz Augusto von Dentz @ 2026-06-10 16:59 UTC (permalink / raw)
  To: Siwei Zhang; +Cc: linux-bluetooth
In-Reply-To: <3cf8c12c-10c3-4ba8-9037-7e41a820d23d@app.fastmail.com>

Hi Siwei,

On Wed, Jun 10, 2026 at 12:33 PM Siwei Zhang <oss@fourdim.xyz> wrote:
>
>
>
> On Wed, Jun 10, 2026, at 11:57 AM, Luiz Augusto von Dentz wrote:
> > Hi Siwei,
> >
> > On Mon, Jun 8, 2026 at 9:29 AM Siwei Zhang <oss@fourdim.xyz> wrote:
> >>
> >> Hi Luiz,
> >>
> >> On Thu, Jun 4, 2026, at 11:52 AM, Siwei Zhang wrote:
> >> > Hi Luiz,
> >> >
> >> > On Wed, Jun 3, 2026, at 2:17 PM, Luiz Augusto von Dentz wrote:
> >> >> Hi Siwei,
> >> >>
> >> >> On Wed, Jun 3, 2026 at 11:09 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-8
> >> >>> Signed-off-by: Siwei Zhang <oss@fourdim.xyz>
> >> >>> ---
> >> >>>  include/net/bluetooth/l2cap.h | 10 +++--
> >> >>>  net/bluetooth/6lowpan.c       | 31 +++++++------
> >> >>>  net/bluetooth/l2cap_core.c    | 41 ++++++++++++-----
> >> >>>  net/bluetooth/l2cap_sock.c    | 83 +++++++++++++++++++++--------------
> >> >>>  net/bluetooth/smp.c           | 17 ++++---
> >> >>>  5 files changed, 113 insertions(+), 69 deletions(-)
> >> >>>
> >> >>> diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h
> >> >>> index e0a1f2293679..7f5e4647f6e0 100644
> >> >>> --- a/include/net/bluetooth/l2cap.h
> >> >>> +++ b/include/net/bluetooth/l2cap.h
> >> >>> @@ -620,7 +620,9 @@ struct l2cap_chan {
> >> >>>  struct l2cap_ops {
> >> >>>         char                    *name;
> >> >>>
> >> >>> -       struct l2cap_chan       *(*new_connection) (struct l2cap_chan *chan);
> >> >>> +       int                     (*new_connection)(struct l2cap_conn *conn,
> >> >>> +                                                 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 +886,11 @@ 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_conn *conn,
> >> >>> +                                              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..94863af97a44 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,19 @@ 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_conn *conn,
> >> >>> +                                  struct l2cap_chan *pchan,
> >> >>> +                                  struct l2cap_chan *chan)
> >> >>>  {
> >> >>> -       struct l2cap_chan *chan;
> >> >>> -
> >> >>> -       chan = chan_create();
> >> >>> -       if (!chan)
> >> >>> -               return NULL;
> >> >>> -
> >> >>> +       chan_init(chan);
>
> ref1: chan->chan_type = L2CAP_CHAN_CONN_ORIENTED; set
> in chan_init.
>
> >> >>>         chan->ops = pchan->ops;
> >> >>>
> >> >>> +       /* Take the conn list reference; see l2cap_new_connection(). */
> >> >>> +       __l2cap_chan_add(conn, 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..62acf90837fb 100644
> >> >>> --- a/net/bluetooth/l2cap_core.c
> >> >>> +++ b/net/bluetooth/l2cap_core.c
> >> >>> @@ -4007,6 +4007,31 @@ static inline int l2cap_command_rej(struct l2cap_conn *conn,
> >> >>>         return 0;
> >> >>>  }
> >> >>>
> >> >>> +/* Allocate and initialise a channel for an incoming connection.
> >> >>> + *
> >> >>> + * ->new_connection() initialises the channel and links it into @conn with
> >> >>> + * __l2cap_chan_add(). The l2cap_chan_create() reference becomes the one owned
> >> >>> + * by the parent subsystem (l2cap_pi(sk)->chan, conn->smp or peer->chan) and is
> >> >>> + * released by its teardown callback; the conn list reference is released by
> >> >>> + * l2cap_chan_del().
> >> >>> + */
> >> >>> +static struct l2cap_chan *l2cap_new_connection(struct l2cap_conn *conn,
> >> >>> +                                              struct l2cap_chan *pchan)
> >> >>> +{
> >> >>> +       struct l2cap_chan *chan;
> >> >>> +
> >> >>> +       chan = l2cap_chan_create();
> >> >>> +       if (!chan)
> >> >>> +               return NULL;
> >> >>> +
> >> >>> +       if (pchan->ops->new_connection(conn, pchan, chan) < 0) {
> >> >>> +               l2cap_chan_put(chan);
> >> >>> +               return NULL;
> >> >>> +       }
> >> >>
> >> >> I don't quite get why we can't just place __l2cap_chan_add here
> >> >> instead of having it called by new_connection callbacks?
> >> >>
> >> >
> >> > It's specifically the l2cap_sock_new_connection_cb() case - the very
> >> > use-after-free this patch fixes. The __l2cap_chan_add() has to happen while
> >> > the parent lock is still held, and only the callback holds that lock.
> >> >
> >> > The reference counting on the new child chan starts at one ref,
> >> > owned by the new socket:
> >> >
> >> >       /* l2cap_new_connection() */
> >> >       chan = l2cap_chan_create();             /* refcount = 1 */
> >> >       if (!chan)
> >> >               return NULL;
> >> >
> >> >       pchan->ops->new_connection(conn, pchan, chan);
> >> >
> >> > and inside the socket callback:
> >> >
> >> >       /* l2cap_sock_new_connection_cb() */
> >> >       lock_sock(parent);
> >> >       ...
> >> >       sk = l2cap_sock_alloc(..., new_chan);   /* sk owns the chan_create ref */
> >> >       ...
> >> >       l2cap_sock_init(sk, parent);
> >> >
> >> >       __l2cap_chan_add(conn, new_chan);       /* (A) conn list takes a ref */
> >> >       bt_accept_enqueue(parent, sk, false);   /* (B) sk now on accept queue */
> >> >
> >> >       release_sock(parent);                   /* (C) parent lock dropped */
> >> >       return 0;
> >> >
> >> > The moment we hit (C), sk is reachable through the parent's accept queue, so
> >> > another task can grab and tear it down:
> >> >
> >> >       accept() -> l2cap_sock_kill() -> l2cap_sock_put_chan()
> >> >               chan->data = NULL;
> >> >               l2cap_chan_put(chan);           /* drops the sk's chan ref */
> >> >
> >> > If __l2cap_chan_add() at (A) hadn't already taken the conn list reference,
> >> > that put would drop the last ref and free new_chan. Control then returns up
> >> > to l2cap_new_connection(), which hands the now-freed chan back to
> >> > l2cap_connect():
> >> >
> >> >       /* l2cap_connect() - runs after the callback returns */
> >> >       chan = l2cap_new_connection(conn, pchan);
> >> >       if (!chan)
> >> >               goto response;
> >> >       ...
> >> >       bacpy(&chan->src, &conn->hcon->src);    /* <-- UAF on freed chan */
> >> >       chan->psm  = psm;
> >> >       chan->dcid = scid;
> >> >
> >> > The conn list reference taken at (A), before (C), is what keeps new_chan
> >> > alive across the release_sock() window so l2cap_connect() can keep using it.
> >> >
> >> > So __l2cap_chan_add() can't move out to l2cap_new_connection(): by the time
> >> > the callback returns, the parent lock is already dropped and chan may already
> >> > be freed - which is exactly the race. It has to be taken inside the callback,
> >> > under the parent lock, before the socket is exposed.
> >
> > If you do after l2cap_new_connection, yes, but what if you do before
> > you call ->new_connect:
> >
> > diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
> > index 3991c179b98f..cd864f400985 100644
> > --- a/net/bluetooth/l2cap_core.c
> > +++ b/net/bluetooth/l2cap_core.c
> > @@ -4027,8 +4027,10 @@ static struct l2cap_chan
> > *l2cap_new_connection(struct l2cap_conn *conn,
> >         if (!chan)
> >                 return NULL;
> >
> > +       __l2cap_chan_add(conn, chan);
> > +
> >         if (pchan->ops->new_connection(conn, pchan, chan) < 0) {
> > -               l2cap_chan_put(chan);
> > +               l2cap_chan_del(chan, 0);
> >                 return NULL;
> >         }
> >
> > This means we have to call l2cap_chan_del if new_connection fails, but
> > we can eliminate other functions having to call __l2cap_chan_add with
> > this. If the issue is then having l2cap_chan_del called concurrently,
> > we can add a l2cap_chan_hold; actually, we may need a reference anyway
> > since sk can be released and call l2cap_chan_del, releasing both
> > references.
> >
>
> In:
>
> void __l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan)
> {
>         ...
>         switch (chan->chan_type) {
>         case L2CAP_CHAN_CONN_ORIENTED:
>                 ...
>                 break;
>         case L2CAP_CHAN_CONN_LESS:
>                 ...
>                 break;
>         case L2CAP_CHAN_FIXED:
>                 ...
>                 break;
>         default:
>                 ...
>         }
> }
>
> Apparently it depends on chan->chan_type and it is set by ref1.
> It is only set in cb function.

Ok, this probably needs fixing in 6lowpan. These defaults should come
from the parent channel, similar to how it's done in l2cap_sock_init.
Perhaps we should promote that logic to l2cap_chan_set_defaults
passing pchan so it can initialize the channel before calling
__l2cap_chan_add.

^ permalink raw reply

* Re: [PATCH] Bluetooth: hci_bcm4377: Use named initializers for pci_device_id array
From: Uwe Kleine-König (The Capable Hub) @ 2026-06-10 16:59 UTC (permalink / raw)
  To: Sven Peter, Janne Grunau, Neal Gompa, Marcel Holtmann,
	Luiz Augusto von Dentz
  Cc: Markus Schneider-Pargmann, asahi, linux-arm-kernel,
	linux-bluetooth, linux-kernel
In-Reply-To: <20260504160940.2168650-2-u.kleine-koenig@baylibre.com>

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

On Mon, May 04, 2026 at 06:09:40PM +0200, Uwe Kleine-König (The Capable Hub) wrote:
> Initializing a struct using list initializers is hard to read, compared
> to that using named initializers is more ideomatic. Convert the macro
> used to assign values in the driver's pci_device_id array accordingly.
> 
> This change doesn't introduce any changes to the compiled array on an
> x86 and an arm64 build.
> 
> Signed-off-by: Uwe Kleine-König (The Capable Hub) <u.kleine-koenig@baylibre.com>
> ---
> Hello,
> 
> this is a preparing change for making struct pci_device_id::driver_data an
> anonymous union (similar to
> https://lore.kernel.org/all/cover.1776579304.git.u.kleine-koenig@baylibre.com/).
> This requires named initializers for .driver_data. But even without that
> this is a nice cleanup making the macro better readable.
> 
> Gcc is happy with simplifying the assignment further using
> PCI_VDEVICE(BROADCOM, BCM ## id ## _DEVICE_ID), but this is a bit fishy
> because PCI_VDEVICE also assigns .class and .class_mask (using list
> initializers), so I didn't convert that.

In the meantime I learned that doing that would break W=1 builds, so it
was a good choice to not go that path.

> Once all pci_device_id use
> named initializers, the two zeros can be dropped from PCI_VDEVICE and
> this entry simplified accordingly.

Is this patch still on someone's radar? Ideally for application in time
for 7.2-rc1?

Best regards
Uwe

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

^ permalink raw reply

* [bluez/bluez]
From: BluezTestBot @ 2026-06-10 16:50 UTC (permalink / raw)
  To: linux-bluetooth

  Branch: refs/heads/1092801
  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


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