Linux bluetooth development
 help / color / mirror / Atom feed
* RE: Bluetooth: L2CAP: Fix use-after-free in l2cap_sock_new_connection_cb()
  2026-05-11  3:18 [PATCH 1/1] " Siwei Zhang
@ 2026-05-11  4:21 ` bluez.test.bot
  0 siblings, 0 replies; 10+ messages in thread
From: bluez.test.bot @ 2026-05-11  4:21 UTC (permalink / raw)
  To: linux-bluetooth, oss

[-- Attachment #1: Type: text/plain, Size: 555 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: net/bluetooth/l2cap_sock.c:1497
error: net/bluetooth/l2cap_sock.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	[flat|nested] 10+ messages in thread

* RE: Bluetooth: L2CAP: Fix use-after-free in l2cap_sock_new_connection_cb()
  2026-05-11  4:51 [PATCH 1/1] " Siwei Zhang
@ 2026-05-11  8:32 ` bluez.test.bot
  0 siblings, 0 replies; 10+ messages in thread
From: bluez.test.bot @ 2026-05-11  8:32 UTC (permalink / raw)
  To: linux-bluetooth, oss

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

---Test result---

Test Summary:
CheckPatch                    PASS      2.09 seconds
GitLint                       PASS      0.32 seconds
SubjectPrefix                 PASS      0.12 seconds
BuildKernel                   PASS      25.70 seconds
CheckAllWarning               PASS      28.70 seconds
CheckSparse                   PASS      27.32 seconds
BuildKernel32                 PASS      25.31 seconds
TestRunnerSetup               PASS      561.40 seconds
TestRunner_l2cap-tester       PASS      378.21 seconds
TestRunner_smp-tester         PASS      18.06 seconds
TestRunner_6lowpan-tester     PASS      51.06 seconds
IncrementalBuild              PASS      24.97 seconds



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

---
Regards,
Linux Bluetooth


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

* RE: Bluetooth: L2CAP: Fix use-after-free in l2cap_sock_new_connection_cb()
  2026-05-11 17:09 [PATCH RESEND v4 1/1] " Siwei Zhang
@ 2026-05-11 18:49 ` bluez.test.bot
  0 siblings, 0 replies; 10+ messages in thread
From: bluez.test.bot @ 2026-05-11 18:49 UTC (permalink / raw)
  To: linux-bluetooth, oss

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

---Test result---

Test Summary:
CheckPatch                    PASS      1.40 seconds
GitLint                       FAIL      0.34 seconds
SubjectPrefix                 PASS      0.13 seconds
BuildKernel                   PASS      26.78 seconds
CheckAllWarning               PASS      27.90 seconds
CheckSparse                   PASS      26.85 seconds
BuildKernel32                 PASS      24.71 seconds
TestRunnerSetup               PASS      524.97 seconds
TestRunner_l2cap-tester       PASS      376.41 seconds
TestRunner_smp-tester         PASS      18.41 seconds
TestRunner_6lowpan-tester     PASS      51.29 seconds
IncrementalBuild              PASS      23.95 seconds

Details
##############################
Test: GitLint - FAIL
Desc: Run gitlint
Output:
[RESEND,v4,1/1] Bluetooth: L2CAP: Fix use-after-free in l2cap_sock_new_connection_cb()

WARNING: I3 - ignore-body-lines: gitlint will be switching from using Python regex 'match' (match beginning) to 'search' (match anywhere) semantics. Please review your ignore-body-lines.regex option accordingly. To remove this warning, set general.regex-style-search=True. More details: https://jorisroovers.github.io/gitlint/configuration/#regex-style-search
1: T1 Title exceeds max length (86>80): "[RESEND,v4,1/1] Bluetooth: L2CAP: Fix use-after-free in l2cap_sock_new_connection_cb()"


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

---
Regards,
Linux Bluetooth


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

* RE: Bluetooth: L2CAP: Fix use-after-free in l2cap_sock_new_connection_cb()
  2026-05-20 16:20 [PATCH v5 1/1] " Siwei Zhang
@ 2026-05-20 18:07 ` bluez.test.bot
  0 siblings, 0 replies; 10+ messages in thread
From: bluez.test.bot @ 2026-05-20 18:07 UTC (permalink / raw)
  To: linux-bluetooth, oss

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

---Test result---

Test Summary:
CheckPatch                    PASS      1.67 seconds
GitLint                       PASS      0.34 seconds
SubjectPrefix                 PASS      0.13 seconds
BuildKernel                   PASS      24.93 seconds
CheckAllWarning               PASS      27.79 seconds
CheckSparse                   PASS      26.40 seconds
BuildKernel32                 PASS      24.49 seconds
TestRunnerSetup               PASS      521.38 seconds
TestRunner_l2cap-tester       PASS      376.22 seconds
TestRunner_smp-tester         PASS      17.96 seconds
TestRunner_6lowpan-tester     PASS      50.91 seconds
IncrementalBuild              PASS      24.22 seconds



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

---
Regards,
Linux Bluetooth


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

* RE: Bluetooth: L2CAP: Fix use-after-free in l2cap_sock_new_connection_cb()
  2026-05-29 16:54 [PATCH v6 1/1] " Siwei Zhang
@ 2026-05-29 18:21 ` bluez.test.bot
  0 siblings, 0 replies; 10+ messages in thread
From: bluez.test.bot @ 2026-05-29 18:21 UTC (permalink / raw)
  To: linux-bluetooth, oss

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

---Test result---

Test Summary:
CheckPatch                    PASS      1.68 seconds
VerifyFixes                   PASS      0.14 seconds
VerifySignedoff               PASS      0.14 seconds
GitLint                       PASS      0.35 seconds
SubjectPrefix                 PASS      0.13 seconds
BuildKernel                   PASS      25.47 seconds
CheckAllWarning               PASS      27.77 seconds
CheckSparse                   PASS      26.54 seconds
BuildKernel32                 PASS      24.52 seconds
TestRunnerSetup               PASS      530.14 seconds
TestRunner_l2cap-tester       FAIL      55.83 seconds
TestRunner_smp-tester         FAIL      23.82 seconds
TestRunner_6lowpan-tester     FAIL      22.93 seconds
IncrementalBuild              PASS      25.60 seconds

Details
##############################
Test: TestRunner_l2cap-tester - FAIL
Desc: Run l2cap-tester with test-runner
Output:
WARNING: held lock freed!
7.1.0-rc1-g5f2fcd0833d0 #1 Not tainted
-------------------------
memcheck-amd64-/34 is freeing memory ffff888002762000-ffff8880027627ff, with a lock still held there!
ffff888002762508 (&chan->lock#4){+.+.}-{4:4}, at: l2cap_conn_del+0x33b/0x660
5 locks held by memcheck-amd64-/34:
 #0: ffff8880026e0e80 (&hdev->req_lock){+.+.}-{4:4}, at: hci_dev_do_close+0x5d/0x90
 #1: ffff8880026e00b0 (&hdev->lock){+.+.}-{4:4}, at: hci_dev_close_sync+0x2ca/0xfa0
 #2: ffffffffb92bc278 (hci_cb_list_lock){+.+.}-{4:4}, at: hci_conn_hash_flush+0xed/0x230
 #3: ffff8880022ec2f0 (&conn->lock){+.+.}-{4:4}, at: l2cap_conn_del+0x9b/0x660
 #4: ffff888002762508 (&chan->lock#4){+.+.}-{4:4}, at: l2cap_conn_del+0x33b/0x660

stack backtrace:
CPU: 0 UID: 0 PID: 34 Comm: memcheck-amd64- Not tainted 7.1.0-rc1-g5f2fcd0833d0 #1 PREEMPT(lazy) 
Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS 1.13.0-1ubuntu1.1 04/01/2014
Call Trace:
 <TASK>
 debug_check_no_locks_freed+0x102/0x140
 ? l2cap_chan_del+0x220/0x770
 kfree+0x22b/0x4c0
 ? _raw_write_unlock+0x1e/0x40
 l2cap_chan_del+0x220/0x770
 l2cap_conn_del+0x346/0x660
 hci_conn_hash_flush+0x135/0x230
 hci_dev_close_sync+0x4f8/0xfa0
 hci_dev_do_close+0x65/0x90
 hci_unregister_dev+0x254/0x510
 vhci_release+0x183/0x240
 __fput+0x356/0x9c0
 ? lock_is_held_type+0x9b/0x110
 fput_close_sync+0xd6/0x180
 ? __pfx_fput_close_sync+0x10/0x10
 __x64_sys_close+0x78/0xd0
 do_syscall_64+0x9f/0x560
 entry_SYSCALL_64_after_hwframe+0x74/0x7c
RIP: 0033:0x5805ccc9
Code: 00 e8 eb a4 fe ff 66 2e 0f 1f 84 00 00 00 00 00 90 48 89 f8 48 89 f7 48 89 d6 48 89 ca 4d 89 c2 4d 89 c8 4c 8b 4c 24 08 0f 05 <c3> 66 0f 1f 44 00 00 f3 0f 1e fa 8d 87 ff 0f 00 00 89 fa 89 ff 3d
RSP: 002b:0000001002db9d08 EFLAGS: 00000206 ORIG_RAX: 0000000000000003
RAX: ffffffffffffffda RBX: 0000001002386d90 RCX: 000000005805ccc9
RDX: 0000000000000000 RSI: 0000000000000000 RDI: 0000000000000007
...
BUG: KASAN: slab-use-after-free in l2cap_chan_del+0x6ee/0x770
Write of size 8 at addr ffff888002762000 by task memcheck-amd64-/34

CPU: 0 UID: 0 PID: 34 Comm: memcheck-amd64- Not tainted 7.1.0-rc1-g5f2fcd0833d0 #1 PREEMPT(lazy) 
Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS 1.13.0-1ubuntu1.1 04/01/2014
Call Trace:
 <TASK>
 print_report+0x108/0x5c0
 ? __virt_addr_valid+0x21c/0x3f0
 ? l2cap_chan_del+0x6ee/0x770
 kasan_report+0x94/0xc0
 ? l2cap_chan_del+0x6ee/0x770
 l2cap_chan_del+0x6ee/0x770
 l2cap_conn_del+0x346/0x660
 hci_conn_hash_flush+0x135/0x230
 hci_dev_close_sync+0x4f8/0xfa0
 hci_dev_do_close+0x65/0x90
 hci_unregister_dev+0x254/0x510
 vhci_release+0x183/0x240
 __fput+0x356/0x9c0
 ? lock_is_held_type+0x9b/0x110
 fput_close_sync+0xd6/0x180
 ? __pfx_fput_close_sync+0x10/0x10
 __x64_sys_close+0x78/0xd0
 do_syscall_64+0x9f/0x560
 entry_SYSCALL_64_after_hwframe+0x74/0x7c
RIP: 0033:0x5805ccc9
Code: 00 e8 eb a4 fe ff 66 2e 0f 1f 84 00 00 00 00 00 90 48 89 f8 48 89 f7 48 89 d6 48 89 ca 4d 89 c2 4d 89 c8 4c 8b 4c 24 08 0f 05 <c3> 66 0f 1f 44 00 00 f3 0f 1e fa 8d 87 ff 0f 00 00 89 fa 89 ff 3d
RSP: 002b:0000001002db9d08 EFLAGS: 00000206 ORIG_RAX: 0000000000000003
RAX: ffffffffffffffda RBX: 0000001002386d90 RCX: 000000005805ccc9
RDX: 0000000000000000 RSI: 0000000000000000 RDI: 0000000000000007
RBP: 0000000000000001 R08: 0000000005229e80 R09: 0000000000000040
R10: 00000000000002fa R11: 0000000000000206 R12: 0000001002386e20
R13: 0000001002008360 R14: 0000000000000003 R15: 0000001002db9d70
Total: 96, Passed: 96 (100.0%), Failed: 0, Not Run: 0
##############################
Test: TestRunner_smp-tester - FAIL
Desc: Run smp-tester with test-runner
Output:
WARNING: held lock freed!
7.1.0-rc1-g5f2fcd0833d0 #1 Not tainted
-------------------------
memcheck-amd64-/34 is freeing memory ffff8880021b6000-ffff8880021b67ff, with a lock still held there!
ffff8880021b6508 (&chan->lock#3){+.+.}-{4:4}, at: l2cap_conn_del+0x33b/0x660
5 locks held by memcheck-amd64-/34:
 #0: ffff8880024e4e80 (&hdev->req_lock){+.+.}-{4:4}, at: hci_dev_do_close+0x5d/0x90
 #1: ffff8880024e40b0 (&hdev->lock){+.+.}-{4:4}, at: hci_dev_close_sync+0x2ca/0xfa0
 #2: ffffffffb6ebc278 (hci_cb_list_lock){+.+.}-{4:4}, at: hci_conn_hash_flush+0xed/0x230
 #3: ffff8880022fb2f0 (&conn->lock){+.+.}-{4:4}, at: l2cap_conn_del+0x9b/0x660
 #4: ffff8880021b6508 (&chan->lock#3){+.+.}-{4:4}, at: l2cap_conn_del+0x33b/0x660

stack backtrace:
CPU: 0 UID: 0 PID: 34 Comm: memcheck-amd64- Not tainted 7.1.0-rc1-g5f2fcd0833d0 #1 PREEMPT(lazy) 
Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS 1.13.0-1ubuntu1.1 04/01/2014
Call Trace:
 <TASK>
 debug_check_no_locks_freed+0x102/0x140
 ? l2cap_chan_del+0x220/0x770
 kfree+0x22b/0x4c0
 ? _raw_write_unlock+0x1e/0x40
 l2cap_chan_del+0x220/0x770
 l2cap_conn_del+0x346/0x660
 hci_conn_hash_flush+0x135/0x230
 hci_dev_close_sync+0x4f8/0xfa0
 hci_dev_do_close+0x65/0x90
 hci_unregister_dev+0x254/0x510
 vhci_release+0x183/0x240
 __fput+0x356/0x9c0
 ? lock_is_held_type+0x9b/0x110
 fput_close_sync+0xd6/0x180
 ? __pfx_fput_close_sync+0x10/0x10
 __x64_sys_close+0x78/0xd0
 do_syscall_64+0x9f/0x560
 entry_SYSCALL_64_after_hwframe+0x74/0x7c
RIP: 0033:0x5805ccc9
Code: 00 e8 eb a4 fe ff 66 2e 0f 1f 84 00 00 00 00 00 90 48 89 f8 48 89 f7 48 89 d6 48 89 ca 4d 89 c2 4d 89 c8 4c 8b 4c 24 08 0f 05 <c3> 66 0f 1f 44 00 00 f3 0f 1e fa 8d 87 ff 0f 00 00 89 fa 89 ff 3d
RSP: 002b:0000001002db5d08 EFLAGS: 00000206 ORIG_RAX: 0000000000000003
RAX: ffffffffffffffda RBX: 0000001002386d90 RCX: 000000005805ccc9
RDX: 0000000000000000 RSI: 0000000000000000 RDI: 000000000000000a
...
BUG: KASAN: slab-use-after-free in l2cap_chan_del+0x6ee/0x770
Write of size 8 at addr ffff8880021b6000 by task memcheck-amd64-/34

CPU: 0 UID: 0 PID: 34 Comm: memcheck-amd64- Not tainted 7.1.0-rc1-g5f2fcd0833d0 #1 PREEMPT(lazy) 
Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS 1.13.0-1ubuntu1.1 04/01/2014
Call Trace:
 <TASK>
 print_report+0x108/0x5c0
 ? __virt_addr_valid+0x21c/0x3f0
 ? l2cap_chan_del+0x6ee/0x770
 kasan_report+0x94/0xc0
 ? l2cap_chan_del+0x6ee/0x770
 l2cap_chan_del+0x6ee/0x770
 l2cap_conn_del+0x346/0x660
 hci_conn_hash_flush+0x135/0x230
 hci_dev_close_sync+0x4f8/0xfa0
 hci_dev_do_close+0x65/0x90
 hci_unregister_dev+0x254/0x510
 vhci_release+0x183/0x240
 __fput+0x356/0x9c0
 ? lock_is_held_type+0x9b/0x110
 fput_close_sync+0xd6/0x180
 ? __pfx_fput_close_sync+0x10/0x10
 __x64_sys_close+0x78/0xd0
 do_syscall_64+0x9f/0x560
 entry_SYSCALL_64_after_hwframe+0x74/0x7c
RIP: 0033:0x5805ccc9
Code: 00 e8 eb a4 fe ff 66 2e 0f 1f 84 00 00 00 00 00 90 48 89 f8 48 89 f7 48 89 d6 48 89 ca 4d 89 c2 4d 89 c8 4c 8b 4c 24 08 0f 05 <c3> 66 0f 1f 44 00 00 f3 0f 1e fa 8d 87 ff 0f 00 00 89 fa 89 ff 3d
RSP: 002b:0000001002db5d08 EFLAGS: 00000206 ORIG_RAX: 0000000000000003
RAX: ffffffffffffffda RBX: 0000001002386d90 RCX: 000000005805ccc9
RDX: 0000000000000000 RSI: 0000000000000000 RDI: 000000000000000a
RBP: 0000000000000001 R08: 0000000004c198e0 R09: 0000000000000040
R10: 0000000000000002 R11: 0000000000000206 R12: 0000001002386e20
R13: 0000001002008360 R14: 0000000000000003 R15: 0000001002db5d70
Total: 8, Passed: 8 (100.0%), Failed: 0, Not Run: 0
##############################
Test: TestRunner_6lowpan-tester - FAIL
Desc: Run 6lowpan-tester with test-runner
Output:
WARNING: held lock freed!
7.1.0-rc1-g5f2fcd0833d0 #1 Not tainted
-------------------------
memcheck-amd64-/34 is freeing memory ffff8880026af000-ffff8880026af7ff, with a lock still held there!
ffff8880026af508 (&chan->lock#4){+.+.}-{4:4}, at: l2cap_conn_del+0x33b/0x660
5 locks held by memcheck-amd64-/34:
 #0: ffff8880025ece80 (&hdev->req_lock){+.+.}-{4:4}, at: hci_dev_do_close+0x5d/0x90
 #1: ffff8880025ec0b0 (&hdev->lock){+.+.}-{4:4}, at: hci_dev_close_sync+0x2ca/0xfa0
 #2: ffffffff84ebc278 (hci_cb_list_lock){+.+.}-{4:4}, at: hci_conn_hash_flush+0xed/0x230
 #3: ffff888001fcbaf0 (&conn->lock){+.+.}-{4:4}, at: l2cap_conn_del+0x9b/0x660
 #4: ffff8880026af508 (&chan->lock#4){+.+.}-{4:4}, at: l2cap_conn_del+0x33b/0x660

stack backtrace:
CPU: 0 UID: 0 PID: 34 Comm: memcheck-amd64- Not tainted 7.1.0-rc1-g5f2fcd0833d0 #1 PREEMPT(lazy) 
Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS 1.13.0-1ubuntu1.1 04/01/2014
Call Trace:
 <TASK>
 debug_check_no_locks_freed+0x102/0x140
 ? l2cap_chan_del+0x220/0x770
 kfree+0x22b/0x4c0
 ? _raw_write_unlock+0x1e/0x40
 l2cap_chan_del+0x220/0x770
 l2cap_conn_del+0x346/0x660
 hci_conn_hash_flush+0x135/0x230
 hci_dev_close_sync+0x4f8/0xfa0
 hci_dev_do_close+0x65/0x90
 hci_unregister_dev+0x254/0x510
 vhci_release+0x183/0x240
 __fput+0x356/0x9c0
 ? lock_is_held_type+0x9b/0x110
 fput_close_sync+0xd6/0x180
 ? __pfx_fput_close_sync+0x10/0x10
 __x64_sys_close+0x78/0xd0
 do_syscall_64+0x9f/0x560
 entry_SYSCALL_64_after_hwframe+0x74/0x7c
RIP: 0033:0x5805ccc9
Code: 00 e8 eb a4 fe ff 66 2e 0f 1f 84 00 00 00 00 00 90 48 89 f8 48 89 f7 48 89 d6 48 89 ca 4d 89 c2 4d 89 c8 4c 8b 4c 24 08 0f 05 <c3> 66 0f 1f 44 00 00 f3 0f 1e fa 8d 87 ff 0f 00 00 89 fa 89 ff 3d
RSP: 002b:0000001002cb5d08 EFLAGS: 00000206 ORIG_RAX: 0000000000000003
RAX: ffffffffffffffda RBX: 0000001002386d90 RCX: 000000005805ccc9
RDX: 0000000000000000 RSI: 0000000000000000 RDI: 0000000000000007
...
BUG: KASAN: slab-use-after-free in l2cap_chan_del+0x6ee/0x770
Write of size 8 at addr ffff8880026af000 by task memcheck-amd64-/34

CPU: 0 UID: 0 PID: 34 Comm: memcheck-amd64- Not tainted 7.1.0-rc1-g5f2fcd0833d0 #1 PREEMPT(lazy) 
Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS 1.13.0-1ubuntu1.1 04/01/2014
Call Trace:
 <TASK>
 print_report+0x108/0x5c0
 ? __virt_addr_valid+0x21c/0x3f0
 ? l2cap_chan_del+0x6ee/0x770
 kasan_report+0x94/0xc0
 ? l2cap_chan_del+0x6ee/0x770
 l2cap_chan_del+0x6ee/0x770
 l2cap_conn_del+0x346/0x660
 hci_conn_hash_flush+0x135/0x230
 hci_dev_close_sync+0x4f8/0xfa0
 hci_dev_do_close+0x65/0x90
 hci_unregister_dev+0x254/0x510
 vhci_release+0x183/0x240
 __fput+0x356/0x9c0
 ? lock_is_held_type+0x9b/0x110
 fput_close_sync+0xd6/0x180
 ? __pfx_fput_close_sync+0x10/0x10
 __x64_sys_close+0x78/0xd0
 do_syscall_64+0x9f/0x560
 entry_SYSCALL_64_after_hwframe+0x74/0x7c
RIP: 0033:0x5805ccc9
Code: 00 e8 eb a4 fe ff 66 2e 0f 1f 84 00 00 00 00 00 90 48 89 f8 48 89 f7 48 89 d6 48 89 ca 4d 89 c2 4d 89 c8 4c 8b 4c 24 08 0f 05 <c3> 66 0f 1f 44 00 00 f3 0f 1e fa 8d 87 ff 0f 00 00 89 fa 89 ff 3d
RSP: 002b:0000001002cb5d08 EFLAGS: 00000206 ORIG_RAX: 0000000000000003
RAX: ffffffffffffffda RBX: 0000001002386d90 RCX: 000000005805ccc9
RDX: 0000000000000000 RSI: 0000000000000000 RDI: 0000000000000007
RBP: 0000000000000001 R08: 0000000004c205f0 R09: 0000000000000040
R10: 0000000000000002 R11: 0000000000000206 R12: 0000001002386e20
R13: 0000001002008360 R14: 0000000000000003 R15: 0000001002cb5d70
Total: 8, Passed: 8 (100.0%), Failed: 0, Not Run: 0


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

---
Regards,
Linux Bluetooth


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

* RE: Bluetooth: L2CAP: Fix use-after-free in l2cap_sock_new_connection_cb()
  2026-06-01 14:03 [PATCH v7 " Siwei Zhang
@ 2026-06-01 18:50 ` bluez.test.bot
  0 siblings, 0 replies; 10+ messages in thread
From: bluez.test.bot @ 2026-06-01 18:50 UTC (permalink / raw)
  To: linux-bluetooth, oss

[-- 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=1104048

---Test result---

Test Summary:
CheckPatch                    PASS      1.63 seconds
VerifyFixes                   PASS      0.11 seconds
VerifySignedoff               PASS      0.11 seconds
GitLint                       PASS      0.28 seconds
SubjectPrefix                 PASS      0.10 seconds
BuildKernel                   PASS      25.36 seconds
CheckAllWarning               PASS      28.79 seconds
CheckSparse                   PASS      26.78 seconds
BuildKernel32                 PASS      24.76 seconds
TestRunnerSetup               PASS      529.97 seconds
TestRunner_l2cap-tester       PASS      59.39 seconds
TestRunner_smp-tester         PASS      23.58 seconds
TestRunner_6lowpan-tester     PASS      22.70 seconds
IncrementalBuild              PASS      24.41 seconds



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

---
Regards,
Linux Bluetooth


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

* [PATCH v8 0/1] Bluetooth: L2CAP: Fix use-after-free in l2cap_sock_new_connection_cb()
@ 2026-06-02 12:55 Siwei Zhang
  2026-06-02 12:55 ` [PATCH v8 1/1] " Siwei Zhang
  0 siblings, 1 reply; 10+ messages in thread
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	[flat|nested] 10+ messages in thread

* [PATCH v8 1/1] Bluetooth: L2CAP: Fix use-after-free in l2cap_sock_new_connection_cb()
  2026-06-02 12:55 [PATCH v8 0/1] Bluetooth: L2CAP: Fix use-after-free in l2cap_sock_new_connection_cb() Siwei Zhang
@ 2026-06-02 12:55 ` Siwei Zhang
  2026-06-02 15:27   ` bluez.test.bot
  2026-06-02 16:33   ` [PATCH v8 1/1] " Luiz Augusto von Dentz
  0 siblings, 2 replies; 10+ messages in thread
From: Siwei Zhang @ 2026-06-02 12:55 UTC (permalink / raw)
  To: Marcel Holtmann, Luiz Augusto von Dentz; +Cc: linux-bluetooth, Siwei Zhang

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	[flat|nested] 10+ messages in thread

* RE: Bluetooth: L2CAP: Fix use-after-free in l2cap_sock_new_connection_cb()
  2026-06-02 12:55 ` [PATCH v8 1/1] " Siwei Zhang
@ 2026-06-02 15:27   ` bluez.test.bot
  2026-06-02 16:33   ` [PATCH v8 1/1] " Luiz Augusto von Dentz
  1 sibling, 0 replies; 10+ messages in thread
From: bluez.test.bot @ 2026-06-02 15:27 UTC (permalink / raw)
  To: linux-bluetooth, oss

[-- 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	[flat|nested] 10+ messages in thread

* Re: [PATCH v8 1/1] Bluetooth: L2CAP: Fix use-after-free in l2cap_sock_new_connection_cb()
  2026-06-02 12:55 ` [PATCH v8 1/1] " Siwei Zhang
  2026-06-02 15:27   ` bluez.test.bot
@ 2026-06-02 16:33   ` Luiz Augusto von Dentz
  1 sibling, 0 replies; 10+ messages in thread
From: Luiz Augusto von Dentz @ 2026-06-02 16:33 UTC (permalink / raw)
  To: Siwei Zhang; +Cc: Marcel Holtmann, linux-bluetooth

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	[flat|nested] 10+ messages in thread

end of thread, other threads:[~2026-06-02 16:33 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-06-02 12:55 [PATCH v8 0/1] Bluetooth: L2CAP: Fix use-after-free in l2cap_sock_new_connection_cb() Siwei Zhang
2026-06-02 12:55 ` [PATCH v8 1/1] " Siwei Zhang
2026-06-02 15:27   ` bluez.test.bot
2026-06-02 16:33   ` [PATCH v8 1/1] " Luiz Augusto von Dentz
  -- strict thread matches above, loose matches on Subject: below --
2026-06-01 14:03 [PATCH v7 " Siwei Zhang
2026-06-01 18:50 ` bluez.test.bot
2026-05-29 16:54 [PATCH v6 1/1] " Siwei Zhang
2026-05-29 18:21 ` bluez.test.bot
2026-05-20 16:20 [PATCH v5 1/1] " Siwei Zhang
2026-05-20 18:07 ` bluez.test.bot
2026-05-11 17:09 [PATCH RESEND v4 1/1] " Siwei Zhang
2026-05-11 18:49 ` bluez.test.bot
2026-05-11  4:51 [PATCH 1/1] " Siwei Zhang
2026-05-11  8:32 ` bluez.test.bot
2026-05-11  3:18 [PATCH 1/1] " Siwei Zhang
2026-05-11  4:21 ` bluez.test.bot

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