* RE: Bluetooth: L2CAP: Fix use-after-free in l2cap_sock_new_connection_cb()
From: bluez.test.bot @ 2026-05-29 18:21 UTC (permalink / raw)
To: linux-bluetooth, oss
In-Reply-To: <20260529165449.3553936-2-oss@fourdim.xyz>
[-- 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
* Re: [GIT PULL] bluetooth 2026-05-28
From: Jakub Kicinski @ 2026-05-29 18:20 UTC (permalink / raw)
To: Paolo Abeni; +Cc: Luiz Augusto von Dentz, davem, linux-bluetooth, netdev
In-Reply-To: <de887211-1005-43cf-b1d3-ddf1a82c283e@redhat.com>
On Fri, 29 May 2026 09:35:20 +0200 Paolo Abeni wrote:
> Even multiple PRs per week makes sense to me, if the average size is
> still significant. I'm not sure about others maintainers opinion, please
> don't take my last statement as "a please go ahead with this" before
> more acks.
That's a pretty costly fix. It takes me ~3h to generate the PR I suspect
it takes you similar amount of time. So it's not going to help the
patch review queue if we waste time generating multiple PRs.
Luiz, simply run this bash script before you send the PR:
github.com/linux-netdev/nipa/blob/master/tests/patch/verify_signedoff/verify_signedoff.sh
it's not the first time you're missing SoBs
^ permalink raw reply
* Re: [PATCH v1 1/1] Bluetooth: L2CAP: fix heap over-read in l2cap_get_conf_opt
From: Paul Menzel @ 2026-05-29 18:15 UTC (permalink / raw)
To: Muhammad Bilal
Cc: linux-bluetooth, marcel, luiz.dentz, gregkh, linux-kernel, stable
In-Reply-To: <20260527051808.47220-1-meatuni001@gmail.com>
Dear Muhammad,
Am 27.05.26 um 07:18 schrieb Muhammad Bilal:
>> By any chance, do you have a reproducer?
>
> No standalone reproducer is available. The issue can be triggered by
> a malformed L2CAP configuration request where opt->len exceeds the
> remaining buffer, i.e. a crafted packet from a remote peer.
Understood.
>> I always wonder, if Linux should log a debug message or even warning.
>
> Existing callers generally handle malformed configuration options by
> silently aborting parsing, so I followed the same pattern. Adding a
> BT_ERR() on -EINVAL could be reasonable; I can include that in a v2
> if preferred.
Thank you for sharing the reasoning. It makes sense, and no need to add
it then.
Kind regards,
Paul
^ permalink raw reply
* [PATCH 4/4] Bluetooth: qca: combine NVM and calibration data for QCC2072
From: Yepuri Siddu @ 2026-05-29 18:04 UTC (permalink / raw)
To: Bartosz Golaszewski, Marcel Holtmann, Luiz Augusto von Dentz,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Bjorn Andersson,
Konrad Dybcio, Balakrishna Godavarthi, Rocky Liao
Cc: quic_mohamull, quic_hbandi, rahul.samana, harshitha.reddy,
dishank.garg, linux-arm-msm, linux-bluetooth, linux-kernel,
Yepuri Siddu
QCC2072 requires the NVM and calibration data to be delivered to the
controller bundled together in an outer TLV of type 4. After loading
the NVM file, load the calibration file (qca/ornbcscal<ver>.bin) and
combine both into a single buffer with the outer TLV header before
passing it to qca_tlv_check_data().
The outer TLV header encodes the combined payload length in the high
24 bits and type 4 in the low 8 bits of the type_len field.
If the calibration file is unavailable, fall back to downloading the
NVM alone.
Signed-off-by: Yepuri Siddu <yepuri.siddu@oss.qualcomm.com>
---
drivers/bluetooth/btqca.c | 47 +++++++++++++++++++++++++++++++++++++++
1 file changed, 47 insertions(+)
diff --git a/drivers/bluetooth/btqca.c b/drivers/bluetooth/btqca.c
index 0ef7546e7c7a..37db1cd9e8cf 100644
--- a/drivers/bluetooth/btqca.c
+++ b/drivers/bluetooth/btqca.c
@@ -612,6 +612,53 @@ static int qca_download_firmware(struct hci_dev *hdev,
memcpy(data, fw->data, size);
release_firmware(fw);
+ /* For QCC2072, combine the NVM (type 2) with the calibration file
+ * into a single TLV of outer type 4.
+ */
+ if (soc_type == QCA_QCC2072 && config->type == TLV_TYPE_NVM) {
+ const struct firmware *calib_fw = NULL;
+ char calib_name[32];
+ u8 *combined_data = NULL;
+ size_t inner_len, combined_size;
+ struct tlv_type_hdr *outer_hdr;
+ int err;
+
+ snprintf(calib_name, sizeof(calib_name),
+ "qca/ornbcscal%02x.bin", rom_ver);
+ err = request_firmware(&calib_fw, calib_name, &hdev->dev);
+ if (err) {
+ bt_dev_err(hdev, "QCA Failed to request file: %s (%d)",
+ calib_name, err);
+ goto skip_combination;
+ }
+
+ bt_dev_info(hdev, "QCA Downloading %s", calib_name);
+
+ inner_len = size + calib_fw->size;
+ combined_size = sizeof(*outer_hdr) + inner_len;
+ combined_data = vmalloc(combined_size);
+ if (!combined_data) {
+ bt_dev_warn(hdev,
+ "QCA Failed to allocate memory for file: %s",
+ calib_name);
+ release_firmware(calib_fw);
+ goto skip_combination;
+ }
+
+ outer_hdr = (struct tlv_type_hdr *)combined_data;
+ /* high 24 bits = payload length, low 8 bits = type */
+ outer_hdr->type_len = cpu_to_le32((inner_len << 8) | 4);
+ memcpy(combined_data + sizeof(*outer_hdr), data, size);
+ memcpy(combined_data + sizeof(*outer_hdr) + size,
+ calib_fw->data, calib_fw->size);
+ release_firmware(calib_fw);
+ vfree(data);
+ data = combined_data;
+ size = combined_size;
+skip_combination:
+ ;
+ }
+
ret = qca_tlv_check_data(hdev, config, data, size, soc_type);
if (ret)
goto out;
--
2.34.1
^ permalink raw reply related
* [PATCH 2/4] Bluetooth: qca: add QCC2072 support
From: Yepuri Siddu @ 2026-05-29 17:58 UTC (permalink / raw)
To: Bartosz Golaszewski, Marcel Holtmann, Luiz Augusto von Dentz,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Bjorn Andersson,
Konrad Dybcio, Balakrishna Godavarthi, Rocky Liao
Cc: quic_mohamull, quic_hbandi, rahul.samana, harshitha.reddy,
dishank.garg, linux-arm-msm, linux-bluetooth, linux-kernel,
Yepuri Siddu
QCC2072 is a BT/WiFi combo SoC that uses different firmware
filenames and requires no external voltage regulators, so add
it as a new SoC type.
The chip supports the wideband speech and valid LE states
capabilities. Its firmware is named using the "orn" prefix and
follows the standard rom-version-based scheme:
- qca/ornbtfw<ver>.tlv
- qca/ornnv<ver>.bin
These firmware files are already present in the linux-firmware
repository.
Signed-off-by: Yepuri Siddu <yepuri.siddu@oss.qualcomm.com>
---
drivers/bluetooth/btqca.c | 9 +++++++++
drivers/bluetooth/btqca.h | 1 +
drivers/bluetooth/hci_qca.c | 24 ++++++++++++++++++++++++
3 files changed, 34 insertions(+)
diff --git a/drivers/bluetooth/btqca.c b/drivers/bluetooth/btqca.c
index dda76365726f..0ef7546e7c7a 100644
--- a/drivers/bluetooth/btqca.c
+++ b/drivers/bluetooth/btqca.c
@@ -843,6 +843,10 @@ int qca_uart_setup(struct hci_dev *hdev, uint8_t baudrate,
snprintf(config.fwname, sizeof(config.fwname),
"qca/hmtbtfw%02x.tlv", rom_ver);
break;
+ case QCA_QCC2072:
+ snprintf(config.fwname, sizeof(config.fwname),
+ "qca/ornbtfw%02x.tlv", rom_ver);
+ break;
default:
snprintf(config.fwname, sizeof(config.fwname),
"qca/rampatch_%08x.bin", soc_ver);
@@ -937,6 +941,10 @@ int qca_uart_setup(struct hci_dev *hdev, uint8_t baudrate,
qca_get_nvm_name_by_board(config.fwname, sizeof(config.fwname),
"hmtnv", soc_type, ver, rom_ver, boardid);
break;
+ case QCA_QCC2072:
+ snprintf(config.fwname, sizeof(config.fwname),
+ "qca/ornnv%02x.bin", rom_ver);
+ break;
default:
snprintf(config.fwname, sizeof(config.fwname),
"qca/nvm_%08x.bin", soc_ver);
@@ -999,6 +1007,7 @@ int qca_uart_setup(struct hci_dev *hdev, uint8_t baudrate,
case QCA_WCN6750:
case QCA_WCN6855:
case QCA_WCN7850:
+ case QCA_QCC2072:
/* get fw build info */
err = qca_read_fw_build_info(hdev);
if (err < 0)
diff --git a/drivers/bluetooth/btqca.h b/drivers/bluetooth/btqca.h
index 8f3c1b1c77b3..a175ac31e7b2 100644
--- a/drivers/bluetooth/btqca.h
+++ b/drivers/bluetooth/btqca.h
@@ -158,6 +158,7 @@ enum qca_btsoc_type {
QCA_WCN6750,
QCA_WCN6855,
QCA_WCN7850,
+ QCA_QCC2072,
};
#if IS_ENABLED(CONFIG_BT_QCA)
diff --git a/drivers/bluetooth/hci_qca.c b/drivers/bluetooth/hci_qca.c
index ed280399bf47..fc67ba0e4984 100644
--- a/drivers/bluetooth/hci_qca.c
+++ b/drivers/bluetooth/hci_qca.c
@@ -1372,6 +1372,7 @@ static int qca_set_baudrate(struct hci_dev *hdev, uint8_t baudrate)
/* Give the controller time to process the request */
switch (qca_soc_type(hu)) {
+ case QCA_QCC2072:
case QCA_WCN3950:
case QCA_WCN3988:
case QCA_WCN3990:
@@ -1459,6 +1460,7 @@ static unsigned int qca_get_speed(struct hci_uart *hu,
static int qca_check_speeds(struct hci_uart *hu)
{
switch (qca_soc_type(hu)) {
+ case QCA_QCC2072:
case QCA_WCN3950:
case QCA_WCN3988:
case QCA_WCN3990:
@@ -1510,6 +1512,7 @@ static int qca_set_speed(struct hci_uart *hu, enum qca_speed_type speed_type)
case QCA_WCN6750:
case QCA_WCN6855:
case QCA_WCN7850:
+ case QCA_QCC2072:
hci_uart_set_flow_control(hu, true);
break;
@@ -1545,6 +1548,7 @@ static int qca_set_speed(struct hci_uart *hu, enum qca_speed_type speed_type)
case QCA_WCN6750:
case QCA_WCN6855:
case QCA_WCN7850:
+ case QCA_QCC2072:
hci_uart_set_flow_control(hu, false);
break;
@@ -1861,6 +1865,7 @@ static int qca_power_on(struct hci_dev *hdev)
case QCA_WCN6750:
case QCA_WCN6855:
case QCA_WCN7850:
+ case QCA_QCC2072:
ret = qca_regulator_init(hu);
break;
@@ -1957,6 +1962,10 @@ static int qca_setup(struct hci_uart *hu)
soc_name = "wcn7850";
break;
+ case QCA_QCC2072:
+ soc_name = "qcc2072";
+ break;
+
default:
soc_name = "ROME/QCA6390";
}
@@ -1980,6 +1989,7 @@ static int qca_setup(struct hci_uart *hu)
case QCA_WCN6750:
case QCA_WCN6855:
case QCA_WCN7850:
+ case QCA_QCC2072:
if (qcadev->bdaddr_property_broken)
hci_set_quirk(hdev, HCI_QUIRK_BDADDR_PROPERTY_BROKEN);
@@ -2013,6 +2023,7 @@ static int qca_setup(struct hci_uart *hu)
case QCA_WCN6750:
case QCA_WCN6855:
case QCA_WCN7850:
+ case QCA_QCC2072:
break;
default:
@@ -2166,6 +2177,12 @@ static const struct qca_device_data qca_soc_data_wcn3998 __maybe_unused = {
.num_vregs = 4,
};
+static const struct qca_device_data qca_soc_data_qcc2072 __maybe_unused = {
+ .soc_type = QCA_QCC2072,
+ .num_vregs = 0,
+ .capabilities = QCA_CAP_WIDEBAND_SPEECH | QCA_CAP_VALID_LE_STATES,
+};
+
static const struct qca_device_data qca_soc_data_wcn6750 __maybe_unused = {
.soc_type = QCA_WCN6750,
.vregs = (struct qca_vreg []) {
@@ -2268,6 +2285,7 @@ static void qca_power_off(struct hci_uart *hu)
case QCA_WCN6750:
case QCA_WCN6855:
+ case QCA_QCC2072:
gpiod_set_value_cansleep(qcadev->bt_en, 0);
msleep(100);
qca_regulator_disable(qcadev);
@@ -2414,6 +2432,7 @@ static int qca_serdev_probe(struct serdev_device *serdev)
qcadev->btsoc_type = QCA_ROME;
switch (qcadev->btsoc_type) {
+ case QCA_QCC2072:
case QCA_QCA6390:
case QCA_WCN3950:
case QCA_WCN3988:
@@ -2434,6 +2453,7 @@ static int qca_serdev_probe(struct serdev_device *serdev)
}
switch (qcadev->btsoc_type) {
+ case QCA_QCC2072:
case QCA_WCN3950:
case QCA_WCN3988:
case QCA_WCN3990:
@@ -2484,6 +2504,7 @@ static int qca_serdev_probe(struct serdev_device *serdev)
if (!qcadev->bt_en &&
(data->soc_type == QCA_WCN6750 ||
data->soc_type == QCA_WCN6855 ||
+ data->soc_type == QCA_QCC2072 ||
data->soc_type == QCA_WCN7850))
power_ctrl_enabled = false;
@@ -2492,6 +2513,7 @@ static int qca_serdev_probe(struct serdev_device *serdev)
if (IS_ERR(qcadev->sw_ctrl) &&
(data->soc_type == QCA_WCN6750 ||
data->soc_type == QCA_WCN6855 ||
+ data->soc_type == QCA_QCC2072 ||
data->soc_type == QCA_WCN7850)) {
dev_err(&serdev->dev, "failed to acquire SW_CTRL gpio\n");
return PTR_ERR(qcadev->sw_ctrl);
@@ -2570,6 +2592,7 @@ static void qca_serdev_remove(struct serdev_device *serdev)
struct qca_power *power = qcadev->bt_power;
switch (qcadev->btsoc_type) {
+ case QCA_QCC2072:
case QCA_WCN3988:
case QCA_WCN3990:
case QCA_WCN3991:
@@ -2779,6 +2802,7 @@ static const struct of_device_id qca_bluetooth_of_match[] = {
{ .compatible = "qcom,wcn6750-bt", .data = &qca_soc_data_wcn6750},
{ .compatible = "qcom,wcn6855-bt", .data = &qca_soc_data_wcn6855},
{ .compatible = "qcom,wcn7850-bt", .data = &qca_soc_data_wcn7850},
+ { .compatible = "qcom,qcc2072-bt", .data = &qca_soc_data_qcc2072},
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, qca_bluetooth_of_match);
--
2.34.1
^ permalink raw reply related
* [PATCH 1/4] dt-bindings: bluetooth: qcom,qcc2072-bt: add bindings for QCC2072
From: Yepuri Siddu @ 2026-05-29 17:53 UTC (permalink / raw)
To: Bartosz Golaszewski, Marcel Holtmann, Luiz Augusto von Dentz,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Bjorn Andersson,
Konrad Dybcio, Balakrishna Godavarthi, Rocky Liao
Cc: quic_mohamull, quic_hbandi, rahul.samana, harshitha.reddy,
dishank.garg, linux-arm-msm, linux-bluetooth, devicetree,
linux-kernel, Yepuri Siddu
Document the YAML binding schema for the Qualcomm QCC2072 UART-based
Bluetooth controller.
Unlike other Qualcomm Bluetooth chips, QCC2072 requires no external
voltage regulators. The schema inherits common Qualcomm Bluetooth
properties via qcom,bluetooth-common.yaml and serial peripheral
interface properties for the UART link.
Signed-off-by: Yepuri Siddu <yepuri.siddu@oss.qualcomm.com>
---
.../net/bluetooth/qcom,qcc2072-bt.yaml | 38 +++++++++++++++++++
1 file changed, 38 insertions(+)
create mode 100644 Documentation/devicetree/bindings/net/bluetooth/qcom,qcc2072-bt.yaml
diff --git a/Documentation/devicetree/bindings/net/bluetooth/qcom,qcc2072-bt.yaml b/Documentation/devicetree/bindings/net/bluetooth/qcom,qcc2072-bt.yaml
new file mode 100644
index 000000000000..8e2f15a75d62
--- /dev/null
+++ b/Documentation/devicetree/bindings/net/bluetooth/qcom,qcc2072-bt.yaml
@@ -0,0 +1,38 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/net/bluetooth/qcom,qcc2072-bt.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Qualcomm QCC2072 Bluetooth
+
+maintainers:
+ - Balakrishna Godavarthi <quic_bgodavar@quicinc.com>
+ - Rocky Liao <quic_rjliao@quicinc.com>
+
+description:
+ Qualcomm QCC2072 is a UART-based Bluetooth controller.
+
+properties:
+ compatible:
+ enum:
+ - qcom,qcc2072-bt
+
+required:
+ - compatible
+
+allOf:
+ - $ref: bluetooth-controller.yaml#
+ - $ref: qcom,bluetooth-common.yaml#
+ - $ref: /schemas/serial/serial-peripheral-props.yaml#
+
+unevaluatedProperties: false
+
+examples:
+ - |
+ serial {
+ bluetooth {
+ compatible = "qcom,qcc2072-bt";
+ max-speed = <3200000>;
+ };
+ };
--
2.34.1
^ permalink raw reply related
* [PATCH v1 2/2] Bluetooth: SCO: Fix data-race on dst in sco_connect
From: SeungJu Cheon @ 2026-05-29 17:33 UTC (permalink / raw)
To: marcel, luiz.dentz
Cc: linux-bluetooth, linux-kernel, me, skhan, linux-kernel-mentees,
SeungJu Cheon
In-Reply-To: <20260529173347.43967-1-suunj1331@gmail.com>
sco_sock_connect() copies the destination address into
sco_pi(sk)->dst under lock_sock, then releases the lock and calls
sco_connect(), which reads dst back without holding any lock in
hci_get_route() and hci_connect_sco().
If two threads call connect() on the same socket concurrently with
different addresses, one thread can overwrite dst before the other
thread's sco_connect() reads it.
Fix by snapshotting dst into a local variable under lock_sock at
the start of sco_connect(), matching the approach used for ISO in
the previous patch.
BUG: KCSAN: data-race in memcmp+0x45/0xb0
race at unknown origin, with read to 0xffff88800e6b0dd0 of 1 bytes by task 315 on cpu 0:
memcmp+0x45/0xb0
hci_connect_acl+0x1b7/0x6b0
hci_connect_sco+0x4d/0xb30
sco_sock_connect+0x27b/0xd60
__sys_connect_file+0xbd/0xe0
__sys_connect+0xe0/0x110
__x64_sys_connect+0x40/0x50
x64_sys_call+0xcad/0x1c60
do_syscall_64+0x133/0x590
entry_SYSCALL_64_after_hwframe+0x77/0x7f
Fixes: 9a8ec9e8ebb5 ("Bluetooth: Fix three socket race condition bugs in sco.c")
Signed-off-by: SeungJu Cheon <suunj1331@gmail.com>
---
net/bluetooth/sco.c | 11 ++++++++---
1 file changed, 8 insertions(+), 3 deletions(-)
diff --git a/net/bluetooth/sco.c b/net/bluetooth/sco.c
index f1799c6a6f87..c9f6a8aaee57 100644
--- a/net/bluetooth/sco.c
+++ b/net/bluetooth/sco.c
@@ -312,11 +312,16 @@ static int sco_connect(struct sock *sk)
struct sco_conn *conn;
struct hci_conn *hcon;
struct hci_dev *hdev;
+ bdaddr_t dst;
int err, type;
- BT_DBG("%pMR -> %pMR", &sco_pi(sk)->src, &sco_pi(sk)->dst);
+ lock_sock(sk);
+ bacpy(&dst, &sco_pi(sk)->dst);
+ release_sock(sk);
+
+ BT_DBG("%pMR -> %pMR", &sco_pi(sk)->src, &dst);
- hdev = hci_get_route(&sco_pi(sk)->dst, &sco_pi(sk)->src, BDADDR_BREDR);
+ hdev = hci_get_route(&dst, &sco_pi(sk)->src, BDADDR_BREDR);
if (!hdev)
return -EHOSTUNREACH;
@@ -336,7 +341,7 @@ static int sco_connect(struct sock *sk)
break;
}
- hcon = hci_connect_sco(hdev, type, &sco_pi(sk)->dst,
+ hcon = hci_connect_sco(hdev, type, &dst,
sco_pi(sk)->setting, &sco_pi(sk)->codec,
READ_ONCE(sk->sk_sndtimeo));
if (IS_ERR(hcon)) {
--
2.52.0
^ permalink raw reply related
* [PATCH v1 1/2] Bluetooth: ISO: Fix data-race on iso_pi fields in hci_get_route calls
From: SeungJu Cheon @ 2026-05-29 17:33 UTC (permalink / raw)
To: marcel, luiz.dentz
Cc: linux-bluetooth, linux-kernel, me, skhan, linux-kernel-mentees,
SeungJu Cheon
In-Reply-To: <20260529173347.43967-1-suunj1331@gmail.com>
iso_connect_bis(), iso_connect_cis(), iso_listen_bis(), and
iso_conn_big_sync() all call hci_get_route() reading iso_pi(sk)->dst,
iso_pi(sk)->src, and iso_pi(sk)->src_type without holding lock_sock.
These fields can be concurrently written by another thread calling
connect() or setsockopt() on the same socket, leading to torn reads
or TOCTOU mismatches.
Fix by snapshotting dst, src, and src_type into local variables under
lock_sock before calling hci_get_route() in all four functions.
BUG: KCSAN: data-race in memcmp+0x45/0xb0
race at unknown origin, with read to 0xffff8880122135cf of 1 bytes by task 333 on cpu 1:
memcmp+0x45/0xb0
hci_get_route+0x27e/0x490
iso_connect_cis+0x4c/0xa10
iso_sock_connect+0x60e/0xb30
__sys_connect_file+0xbd/0xe0
__sys_connect+0xe0/0x110
__x64_sys_connect+0x40/0x50
x64_sys_call+0xcad/0x1c60
do_syscall_64+0x133/0x590
entry_SYSCALL_64_after_hwframe+0x77/0x7f
Fixes: 241f51931c35 ("Bluetooth: ISO: Avoid circular locking dependency")
Signed-off-by: SeungJu Cheon <suunj1331@gmail.com>
---
net/bluetooth/iso.c | 51 ++++++++++++++++++++++++++++++++++-----------
1 file changed, 39 insertions(+), 12 deletions(-)
diff --git a/net/bluetooth/iso.c b/net/bluetooth/iso.c
index d7af617cda45..58bb3a10d49f 100644
--- a/net/bluetooth/iso.c
+++ b/net/bluetooth/iso.c
@@ -337,12 +337,19 @@ static int iso_connect_bis(struct sock *sk)
struct iso_conn *conn;
struct hci_conn *hcon;
struct hci_dev *hdev;
+ bdaddr_t src, dst;
+ u8 src_type;
int err;
- BT_DBG("%pMR (SID 0x%2.2x)", &iso_pi(sk)->src, iso_pi(sk)->bc_sid);
+ lock_sock(sk);
+ bacpy(&dst, &iso_pi(sk)->dst);
+ bacpy(&src, &iso_pi(sk)->src);
+ src_type = iso_pi(sk)->src_type;
+ release_sock(sk);
+
+ BT_DBG("%pMR (SID 0x%2.2x)", &src, iso_pi(sk)->bc_sid);
- hdev = hci_get_route(&iso_pi(sk)->dst, &iso_pi(sk)->src,
- iso_pi(sk)->src_type);
+ hdev = hci_get_route(&dst, &src, src_type);
if (!hdev)
return -EHOSTUNREACH;
@@ -430,12 +437,19 @@ static int iso_connect_cis(struct sock *sk)
struct iso_conn *conn;
struct hci_conn *hcon;
struct hci_dev *hdev;
+ bdaddr_t src, dst;
+ u8 src_type;
int err;
- BT_DBG("%pMR -> %pMR", &iso_pi(sk)->src, &iso_pi(sk)->dst);
+ lock_sock(sk);
+ bacpy(&dst, &iso_pi(sk)->dst);
+ bacpy(&src, &iso_pi(sk)->src);
+ src_type = iso_pi(sk)->src_type;
+ release_sock(sk);
+
+ BT_DBG("%pMR -> %pMR", &src, &dst);
- hdev = hci_get_route(&iso_pi(sk)->dst, &iso_pi(sk)->src,
- iso_pi(sk)->src_type);
+ hdev = hci_get_route(&dst, &src, src_type);
if (!hdev)
return -EHOSTUNREACH;
@@ -1210,11 +1224,18 @@ static int iso_listen_bis(struct sock *sk)
{
struct hci_dev *hdev;
int err = 0;
+ bdaddr_t src, dst;
+ u8 src_type;
struct iso_conn *conn;
struct hci_conn *hcon;
- BT_DBG("%pMR -> %pMR (SID 0x%2.2x)", &iso_pi(sk)->src,
- &iso_pi(sk)->dst, iso_pi(sk)->bc_sid);
+ lock_sock(sk);
+ bacpy(&dst, &iso_pi(sk)->dst);
+ bacpy(&src, &iso_pi(sk)->src);
+ src_type = iso_pi(sk)->src_type;
+ release_sock(sk);
+
+ BT_DBG("%pMR -> %pMR (SID 0x%2.2x)", &src, &dst, iso_pi(sk)->bc_sid);
write_lock(&iso_sk_list.lock);
@@ -1227,8 +1248,7 @@ static int iso_listen_bis(struct sock *sk)
if (err)
return err;
- hdev = hci_get_route(&iso_pi(sk)->dst, &iso_pi(sk)->src,
- iso_pi(sk)->src_type);
+ hdev = hci_get_route(&dst, &src, src_type);
if (!hdev)
return -EHOSTUNREACH;
@@ -1564,9 +1584,16 @@ static void iso_conn_big_sync(struct sock *sk)
{
int err;
struct hci_dev *hdev;
+ bdaddr_t src, dst;
+ u8 src_type;
+
+ lock_sock(sk);
+ bacpy(&dst, &iso_pi(sk)->dst);
+ bacpy(&src, &iso_pi(sk)->src);
+ src_type = iso_pi(sk)->src_type;
+ release_sock(sk);
- hdev = hci_get_route(&iso_pi(sk)->dst, &iso_pi(sk)->src,
- iso_pi(sk)->src_type);
+ hdev = hci_get_route(&dst, &src, src_type);
if (!hdev)
return;
--
2.52.0
^ permalink raw reply related
* [PATCH v1 0/2] Bluetooth: Fix data-race on dst/src in connect paths
From: SeungJu Cheon @ 2026-05-29 17:33 UTC (permalink / raw)
To: marcel, luiz.dentz
Cc: linux-bluetooth, linux-kernel, me, skhan, linux-kernel-mentees,
SeungJu Cheon
Two KCSAN-reported data races on socket address fields passed to
hci_get_route() without proper synchronization.
Patch 1/2 fixes ISO: iso_connect_bis(), iso_connect_cis(),
iso_listen_bis(), and iso_conn_big_sync() read iso_pi(sk)->dst/src
without lock_sock before calling hci_get_route().
Patch 2/2 fixes SCO: sco_connect() reads sco_pi(sk)->dst after
lock_sock has been released by the caller.
Both races were confirmed with KCSAN using VHCI-based reproducers.
SeungJu Cheon (2):
Bluetooth: ISO: Fix data-race on iso_pi fields in hci_get_route calls
Bluetooth: SCO: Fix data-race on dst in sco_connect
net/bluetooth/iso.c | 51 ++++++++++++++++++++++++++++++++++-----------
net/bluetooth/sco.c | 11 +++++++---
2 files changed, 47 insertions(+), 15 deletions(-)
--
2.52.0
^ permalink raw reply
* [PATCH v6 1/1] Bluetooth: L2CAP: Fix use-after-free in l2cap_sock_new_connection_cb()
From: Siwei Zhang @ 2026-05-29 16:54 UTC (permalink / raw)
To: Marcel Holtmann, Luiz Augusto von Dentz; +Cc: linux-bluetooth, Siwei Zhang
In-Reply-To: <20260529165449.3553936-1-oss@fourdim.xyz>
l2cap_sock_new_connection_cb() accesses l2cap_pi(sk)->chan after
release_sock(parent). Once the parent lock is released, the child
socket sk can be freed by another task.
Allocate the channel outside the func to prevent this.
Fixes: 8ffb929098a5 ("Bluetooth: Remove parent socket usage from l2cap_core.c")
Cc: stable@kernel.org
Assisted-by: Claude:claude-opus-4-6
Signed-off-by: Siwei Zhang <oss@fourdim.xyz>
---
include/net/bluetooth/l2cap.h | 8 +++--
net/bluetooth/6lowpan.c | 27 ++++++++--------
net/bluetooth/l2cap_core.c | 58 ++++++++++++++++++++++++++++-------
net/bluetooth/l2cap_sock.c | 48 +++++++++++++++++------------
net/bluetooth/smp.c | 13 +++-----
5 files changed, 98 insertions(+), 56 deletions(-)
diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h
index 5172afee5494..f7a11e6431f0 100644
--- a/include/net/bluetooth/l2cap.h
+++ b/include/net/bluetooth/l2cap.h
@@ -619,7 +619,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);
@@ -883,9 +884,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 23a229ab6a33..a5830b5746d8 100644
--- a/net/bluetooth/6lowpan.c
+++ b/net/bluetooth/6lowpan.c
@@ -622,6 +622,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;
@@ -630,11 +639,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;
}
@@ -743,19 +748,15 @@ 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;
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 fdccd62ccca8..505f32034971 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -4051,10 +4051,16 @@ static void l2cap_connect(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd,
goto response;
}
- chan = pchan->ops->new_connection(pchan);
+ chan = l2cap_chan_create();
if (!chan)
goto response;
+ if (pchan->ops->new_connection(pchan, chan) < 0) {
+ l2cap_chan_put(chan);
+ chan = NULL;
+ goto response;
+ }
+
/* For certain devices (ex: HID mouse), support for authentication,
* pairing and bonding is optional. For such devices, inorder to avoid
* the ACL alive for too long after L2CAP disconnection, reset the ACL
@@ -4132,6 +4138,10 @@ static void l2cap_connect(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd,
chan->num_conf_req++;
}
+ /* Drop our local ref; __l2cap_chan_add() pinned chan via the conn list. */
+ if (chan)
+ l2cap_chan_put(chan);
+
l2cap_chan_unlock(pchan);
l2cap_chan_put(pchan);
}
@@ -4881,6 +4891,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;
@@ -4893,6 +4904,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;
@@ -4953,12 +4966,19 @@ static int l2cap_le_connect_req(struct l2cap_conn *conn,
goto response_unlock;
}
- chan = pchan->ops->new_connection(pchan);
+ chan = l2cap_chan_create();
if (!chan) {
result = L2CAP_CR_LE_NO_MEM;
goto response_unlock;
}
+ if (pchan->ops->new_connection(pchan, chan) < 0) {
+ l2cap_chan_put(chan);
+ chan = NULL;
+ result = L2CAP_CR_LE_NO_MEM;
+ goto response_unlock;
+ }
+
bacpy(&chan->src, &conn->hcon->src);
bacpy(&chan->dst, &conn->hcon->dst);
chan->src_type = bdaddr_src_type(conn->hcon);
@@ -4974,6 +4994,8 @@ static int l2cap_le_connect_req(struct l2cap_conn *conn,
dcid = chan->scid;
credits = chan->rx_credits;
+ rsp_mtu = chan->imtu;
+ rsp_mps = chan->mps;
__set_chan_timer(chan, chan->ops->get_sndtimeo(chan));
@@ -4993,6 +5015,9 @@ static int l2cap_le_connect_req(struct l2cap_conn *conn,
result = L2CAP_CR_LE_SUCCESS;
}
+ /* Drop our local ref; __l2cap_chan_add() pinned chan via the conn list. */
+ l2cap_chan_put(chan);
+
response_unlock:
l2cap_chan_unlock(pchan);
l2cap_chan_put(pchan);
@@ -5001,13 +5026,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);
@@ -5177,12 +5197,18 @@ static inline int l2cap_ecred_conn_req(struct l2cap_conn *conn,
continue;
}
- chan = pchan->ops->new_connection(pchan);
+ chan = l2cap_chan_create();
if (!chan) {
result = L2CAP_CR_LE_NO_MEM;
continue;
}
+ if (pchan->ops->new_connection(pchan, chan) < 0) {
+ l2cap_chan_put(chan);
+ result = L2CAP_CR_LE_NO_MEM;
+ continue;
+ }
+
bacpy(&chan->src, &conn->hcon->src);
bacpy(&chan->dst, &conn->hcon->dst);
chan->src_type = bdaddr_src_type(conn->hcon);
@@ -5217,6 +5243,9 @@ static inline int l2cap_ecred_conn_req(struct l2cap_conn *conn,
} else {
l2cap_chan_ready(chan);
}
+
+ /* Drop our local ref; __l2cap_chan_add() pinned chan via the conn list. */
+ l2cap_chan_put(chan);
}
unlock:
@@ -7399,7 +7428,11 @@ 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_chan_create();
+ if (chan && pchan->ops->new_connection(pchan, chan) < 0) {
+ l2cap_chan_put(chan);
+ chan = NULL;
+ }
if (chan) {
bacpy(&chan->src, &hcon->src);
bacpy(&chan->dst, &hcon->dst);
@@ -7407,6 +7440,9 @@ static void l2cap_connect_cfm(struct hci_conn *hcon, u8 status)
chan->dst_type = dst_type;
__l2cap_chan_add(conn, chan);
+
+ /* Drop our local ref; __l2cap_chan_add() pinned chan via the conn list. */
+ l2cap_chan_put(chan);
}
l2cap_chan_unlock(pchan);
diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c
index dede550d6031..598f24c8f704 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)
@@ -1507,12 +1508,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);
@@ -1520,15 +1522,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);
@@ -1538,7 +1540,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)
@@ -1939,10 +1941,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)
@@ -1953,14 +1955,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 two refs on chan, matching the puts in
+ * l2cap_sock_kill() and l2cap_sock_destruct(). The caller keeps
+ * its own ref independent of these.
+ */
+ l2cap_chan_hold(chan);
l2cap_chan_hold(chan);
l2cap_pi(sk)->chan = chan;
@@ -1972,6 +1971,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);
@@ -1986,10 +1986,18 @@ 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);
return 0;
diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c
index 1739c1989dbd..25cb5dc580bf 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,9 @@ 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);
+ BT_DBG("initialised chan %p", chan);
- return chan;
+ return 0;
}
static const struct l2cap_ops smp_root_chan_ops = {
--
2.54.0
^ permalink raw reply related
* [PATCH v6 0/1] Bluetooth: L2CAP: Fix use-after-free in l2cap_sock_new_connection_cb()
From: Siwei Zhang @ 2026-05-29 16:54 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.
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 | 27 ++++++++--------
net/bluetooth/l2cap_core.c | 58 ++++++++++++++++++++++++++++-------
net/bluetooth/l2cap_sock.c | 48 +++++++++++++++++------------
net/bluetooth/smp.c | 13 +++-----
5 files changed, 98 insertions(+), 56 deletions(-)
--
2.54.0
^ permalink raw reply
* Re: [PATCH v5 1/1] Bluetooth: L2CAP: Fix use-after-free in l2cap_sock_new_connection_cb()
From: Luiz Augusto von Dentz @ 2026-05-29 16:40 UTC (permalink / raw)
To: Siwei Zhang; +Cc: Marcel Holtmann, linux-bluetooth
In-Reply-To: <460b3909-2210-4cf3-be9e-4f8af3175160@app.fastmail.com>
Hi Siwei,
On Fri, May 29, 2026 at 12:33 PM Siwei Zhang <oss@fourdim.xyz> wrote:
>
> Hi Luiz,
>
> On Wed, May 27, 2026, at 12:16 AM, Siwei Zhang wrote:
> > Hi Luiz,
> >
> > On Tue, May 26, 2026, at 4:46 PM, Luiz Augusto von Dentz wrote:
> >> Hi Siwei,
> >>
> >> On Wed, May 20, 2026 at 12:20 PM 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 | 14 ++++-----
> >>> net/bluetooth/l2cap_core.c | 58 ++++++++++++++++++++++++++++-------
> >>> net/bluetooth/l2cap_sock.c | 48 +++++++++++++++++------------
> >>> net/bluetooth/smp.c | 13 +++-----
> >>> 5 files changed, 91 insertions(+), 50 deletions(-)
> >>>
> >>> diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h
> >>> index 5172afee5494..f7a11e6431f0 100644
> >>> --- a/include/net/bluetooth/l2cap.h
> >>> +++ b/include/net/bluetooth/l2cap.h
> >>> @@ -619,7 +619,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);
> >>> @@ -883,9 +884,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 23a229ab6a33..286c0b45055b 100644
> >>> --- a/net/bluetooth/6lowpan.c
> >>> +++ b/net/bluetooth/6lowpan.c
> >>> @@ -743,19 +743,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_chan *pchan,
> >>> + struct l2cap_chan *chan)
> >>> {
> >>> - struct l2cap_chan *chan;
> >>> -
> >>> - chan = chan_create();
> >>> - 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;
> >>
> >> The 3 lines above make no sense.
> >>
> >
> > chan_create code in 6lowpan.c
> >
> > static struct l2cap_chan *chan_create(void)
> > {
> > struct l2cap_chan *chan;
> >
> > chan = l2cap_chan_create();
> > 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;
> >
> > return chan;
> > }
> >
> > Since we allocate chan outside and replace the chan_create here,
> > I do think these are needed and they are specific to 6lowpan only.
> >
> > I can refactor it in this patch or in a follow-up patch. I would prefer it
> > to be in a follow-up patch.
> >
>
> What do you think. Please let me know if you want me to change anything.
There is something off then, because nothing is being removed that
sets similar values which is what led me to believe it was necessary
at first.
> >>> chan->ops = pchan->ops;
> >>>
> >>> 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 fdccd62ccca8..505f32034971 100644
> >>> --- a/net/bluetooth/l2cap_core.c
> >>> +++ b/net/bluetooth/l2cap_core.c
> >>> @@ -4051,10 +4051,16 @@ static void l2cap_connect(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd,
> >>> goto response;
> >>> }
> >>>
> >>> - chan = pchan->ops->new_connection(pchan);
> >>> + chan = l2cap_chan_create();
> >>> if (!chan)
> >>> goto response;
> >>>
> >>> + if (pchan->ops->new_connection(pchan, chan) < 0) {
> >>> + l2cap_chan_put(chan);
> >>> + chan = NULL;
> >>> + goto response;
> >>> + }
> >>> +
> >>> /* For certain devices (ex: HID mouse), support for authentication,
> >>> * pairing and bonding is optional. For such devices, inorder to avoid
> >>> * the ACL alive for too long after L2CAP disconnection, reset the ACL
> >>> @@ -4132,6 +4138,10 @@ static void l2cap_connect(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd,
> >>> chan->num_conf_req++;
> >>> }
> >>>
> >>> + /* Drop our local ref; __l2cap_chan_add() pinned chan via the conn list. */
> >>> + if (chan)
> >>> + l2cap_chan_put(chan);
> >>> +
> >>> l2cap_chan_unlock(pchan);
> >>> l2cap_chan_put(pchan);
> >>> }
> >>> @@ -4881,6 +4891,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;
> >>>
> >>> @@ -4893,6 +4904,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;
> >>> @@ -4953,12 +4966,19 @@ static int l2cap_le_connect_req(struct l2cap_conn *conn,
> >>> goto response_unlock;
> >>> }
> >>>
> >>> - chan = pchan->ops->new_connection(pchan);
> >>> + chan = l2cap_chan_create();
> >>> if (!chan) {
> >>> result = L2CAP_CR_LE_NO_MEM;
> >>> goto response_unlock;
> >>> }
> >>>
> >>> + if (pchan->ops->new_connection(pchan, chan) < 0) {
> >>> + l2cap_chan_put(chan);
> >>> + chan = NULL;
> >>> + result = L2CAP_CR_LE_NO_MEM;
> >>> + goto response_unlock;
> >>> + }
> >>> +
> >>> bacpy(&chan->src, &conn->hcon->src);
> >>> bacpy(&chan->dst, &conn->hcon->dst);
> >>> chan->src_type = bdaddr_src_type(conn->hcon);
> >>> @@ -4974,6 +4994,8 @@ static int l2cap_le_connect_req(struct l2cap_conn *conn,
> >>>
> >>> dcid = chan->scid;
> >>> credits = chan->rx_credits;
> >>> + rsp_mtu = chan->imtu;
> >>> + rsp_mps = chan->mps;
> >>>
> >>> __set_chan_timer(chan, chan->ops->get_sndtimeo(chan));
> >>>
> >>> @@ -4993,6 +5015,9 @@ static int l2cap_le_connect_req(struct l2cap_conn *conn,
> >>> result = L2CAP_CR_LE_SUCCESS;
> >>> }
> >>>
> >>> + /* Drop our local ref; __l2cap_chan_add() pinned chan via the conn list. */
> >>> + l2cap_chan_put(chan);
> >>> +
> >>> response_unlock:
> >>> l2cap_chan_unlock(pchan);
> >>> l2cap_chan_put(pchan);
> >>> @@ -5001,13 +5026,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);
> >>> @@ -5177,12 +5197,18 @@ static inline int l2cap_ecred_conn_req(struct l2cap_conn *conn,
> >>> continue;
> >>> }
> >>>
> >>> - chan = pchan->ops->new_connection(pchan);
> >>> + chan = l2cap_chan_create();
> >>> if (!chan) {
> >>> result = L2CAP_CR_LE_NO_MEM;
> >>> continue;
> >>> }
> >>>
> >>> + if (pchan->ops->new_connection(pchan, chan) < 0) {
> >>> + l2cap_chan_put(chan);
> >>> + result = L2CAP_CR_LE_NO_MEM;
> >>> + continue;
> >>> + }
> >>> +
> >>> bacpy(&chan->src, &conn->hcon->src);
> >>> bacpy(&chan->dst, &conn->hcon->dst);
> >>> chan->src_type = bdaddr_src_type(conn->hcon);
> >>> @@ -5217,6 +5243,9 @@ static inline int l2cap_ecred_conn_req(struct l2cap_conn *conn,
> >>> } else {
> >>> l2cap_chan_ready(chan);
> >>> }
> >>> +
> >>> + /* Drop our local ref; __l2cap_chan_add() pinned chan via the conn list. */
> >>> + l2cap_chan_put(chan);
> >>> }
> >>>
> >>> unlock:
> >>> @@ -7399,7 +7428,11 @@ 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_chan_create();
> >>> + if (chan && pchan->ops->new_connection(pchan, chan) < 0) {
> >>> + l2cap_chan_put(chan);
> >>> + chan = NULL;
> >>> + }
> >>> if (chan) {
> >>> bacpy(&chan->src, &hcon->src);
> >>> bacpy(&chan->dst, &hcon->dst);
> >>> @@ -7407,6 +7440,9 @@ static void l2cap_connect_cfm(struct hci_conn *hcon, u8 status)
> >>> chan->dst_type = dst_type;
> >>>
> >>> __l2cap_chan_add(conn, chan);
> >>> +
> >>> + /* Drop our local ref; __l2cap_chan_add() pinned chan via the conn list. */
> >>> + l2cap_chan_put(chan);
> >>> }
> >>>
> >>> l2cap_chan_unlock(pchan);
> >>> diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c
> >>> index dede550d6031..598f24c8f704 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)
> >>> @@ -1507,12 +1508,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);
> >>>
> >>> @@ -1520,15 +1522,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);
> >>>
> >>> @@ -1538,7 +1540,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)
> >>> @@ -1939,10 +1941,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)
> >>> @@ -1953,14 +1955,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 two refs on chan, matching the puts in
> >>> + * l2cap_sock_kill() and l2cap_sock_destruct(). The caller keeps
> >>> + * its own ref independent of these.
> >>> + */
> >>> + l2cap_chan_hold(chan);
> >>> l2cap_chan_hold(chan);
> >>>
> >>> l2cap_pi(sk)->chan = chan;
> >>> @@ -1972,6 +1971,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);
> >>>
> >>> @@ -1986,10 +1986,18 @@ 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);
> >>> return 0;
> >>> diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c
> >>> index 1739c1989dbd..25cb5dc580bf 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,9 @@ 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);
> >>> + BT_DBG("initialised chan %p", chan);
> >>>
> >>> - return chan;
> >>> + return 0;
> >>> }
> >>>
> >>> static const struct l2cap_ops smp_root_chan_ops = {
> >>> --
> >>> 2.54.0
> >>>
> >>
> >>
> >> --
> >> Luiz Augusto von Dentz
> >
> > Best,
> > Siwei
>
> Best,
> Siwei
--
Luiz Augusto von Dentz
^ permalink raw reply
* Re: [PATCH v5 1/1] Bluetooth: L2CAP: Fix use-after-free in l2cap_sock_new_connection_cb()
From: Siwei Zhang @ 2026-05-29 16:33 UTC (permalink / raw)
To: Luiz Augusto von Dentz; +Cc: Marcel Holtmann, linux-bluetooth
In-Reply-To: <c45459c5-e7d9-4ea2-bd61-903a33f8778f@app.fastmail.com>
Hi Luiz,
On Wed, May 27, 2026, at 12:16 AM, Siwei Zhang wrote:
> Hi Luiz,
>
> On Tue, May 26, 2026, at 4:46 PM, Luiz Augusto von Dentz wrote:
>> Hi Siwei,
>>
>> On Wed, May 20, 2026 at 12:20 PM 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 | 14 ++++-----
>>> net/bluetooth/l2cap_core.c | 58 ++++++++++++++++++++++++++++-------
>>> net/bluetooth/l2cap_sock.c | 48 +++++++++++++++++------------
>>> net/bluetooth/smp.c | 13 +++-----
>>> 5 files changed, 91 insertions(+), 50 deletions(-)
>>>
>>> diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h
>>> index 5172afee5494..f7a11e6431f0 100644
>>> --- a/include/net/bluetooth/l2cap.h
>>> +++ b/include/net/bluetooth/l2cap.h
>>> @@ -619,7 +619,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);
>>> @@ -883,9 +884,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 23a229ab6a33..286c0b45055b 100644
>>> --- a/net/bluetooth/6lowpan.c
>>> +++ b/net/bluetooth/6lowpan.c
>>> @@ -743,19 +743,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_chan *pchan,
>>> + struct l2cap_chan *chan)
>>> {
>>> - struct l2cap_chan *chan;
>>> -
>>> - chan = chan_create();
>>> - 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;
>>
>> The 3 lines above make no sense.
>>
>
> chan_create code in 6lowpan.c
>
> static struct l2cap_chan *chan_create(void)
> {
> struct l2cap_chan *chan;
>
> chan = l2cap_chan_create();
> 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;
>
> return chan;
> }
>
> Since we allocate chan outside and replace the chan_create here,
> I do think these are needed and they are specific to 6lowpan only.
>
> I can refactor it in this patch or in a follow-up patch. I would prefer it
> to be in a follow-up patch.
>
What do you think. Please let me know if you want me to change anything.
>>> chan->ops = pchan->ops;
>>>
>>> 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 fdccd62ccca8..505f32034971 100644
>>> --- a/net/bluetooth/l2cap_core.c
>>> +++ b/net/bluetooth/l2cap_core.c
>>> @@ -4051,10 +4051,16 @@ static void l2cap_connect(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd,
>>> goto response;
>>> }
>>>
>>> - chan = pchan->ops->new_connection(pchan);
>>> + chan = l2cap_chan_create();
>>> if (!chan)
>>> goto response;
>>>
>>> + if (pchan->ops->new_connection(pchan, chan) < 0) {
>>> + l2cap_chan_put(chan);
>>> + chan = NULL;
>>> + goto response;
>>> + }
>>> +
>>> /* For certain devices (ex: HID mouse), support for authentication,
>>> * pairing and bonding is optional. For such devices, inorder to avoid
>>> * the ACL alive for too long after L2CAP disconnection, reset the ACL
>>> @@ -4132,6 +4138,10 @@ static void l2cap_connect(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd,
>>> chan->num_conf_req++;
>>> }
>>>
>>> + /* Drop our local ref; __l2cap_chan_add() pinned chan via the conn list. */
>>> + if (chan)
>>> + l2cap_chan_put(chan);
>>> +
>>> l2cap_chan_unlock(pchan);
>>> l2cap_chan_put(pchan);
>>> }
>>> @@ -4881,6 +4891,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;
>>>
>>> @@ -4893,6 +4904,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;
>>> @@ -4953,12 +4966,19 @@ static int l2cap_le_connect_req(struct l2cap_conn *conn,
>>> goto response_unlock;
>>> }
>>>
>>> - chan = pchan->ops->new_connection(pchan);
>>> + chan = l2cap_chan_create();
>>> if (!chan) {
>>> result = L2CAP_CR_LE_NO_MEM;
>>> goto response_unlock;
>>> }
>>>
>>> + if (pchan->ops->new_connection(pchan, chan) < 0) {
>>> + l2cap_chan_put(chan);
>>> + chan = NULL;
>>> + result = L2CAP_CR_LE_NO_MEM;
>>> + goto response_unlock;
>>> + }
>>> +
>>> bacpy(&chan->src, &conn->hcon->src);
>>> bacpy(&chan->dst, &conn->hcon->dst);
>>> chan->src_type = bdaddr_src_type(conn->hcon);
>>> @@ -4974,6 +4994,8 @@ static int l2cap_le_connect_req(struct l2cap_conn *conn,
>>>
>>> dcid = chan->scid;
>>> credits = chan->rx_credits;
>>> + rsp_mtu = chan->imtu;
>>> + rsp_mps = chan->mps;
>>>
>>> __set_chan_timer(chan, chan->ops->get_sndtimeo(chan));
>>>
>>> @@ -4993,6 +5015,9 @@ static int l2cap_le_connect_req(struct l2cap_conn *conn,
>>> result = L2CAP_CR_LE_SUCCESS;
>>> }
>>>
>>> + /* Drop our local ref; __l2cap_chan_add() pinned chan via the conn list. */
>>> + l2cap_chan_put(chan);
>>> +
>>> response_unlock:
>>> l2cap_chan_unlock(pchan);
>>> l2cap_chan_put(pchan);
>>> @@ -5001,13 +5026,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);
>>> @@ -5177,12 +5197,18 @@ static inline int l2cap_ecred_conn_req(struct l2cap_conn *conn,
>>> continue;
>>> }
>>>
>>> - chan = pchan->ops->new_connection(pchan);
>>> + chan = l2cap_chan_create();
>>> if (!chan) {
>>> result = L2CAP_CR_LE_NO_MEM;
>>> continue;
>>> }
>>>
>>> + if (pchan->ops->new_connection(pchan, chan) < 0) {
>>> + l2cap_chan_put(chan);
>>> + result = L2CAP_CR_LE_NO_MEM;
>>> + continue;
>>> + }
>>> +
>>> bacpy(&chan->src, &conn->hcon->src);
>>> bacpy(&chan->dst, &conn->hcon->dst);
>>> chan->src_type = bdaddr_src_type(conn->hcon);
>>> @@ -5217,6 +5243,9 @@ static inline int l2cap_ecred_conn_req(struct l2cap_conn *conn,
>>> } else {
>>> l2cap_chan_ready(chan);
>>> }
>>> +
>>> + /* Drop our local ref; __l2cap_chan_add() pinned chan via the conn list. */
>>> + l2cap_chan_put(chan);
>>> }
>>>
>>> unlock:
>>> @@ -7399,7 +7428,11 @@ 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_chan_create();
>>> + if (chan && pchan->ops->new_connection(pchan, chan) < 0) {
>>> + l2cap_chan_put(chan);
>>> + chan = NULL;
>>> + }
>>> if (chan) {
>>> bacpy(&chan->src, &hcon->src);
>>> bacpy(&chan->dst, &hcon->dst);
>>> @@ -7407,6 +7440,9 @@ static void l2cap_connect_cfm(struct hci_conn *hcon, u8 status)
>>> chan->dst_type = dst_type;
>>>
>>> __l2cap_chan_add(conn, chan);
>>> +
>>> + /* Drop our local ref; __l2cap_chan_add() pinned chan via the conn list. */
>>> + l2cap_chan_put(chan);
>>> }
>>>
>>> l2cap_chan_unlock(pchan);
>>> diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c
>>> index dede550d6031..598f24c8f704 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)
>>> @@ -1507,12 +1508,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);
>>>
>>> @@ -1520,15 +1522,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);
>>>
>>> @@ -1538,7 +1540,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)
>>> @@ -1939,10 +1941,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)
>>> @@ -1953,14 +1955,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 two refs on chan, matching the puts in
>>> + * l2cap_sock_kill() and l2cap_sock_destruct(). The caller keeps
>>> + * its own ref independent of these.
>>> + */
>>> + l2cap_chan_hold(chan);
>>> l2cap_chan_hold(chan);
>>>
>>> l2cap_pi(sk)->chan = chan;
>>> @@ -1972,6 +1971,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);
>>>
>>> @@ -1986,10 +1986,18 @@ 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);
>>> return 0;
>>> diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c
>>> index 1739c1989dbd..25cb5dc580bf 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,9 @@ 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);
>>> + BT_DBG("initialised chan %p", chan);
>>>
>>> - return chan;
>>> + return 0;
>>> }
>>>
>>> static const struct l2cap_ops smp_root_chan_ops = {
>>> --
>>> 2.54.0
>>>
>>
>>
>> --
>> Luiz Augusto von Dentz
>
> Best,
> Siwei
Best,
Siwei
^ permalink raw reply
* [bluez/bluez]
From: BluezTestBot @ 2026-05-29 16:26 UTC (permalink / raw)
To: linux-bluetooth
Branch: refs/heads/1087593
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-05-29 16:26 UTC (permalink / raw)
To: linux-bluetooth
Branch: refs/heads/1102048
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] 17fbb4: mgmt: Remove mgmt_ev[] strings of undefined MGMT e...
From: fdanis-oss @ 2026-05-29 16:25 UTC (permalink / raw)
To: linux-bluetooth
Branch: refs/heads/master
Home: https://github.com/bluez/bluez
Commit: 17fbb48d8f7c22d0702b3b9daf69f9c06231d774
https://github.com/bluez/bluez/commit/17fbb48d8f7c22d0702b3b9daf69f9c06231d774
Author: Frédéric Danis <frederic.danis@collabora.com>
Date: 2026-05-29 (Fri, 29 May 2026)
Changed paths:
M lib/bluetooth/mgmt.h
Log Message:
-----------
mgmt: Remove mgmt_ev[] strings of undefined MGMT events
Remove event strings introduced in mgmt_ev[] but for which the MGMT
events has not been defined.
Those events are already part of the events_le_table[] in
monitor/packet.c
Fixes: f9557931ad36 ("monitor: Add decoding support for Sync Receiver events")
To unsubscribe from these emails, change your notification settings at https://github.com/bluez/bluez/settings/notifications
^ permalink raw reply
* Re: [PATCH v5] Bluetooth: bnep: reject short frames before parsing
From: patchwork-bot+bluetooth @ 2026-05-29 15:50 UTC (permalink / raw)
To: Zhang Cen
Cc: marcel, luiz.dentz, linux-bluetooth, linux-kernel, zerocling0077,
2045gemini
In-Reply-To: <20260529032209.2269753-1-rollkingzzc@gmail.com>
Hello:
This patch was applied to bluetooth/bluetooth-next.git (master)
by Luiz Augusto von Dentz <luiz.von.dentz@intel.com>:
On Fri, 29 May 2026 11:22:09 +0800 you wrote:
> A BNEP peer can send a short BNEP SDU. bnep_rx_frame() reads the
> packet type byte immediately and, for control packets, reads the control
> opcode and setup UUID-size byte before proving that those bytes are
> present. bnep_rx_control() also dereferences the control opcode without
> rejecting an empty control payload.
>
> Use skb_pull_data() for the fixed fields in bnep_rx_frame() so a NULL
> return gates each dereference. Split the control handler so the frame
> path can pass an opcode that has already been pulled, and keep the
> byte-buffer wrapper for extension control payloads.
>
> [...]
Here is the summary with links:
- [v5] Bluetooth: bnep: reject short frames before parsing
https://git.kernel.org/bluetooth/bluetooth-next/c/379b101059b4
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 v4] Bluetooth: L2CAP: reject BR/EDR signaling packets over MTUsig
From: patchwork-bot+bluetooth @ 2026-05-29 15:50 UTC (permalink / raw)
To: Michael Bommarito; +Cc: marcel, luiz.dentz, linux-bluetooth
In-Reply-To: <20260521144518.1361335-1-michael.bommarito@gmail.com>
Hello:
This patch was applied to bluetooth/bluetooth-next.git (master)
by Luiz Augusto von Dentz <luiz.von.dentz@intel.com>:
On Thu, 21 May 2026 10:45:17 -0400 you wrote:
> net/bluetooth/l2cap_core.c:l2cap_sig_channel() accepts BR/EDR
> signaling packets up to the channel MTU and dispatches each command
> without enforcing the signaling MTU (MTUsig). A Bluetooth BR/EDR peer
> within radio range can send a fixed-channel CID 0x0001 packet that is
> larger than MTUsig and contains many L2CAP_ECHO_REQ commands before
> pairing. In a real-radio stock-kernel run, one 681-byte signaling
> packet containing 168 zero-length ECHO_REQ commands made the target
> transmit 168 ECHO_RSP frames over about 220 ms.
>
> [...]
Here is the summary with links:
- [v4] Bluetooth: L2CAP: reject BR/EDR signaling packets over MTUsig
https://git.kernel.org/bluetooth/bluetooth-next/c/a6273f046450
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 1/1] Bluetooth: hci_sync: reject oversized Broadcast Announcement prepend
From: patchwork-bot+bluetooth @ 2026-05-29 15:50 UTC (permalink / raw)
To: Ren Wei
Cc: linux-bluetooth, marcel, luiz.dentz, yuantan098, zcliangcn, bird,
xuyq21
In-Reply-To: <9089784d08f1afd038b4ce0df1fb89904f4879ee.1779634468.git.xuyq21@lenovo.com>
Hello:
This patch was applied to bluetooth/bluetooth-next.git (master)
by Luiz Augusto von Dentz <luiz.von.dentz@intel.com>:
On Fri, 29 May 2026 16:54:23 +0800 you wrote:
> From: Yuqi Xu <xuyq21@lenovo.com>
>
> Existing advertising instances can already hold the maximum extended
> advertising payload. When hci_adv_bcast_annoucement() prepends the
> Broadcast Announcement service data to that payload, the combined data
> may no longer fit in the temporary buffer used to rebuild the
> advertising data.
>
> [...]
Here is the summary with links:
- [1/1] Bluetooth: hci_sync: reject oversized Broadcast Announcement prepend
https://git.kernel.org/bluetooth/bluetooth-next/c/0bc614e5e938
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] mgmt: Remove mgmt_ev[] strings of undefined MGMT events
From: patchwork-bot+bluetooth @ 2026-05-29 15:40 UTC (permalink / raw)
To: =?utf-8?b?RnLDqWTDqXJpYyBEYW5pcyA8ZnJlZGVyaWMuZGFuaXNAY29sbGFib3JhLmNvbT4=?=
Cc: linux-bluetooth
In-Reply-To: <20260528074938.385847-1-frederic.danis@collabora.com>
Hello:
This patch was applied to bluetooth/bluez.git (master)
by Luiz Augusto von Dentz <luiz.von.dentz@intel.com>:
On Thu, 28 May 2026 09:49:38 +0200 you wrote:
> Remove event strings introduced in mgmt_ev[] but for which the MGMT
> events has not been defined.
>
> Those events are already part of the events_le_table[] in
> monitor/packet.c
>
> Fixes: f9557931ad36 ("monitor: Add decoding support for Sync Receiver events")
>
> [...]
Here is the summary with links:
- [BlueZ] mgmt: Remove mgmt_ev[] strings of undefined MGMT events
https://git.kernel.org/pub/scm/bluetooth/bluez.git/?id=17fbb48d8f7c
You are awesome, thank you!
--
Deet-doot-dot, I am a bot.
https://korg.docs.kernel.org/patchwork/pwbot.html
^ permalink raw reply
* RE: [1/1] Bluetooth: hci_codec: validate capability record length
From: bluez.test.bot @ 2026-05-29 15:09 UTC (permalink / raw)
To: linux-bluetooth, n05ec
In-Reply-To: <4927cae4fe043f3e2aa80f4ee6bed05e4fb5a6d4.1779633761.git.xuyq21@lenovo.com>
[-- Attachment #1: Type: text/plain, Size: 3355 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=1102899
---Test result---
Test Summary:
CheckPatch FAIL 0.60 seconds
VerifyFixes PASS 0.09 seconds
VerifySignedoff PASS 0.09 seconds
GitLint PASS 0.25 seconds
SubjectPrefix PASS 0.47 seconds
BuildKernel PASS 26.89 seconds
CheckAllWarning PASS 28.89 seconds
CheckSparse PASS 27.74 seconds
BuildKernel32 PASS 25.94 seconds
TestRunnerSetup PASS 574.02 seconds
TestRunner_l2cap-tester PASS 60.78 seconds
TestRunner_iso-tester PASS 80.04 seconds
TestRunner_bnep-tester PASS 19.62 seconds
TestRunner_mgmt-tester FAIL 221.48 seconds
TestRunner_rfcomm-tester PASS 25.72 seconds
TestRunner_sco-tester PASS 33.76 seconds
TestRunner_ioctl-tester PASS 26.62 seconds
TestRunner_mesh-tester FAIL 26.89 seconds
TestRunner_smp-tester PASS 24.22 seconds
TestRunner_userchan-tester PASS 21.02 seconds
TestRunner_6lowpan-tester PASS 24.16 seconds
IncrementalBuild PASS 25.60 seconds
Details
##############################
Test: CheckPatch - FAIL
Desc: Run checkpatch.pl script
Output:
[1/1] Bluetooth: hci_codec: validate capability record length
WARNING: Reported-by: should be immediately followed by Closes: with a URL to the report
#89:
Reported-by: Yuan Tan <yuantan098@gmail.com>
Reported-by: Zhengchuan Liang <zcliangcn@gmail.com>
WARNING: Reported-by: should be immediately followed by Closes: with a URL to the report
#90:
Reported-by: Zhengchuan Liang <zcliangcn@gmail.com>
Reported-by: Xin Liu <bird@lzu.edu.cn>
WARNING: Reported-by: should be immediately followed by Closes: with a URL to the report
#91:
Reported-by: Xin Liu <bird@lzu.edu.cn>
Assisted-by: Codex:GPT-5.4
total: 0 errors, 3 warnings, 0 checks, 8 lines checked
NOTE: For some of the reported defects, checkpatch may be able to
mechanically convert to the typical style using --fix or --fix-inplace.
/github/workspace/src/patch/14601083.patch has style problems, please review.
NOTE: Ignored message types: UNKNOWN_COMMIT_ID
NOTE: If any of the errors are false positives, please report
them to the maintainer, see CHECKPATCH in MAINTAINERS.
##############################
Test: 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.238 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.550 seconds
Mesh - Send cancel - 2 Timed out 1.993 seconds
https://github.com/bluez/bluetooth-next/pull/255
---
Regards,
Linux Bluetooth
^ permalink raw reply
* [bluetooth-next:master] BUILD SUCCESS a82ccb946ae5d399437ece698590421c332252ed
From: kernel test robot @ 2026-05-29 14:09 UTC (permalink / raw)
To: Luiz Augusto von Dentz; +Cc: linux-bluetooth
tree/branch: https://git.kernel.org/pub/scm/linux/kernel/git/bluetooth/bluetooth-next.git master
branch HEAD: a82ccb946ae5d399437ece698590421c332252ed Bluetooth: RFCOMM: validate skb length in MCC handlers
elapsed time: 1292m
configs tested: 187
configs skipped: 2
The following configs have been built successfully.
More configs may be tested in the coming days.
tested configs:
alpha allnoconfig gcc-15.2.0
alpha allyesconfig gcc-15.2.0
alpha defconfig gcc-15.2.0
arc allmodconfig clang-16
arc allnoconfig gcc-15.2.0
arc allyesconfig clang-23
arc defconfig gcc-15.2.0
arc randconfig-001-20260529 clang-23
arc randconfig-002-20260529 clang-23
arm allnoconfig gcc-15.2.0
arm allyesconfig clang-16
arm defconfig gcc-15.2.0
arm randconfig-001-20260529 clang-23
arm randconfig-002-20260529 clang-23
arm randconfig-003-20260529 clang-23
arm randconfig-004-20260529 clang-23
arm64 allmodconfig clang-23
arm64 allnoconfig gcc-15.2.0
arm64 defconfig gcc-15.2.0
arm64 randconfig-001-20260529 clang-23
arm64 randconfig-002-20260529 clang-23
arm64 randconfig-003-20260529 clang-23
arm64 randconfig-004-20260529 clang-23
csky allmodconfig gcc-15.2.0
csky allnoconfig gcc-15.2.0
csky defconfig gcc-15.2.0
csky randconfig-001-20260529 clang-23
csky randconfig-002-20260529 clang-23
hexagon allmodconfig gcc-15.2.0
hexagon allnoconfig gcc-15.2.0
hexagon defconfig gcc-15.2.0
hexagon randconfig-001-20260529 gcc-8.5.0
hexagon randconfig-002-20260529 gcc-8.5.0
i386 allmodconfig clang-20
i386 allnoconfig gcc-15.2.0
i386 allyesconfig clang-20
i386 buildonly-randconfig-001-20260529 gcc-12
i386 buildonly-randconfig-002-20260529 gcc-12
i386 buildonly-randconfig-003-20260529 gcc-12
i386 buildonly-randconfig-004-20260529 gcc-12
i386 buildonly-randconfig-005-20260529 gcc-12
i386 buildonly-randconfig-006-20260529 gcc-12
i386 defconfig gcc-15.2.0
i386 randconfig-001 gcc-14
i386 randconfig-001-20260529 gcc-14
i386 randconfig-002 gcc-14
i386 randconfig-002-20260529 gcc-14
i386 randconfig-003 gcc-14
i386 randconfig-003-20260529 gcc-14
i386 randconfig-004 gcc-14
i386 randconfig-004-20260529 gcc-14
i386 randconfig-005 gcc-14
i386 randconfig-005-20260529 gcc-14
i386 randconfig-006 gcc-14
i386 randconfig-006-20260529 gcc-14
i386 randconfig-007 gcc-14
i386 randconfig-007-20260529 gcc-14
i386 randconfig-011-20260529 gcc-14
i386 randconfig-012-20260529 gcc-14
i386 randconfig-013-20260529 gcc-14
i386 randconfig-014-20260529 gcc-14
i386 randconfig-015-20260529 gcc-14
i386 randconfig-016-20260529 gcc-14
i386 randconfig-017-20260529 gcc-14
loongarch allmodconfig clang-23
loongarch allnoconfig gcc-15.2.0
loongarch defconfig clang-19
loongarch randconfig-001-20260529 gcc-8.5.0
loongarch randconfig-002-20260529 gcc-8.5.0
m68k allmodconfig gcc-15.2.0
m68k allnoconfig gcc-15.2.0
m68k allyesconfig clang-16
m68k defconfig clang-19
microblaze allnoconfig gcc-15.2.0
microblaze allyesconfig gcc-15.2.0
microblaze defconfig clang-19
mips allmodconfig gcc-15.2.0
mips allnoconfig gcc-15.2.0
mips allyesconfig gcc-15.2.0
nios2 alldefconfig gcc-11.5.0
nios2 allmodconfig clang-23
nios2 allnoconfig clang-23
nios2 defconfig clang-19
nios2 randconfig-001-20260529 gcc-8.5.0
nios2 randconfig-002-20260529 gcc-8.5.0
openrisc allmodconfig clang-23
openrisc allnoconfig clang-23
openrisc defconfig gcc-15.2.0
parisc allmodconfig gcc-15.2.0
parisc allnoconfig clang-23
parisc allyesconfig clang-19
parisc defconfig gcc-15.2.0
parisc randconfig-001 clang-19
parisc randconfig-001-20260529 clang-19
parisc randconfig-002 clang-19
parisc randconfig-002-20260529 clang-19
parisc64 defconfig clang-19
powerpc allmodconfig gcc-15.2.0
powerpc allnoconfig clang-23
powerpc randconfig-001 clang-19
powerpc randconfig-001-20260529 clang-19
powerpc randconfig-002 clang-19
powerpc randconfig-002-20260529 clang-19
powerpc64 randconfig-001 clang-19
powerpc64 randconfig-001-20260529 clang-19
powerpc64 randconfig-002 clang-19
powerpc64 randconfig-002-20260529 clang-19
riscv allmodconfig clang-23
riscv allnoconfig clang-23
riscv allyesconfig clang-16
riscv defconfig gcc-15.2.0
riscv randconfig-001-20260529 gcc-15.2.0
riscv randconfig-002-20260529 gcc-15.2.0
s390 allmodconfig clang-19
s390 allnoconfig clang-23
s390 allyesconfig gcc-15.2.0
s390 defconfig gcc-15.2.0
s390 randconfig-001-20260529 gcc-15.2.0
s390 randconfig-002-20260529 gcc-15.2.0
sh allmodconfig gcc-15.2.0
sh allnoconfig clang-23
sh allyesconfig clang-19
sh defconfig gcc-14
sh randconfig-001-20260529 gcc-15.2.0
sh randconfig-002-20260529 gcc-15.2.0
sparc allnoconfig clang-23
sparc defconfig gcc-15.2.0
sparc randconfig-001-20260529 gcc-11.5.0
sparc randconfig-002-20260529 gcc-11.5.0
sparc64 allmodconfig clang-23
sparc64 defconfig gcc-14
sparc64 randconfig-001-20260529 gcc-11.5.0
sparc64 randconfig-002-20260529 gcc-11.5.0
um allmodconfig clang-19
um allnoconfig clang-23
um allyesconfig gcc-15.2.0
um defconfig gcc-14
um i386_defconfig gcc-14
um randconfig-001-20260529 gcc-11.5.0
um randconfig-002-20260529 gcc-11.5.0
um x86_64_defconfig gcc-14
x86_64 allmodconfig clang-20
x86_64 allnoconfig clang-23
x86_64 allyesconfig clang-20
x86_64 buildonly-randconfig-001-20260529 gcc-14
x86_64 buildonly-randconfig-002-20260529 gcc-14
x86_64 buildonly-randconfig-003-20260529 gcc-14
x86_64 buildonly-randconfig-004-20260529 gcc-14
x86_64 buildonly-randconfig-005-20260529 gcc-14
x86_64 buildonly-randconfig-006-20260529 gcc-14
x86_64 defconfig gcc-14
x86_64 kexec clang-20
x86_64 randconfig-001 clang-20
x86_64 randconfig-001-20260529 clang-20
x86_64 randconfig-002 clang-20
x86_64 randconfig-002-20260529 clang-20
x86_64 randconfig-003 clang-20
x86_64 randconfig-003-20260529 clang-20
x86_64 randconfig-004 clang-20
x86_64 randconfig-004-20260529 clang-20
x86_64 randconfig-005 clang-20
x86_64 randconfig-005-20260529 clang-20
x86_64 randconfig-006 clang-20
x86_64 randconfig-006-20260529 clang-20
x86_64 randconfig-011-20260529 clang-20
x86_64 randconfig-012-20260529 clang-20
x86_64 randconfig-013-20260529 clang-20
x86_64 randconfig-014-20260529 clang-20
x86_64 randconfig-015-20260529 clang-20
x86_64 randconfig-016-20260529 clang-20
x86_64 randconfig-071-20260529 clang-20
x86_64 randconfig-072-20260529 clang-20
x86_64 randconfig-073-20260529 clang-20
x86_64 randconfig-074-20260529 clang-20
x86_64 randconfig-075-20260529 clang-20
x86_64 randconfig-076-20260529 clang-20
x86_64 rhel-9.4 clang-20
x86_64 rhel-9.4-bpf gcc-14
x86_64 rhel-9.4-func clang-20
x86_64 rhel-9.4-kselftests clang-20
x86_64 rhel-9.4-kunit gcc-14
x86_64 rhel-9.4-ltp gcc-14
x86_64 rhel-9.4-rust clang-20
xtensa allnoconfig clang-23
xtensa allyesconfig clang-23
xtensa randconfig-001-20260529 gcc-11.5.0
xtensa randconfig-002-20260529 gcc-11.5.0
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
^ permalink raw reply
* Re: [PATCH 1/1] Bluetooth: hci_codec: validate capability record length
From: Luiz Augusto von Dentz @ 2026-05-29 14:08 UTC (permalink / raw)
To: Ren Wei
Cc: linux-bluetooth, marcel, kiran.k, chethan.tumkur.narayan,
ravishankar.srivatsa, yuantan098, zcliangcn, bird, xuyq21
In-Reply-To: <4927cae4fe043f3e2aa80f4ee6bed05e4fb5a6d4.1779633761.git.xuyq21@lenovo.com>
Hi Ren,
On Fri, May 29, 2026 at 9:12 AM Ren Wei <n05ec@lzu.edu.cn> wrote:
>
> From: Yuqi Xu <xuyq21@lenovo.com>
>
> hci_read_codec_capabilities() validates each capability entry before
> adding its serialized size to len and advancing the skb.
>
> The current check only compares skb->len against caps->len, even
> though the code consumes the length byte and the payload. Validate
> the full record size so the cached capability length matches the
> bytes available in the command response.
>
> Fixes: 8961987f3f5f ("Bluetooth: Enumerate local supported codec and cache details")
> Cc: stable@kernel.org
> Reported-by: Yuan Tan <yuantan098@gmail.com>
> Reported-by: Zhengchuan Liang <zcliangcn@gmail.com>
> Reported-by: Xin Liu <bird@lzu.edu.cn>
> Assisted-by: Codex:GPT-5.4
> Signed-off-by: Yuqi Xu <xuyq21@lenovo.com>
> Signed-off-by: Ren Wei <n05ec@lzu.edu.cn>
> ---
> net/bluetooth/hci_codec.c | 2 +-
> 1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/net/bluetooth/hci_codec.c b/net/bluetooth/hci_codec.c
> index 3cc135bb1d30..5bc5003c387c 100644
> --- a/net/bluetooth/hci_codec.c
> +++ b/net/bluetooth/hci_codec.c
> @@ -100,7 +100,7 @@ static void hci_read_codec_capabilities(struct hci_dev *hdev, __u8 transport,
> caps = (void *)skb->data;
> if (skb->len < sizeof(*caps))
> goto error;
> - if (skb->len < caps->len)
> + if (skb->len < sizeof(caps->len) + caps->len)
> goto error;
Id go with skb_pull_data instead, that could probably be used first to
pull caps, and then another time for caps->len.
> len += sizeof(caps->len) + caps->len;
> skb_pull(skb, sizeof(caps->len) + caps->len);
> --
> 2.54.0
>
--
Luiz Augusto von Dentz
^ permalink raw reply
* RE: [v2] Bluetooth: btusb: Add TP-Link UB600 for Realtek 8761BUV
From: Nils Helmig @ 2026-05-29 13:38 UTC (permalink / raw)
To: bluez.test.bot; +Cc: linux-bluetooth, marcel, luiz.dentz, nils.helmig
In-Reply-To: <69ed185e.050a0220.107d78.67fa@mx.google.com>
I saw that the merge request https://github.com/bluez/bluetooth-next/pull/127 is closed. Any news on this patch? Is there anything I should do?
Regards,
Nils Helmig
^ permalink raw reply
* [PATCH 1/1] Bluetooth: hci_codec: validate capability record length
From: Ren Wei @ 2026-05-29 13:12 UTC (permalink / raw)
To: linux-bluetooth
Cc: marcel, luiz.dentz, kiran.k, chethan.tumkur.narayan,
ravishankar.srivatsa, yuantan098, zcliangcn, bird, xuyq21, n05ec
In-Reply-To: <cover.1779633761.git.xuyq21@lenovo.com>
From: Yuqi Xu <xuyq21@lenovo.com>
hci_read_codec_capabilities() validates each capability entry before
adding its serialized size to len and advancing the skb.
The current check only compares skb->len against caps->len, even
though the code consumes the length byte and the payload. Validate
the full record size so the cached capability length matches the
bytes available in the command response.
Fixes: 8961987f3f5f ("Bluetooth: Enumerate local supported codec and cache details")
Cc: stable@kernel.org
Reported-by: Yuan Tan <yuantan098@gmail.com>
Reported-by: Zhengchuan Liang <zcliangcn@gmail.com>
Reported-by: Xin Liu <bird@lzu.edu.cn>
Assisted-by: Codex:GPT-5.4
Signed-off-by: Yuqi Xu <xuyq21@lenovo.com>
Signed-off-by: Ren Wei <n05ec@lzu.edu.cn>
---
net/bluetooth/hci_codec.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/net/bluetooth/hci_codec.c b/net/bluetooth/hci_codec.c
index 3cc135bb1d30..5bc5003c387c 100644
--- a/net/bluetooth/hci_codec.c
+++ b/net/bluetooth/hci_codec.c
@@ -100,7 +100,7 @@ static void hci_read_codec_capabilities(struct hci_dev *hdev, __u8 transport,
caps = (void *)skb->data;
if (skb->len < sizeof(*caps))
goto error;
- if (skb->len < caps->len)
+ if (skb->len < sizeof(caps->len) + caps->len)
goto error;
len += sizeof(caps->len) + caps->len;
skb_pull(skb, sizeof(caps->len) + caps->len);
--
2.54.0
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox