Linux bluetooth development
 help / color / mirror / Atom feed
* RE: [5.10] Bluetooth: hci_core: Fix use-after-free in vhci_flush()
From: bluez.test.bot @ 2026-06-04  0:19 UTC (permalink / raw)
  To: linux-bluetooth, vlad102nikolaev
In-Reply-To: <20260603234343.445-1-vlad102nikolaev@gmail.com>

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

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

Dear Submitter,

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

----- Output -----

error: patch failed: include/net/bluetooth/hci_core.h:28
error: include/net/bluetooth/hci_core.h: patch does not apply
error: patch failed: net/bluetooth/hci_core.c:1040
error: net/bluetooth/hci_core.c: patch does not apply
hint: Use 'git am --show-current-patch' to see the failed patch

Please resolve the issue and submit the patches again.


---
Regards,
Linux Bluetooth


^ permalink raw reply

* [PATCH 5.10] Bluetooth: hci_core: Fix use-after-free in vhci_flush()
From: Vladislav Nikolaev @ 2026-06-03 23:43 UTC (permalink / raw)
  To: stable, Greg Kroah-Hartman
  Cc: Vladislav Nikolaev, Marcel Holtmann, Johan Hedberg,
	David S. Miller, Jakub Kicinski, David Herrmann, linux-bluetooth,
	netdev, linux-kernel, Luiz Augusto von Dentz, David Rheinsberg,
	Johan Hedberg, lvc-project, syzbot+2faa4825e556199361f9,
	Kuniyuki Iwashima, Paul Menzel, Luiz Augusto von Dentz

From: Kuniyuki Iwashima <kuniyu@google.com>

commit 1d6123102e9fbedc8d25bf4731da6d513173e49e upstream.

syzbot reported use-after-free in vhci_flush() without repro. [0]

From the splat, a thread close()d a vhci file descriptor while
its device was being used by iotcl() on another thread.

Once the last fd refcnt is released, vhci_release() calls
hci_unregister_dev(), hci_free_dev(), and kfree() for struct
vhci_data, which is set to hci_dev->dev->driver_data.

The problem is that there is no synchronisation after unlinking
hdev from hci_dev_list in hci_unregister_dev().  There might be
another thread still accessing the hdev which was fetched before
the unlink operation.

We can use SRCU for such synchronisation.

Let's run hci_dev_reset() under SRCU and wait for its completion
in hci_unregister_dev().

Another option would be to restore hci_dev->destruct(), which was
removed in commit 587ae086f6e4 ("Bluetooth: Remove unused
hci-destruct cb").  However, this would not be a good solution, as
we should not run hci_unregister_dev() while there are in-flight
ioctl() requests, which could lead to another data-race KCSAN splat.

Note that other drivers seem to have the same problem, for exmaple,
virtbt_remove().

[0]:
BUG: KASAN: slab-use-after-free in skb_queue_empty_lockless include/linux/skbuff.h:1891 [inline]
BUG: KASAN: slab-use-after-free in skb_queue_purge_reason+0x99/0x360 net/core/skbuff.c:3937
Read of size 8 at addr ffff88807cb8d858 by task syz.1.219/6718

CPU: 1 UID: 0 PID: 6718 Comm: syz.1.219 Not tainted 6.16.0-rc1-syzkaller-00196-g08207f42d3ff #0 PREEMPT(full)
Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 05/07/2025
Call Trace:
 <TASK>
 dump_stack_lvl+0x189/0x250 lib/dump_stack.c:120
 print_address_description mm/kasan/report.c:408 [inline]
 print_report+0xd2/0x2b0 mm/kasan/report.c:521
 kasan_report+0x118/0x150 mm/kasan/report.c:634
 skb_queue_empty_lockless include/linux/skbuff.h:1891 [inline]
 skb_queue_purge_reason+0x99/0x360 net/core/skbuff.c:3937
 skb_queue_purge include/linux/skbuff.h:3368 [inline]
 vhci_flush+0x44/0x50 drivers/bluetooth/hci_vhci.c:69
 hci_dev_do_reset net/bluetooth/hci_core.c:552 [inline]
 hci_dev_reset+0x420/0x5c0 net/bluetooth/hci_core.c:592
 sock_do_ioctl+0xd9/0x300 net/socket.c:1190
 sock_ioctl+0x576/0x790 net/socket.c:1311
 vfs_ioctl fs/ioctl.c:51 [inline]
 __do_sys_ioctl fs/ioctl.c:907 [inline]
 __se_sys_ioctl+0xf9/0x170 fs/ioctl.c:893
 do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline]
 do_syscall_64+0xfa/0x3b0 arch/x86/entry/syscall_64.c:94
 entry_SYSCALL_64_after_hwframe+0x77/0x7f
RIP: 0033:0x7fcf5b98e929
Code: ff ff c3 66 2e 0f 1f 84 00 00 00 00 00 0f 1f 40 00 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 <48> 3d 01 f0 ff ff 73 01 c3 48 c7 c1 a8 ff ff ff f7 d8 64 89 01 48
RSP: 002b:00007fcf5c7b9038 EFLAGS: 00000246 ORIG_RAX: 0000000000000010
RAX: ffffffffffffffda RBX: 00007fcf5bbb6160 RCX: 00007fcf5b98e929
RDX: 0000000000000000 RSI: 00000000400448cb RDI: 0000000000000009
RBP: 00007fcf5ba10b39 R08: 0000000000000000 R09: 0000000000000000
R10: 0000000000000000 R11: 0000000000000246 R12: 0000000000000000
R13: 0000000000000000 R14: 00007fcf5bbb6160 R15: 00007ffd6353d528
 </TASK>

Allocated by task 6535:
 kasan_save_stack mm/kasan/common.c:47 [inline]
 kasan_save_track+0x3e/0x80 mm/kasan/common.c:68
 poison_kmalloc_redzone mm/kasan/common.c:377 [inline]
 __kasan_kmalloc+0x93/0xb0 mm/kasan/common.c:394
 kasan_kmalloc include/linux/kasan.h:260 [inline]
 __kmalloc_cache_noprof+0x230/0x3d0 mm/slub.c:4359
 kmalloc_noprof include/linux/slab.h:905 [inline]
 kzalloc_noprof include/linux/slab.h:1039 [inline]
 vhci_open+0x57/0x360 drivers/bluetooth/hci_vhci.c:635
 misc_open+0x2bc/0x330 drivers/char/misc.c:161
 chrdev_open+0x4c9/0x5e0 fs/char_dev.c:414
 do_dentry_open+0xdf0/0x1970 fs/open.c:964
 vfs_open+0x3b/0x340 fs/open.c:1094
 do_open fs/namei.c:3887 [inline]
 path_openat+0x2ee5/0x3830 fs/namei.c:4046
 do_filp_open+0x1fa/0x410 fs/namei.c:4073
 do_sys_openat2+0x121/0x1c0 fs/open.c:1437
 do_sys_open fs/open.c:1452 [inline]
 __do_sys_openat fs/open.c:1468 [inline]
 __se_sys_openat fs/open.c:1463 [inline]
 __x64_sys_openat+0x138/0x170 fs/open.c:1463
 do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline]
 do_syscall_64+0xfa/0x3b0 arch/x86/entry/syscall_64.c:94
 entry_SYSCALL_64_after_hwframe+0x77/0x7f

Freed by task 6535:
 kasan_save_stack mm/kasan/common.c:47 [inline]
 kasan_save_track+0x3e/0x80 mm/kasan/common.c:68
 kasan_save_free_info+0x46/0x50 mm/kasan/generic.c:576
 poison_slab_object mm/kasan/common.c:247 [inline]
 __kasan_slab_free+0x62/0x70 mm/kasan/common.c:264
 kasan_slab_free include/linux/kasan.h:233 [inline]
 slab_free_hook mm/slub.c:2381 [inline]
 slab_free mm/slub.c:4643 [inline]
 kfree+0x18e/0x440 mm/slub.c:4842
 vhci_release+0xbc/0xd0 drivers/bluetooth/hci_vhci.c:671
 __fput+0x44c/0xa70 fs/file_table.c:465
 task_work_run+0x1d1/0x260 kernel/task_work.c:227
 exit_task_work include/linux/task_work.h:40 [inline]
 do_exit+0x6ad/0x22e0 kernel/exit.c:955
 do_group_exit+0x21c/0x2d0 kernel/exit.c:1104
 __do_sys_exit_group kernel/exit.c:1115 [inline]
 __se_sys_exit_group kernel/exit.c:1113 [inline]
 __x64_sys_exit_group+0x3f/0x40 kernel/exit.c:1113
 x64_sys_call+0x21ba/0x21c0 arch/x86/include/generated/asm/syscalls_64.h:232
 do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline]
 do_syscall_64+0xfa/0x3b0 arch/x86/entry/syscall_64.c:94
 entry_SYSCALL_64_after_hwframe+0x77/0x7f

The buggy address belongs to the object at ffff88807cb8d800
 which belongs to the cache kmalloc-1k of size 1024
The buggy address is located 88 bytes inside of
 freed 1024-byte region [ffff88807cb8d800, ffff88807cb8dc00)

Fixes: bf18c7118cf8 ("Bluetooth: vhci: Free driver_data on file release")
Reported-by: syzbot+2faa4825e556199361f9@syzkaller.appspotmail.com
Closes: https://syzkaller.appspot.com/bug?extid=f62d64848fc4c7c30cd6
Signed-off-by: Kuniyuki Iwashima <kuniyu@google.com>
Acked-by: Paul Menzel <pmenzel@molgen.mpg.de>
Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
Signed-off-by: Vladislav Nikolaev <vlad102nikolaev@gmail.com>
---
Backport fix for CVE-2025-38250
 include/net/bluetooth/hci_core.h |  2 ++
 net/bluetooth/hci_core.c         | 34 ++++++++++++++++++++++++++++----
 2 files changed, 32 insertions(+), 4 deletions(-)

diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index fe62943a35dd..bc4e2856f235 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -28,6 +28,7 @@
 #include <linux/idr.h>
 #include <linux/leds.h>
 #include <linux/rculist.h>
+#include <linux/srcu.h>
 
 #include <net/bluetooth/hci.h>
 #include <net/bluetooth/hci_sock.h>
@@ -285,6 +286,7 @@ struct amp_assoc {
 
 struct hci_dev {
 	struct list_head list;
+	struct srcu_struct srcu;
 	struct mutex	lock;
 
 	const char	*name;
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
index 9787a4c55113..a718e38f3da3 100644
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -1040,7 +1040,7 @@ static int hci_linkpol_req(struct hci_request *req, unsigned long opt)
 
 /* Get HCI device by index.
  * Device is held on return. */
-struct hci_dev *hci_dev_get(int index)
+static struct hci_dev *__hci_dev_get(int index, int *srcu_index)
 {
 	struct hci_dev *hdev = NULL, *d;
 
@@ -1053,6 +1053,8 @@ struct hci_dev *hci_dev_get(int index)
 	list_for_each_entry(d, &hci_dev_list, list) {
 		if (d->id == index) {
 			hdev = hci_dev_hold(d);
+			if (srcu_index)
+				*srcu_index = srcu_read_lock(&d->srcu);
 			break;
 		}
 	}
@@ -1060,6 +1062,22 @@ struct hci_dev *hci_dev_get(int index)
 	return hdev;
 }
 
+struct hci_dev *hci_dev_get(int index)
+{
+	return __hci_dev_get(index, NULL);
+}
+
+static struct hci_dev *hci_dev_get_srcu(int index, int *srcu_index)
+{
+	return __hci_dev_get(index, srcu_index);
+}
+
+static void hci_dev_put_srcu(struct hci_dev *hdev, int srcu_index)
+{
+	srcu_read_unlock(&hdev->srcu, srcu_index);
+	hci_dev_put(hdev);
+}
+
 /* ---- Inquiry support ---- */
 
 bool hci_discovery_active(struct hci_dev *hdev)
@@ -1906,9 +1924,9 @@ static int hci_dev_do_reset(struct hci_dev *hdev)
 int hci_dev_reset(__u16 dev)
 {
 	struct hci_dev *hdev;
-	int err;
+	int err, srcu_index;
 
-	hdev = hci_dev_get(dev);
+	hdev = hci_dev_get_srcu(dev, &srcu_index);
 	if (!hdev)
 		return -ENODEV;
 
@@ -1930,7 +1948,7 @@ int hci_dev_reset(__u16 dev)
 	err = hci_dev_do_reset(hdev);
 
 done:
-	hci_dev_put(hdev);
+	hci_dev_put_srcu(hdev, srcu_index);
 	return err;
 }
 
@@ -3596,6 +3614,11 @@ struct hci_dev *hci_alloc_dev(void)
 	if (!hdev)
 		return NULL;
 
+	if (init_srcu_struct(&hdev->srcu)) {
+		kfree(hdev);
+		return NULL;
+	}
+
 	hdev->pkt_type  = (HCI_DM1 | HCI_DH1 | HCI_HV1);
 	hdev->esco_type = (ESCO_HV1);
 	hdev->link_mode = (HCI_LM_ACCEPT);
@@ -3839,6 +3862,9 @@ void hci_unregister_dev(struct hci_dev *hdev)
 	list_del(&hdev->list);
 	write_unlock(&hci_dev_list_lock);
 
+	synchronize_srcu(&hdev->srcu);
+	cleanup_srcu_struct(&hdev->srcu);
+
 	cancel_work_sync(&hdev->rx_work);
 	cancel_work_sync(&hdev->cmd_work);
 	cancel_work_sync(&hdev->tx_work);
-- 
2.47.3

^ permalink raw reply related

* [bluez/bluez]
From: BluezTestBot @ 2026-06-03 22:15 UTC (permalink / raw)
  To: linux-bluetooth

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

* RE: [BlueZ,v1,1/2] client/mgmt: Add options to ltks command for loading entries
From: bluez.test.bot @ 2026-06-03 20:36 UTC (permalink / raw)
  To: linux-bluetooth, luiz.dentz
In-Reply-To: <20260603190358.425835-1-luiz.dentz@gmail.com>

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

---Test result---

Test Summary:
CheckPatch                    PASS      0.88 seconds
GitLint                       PASS      0.58 seconds
BuildEll                      PASS      17.95 seconds
BluezMake                     PASS      654.52 seconds
MakeCheck                     PASS      18.33 seconds
MakeDistcheck                 PASS      223.87 seconds
CheckValgrind                 PASS      277.86 seconds
CheckSmatch                   PASS      312.38 seconds
bluezmakeextell               PASS      166.67 seconds
IncrementalBuild              PASS      636.29 seconds
ScanBuild                     PASS      923.83 seconds



https://github.com/bluez/bluez/pull/2173

---
Regards,
Linux Bluetooth


^ permalink raw reply

* [bluez/bluez] 67058b: client/mgmt: Add options to ltks command for loadi...
From: Luiz Augusto von Dentz @ 2026-06-03 19:41 UTC (permalink / raw)
  To: linux-bluetooth

  Branch: refs/heads/1105509
  Home:   https://github.com/bluez/bluez
  Commit: 67058b3f707cbd1acc867b598f471c744bd95f85
      https://github.com/bluez/bluez/commit/67058b3f707cbd1acc867b598f471c744bd95f85
  Author: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
  Date:   2026-06-03 (Wed, 03 Jun 2026)

  Changed paths:
    M client/mgmt.c

  Log Message:
  -----------
  client/mgmt: Add options to ltks command for loading entries

Add support for optionally specifying a single LTK entry when using
the ltks command. When called without arguments it clears all LTKs
(existing behavior). When called with an address and key parameters
it loads exactly one LTK entry, useful for testing.

Options:
  -a addr_type  Address type (1=LE Public, 2=LE Random)
  -t key_type   Key type (0=Unauthenticated, 1=Authenticated)
  -c central    Central flag (0 or 1)
  -e enc_size   Encryption key size (7-16)
  -d ediv       Encrypted Diversifier
  -r rand       Random number (64-bit)
  -k key        128-bit key as 32 hex characters


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

  Changed paths:
    M doc/bluetoothctl-mgmt.rst

  Log Message:
  -----------
  doc/bluetoothctl-mgmt: Update ltks command documentation

Document the new options for the ltks command including address type,
key type, central flag, encryption size, EDIV, random number and key
value parameters.


Compare: https://github.com/bluez/bluez/compare/67058b3f707c%5E...14aeb5480c3b

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

^ permalink raw reply

* [PATCH BlueZ v1 2/2] doc/bluetoothctl-mgmt: Update ltks command documentation
From: Luiz Augusto von Dentz @ 2026-06-03 19:03 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <20260603190358.425835-1-luiz.dentz@gmail.com>

From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>

Document the new options for the ltks command including address type,
key type, central flag, encryption size, EDIV, random number and key
value parameters.
---
 doc/bluetoothctl-mgmt.rst | 19 ++++++++++++++++---
 1 file changed, 16 insertions(+), 3 deletions(-)

diff --git a/doc/bluetoothctl-mgmt.rst b/doc/bluetoothctl-mgmt.rst
index 646c2dcb4365..da04f9c225b3 100644
--- a/doc/bluetoothctl-mgmt.rst
+++ b/doc/bluetoothctl-mgmt.rst
@@ -509,11 +509,24 @@ Load Link Keys
 ltks
 ----
 
-Load Long Term Keys
+Load Long Term Keys. Note that loading keys replaces all previously loaded
+keys, so loading a single entry invalidates all previously loaded keys.
 
-:Usage: **> ltks**
-:Example Load stored LE long term keys:
+:Usage: **> ltks [-a addr_type] [-t key_type] [-c central] [-e enc_size] [-d ediv] [-r rand] [-k key] [address]**
+:[-a addr_type]: Address type (1=LE Public, 2=LE Random). Default: 1 (LE Public)
+:[-t key_type]: Key type (0=Unauthenticated, 1=Authenticated). Default: 0 (Unauthenticated)
+:[-c central]: Central flag (0 or 1). Default: 0
+:[-e enc_size]: Encryption key size (7-16). Default: 0
+:[-d ediv]: Encrypted Diversifier (16-bit value). Default: 0x0000
+:[-r rand]: Random number (64-bit value). Default: 0x0000000000000000
+:[-k key]: 128-bit key as 32 hex characters. Default: all zeros
+:[address]: Bluetooth address of the peer device
+:Example Clear all long term keys:
 	| **> ltks**
+:Example Load an authenticated LTK for a specific device:
+	| **> ltks -t 1 -c 1 -e 16 -d 0x1234 -r 0xABCD -k 0123456789abcdef0123456789abcdef 00:11:22:33:44:55**
+:Example Load an LTK with LE Random address type:
+	| **> ltks -a 2 -t 0 -c 1 -e 16 -d 0 -r 0 -k 0123456789abcdef0123456789abcdef AA:BB:CC:DD:EE:FF**
 
 irks
 ----
-- 
2.54.0


^ permalink raw reply related

* [PATCH BlueZ v1 1/2] client/mgmt: Add options to ltks command for loading entries
From: Luiz Augusto von Dentz @ 2026-06-03 19:03 UTC (permalink / raw)
  To: linux-bluetooth

From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>

Add support for optionally specifying a single LTK entry when using
the ltks command. When called without arguments it clears all LTKs
(existing behavior). When called with an address and key parameters
it loads exactly one LTK entry, useful for testing.

Options:
  -a addr_type  Address type (1=LE Public, 2=LE Random)
  -t key_type   Key type (0=Unauthenticated, 1=Authenticated)
  -c central    Central flag (0 or 1)
  -e enc_size   Encryption key size (7-16)
  -d ediv       Encrypted Diversifier
  -r rand       Random number (64-bit)
  -k key        128-bit key as 32 hex characters
---
 client/mgmt.c | 100 +++++++++++++++++++++++++++++++++++++++++++++++---
 1 file changed, 94 insertions(+), 6 deletions(-)

diff --git a/client/mgmt.c b/client/mgmt.c
index 50558a313866..6d6ada95f43d 100644
--- a/client/mgmt.c
+++ b/client/mgmt.c
@@ -3535,21 +3535,107 @@ static void ltks_rsp(uint8_t status, uint16_t len, const void *param,
 	bt_shell_noninteractive_quit(EXIT_SUCCESS);
 }
 
+static const struct option ltks_options[] = {
+	{ "help",	0, 0, 'h' },
+	{ "address-type", 1, 0, 'a' },
+	{ "type",	1, 0, 't' },
+	{ "central",	1, 0, 'c' },
+	{ "enc-size",	1, 0, 'e' },
+	{ "ediv",	1, 0, 'd' },
+	{ "rand",	1, 0, 'r' },
+	{ "key",	1, 0, 'k' },
+	{ 0, 0, 0, 0 }
+};
+
 static void cmd_ltks(int argc, char **argv)
 {
-	struct mgmt_cp_load_long_term_keys cp;
+	struct mgmt_cp_load_long_term_keys *cp;
+	uint8_t buf[sizeof(*cp) + sizeof(struct mgmt_ltk_info)];
+	uint16_t count = 0;
+	struct mgmt_ltk_info *ltk;
+	uint8_t addr_type = BDADDR_LE_PUBLIC;
+	int opt;
 	uint16_t index;
 
 	index = mgmt_index;
 	if (index == MGMT_INDEX_NONE)
 		index = 0;
 
-	memset(&cp, 0, sizeof(cp));
+	cp = (void *) buf;
+	memset(buf, 0, sizeof(buf));
+	ltk = &cp->keys[0];
 
-	if (mgmt_send(mgmt, MGMT_OP_LOAD_LONG_TERM_KEYS, index, sizeof(cp), &cp,
-						ltks_rsp, NULL, NULL) == 0) {
+	while ((opt = getopt_long(argc, argv, "+a:t:c:e:d:r:k:h",
+					ltks_options, NULL)) != -1) {
+		switch (opt) {
+		case 'a':
+			addr_type = strtol(optarg, NULL, 0);
+			if (addr_type != BDADDR_LE_PUBLIC &&
+					addr_type != BDADDR_LE_RANDOM) {
+				error("Invalid address type (expected 1=LE "
+							"Public, 2=LE Random)");
+				optind = 0;
+				return bt_shell_noninteractive_quit(
+								EXIT_FAILURE);
+			}
+			break;
+		case 't':
+			ltk->type = strtol(optarg, NULL, 0);
+			break;
+		case 'c':
+			ltk->central = strtol(optarg, NULL, 0);
+			break;
+		case 'e':
+			ltk->enc_size = strtol(optarg, NULL, 0);
+			break;
+		case 'd':
+			ltk->ediv = strtol(optarg, NULL, 0);
+			break;
+		case 'r':
+			ltk->rand = strtoull(optarg, NULL, 0);
+			break;
+		case 'k':
+			if (strlen(optarg) != 32) {
+				error("Invalid key length (expected 32 hex "
+								"chars)");
+				optind = 0;
+				return bt_shell_noninteractive_quit(
+								EXIT_FAILURE);
+			}
+			for (int i = 0; i < 16; i++) {
+				char byte[3] = { optarg[i * 2],
+						optarg[i * 2 + 1], 0 };
+				ltk->val[i] = strtol(byte, NULL, 16);
+			}
+			break;
+		case 'h':
+			bt_shell_usage();
+			optind = 0;
+			return bt_shell_noninteractive_quit(EXIT_SUCCESS);
+		default:
+			bt_shell_usage();
+			optind = 0;
+			return bt_shell_noninteractive_quit(EXIT_FAILURE);
+		}
+	}
+
+	argc -= optind;
+	argv += optind;
+	optind = 0;
+
+	if (argc > 0) {
+		str2ba(argv[0], &ltk->addr.bdaddr);
+		ltk->addr.type = addr_type;
+		count = 1;
+	}
+
+	cp->key_count = cpu_to_le16(count);
+
+	if (mgmt_send(mgmt, MGMT_OP_LOAD_LONG_TERM_KEYS, index,
+				sizeof(*cp) + count * sizeof(*ltk), cp,
+				ltks_rsp, NULL, NULL) == 0) {
 		error("Unable to send load_ltks cmd");
-		return bt_shell_noninteractive_quit(EXIT_SUCCESS);
+		return bt_shell_noninteractive_quit(EXIT_FAILURE);
 	}
 }
 
@@ -6136,7 +6222,9 @@ static const struct bt_shell_menu mgmt_menu = {
 		cmd_unpair,		"Unpair device"			},
 	{ "keys",		NULL,
 		cmd_keys,		"Load Link Keys"		},
-	{ "ltks",		NULL,
+	{ "ltks",		"[-a addr_type] [-t key_type] [-c central] "
+				"[-e enc_size] [-d ediv] [-r rand] [-k key] "
+				"[address]",
 		cmd_ltks,		"Load Long Term Keys"		},
 	{ "irks",		"[--local index] [--file file path]",
 		cmd_irks,		"Load Identity Resolving Keys"	},
-- 
2.54.0


^ permalink raw reply related

* Re: [PATCH v9 1/1] Bluetooth: L2CAP: Fix use-after-free in l2cap_sock_new_connection_cb()
From: Luiz Augusto von Dentz @ 2026-06-03 18:17 UTC (permalink / raw)
  To: Siwei Zhang; +Cc: Marcel Holtmann, linux-bluetooth
In-Reply-To: <20260603150835.3539963-2-oss@fourdim.xyz>

Hi Siwei,

On Wed, Jun 3, 2026 at 11:09 AM Siwei Zhang <oss@fourdim.xyz> wrote:
>
> l2cap_sock_new_connection_cb() accesses l2cap_pi(sk)->chan after
> release_sock(parent). Once the parent lock is released, the child
> socket sk can be freed by another task.
>
> Allocate the channel outside the func to prevent this.
>
> Fixes: 8ffb929098a5 ("Bluetooth: Remove parent socket usage from l2cap_core.c")
> Cc: stable@kernel.org
> Assisted-by: Claude:claude-opus-4-8
> Signed-off-by: Siwei Zhang <oss@fourdim.xyz>
> ---
>  include/net/bluetooth/l2cap.h | 10 +++--
>  net/bluetooth/6lowpan.c       | 31 +++++++------
>  net/bluetooth/l2cap_core.c    | 41 ++++++++++++-----
>  net/bluetooth/l2cap_sock.c    | 83 +++++++++++++++++++++--------------
>  net/bluetooth/smp.c           | 17 ++++---
>  5 files changed, 113 insertions(+), 69 deletions(-)
>
> diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h
> index e0a1f2293679..7f5e4647f6e0 100644
> --- a/include/net/bluetooth/l2cap.h
> +++ b/include/net/bluetooth/l2cap.h
> @@ -620,7 +620,9 @@ struct l2cap_chan {
>  struct l2cap_ops {
>         char                    *name;
>
> -       struct l2cap_chan       *(*new_connection) (struct l2cap_chan *chan);
> +       int                     (*new_connection)(struct l2cap_conn *conn,
> +                                                 struct l2cap_chan *chan,
> +                                                 struct l2cap_chan *new_chan);
>         int                     (*recv) (struct l2cap_chan * chan,
>                                          struct sk_buff *skb);
>         void                    (*teardown) (struct l2cap_chan *chan, int err);
> @@ -884,9 +886,11 @@ static inline __u16 __next_seq(struct l2cap_chan *chan, __u16 seq)
>         return (seq + 1) % (chan->tx_win_max + 1);
>  }
>
> -static inline struct l2cap_chan *l2cap_chan_no_new_connection(struct l2cap_chan *chan)
> +static inline int l2cap_chan_no_new_connection(struct l2cap_conn *conn,
> +                                              struct l2cap_chan *chan,
> +                                              struct l2cap_chan *new_chan)
>  {
> -       return NULL;
> +       return -EOPNOTSUPP;
>  }
>
>  static inline int l2cap_chan_no_recv(struct l2cap_chan *chan, struct sk_buff *skb)
> diff --git a/net/bluetooth/6lowpan.c b/net/bluetooth/6lowpan.c
> index cb1e329d66fd..94863af97a44 100644
> --- a/net/bluetooth/6lowpan.c
> +++ b/net/bluetooth/6lowpan.c
> @@ -624,6 +624,15 @@ static bool is_bt_6lowpan(struct hci_conn *hcon)
>         return true;
>  }
>
> +static void chan_init(struct l2cap_chan *chan)
> +{
> +       l2cap_chan_set_defaults(chan);
> +
> +       chan->chan_type = L2CAP_CHAN_CONN_ORIENTED;
> +       chan->mode = L2CAP_MODE_LE_FLOWCTL;
> +       chan->imtu = 1280;
> +}
> +
>  static struct l2cap_chan *chan_create(void)
>  {
>         struct l2cap_chan *chan;
> @@ -632,11 +641,7 @@ static struct l2cap_chan *chan_create(void)
>         if (!chan)
>                 return NULL;
>
> -       l2cap_chan_set_defaults(chan);
> -
> -       chan->chan_type = L2CAP_CHAN_CONN_ORIENTED;
> -       chan->mode = L2CAP_MODE_LE_FLOWCTL;
> -       chan->imtu = 1280;
> +       chan_init(chan);
>
>         return chan;
>  }
> @@ -745,19 +750,19 @@ static inline void chan_ready_cb(struct l2cap_chan *chan)
>         ifup(dev->netdev);
>  }
>
> -static inline struct l2cap_chan *chan_new_conn_cb(struct l2cap_chan *pchan)
> +static inline int chan_new_conn_cb(struct l2cap_conn *conn,
> +                                  struct l2cap_chan *pchan,
> +                                  struct l2cap_chan *chan)
>  {
> -       struct l2cap_chan *chan;
> -
> -       chan = chan_create();
> -       if (!chan)
> -               return NULL;
> -
> +       chan_init(chan);
>         chan->ops = pchan->ops;
>
> +       /* Take the conn list reference; see l2cap_new_connection(). */
> +       __l2cap_chan_add(conn, chan);
> +
>         BT_DBG("chan %p pchan %p", chan, pchan);
>
> -       return chan;
> +       return 0;
>  }
>
>  static void unregister_dev(struct lowpan_btle_dev *dev)
> diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
> index c4ccfbda9d78..62acf90837fb 100644
> --- a/net/bluetooth/l2cap_core.c
> +++ b/net/bluetooth/l2cap_core.c
> @@ -4007,6 +4007,31 @@ static inline int l2cap_command_rej(struct l2cap_conn *conn,
>         return 0;
>  }
>
> +/* Allocate and initialise a channel for an incoming connection.
> + *
> + * ->new_connection() initialises the channel and links it into @conn with
> + * __l2cap_chan_add(). The l2cap_chan_create() reference becomes the one owned
> + * by the parent subsystem (l2cap_pi(sk)->chan, conn->smp or peer->chan) and is
> + * released by its teardown callback; the conn list reference is released by
> + * l2cap_chan_del().
> + */
> +static struct l2cap_chan *l2cap_new_connection(struct l2cap_conn *conn,
> +                                              struct l2cap_chan *pchan)
> +{
> +       struct l2cap_chan *chan;
> +
> +       chan = l2cap_chan_create();
> +       if (!chan)
> +               return NULL;
> +
> +       if (pchan->ops->new_connection(conn, pchan, chan) < 0) {
> +               l2cap_chan_put(chan);
> +               return NULL;
> +       }

I don't quite get why we can't just place __l2cap_chan_add here
instead of having it called by new_connection callbacks?

> +
> +       return chan;
> +}
> +
>  static void l2cap_connect(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd,
>                           u8 *data, u8 rsp_code)
>  {
> @@ -4053,7 +4078,7 @@ static void l2cap_connect(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd,
>                 goto response;
>         }
>
> -       chan = pchan->ops->new_connection(pchan);
> +       chan = l2cap_new_connection(conn, pchan);
>         if (!chan)
>                 goto response;
>
> @@ -4071,8 +4096,6 @@ static void l2cap_connect(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd,
>         chan->psm  = psm;
>         chan->dcid = scid;
>
> -       __l2cap_chan_add(conn, chan);
> -
>         dcid = chan->scid;
>
>         __set_chan_timer(chan, chan->ops->get_sndtimeo(chan));
> @@ -4955,7 +4978,7 @@ static int l2cap_le_connect_req(struct l2cap_conn *conn,
>                 goto response_unlock;
>         }
>
> -       chan = pchan->ops->new_connection(pchan);
> +       chan = l2cap_new_connection(conn, pchan);
>         if (!chan) {
>                 result = L2CAP_CR_LE_NO_MEM;
>                 goto response_unlock;
> @@ -4970,8 +4993,6 @@ static int l2cap_le_connect_req(struct l2cap_conn *conn,
>         chan->omtu = mtu;
>         chan->remote_mps = mps;
>
> -       __l2cap_chan_add(conn, chan);
> -
>         l2cap_le_flowctl_init(chan, __le16_to_cpu(req->credits));
>
>         dcid = chan->scid;
> @@ -5179,7 +5200,7 @@ static inline int l2cap_ecred_conn_req(struct l2cap_conn *conn,
>                         continue;
>                 }
>
> -               chan = pchan->ops->new_connection(pchan);
> +               chan = l2cap_new_connection(conn, pchan);
>                 if (!chan) {
>                         result = L2CAP_CR_LE_NO_MEM;
>                         continue;
> @@ -5194,8 +5215,6 @@ static inline int l2cap_ecred_conn_req(struct l2cap_conn *conn,
>                 chan->omtu = mtu;
>                 chan->remote_mps = mps;
>
> -               __l2cap_chan_add(conn, chan);
> -
>                 l2cap_ecred_init(chan, __le16_to_cpu(req->credits));
>
>                 /* Init response */
> @@ -7470,14 +7489,12 @@ static void l2cap_connect_cfm(struct hci_conn *hcon, u8 status)
>                         goto next;
>
>                 l2cap_chan_lock(pchan);
> -               chan = pchan->ops->new_connection(pchan);
> +               chan = l2cap_new_connection(conn, pchan);
>                 if (chan) {
>                         bacpy(&chan->src, &hcon->src);
>                         bacpy(&chan->dst, &hcon->dst);
>                         chan->src_type = bdaddr_src_type(hcon);
>                         chan->dst_type = dst_type;
> -
> -                       __l2cap_chan_add(conn, chan);
>                 }
>
>                 l2cap_chan_unlock(pchan);
> diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c
> index 025329636353..87f4c0db5c0c 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)
> @@ -1287,6 +1288,23 @@ static int l2cap_sock_recvmsg(struct socket *sock, struct msghdr *msg,
>         return err;
>  }
>
> +/* Release the sock's ref on chan and clear the pointer so that the ref is
> + * dropped exactly once even if both l2cap_sock_kill() and
> + * l2cap_sock_destruct() run. Setting chan->data to NULL first stops any other
> + * task from dereferencing the now-dead sock pointer.
> + */
> +static void l2cap_sock_put_chan(struct sock *sk)
> +{
> +       struct l2cap_chan *chan = l2cap_pi(sk)->chan;
> +
> +       if (!chan)
> +               return;
> +
> +       chan->data = NULL;
> +       l2cap_pi(sk)->chan = NULL;
> +       l2cap_chan_put(chan);
> +}
> +
>  /* Kill socket (only if zapped and orphan)
>   * Must be called on unlocked socket, with l2cap channel lock.
>   */
> @@ -1297,13 +1315,9 @@ static void l2cap_sock_kill(struct sock *sk)
>
>         BT_DBG("sk %p state %s", sk, state_to_string(sk->sk_state));
>
> -       /* Sock is dead, so set chan data to NULL, avoid other task use invalid
> -        * sock pointer.
> -        */
> -       l2cap_pi(sk)->chan->data = NULL;
> -       /* Kill poor orphan */
> +       l2cap_sock_put_chan(sk);
>
> -       l2cap_chan_put(l2cap_pi(sk)->chan);
> +       /* Kill poor orphan */
>         sock_set_flag(sk, SOCK_DEAD);
>         sock_put(sk);
>  }
> @@ -1546,12 +1560,14 @@ 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_conn *conn,
> +                                       struct l2cap_chan *chan,
> +                                       struct l2cap_chan *new_chan)
>  {
>         struct sock *sk, *parent = chan->data;
>
>         if (!parent)
> -               return NULL;
> +               return -EINVAL;
>
>         lock_sock(parent);
>
> @@ -1559,25 +1575,33 @@ 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);
>
>         l2cap_sock_init(sk, parent);
>
> +       /* Link the channel into conn before exposing the new socket via the
> +        * accept queue. Once release_sock() below drops the parent lock the
> +        * socket may be freed by another task, dropping its reference on
> +        * new_chan; the conn list reference taken here keeps new_chan alive so
> +        * the caller can safely use it after ->new_connection() returns.
> +        */
> +       __l2cap_chan_add(conn, new_chan);
> +
>         bt_accept_enqueue(parent, sk, false);
>
>         release_sock(parent);
>
> -       return l2cap_pi(sk)->chan;
> +       return 0;
>  }
>
>  static int l2cap_sock_recv_cb(struct l2cap_chan *chan, struct sk_buff *skb)
> @@ -1874,10 +1898,7 @@ static void l2cap_sock_destruct(struct sock *sk)
>
>         BT_DBG("sk %p", sk);
>
> -       if (l2cap_pi(sk)->chan) {
> -               l2cap_pi(sk)->chan->data = NULL;
> -               l2cap_chan_put(l2cap_pi(sk)->chan);
> -       }
> +       l2cap_sock_put_chan(sk);
>
>         list_for_each_entry_safe(rx_busy, next, &l2cap_pi(sk)->rx_busy, list) {
>                 kfree_skb(rx_busy->skb);
> @@ -1978,10 +1999,10 @@ static struct proto l2cap_proto = {
>  };
>
>  static struct sock *l2cap_sock_alloc(struct net *net, struct socket *sock,
> -                                    int proto, gfp_t prio, int kern)
> +                                    int proto, gfp_t prio, int kern,
> +                                    struct l2cap_chan *chan)
>  {
>         struct sock *sk;
> -       struct l2cap_chan *chan;
>
>         sk = bt_sock_alloc(net, sock, &l2cap_proto, proto, prio, kern);
>         if (!sk)
> @@ -1992,16 +2013,7 @@ 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;
> -       }
> -
> -       l2cap_chan_hold(chan);
> -
> +       /* The sock takes ownership of the caller's reference on chan. */
>         l2cap_pi(sk)->chan = chan;
>
>         return sk;
> @@ -2011,6 +2023,7 @@ static int l2cap_sock_create(struct net *net, struct socket *sock, int protocol,
>                              int kern)
>  {
>         struct sock *sk;
> +       struct l2cap_chan *chan;
>
>         BT_DBG("sock %p", sock);
>
> @@ -2025,10 +2038,16 @@ 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;
> +       }
> +
>         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..2d31c3c7bbc0 100644
> --- a/net/bluetooth/smp.c
> +++ b/net/bluetooth/smp.c
> @@ -3204,16 +3204,12 @@ 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_conn *conn,
> +                                 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 +3225,12 @@ static inline struct l2cap_chan *smp_new_conn_cb(struct l2cap_chan *pchan)
>          */
>         atomic_set(&chan->nesting, L2CAP_NESTING_SMP);
>
> -       BT_DBG("created chan %p", chan);
> +       /* Take the conn list reference; see l2cap_new_connection(). */
> +       __l2cap_chan_add(conn, chan);
>
> -       return chan;
> +       BT_DBG("initialised chan %p", chan);
> +
> +       return 0;
>  }
>
>  static const struct l2cap_ops smp_root_chan_ops = {
> --
> 2.54.0
>


-- 
Luiz Augusto von Dentz

^ permalink raw reply

* Re: [PATCH v3 RESEND 3/5] Bluetooth: btusb: fix wakeup source leak on probe failure
From: Luiz Augusto von Dentz @ 2026-06-03 18:06 UTC (permalink / raw)
  To: Johan Hovold
  Cc: Marcel Holtmann, linux-bluetooth, linux-kernel, stable,
	Rajat Jain
In-Reply-To: <20260603143643.2514595-4-johan@kernel.org>

Hi Johan,

On Wed, Jun 3, 2026 at 10:37 AM Johan Hovold <johan@kernel.org> wrote:
>
> Make sure to disable wakeup on probe failure to avoid leaking the wakeup
> source.
>
> Fixes: fd913ef7ce61 ("Bluetooth: btusb: Add out-of-band wakeup support")
> Cc: stable@vger.kernel.org      # 4.11
> Cc: Rajat Jain <rajatja@google.com>
> Signed-off-by: Johan Hovold <johan@kernel.org>
> ---
>  drivers/bluetooth/btusb.c | 5 ++++-
>  1 file changed, 4 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c
> index d0a83a1ffdf2..622df2fff497 100644
> --- a/drivers/bluetooth/btusb.c
> +++ b/drivers/bluetooth/btusb.c
> @@ -4181,7 +4181,7 @@ static int btusb_probe(struct usb_interface *intf,
>         if (id->driver_info & BTUSB_MARVELL && data->oob_wake_irq) {
>                 err = marvell_config_oob_wake(hdev);
>                 if (err)
> -                       goto out_free_dev;
> +                       goto err_disable_wakeup;
>         }
>  #endif
>         if (id->driver_info & BTUSB_CW6622)
> @@ -4427,6 +4427,9 @@ static int btusb_probe(struct usb_interface *intf,
>         }
>  err_kill_tx_urbs:
>         usb_kill_anchored_urbs(&data->tx_anchor);
> +err_disable_wakeup:
> +       if (data->oob_wake_irq)
> +               device_init_wakeup(&data->udev->dev, false);
>  out_free_dev:
>         if (data->reset_gpio)
>                 gpiod_put(data->reset_gpio);
> --
> 2.53.0

This seem to trigger a compilation problem according to sashiko:

The goto statement targeting err_disable_wakeup is wrapped in an ifdef
CONFIG_PM block earlier in the function, but this label is defined
unconditionally here.
[]https://sashiko.dev/#/patchset/20260603143643.2514595-1-johan%40kernel.org

-- 
Luiz Augusto von Dentz

^ permalink raw reply

* Re: [PATCH] Bluetooth: btmtk: Disable remote wakeup for MT7922/MT7925
From: patchwork-bot+bluetooth @ 2026-06-03 17:50 UTC (permalink / raw)
  To: Rong Zhang
  Cc: marcel, luiz.dentz, matthias.bgg, angelogioacchino.delregno,
	linux-bluetooth, linux-kernel, linux-arm-kernel, linux-mediatek
In-Reply-To: <20260603-btmtk-remote-wakeup-v1-1-5c1006442f36@rong.moe>

Hello:

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

On Wed, 03 Jun 2026 02:38:10 +0800 you wrote:
> These NICs are often reported to lose their Bluetooth interfaces, i.e,
> their USB interfaces suddenly become completely unresponsive, causing
> the USB core to reset them, only to find that they are no longer
> accessible. A power cycle is required to make the Bluetooth interfaces
> recover.
> 
> After some investigations, I found that their USB autosuspend remote
> wakeup capabilities are so broken that they are precisely the culprit
> behind the issue:
> 
> [...]

Here is the summary with links:
  - Bluetooth: btmtk: Disable remote wakeup for MT7922/MT7925
    https://git.kernel.org/bluetooth/bluetooth-next/c/247570151789

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: hci_core: Fix UAF in hci_unregister_dev()
From: patchwork-bot+bluetooth @ 2026-06-03 17:50 UTC (permalink / raw)
  To: Jordan Walters; +Cc: linux-bluetooth, linux-kernel
In-Reply-To: <20260603085047.256779-1-jaggyaur@gmail.com>

Hello:

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

On Wed,  3 Jun 2026 04:50:47 -0400 you wrote:
> hci_unregister_dev() does not disable cmd_timer and ncmd_timer
> before the hci_dev structure is freed. If a timeout fires
> during device teardown, the callback dereferences freed memory
> (including the hdev->reset function pointer), leading to a
> use-after-free.
> 
> Add disable_delayed_work_sync() calls alongside the existing
> disable_work_sync() calls to ensure both timers are fully
> quiesced before teardown proceeds.
> 
> [...]

Here is the summary with links:
  - [v4] Bluetooth: hci_core: Fix UAF in hci_unregister_dev()
    https://git.kernel.org/bluetooth/bluetooth-next/c/eec3deaeaafe

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



^ permalink raw reply

* Re: [PATCH v2] Bluetooth: eir: Fix stack OOB write when prepending the Flags AD
From: patchwork-bot+bluetooth @ 2026-06-03 17:50 UTC (permalink / raw)
  To: Weiming Shi
  Cc: marcel, luiz.dentz, armansito, linux-bluetooth, linux-kernel,
	xmei5
In-Reply-To: <20260602170621.1454711-2-bestswngs@gmail.com>

Hello:

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

On Wed,  3 Jun 2026 01:06:21 +0800 you wrote:
> eir_create_adv_data() builds the advertising data into a fixed-size
> buffer ("size", 31 for the legacy path). It may prepend a 3-byte "Flags"
> AD structure (LE_AD_NO_BREDR on an LE-only controller) and then copies
> the per-instance data without checking that it still fits:
> 
> 	memcpy(ptr, adv->adv_data, adv->adv_data_len);
> 
> [...]

Here is the summary with links:
  - [v2] Bluetooth: eir: Fix stack OOB write when prepending the Flags AD
    https://git.kernel.org/bluetooth/bluetooth-next/c/83dc982fad52

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



^ permalink raw reply

* Re: [PATCH v2] Bluetooth: hci_event: fix simultaneous discovery stuck in FINDING
From: patchwork-bot+bluetooth @ 2026-06-03 17:50 UTC (permalink / raw)
  To: Jiajia Liu
  Cc: marcel, luiz.dentz, brian.gix, linux-bluetooth, linux-kernel,
	liujia6264
In-Reply-To: <20260602070032.51248-1-liujiajia@kylinos.cn>

Hello:

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

On Tue,  2 Jun 2026 15:00:32 +0800 you wrote:
> When hci_inquiry_complete_evt is called between le_scan_disable and
> le_set_scan_enable_complete and no remote name needs to be resolved,
> the interleaved discovery with SIMULTANEOUS quirk gets stuck in
> DISCOVERY_FINDING. le_set_scan_enable_complete does not check inquiry
> state. No one sets DISCOVERY_STOPPED in this process.
> 
> Add state check in le_set_scan_enable_complete and change state if
> the state is DISCOVERY_FINDING. Tested with AX201 (8087:0026) in Dell
> Vostro 13. Discovering disabled MGMT Event below is reported when
> running into the above condition.
> 
> [...]

Here is the summary with links:
  - [v2] Bluetooth: hci_event: fix simultaneous discovery stuck in FINDING
    https://git.kernel.org/bluetooth/bluetooth-next/c/ad85ec7a145b

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



^ permalink raw reply

* Re: [PATCH v2] Bluetooth: btusb: Add support for TP-Link TL-UB250
From: patchwork-bot+bluetooth @ 2026-06-03 17:50 UTC (permalink / raw)
  To: Cris; +Cc: linux-bluetooth, marcel, luiz.dentz, linux-kernel, pmenzel
In-Reply-To: <20260603035818.926654-1-cxs1494089474@gmail.com>

Hello:

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

On Wed,  3 Jun 2026 11:58:18 +0800 you wrote:
> Add USB ID 2357:0607 for TP-Link TL-UB250.
> 
> This is a Realtek RTL8761BUV based Bluetooth adapter.
> 
> Without this entry the device is picked up by the generic Bluetooth USB
> class match and exposes hci0, but the Realtek setup path is not used and
> rtl8761bu firmware/config are not loaded.
> 
> [...]

Here is the summary with links:
  - [v2] Bluetooth: btusb: Add support for TP-Link TL-UB250
    https://git.kernel.org/bluetooth/bluetooth-next/c/7e7dff125429

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



^ permalink raw reply

* RE: Bluetooth: L2CAP: Fix use-after-free in l2cap_sock_new_connection_cb()
From: bluez.test.bot @ 2026-06-03 17:40 UTC (permalink / raw)
  To: linux-bluetooth, oss
In-Reply-To: <20260603150835.3539963-2-oss@fourdim.xyz>

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

This is automated email and please do not reply to this email!

Dear submitter,

Thank you for submitting the patches to the linux bluetooth mailing list.
This is a CI test results with your patch series:
PW Link:https://patchwork.kernel.org/project/bluetooth/list/?series=1105389

---Test result---

Test Summary:
CheckPatch                    PASS      1.55 seconds
VerifyFixes                   PASS      0.10 seconds
VerifySignedoff               PASS      0.07 seconds
GitLint                       PASS      0.32 seconds
SubjectPrefix                 PASS      0.07 seconds
BuildKernel                   PASS      26.94 seconds
CheckAllWarning               PASS      29.57 seconds
CheckSparse                   PASS      27.88 seconds
BuildKernel32                 PASS      26.28 seconds
TestRunnerSetup               PASS      580.30 seconds
TestRunner_l2cap-tester       PASS      60.03 seconds
TestRunner_smp-tester         PASS      23.45 seconds
TestRunner_6lowpan-tester     PASS      22.67 seconds
IncrementalBuild              PASS      25.76 seconds



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

---
Regards,
Linux Bluetooth


^ permalink raw reply

* RE: [v2] Bluetooth: btintel_pcie: Add support for smart trigger dump
From: bluez.test.bot @ 2026-06-03 17:38 UTC (permalink / raw)
  To: linux-bluetooth, kiran.k
In-Reply-To: <20260603155415.50855-1-kiran.k@intel.com>

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

---Test result---

Test Summary:
CheckPatch                    PASS      1.08 seconds
VerifyFixes                   PASS      0.08 seconds
VerifySignedoff               PASS      0.07 seconds
GitLint                       PASS      0.70 seconds
SubjectPrefix                 PASS      0.07 seconds
BuildKernel                   PASS      26.31 seconds
CheckAllWarning               PASS      29.14 seconds
CheckSparse                   PASS      27.48 seconds
BuildKernel32                 PASS      25.47 seconds
TestRunnerSetup               PASS      569.85 seconds
IncrementalBuild              PASS      25.57 seconds



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

---
Regards,
Linux Bluetooth


^ permalink raw reply

* RE: Bluetooth: L2CAP: Fix UAF in l2cap_chan_timeout
From: bluez.test.bot @ 2026-06-03 17:37 UTC (permalink / raw)
  To: linux-bluetooth, elver
In-Reply-To: <20260603123111.2334409-1-elver@google.com>

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

---Test result---

Test Summary:
CheckPatch                    FAIL      0.97 seconds
VerifyFixes                   PASS      0.13 seconds
VerifySignedoff               PASS      0.13 seconds
GitLint                       FAIL      0.33 seconds
SubjectPrefix                 PASS      0.12 seconds
BuildKernel                   PASS      25.11 seconds
CheckAllWarning               PASS      28.16 seconds
CheckSparse                   PASS      26.76 seconds
BuildKernel32                 PASS      24.42 seconds
TestRunnerSetup               PASS      524.47 seconds
TestRunner_l2cap-tester       PASS      58.55 seconds
IncrementalBuild              PASS      23.63 seconds

Details
##############################
Test: CheckPatch - FAIL
Desc: Run checkpatch.pl script
Output:
Bluetooth: L2CAP: Fix UAF in l2cap_chan_timeout
WARNING: Prefer a maximum 75 chars per line (possible unwrapped commit description?)
#98: 
| BUG: KASAN: slab-use-after-free in instrument_atomic_read_write include/linux/instrumented.h:112 [inline]

ERROR: Unrecognized email address: 'https://sashiko.dev/#/patchset/20260521021249.3258069-1-oss%40fourdim.xyz'
#191: 
Reported-by: https://sashiko.dev/#/patchset/20260521021249.3258069-1-oss%40fourdim.xyz

WARNING: Reported-by: should be immediately followed by Closes: with a URL to the report
#191: 
Reported-by: https://sashiko.dev/#/patchset/20260521021249.3258069-1-oss%40fourdim.xyz
Signed-off-by: Marco Elver <elver@google.com>

total: 1 errors, 2 warnings, 0 checks, 89 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/14609364.patch has style problems, please review.

NOTE: Ignored message types: UNKNOWN_COMMIT_ID

NOTE: If any of the errors are false positives, please report
      them to the maintainer, see CHECKPATCH in MAINTAINERS.


##############################
Test: GitLint - FAIL
Desc: Run gitlint
Output:
Bluetooth: L2CAP: Fix UAF in l2cap_chan_timeout

9: B1 Line exceeds max length (107>80): "| BUG: KASAN: slab-use-after-free in instrument_atomic_read_write include/linux/instrumented.h:112 [inline]"
10: B1 Line exceeds max length (125>80): "| BUG: KASAN: slab-use-after-free in atomic_long_try_cmpxchg_acquire include/linux/atomic/atomic-instrumented.h:4456 [inline]"
11: B1 Line exceeds max length (93>80): "| BUG: KASAN: slab-use-after-free in __mutex_trylock_fast kernel/locking/mutex.c:161 [inline]"
12: B1 Line exceeds max length (84>80): "| BUG: KASAN: slab-use-after-free in mutex_lock+0x4f/0xa0 kernel/locking/mutex.c:318"
15: B1 Line exceeds max length (100>80): "| CPU: 2 UID: 0 PID: 83 Comm: kworker/2:1 Not tainted 7.1.0-rc6-next-20260601-dirty #6 PREEMPT(full)"
16: B1 Line exceeds max length (95>80): "| Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.17.0-debian-1.17.0-1 04/01/2014"
21: B1 Line exceeds max length (91>80): "|  atomic_long_try_cmpxchg_acquire include/linux/atomic/atomic-instrumented.h:4456 [inline]"
62: B1 Line exceeds max length (82>80): "|  syscall_exit_to_user_mode_prepare include/linux/irq-entry-common.h:230 [inline]"


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

---
Regards,
Linux Bluetooth


^ permalink raw reply

* RE: Bluetooth: btusb: fix wakeup irq devres lifetime
From: bluez.test.bot @ 2026-06-03 17:36 UTC (permalink / raw)
  To: linux-bluetooth, johan
In-Reply-To: <20260603143643.2514595-2-johan@kernel.org>

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

---Test result---

Test Summary:
CheckPatch                    FAIL      3.64 seconds
VerifyFixes                   PASS      0.14 seconds
VerifySignedoff               PASS      0.14 seconds
GitLint                       FAIL      1.87 seconds
SubjectPrefix                 PASS      0.66 seconds
BuildKernel                   PASS      25.55 seconds
CheckAllWarning               PASS      29.82 seconds
CheckSparse                   PASS      28.84 seconds
BuildKernel32                 PASS      26.46 seconds
TestRunnerSetup               PASS      529.51 seconds
IncrementalBuild              PASS      34.26 seconds

Details
##############################
Test: CheckPatch - FAIL
Desc: Run checkpatch.pl script
Output:
[v3,RESEND,4/5] Bluetooth: btusb: fix wakeup irq devres lifetime
ERROR: Please use git commit description style 'commit <12+ chars of sha1> ("<title line>")' - ie: 'commit 699fb50d9903 ("drivers: base: Free devm resources when unregistering a device")'
#82: 
[1] 699fb50d9903 ("drivers: base: Free devm resources when unregistering

total: 1 errors, 0 warnings, 51 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/14609619.patch has style problems, please review.

NOTE: Ignored message types: UNKNOWN_COMMIT_ID

NOTE: If any of the errors are false positives, please report
      them to the maintainer, see CHECKPATCH in MAINTAINERS.


##############################
Test: GitLint - FAIL
Desc: Run gitlint
Output:
[v3,RESEND,1/5] Bluetooth: btusb: fix use-after-free on registration failure

10: B3 Line contains hard tab characters (\t): "Cc: stable@vger.kernel.org	# 2.6.27"
[v3,RESEND,2/5] Bluetooth: btusb: fix use-after-free on marvell probe failure

10: B3 Line contains hard tab characters (\t): "Cc: stable@vger.kernel.org	# 4.11"
[v3,RESEND,3/5] Bluetooth: btusb: fix wakeup source leak on probe failure

6: B3 Line contains hard tab characters (\t): "Cc: stable@vger.kernel.org	# 4.11"


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

---
Regards,
Linux Bluetooth


^ permalink raw reply

* Re: [PATCH] Bluetooth: L2CAP: Fix UAF in l2cap_chan_timeout
From: Luiz Augusto von Dentz @ 2026-06-03 17:31 UTC (permalink / raw)
  To: Marco Elver
  Cc: Marcel Holtmann, linux-bluetooth, linux-kernel, kasan-dev, stable,
	Siwei Zhang, Luiz Augusto von Dentz
In-Reply-To: <CANpmjNPQCx8rynFhOUfqgagP-KBh0pJsXz6PQt6G3LomdzVJYw@mail.gmail.com>

Hi Marco,

On Wed, Jun 3, 2026 at 9:16 AM Marco Elver <elver@google.com> wrote:
>
> On Wed, 3 Jun 2026 at 14:31, Marco Elver <elver@google.com> wrote:
> >
> > l2cap_chan_timeout() accesses chan->conn without holding a reference to
> > the connection object. If l2cap_conn_del() races and tears down the
> > connection while the timer is waiting for locks, it can result in a
> > use-after-free when the timer wakes up and attempts to acquire
> > conn->lock:
> >
> > | BUG: KASAN: slab-use-after-free in instrument_atomic_read_write include/linux/instrumented.h:112 [inline]
> > | BUG: KASAN: slab-use-after-free in atomic_long_try_cmpxchg_acquire include/linux/atomic/atomic-instrumented.h:4456 [inline]
> > | BUG: KASAN: slab-use-after-free in __mutex_trylock_fast kernel/locking/mutex.c:161 [inline]
> > | BUG: KASAN: slab-use-after-free in mutex_lock+0x4f/0xa0 kernel/locking/mutex.c:318
> > | Write of size 8 at addr ffff8881298d9550 by task kworker/2:1/83
> > |
> > | CPU: 2 UID: 0 PID: 83 Comm: kworker/2:1 Not tainted 7.1.0-rc6-next-20260601-dirty #6 PREEMPT(full)
> > | Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.17.0-debian-1.17.0-1 04/01/2014
> > | Workqueue: events l2cap_chan_timeout
> > | Call Trace:
> > |  <TASK>
> > |  instrument_atomic_read_write include/linux/instrumented.h:112 [inline]
> > |  atomic_long_try_cmpxchg_acquire include/linux/atomic/atomic-instrumented.h:4456 [inline]
> > |  __mutex_trylock_fast kernel/locking/mutex.c:161 [inline]
> > |  mutex_lock+0x4f/0xa0 kernel/locking/mutex.c:318
> > |  l2cap_chan_timeout+0x5d/0x1b0 net/bluetooth/l2cap_core.c:422
> > |  process_one_work kernel/workqueue.c:3326 [inline]
> > |  process_scheduled_works+0x7c8/0xfb0 kernel/workqueue.c:3409
> > |  worker_thread+0x8a9/0xcf0 kernel/workqueue.c:3490
> > |  kthread+0x346/0x430 kernel/kthread.c:436
> > |  ret_from_fork+0x1a3/0x470 arch/x86/kernel/process.c:158
> > |  ret_from_fork_asm+0x1a/0x30 arch/x86/entry/entry_64.S:245
> > |  </TASK>
> > |
> > | Allocated by task 320:
> > |  l2cap_conn_add+0xa7/0x820 net/bluetooth/l2cap_core.c:7075
> > |  l2cap_connect_cfm+0xdb/0xd70 net/bluetooth/l2cap_core.c:7452
> > |  hci_connect_cfm include/net/bluetooth/hci_core.h:2139 [inline]
> > |  hci_remote_features_evt+0x52f/0x9f0 net/bluetooth/hci_event.c:3760
> > |  hci_event_func net/bluetooth/hci_event.c:7796 [inline]
> > |  hci_event_packet+0x561/0xa70 net/bluetooth/hci_event.c:7847
> > |  hci_rx_work+0x370/0x890 net/bluetooth/hci_core.c:4040
> > |  process_one_work kernel/workqueue.c:3326 [inline]
> > |  process_scheduled_works+0x7c8/0xfb0 kernel/workqueue.c:3409
> > |  worker_thread+0x8a9/0xcf0 kernel/workqueue.c:3490
> > |  kthread+0x346/0x430 kernel/kthread.c:436
> > |  ret_from_fork+0x1a3/0x470 arch/x86/kernel/process.c:158
> > |  ret_from_fork_asm+0x1a/0x30 arch/x86/entry/entry_64.S:245
> > |
> > | Freed by task 322:
> > |  hci_disconn_cfm include/net/bluetooth/hci_core.h:2154 [inline]
> > |  hci_conn_hash_flush+0x101/0x1f0 net/bluetooth/hci_conn.c:2736
> > |  hci_dev_close_sync+0x889/0xde0 net/bluetooth/hci_sync.c:5405
> > |  hci_dev_do_close net/bluetooth/hci_core.c:502 [inline]
> > |  hci_unregister_dev+0x1f7/0x370 net/bluetooth/hci_core.c:2679
> > |  vhci_release+0x12a/0x180 drivers/bluetooth/hci_vhci.c:690
> > |  __fput+0x369/0x890 fs/file_table.c:510
> > |  task_work_run+0x160/0x1d0 kernel/task_work.c:233
> > |  get_signal+0xf5b/0x1120 kernel/signal.c:2810
> > |  arch_do_signal_or_restart+0x4d/0x600 arch/x86/kernel/signal.c:337
> > |  __exit_to_user_mode_loop kernel/entry/common.c:64 [inline]
> > |  exit_to_user_mode_loop+0x85/0x510 kernel/entry/common.c:98
> > |  __exit_to_user_mode_prepare include/linux/irq-entry-common.h:207 [inline]
> > |  syscall_exit_to_user_mode_prepare include/linux/irq-entry-common.h:230 [inline]
> > |  syscall_exit_to_user_mode include/linux/entry-common.h:318 [inline]
> > |  do_syscall_64+0x263/0x3d0 arch/x86/entry/syscall_64.c:100
> > |  entry_SYSCALL_64_after_hwframe+0x77/0x7f
> > |
> > | Last potentially related work creation:
> > |  hci_connect_cfm include/net/bluetooth/hci_core.h:2139 [inline]
> > |  hci_remote_features_evt+0x52f/0x9f0 net/bluetooth/hci_event.c:3760
> > |  hci_event_func net/bluetooth/hci_event.c:7796 [inline]
> > |  hci_event_packet+0x561/0xa70 net/bluetooth/hci_event.c:7847
> > |  hci_rx_work+0x370/0x890 net/bluetooth/hci_core.c:4040
> > |  process_one_work kernel/workqueue.c:3326 [inline]
> > |  process_scheduled_works+0x7c8/0xfb0 kernel/workqueue.c:3409
> > |  worker_thread+0x8a9/0xcf0 kernel/workqueue.c:3490
> > |  kthread+0x346/0x430 kernel/kthread.c:436
> > |  ret_from_fork+0x1a3/0x470 arch/x86/kernel/process.c:158
> > |  ret_from_fork_asm+0x1a/0x30 arch/x86/entry/entry_64.S:245
> > |
> > | The buggy address belongs to the object at ffff8881298d9400
> > |  which belongs to the cache kmalloc-512 of size 512
> > | The buggy address is located 336 bytes inside of
> > |  freed 512-byte region [ffff8881298d9400, ffff8881298d9600)
> >
> > Fix it by holding a reference to the connection when the channel timer
> > is scheduled, and releasing it when the timer is either canceled or
> > executes to completion.
> >
> > Since l2cap_chan_del() nullifies chan->conn to disassociate the channel
> > during teardown, the timer handler might read NULL from chan->conn even
> > if it held a reference. To address this, introduce a `timer_conn` field
> > to `struct l2cap_chan` to store the connection pointer associated with
> > the active timer. The timer handler uses this field to acquire locks and
> > release the connection reference, and skips channel closing operations
> > if chan->conn has already been nullified by teardown.
> >
> > Fixes: 75780ca4c6a8 ("Bluetooth: L2CAP: use chan timer to close channels in cleanup_listen()")
> > Cc: <stable@vger.kernel.org>
> > Cc: Siwei Zhang <oss@fourdim.xyz>
> > Cc: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
> > Assisted-by: Gemini:gemini-3.1-pro-preview
> > Reported-by: https://sashiko.dev/#/patchset/20260521021249.3258069-1-oss%40fourdim.xyz
> > Signed-off-by: Marco Elver <elver@google.com>
>
> Sigh, Sashiko points out more problems here:
> https://sashiko.dev/#/patchset/20260603123111.2334409-1-elver%40google.com
>
> > Can this lockless read of chan->timer_conn cause a use-after-free or double
> > free if another thread re-arms the timer concurrently?
>
> I haven't analyzed this further yet, so consider this patch a
> bug-report-only. If anyone finds a better fix sooner, please go ahead.

I was thinking or something like the following:

diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
index c4ccfbda9d78..dfe9318272f3 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -406,17 +406,39 @@ static void l2cap_chan_timeout(struct work_struct *work)
 {
        struct l2cap_chan *chan = container_of(work, struct l2cap_chan,
                                               chan_timer.work);
-       struct l2cap_conn *conn = chan->conn;
+       struct l2cap_conn *conn;
        int reason;

        BT_DBG("chan %p state %s", chan, state_to_string(chan->state));

+       /* Hold a reference to the connection while we are processing this
+        * timeout, to prevent it from being freed out from under us by
+        * l2cap_conn_del().
+        */
+       conn = l2cap_conn_hold_unless_zero(chan->conn);
        if (!conn) {
                l2cap_chan_put(chan);
                return;
        }

        mutex_lock(&conn->lock);
+
+       /* If l2cap_chan_del() was called while waiting for conn->lock the
+        * channel shall be considered already closed and its last reference
+        * shall be released with l2cap_chan_put(chan) here.
+        *
+        * l2cap_conn_del() doesn't wait the channel's works and instead just
+        * leaves the timer reference behind which needs to be released here in
+        * order to free the channel and then l2cap_conn_put() to finally free
+        * the connection.
+        */
+       if (!chan->conn) {
+               mutex_unlock(&conn->lock);
+               l2cap_chan_put(chan);
+               l2cap_conn_put(conn);
+               return;
+       }
+
        /* __set_chan_timer() calls l2cap_chan_hold(chan) while scheduling
         * this work. No need to call l2cap_chan_hold(chan) here again.
         */
@@ -438,6 +460,8 @@ static void l2cap_chan_timeout(struct work_struct *work)
        l2cap_chan_put(chan);

        mutex_unlock(&conn->lock);
+
+       l2cap_conn_put(conn);
 }

 struct l2cap_chan *l2cap_chan_create(void)


> > ---
> >  include/net/bluetooth/l2cap.h | 18 ++++++++++++++++--
> >  net/bluetooth/l2cap_core.c    | 26 +++++++++++++++-----------
> >  2 files changed, 31 insertions(+), 13 deletions(-)
> >
> > diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h
> > index e0a1f2293679..83719777512e 100644
> > --- a/include/net/bluetooth/l2cap.h
> > +++ b/include/net/bluetooth/l2cap.h
> > @@ -514,6 +514,7 @@ struct l2cap_seq_list {
> >
> >  struct l2cap_chan {
> >         struct l2cap_conn       *conn;
> > +       struct l2cap_conn       *timer_conn; /* for chan_timer */
> >         struct kref     kref;
> >         atomic_t        nesting;
> >
> > @@ -835,6 +836,9 @@ static inline void l2cap_chan_unlock(struct l2cap_chan *chan)
> >         mutex_unlock(&chan->lock);
> >  }
> >
> > +struct l2cap_conn *l2cap_conn_get(struct l2cap_conn *conn);
> > +void l2cap_conn_put(struct l2cap_conn *conn);
> > +
> >  static inline void l2cap_set_timer(struct l2cap_chan *chan,
> >                                    struct delayed_work *work, long timeout)
> >  {
> > @@ -843,8 +847,13 @@ static inline void l2cap_set_timer(struct l2cap_chan *chan,
> >
> >         /* If delayed work cancelled do not hold(chan)
> >            since it is already done with previous set_timer */
> > -       if (!cancel_delayed_work(work))
> > +       if (!cancel_delayed_work(work)) {
> >                 l2cap_chan_hold(chan);
> > +               if (work == &chan->chan_timer && chan->conn) {
> > +                       l2cap_conn_get(chan->conn);
> > +                       chan->timer_conn = chan->conn;
> > +               }
> > +       }
> >
> >         schedule_delayed_work(work, timeout);
> >  }
> > @@ -857,8 +866,13 @@ static inline bool l2cap_clear_timer(struct l2cap_chan *chan,
> >         /* put(chan) if delayed work cancelled otherwise it
> >            is done in delayed work function */
> >         ret = cancel_delayed_work(work);
> > -       if (ret)
> > +       if (ret) {
> > +               if (work == &chan->chan_timer && chan->timer_conn) {
> > +                       l2cap_conn_put(chan->timer_conn);
> > +                       chan->timer_conn = NULL;
> > +               }
> >                 l2cap_chan_put(chan);
> > +       }
> >
> >         return ret;
> >  }
> > diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
> > index c4ccfbda9d78..491b03bf6903 100644
> > --- a/net/bluetooth/l2cap_core.c
> > +++ b/net/bluetooth/l2cap_core.c
> > @@ -406,7 +406,7 @@ static void l2cap_chan_timeout(struct work_struct *work)
> >  {
> >         struct l2cap_chan *chan = container_of(work, struct l2cap_chan,
> >                                                chan_timer.work);
> > -       struct l2cap_conn *conn = chan->conn;
> > +       struct l2cap_conn *conn = chan->timer_conn;
> >         int reason;
> >
> >         BT_DBG("chan %p state %s", chan, state_to_string(chan->state));
> > @@ -421,23 +421,27 @@ static void l2cap_chan_timeout(struct work_struct *work)
> >          * this work. No need to call l2cap_chan_hold(chan) here again.
> >          */
> >         l2cap_chan_lock(chan);
> > +       chan->timer_conn = NULL;
> > +
> > +       if (chan->conn) {
> > +               if (chan->state == BT_CONNECTED || chan->state == BT_CONFIG)
> > +                       reason = ECONNREFUSED;
> > +               else if (chan->state == BT_CONNECT &&
> > +                        chan->sec_level != BT_SECURITY_SDP)
> > +                       reason = ECONNREFUSED;
> > +               else
> > +                       reason = ETIMEDOUT;
> >
> > -       if (chan->state == BT_CONNECTED || chan->state == BT_CONFIG)
> > -               reason = ECONNREFUSED;
> > -       else if (chan->state == BT_CONNECT &&
> > -                chan->sec_level != BT_SECURITY_SDP)
> > -               reason = ECONNREFUSED;
> > -       else
> > -               reason = ETIMEDOUT;
> > -
> > -       l2cap_chan_close(chan, reason);
> > +               l2cap_chan_close(chan, reason);
> >
> > -       chan->ops->close(chan);
> > +               chan->ops->close(chan);
> > +       }
> >
> >         l2cap_chan_unlock(chan);
> >         l2cap_chan_put(chan);
> >
> >         mutex_unlock(&conn->lock);
> > +       l2cap_conn_put(conn);
> >  }
> >
> >  struct l2cap_chan *l2cap_chan_create(void)
> > --
> > 2.54.0.1013.g208068f2d8-goog
> >



-- 
Luiz Augusto von Dentz

^ permalink raw reply related

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

The following changes since commit cdf88b35e06f1b385f7f6228060ae541d44fbb72:

  Bluetooth: hci_sync: Reset device counters in hci_dev_close_sync() (2026-05-28 08:52:21 -0400)

are available in the Git repository at:

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

for you to fetch changes up to 149324fc762c2a7acef9c26790566f81f475e51f:

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

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

 - hci_core: fix memory leak in error path of hci_alloc_dev()
 - hci_sync: reject oversized Broadcast Announcement prepend
 - MGMT: Fix backward compatibility with userspace
 - MGMT: validate advertising TLV before type checks
 - L2CAP: reject BR/EDR signaling packets over MTUsig
 - RFCOMM: validate skb length in MCC handlers
 - RFCOMM: hold listener socket in rfcomm_connect_ind()
 - ISO: Fix not releasing hdev reference on iso_conn_big_sync
 - ISO: Fix a use-after-free of the hci_conn pointer
 - ISO: Fix data-race on iso_pi fields in hci_get_route calls
 - SCO: Fix data-race on sco_pi fields in sco_connect
 - BNEP: reject short frames before parsing

----------------------------------------------------------------
Bharath Reddy (1):
      Bluetooth: fix memory leak in error path of hci_alloc_dev()

Luiz Augusto von Dentz (3):
      Bluetooth: ISO: Fix not releasing hdev reference on iso_conn_big_sync
      Bluetooth: ISO: Fix a use-after-free of the hci_conn pointer
      Bluetooth: MGMT: Fix backward compatibility with userspace

Michael Bommarito (1):
      Bluetooth: L2CAP: reject BR/EDR signaling packets over MTUsig

SeungJu Cheon (3):
      Bluetooth: RFCOMM: validate skb length in MCC handlers
      Bluetooth: ISO: Fix data-race on iso_pi fields in hci_get_route calls
      Bluetooth: SCO: Fix data-race on sco_pi fields in sco_connect

Yuqi Xu (1):
      Bluetooth: hci_sync: reject oversized Broadcast Announcement prepend

Zhang Cen (3):
      Bluetooth: RFCOMM: hold listener socket in rfcomm_connect_ind()
      Bluetooth: MGMT: validate advertising TLV before type checks
      Bluetooth: bnep: reject short frames before parsing

 include/net/bluetooth/l2cap.h |  1 +
 net/bluetooth/bnep/core.c     | 57 ++++++++++++++++++++++--------------
 net/bluetooth/hci_sync.c      |  5 ++++
 net/bluetooth/hci_sysfs.c     |  6 ++--
 net/bluetooth/iso.c           | 63 +++++++++++++++++++++++++++++-----------
 net/bluetooth/l2cap_core.c    | 46 +++++++++++++++++++++++++++++
 net/bluetooth/mgmt.c          | 17 +++++------
 net/bluetooth/rfcomm/core.c   | 67 +++++++++++++++++++++++++++++++------------
 net/bluetooth/rfcomm/sock.c   | 26 ++++++++++++++---
 net/bluetooth/sco.c           | 20 +++++++++----
 10 files changed, 233 insertions(+), 75 deletions(-)

^ permalink raw reply

* [bluez/bluez]
From: BluezTestBot @ 2026-06-03 15:58 UTC (permalink / raw)
  To: linux-bluetooth

  Branch: refs/heads/1104846
  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] 2a6968: advertising: Fix sending extra bytes with MGMT_OP_...
From: Luiz Augusto von Dentz @ 2026-06-03 15:57 UTC (permalink / raw)
  To: linux-bluetooth

  Branch: refs/heads/master
  Home:   https://github.com/bluez/bluez
  Commit: 2a6968b40378dca5650e18e03ad0407738c47be5
      https://github.com/bluez/bluez/commit/2a6968b40378dca5650e18e03ad0407738c47be5
  Author: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
  Date:   2026-06-02 (Tue, 02 Jun 2026)

  Changed paths:
    M src/advertising.c

  Log Message:
  -----------
  advertising: Fix sending extra bytes with MGMT_OP_ADD_EXT_ADV_DATA

MGMT_OP_ADD_EXT_ADV_DATA expects the command to be of size of
struct mgmt_cp_add_ext_adv_data not mgmt_cp_add_advertising.



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

^ permalink raw reply

* [PATCH v2] Bluetooth: btintel_pcie: Add support for smart trigger dump
From: Kiran K @ 2026-06-03 15:54 UTC (permalink / raw)
  To: linux-bluetooth
  Cc: ravishankar.srivatsa, chethan.tumkur.narayan,
	chandrashekar.devegowda, Kiran K

Based on the debug configuration, firmware can raise MSI-X interrupt with
firmware trigger cause bit set on specific events like Disconnection,
Connection Timeout, Page Timeout etc.

Upon receiving an MSI-X interrupt with the firmware trigger cause bit
set, the driver performs the following actions:

1. Reads Device Memory: Retrieves data from the device memory,
   constructs an HCI diagnostic event, and sends it to the monitor. This
   event includes details about the trigger, such as connection timeout or
   page timeout.

2. Dumps Device Coredump: Generates a coredump containing firmware
   traces for further analysis.

The coredump can be retrieved using:

  $ cat /sys/class/devcoredump/devcd*/data > /tmp/btintel_coredump.bin

HCI traces:
= Vendor Diagnostic (len 12)
        a5 a5 a5 a5 01 03 00 23 00 01 00 00

Signed-off-by: Kiran K <kiran.k@intel.com>
---
Update in v2:
- commit message update to include HCI traces and coredump retrieval
- convert debug data into hci diagnostic event

 drivers/bluetooth/btintel.h      |   1 +
 drivers/bluetooth/btintel_pcie.c | 164 +++++++++++++++++++++++++++++++
 drivers/bluetooth/btintel_pcie.h |  10 +-
 3 files changed, 174 insertions(+), 1 deletion(-)

diff --git a/drivers/bluetooth/btintel.h b/drivers/bluetooth/btintel.h
index 70d812ad36a2..7cce1bdebae0 100644
--- a/drivers/bluetooth/btintel.h
+++ b/drivers/bluetooth/btintel.h
@@ -53,6 +53,7 @@ struct intel_tlv {
 } __packed;
 
 #define BTINTEL_HCI_OP_RESET	0xfc01
+#define BTINTEL_HCI_OP_DEBUG	0xfcd9
 
 #define BTINTEL_CNVI_BLAZARI		0x900	/* BlazarI - Lunar Lake */
 #define BTINTEL_CNVI_BLAZARIW		0x901	/* BlazarIW - Wildcat Lake */
diff --git a/drivers/bluetooth/btintel_pcie.c b/drivers/bluetooth/btintel_pcie.c
index eeaefffaaf6b..2baef130d101 100644
--- a/drivers/bluetooth/btintel_pcie.c
+++ b/drivers/bluetooth/btintel_pcie.c
@@ -145,6 +145,22 @@ struct btintel_pcie_dbgc_ctxt {
 	struct btintel_pcie_dbgc_ctxt_buf bufs[BTINTEL_PCIE_DBGC_BUFFER_COUNT];
 };
 
+struct btintel_pcie_trigger_evt {
+	u8 type;
+	u8 len;
+	__le32 addr;
+	__le32 size;
+} __packed;
+
+struct btintel_pcie_fwtrigger_evt {
+	__le32 reserved;
+	u8	type; /* Debug Trigger event */
+	__le16	len;
+	u8	event_type;
+	__le16	event_id;
+	__le16	reserved2;
+} __packed;
+
 static LIST_HEAD(btintel_pcie_recovery_list);
 static DEFINE_SPINLOCK(btintel_pcie_recovery_lock);
 
@@ -696,6 +712,11 @@ static int btintel_pcie_read_dram_buffers(struct btintel_pcie_data *data)
 		sizeof(*tlv) + strlen(vendor) +
 		sizeof(*tlv) + strlen(driver);
 
+	if (data->dmp_hdr.event_type && data->dmp_hdr.event_id) {
+		data_len += sizeof(*tlv) + sizeof(data->dmp_hdr.event_type);
+		data_len += sizeof(*tlv) + sizeof(data->dmp_hdr.event_id);
+	}
+
 	/*
 	 * sizeof(u32) - signature
 	 * sizeof(data_len) - to store tlv data size
@@ -743,6 +764,17 @@ static int btintel_pcie_read_dram_buffers(struct btintel_pcie_data *data)
 	p = btintel_pcie_copy_tlv(p, BTINTEL_CNVI_TOP, &data->dmp_hdr.cnvi_top,
 				  sizeof(data->dmp_hdr.cnvi_top));
 
+	if (data->dmp_hdr.event_type && data->dmp_hdr.event_id) {
+		p = btintel_pcie_copy_tlv(p, BTINTEL_EVENT_TYPE,
+					  &data->dmp_hdr.event_type,
+					  sizeof(data->dmp_hdr.event_type));
+		p = btintel_pcie_copy_tlv(p, BTINTEL_EVENT_ID,
+					  &data->dmp_hdr.event_id,
+					  sizeof(data->dmp_hdr.event_id));
+		data->dmp_hdr.event_type = 0;
+		data->dmp_hdr.event_id = 0;
+	}
+
 	memcpy(p, dbgc->bufs[0].data, dbgc->count * BTINTEL_PCIE_DBGC_BUFFER_SIZE);
 	dev_coredumpv(&hdev->dev, pdata, dump_size, GFP_KERNEL);
 	return 0;
@@ -1330,6 +1362,73 @@ static void btintel_pcie_read_hwexp(struct btintel_pcie_data *data)
 	kfree(buf);
 }
 
+static int btintel_pcie_dump_fwtrigger_event(struct btintel_pcie_data *data)
+{
+	struct btintel_pcie_fwtrigger_evt *evt;
+	struct sk_buff *skb;
+	unsigned int len;
+	int err;
+	u8 *buf;
+
+	if (!data->debug_evt_size || !data->debug_evt_addr)
+		return -EINVAL;
+
+	len = data->debug_evt_size;
+
+	len = ALIGN_DOWN(len, 4);
+
+	if (len < sizeof(*evt) || len > HCI_MAX_EVENT_SIZE) {
+		bt_dev_err(data->hdev, "Invalid FW trigger data size (%u bytes)", len);
+		return -EINVAL;
+	}
+
+	buf = kzalloc(len, GFP_KERNEL);
+	if (!buf)
+		return -ENOMEM;
+
+	btintel_pcie_mac_init(data);
+
+	err = btintel_pcie_read_device_mem(data, buf, data->debug_evt_addr,
+					   len);
+	if (err)
+		goto exit_on_error;
+
+	evt = (void *)buf;
+	data->dmp_hdr.event_type = evt->event_type;
+	data->dmp_hdr.event_id = le16_to_cpu(evt->event_id);
+
+	bt_dev_dbg(data->hdev, "event type: 0x%2.2x event id: 0x%4.4x len: %u",
+		   data->dmp_hdr.event_type, data->dmp_hdr.event_id, len);
+
+	skb = bt_skb_alloc(len, GFP_KERNEL);
+	if (!skb) {
+		err = -ENOMEM;
+		goto exit_on_error;
+	}
+	skb_put_data(skb, buf, len);
+
+	hci_recv_diag(data->hdev, skb);
+	err = 0;
+
+exit_on_error:
+	kfree(buf);
+	return err;
+}
+
+static void btintel_pcie_msix_fw_trigger_handler(struct btintel_pcie_data *data)
+{
+	bt_dev_dbg(data->hdev, "Received firmware smart trigger cause");
+
+	if (test_and_set_bit(BTINTEL_PCIE_FWTRIGGER_DUMP_INPROGRESS, &data->flags))
+		return;
+
+	/* Trigger device core dump when there is FW assert */
+	if (!test_and_set_bit(BTINTEL_PCIE_COREDUMP_INPROGRESS, &data->flags))
+		data->dmp_hdr.trigger_reason = BTINTEL_PCIE_TRIGGER_REASON_FW_ASSERT;
+
+	queue_work(data->workqueue, &data->rx_work);
+}
+
 static void btintel_pcie_msix_hw_exp_handler(struct btintel_pcie_data *data)
 {
 	bt_dev_err(data->hdev, "Received hw exception interrupt");
@@ -1352,6 +1451,14 @@ static void btintel_pcie_rx_work(struct work_struct *work)
 	struct btintel_pcie_data *data = container_of(work,
 					struct btintel_pcie_data, rx_work);
 	struct sk_buff *skb;
+	int err;
+
+	if (test_bit(BTINTEL_PCIE_FWTRIGGER_DUMP_INPROGRESS, &data->flags)) {
+		err = btintel_pcie_dump_fwtrigger_event(data);
+		if (err)
+			bt_dev_warn(data->hdev, "failed to log fwtrigger event");
+		clear_bit(BTINTEL_PCIE_FWTRIGGER_DUMP_INPROGRESS, &data->flags);
+	}
 
 	if (test_bit(BTINTEL_PCIE_COREDUMP_INPROGRESS, &data->flags)) {
 		btintel_pcie_dump_traces(data->hdev);
@@ -1509,6 +1616,9 @@ static irqreturn_t btintel_pcie_irq_msix_handler(int irq, void *dev_id)
 			btintel_pcie_msix_tx_handle(data);
 	}
 
+	if (intr_hw & BTINTEL_PCIE_MSIX_HW_INT_CAUSES_FWTRIG)
+		btintel_pcie_msix_fw_trigger_handler(data);
+
 	/* This interrupt is triggered by the firmware after updating
 	 * boot_stage register and image_response register
 	 */
@@ -1583,6 +1693,7 @@ static struct btintel_pcie_causes_list causes_list[] = {
 	{ BTINTEL_PCIE_MSIX_FH_INT_CAUSES_1,	BTINTEL_PCIE_CSR_MSIX_FH_INT_MASK,	0x01 },
 	{ BTINTEL_PCIE_MSIX_HW_INT_CAUSES_GP0,	BTINTEL_PCIE_CSR_MSIX_HW_INT_MASK,	0x20 },
 	{ BTINTEL_PCIE_MSIX_HW_INT_CAUSES_HWEXP, BTINTEL_PCIE_CSR_MSIX_HW_INT_MASK,	0x23 },
+	{ BTINTEL_PCIE_MSIX_HW_INT_CAUSES_FWTRIG, BTINTEL_PCIE_CSR_MSIX_HW_INT_MASK,	0x25 },
 };
 
 /* This function configures the interrupt masks for both HW_INT_CAUSES and
@@ -2069,6 +2180,55 @@ static void btintel_pcie_synchronize_irqs(struct btintel_pcie_data *data)
 		synchronize_irq(data->msix_entries[i].vector);
 }
 
+static int btintel_pcie_get_debug_info_addr(struct hci_dev *hdev)
+{
+	struct btintel_pcie_data *data = hci_get_drvdata(hdev);
+	struct btintel_pcie_trigger_evt *evt;
+	u8 param[1] = {0x10};
+	struct sk_buff *skb;
+	int err = 0;
+
+	skb = __hci_cmd_sync(hdev, BTINTEL_HCI_OP_DEBUG, 1, param,
+			     HCI_CMD_TIMEOUT);
+	if (IS_ERR(skb)) {
+		bt_dev_err(hdev, "Reading Intel read debug info address command failed (%ld)",
+			   PTR_ERR(skb));
+		/* Not all Intel products supports this command */
+		if (PTR_ERR(skb) == -EOPNOTSUPP)
+			return 0;
+		return PTR_ERR(skb);
+	}
+
+	if (skb->len < (1 + sizeof(*evt))) {
+		bt_dev_err(hdev, "Debug info response too short (%u bytes)", skb->len);
+		err = -EIO;
+		goto exit_error;
+	}
+
+	/* Check the status */
+	if (skb->data[0]) {
+		bt_dev_err(hdev, "Reading Intel read debug info command failed (0x%2.2x)",
+			   skb->data[0]);
+		err = -EIO;
+		goto exit_error;
+	}
+
+	/* Consume Command Complete Status field */
+	skb_pull(skb, 1);
+
+	evt = (void *)skb->data;
+
+	data->debug_evt_addr = le32_to_cpu(evt->addr);
+	data->debug_evt_size = le32_to_cpu(evt->size);
+
+	bt_dev_dbg(hdev, "config type: %u config len: %u debug event addr: 0x%8.8x size: 0x%8.8x",
+		   evt->type, evt->len, data->debug_evt_addr,
+		   data->debug_evt_size);
+exit_error:
+	kfree_skb(skb);
+	return err;
+}
+
 static int btintel_pcie_setup_internal(struct hci_dev *hdev)
 {
 	struct btintel_pcie_data *data = hci_get_drvdata(hdev);
@@ -2168,6 +2328,10 @@ static int btintel_pcie_setup_internal(struct hci_dev *hdev)
 	if (ver_tlv.img_type == 0x02 || ver_tlv.img_type == 0x03)
 		data->dmp_hdr.fw_git_sha1 = ver_tlv.git_sha1;
 
+	err = btintel_pcie_get_debug_info_addr(hdev);
+	if (err)
+		goto exit_error;
+
 	btintel_print_fseq_info(hdev);
 exit_error:
 	kfree_skb(skb);
diff --git a/drivers/bluetooth/btintel_pcie.h b/drivers/bluetooth/btintel_pcie.h
index 7fc8c46ed689..cae84b00a700 100644
--- a/drivers/bluetooth/btintel_pcie.h
+++ b/drivers/bluetooth/btintel_pcie.h
@@ -98,6 +98,7 @@ enum msix_hw_int_causes {
 	BTINTEL_PCIE_MSIX_HW_INT_CAUSES_GP0	= BIT(0),	/* cause 32 */
 	BTINTEL_PCIE_MSIX_HW_INT_CAUSES_GP1	= BIT(1),	/* cause 33 */
 	BTINTEL_PCIE_MSIX_HW_INT_CAUSES_HWEXP	= BIT(3),	/* cause 35 */
+	BTINTEL_PCIE_MSIX_HW_INT_CAUSES_FWTRIG	= BIT(5),	/* cause 37 */
 };
 
 /* PCIe device states
@@ -115,6 +116,7 @@ enum {
 	BTINTEL_PCIE_CORE_HALTED,
 	BTINTEL_PCIE_HWEXP_INPROGRESS,
 	BTINTEL_PCIE_COREDUMP_INPROGRESS,
+	BTINTEL_PCIE_FWTRIGGER_DUMP_INPROGRESS,
 	BTINTEL_PCIE_RECOVERY_IN_PROGRESS,
 	BTINTEL_PCIE_SETUP_DONE
 };
@@ -130,7 +132,9 @@ enum btintel_pcie_tlv_type {
 	BTINTEL_DUMP_TIME,
 	BTINTEL_FW_BUILD,
 	BTINTEL_VENDOR,
-	BTINTEL_DRIVER
+	BTINTEL_DRIVER,
+	BTINTEL_EVENT_TYPE,
+	BTINTEL_EVENT_ID
 };
 
 /* causes for the MBOX interrupts */
@@ -430,6 +434,8 @@ struct btintel_pcie_dump_header {
 	u32		wrap_ctr;
 	u16		trigger_reason;
 	int		state;
+	u8		event_type;
+	u16		event_id;
 };
 
 /* struct btintel_pcie_data
@@ -518,6 +524,8 @@ struct btintel_pcie_data {
 	struct btintel_pcie_dbgc	dbgc;
 	struct btintel_pcie_dump_header dmp_hdr;
 	u8	pm_sx_event;
+	u32	debug_evt_addr;
+	u32	debug_evt_size;
 };
 
 static inline u32 btintel_pcie_rd_reg32(struct btintel_pcie_data *data,
-- 
2.54.0


^ permalink raw reply related

* [PATCH v9 1/1] Bluetooth: L2CAP: Fix use-after-free in l2cap_sock_new_connection_cb()
From: Siwei Zhang @ 2026-06-03 15:06 UTC (permalink / raw)
  To: Marcel Holtmann, Luiz Augusto von Dentz; +Cc: linux-bluetooth, Siwei Zhang
In-Reply-To: <20260603150835.3539963-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-8
Signed-off-by: Siwei Zhang <oss@fourdim.xyz>
---
 include/net/bluetooth/l2cap.h | 10 +++--
 net/bluetooth/6lowpan.c       | 31 +++++++------
 net/bluetooth/l2cap_core.c    | 41 ++++++++++++-----
 net/bluetooth/l2cap_sock.c    | 83 +++++++++++++++++++++--------------
 net/bluetooth/smp.c           | 17 ++++---
 5 files changed, 113 insertions(+), 69 deletions(-)

diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h
index e0a1f2293679..7f5e4647f6e0 100644
--- a/include/net/bluetooth/l2cap.h
+++ b/include/net/bluetooth/l2cap.h
@@ -620,7 +620,9 @@ struct l2cap_chan {
 struct l2cap_ops {
 	char			*name;
 
-	struct l2cap_chan	*(*new_connection) (struct l2cap_chan *chan);
+	int			(*new_connection)(struct l2cap_conn *conn,
+						  struct l2cap_chan *chan,
+						  struct l2cap_chan *new_chan);
 	int			(*recv) (struct l2cap_chan * chan,
 					 struct sk_buff *skb);
 	void			(*teardown) (struct l2cap_chan *chan, int err);
@@ -884,9 +886,11 @@ static inline __u16 __next_seq(struct l2cap_chan *chan, __u16 seq)
 	return (seq + 1) % (chan->tx_win_max + 1);
 }
 
-static inline struct l2cap_chan *l2cap_chan_no_new_connection(struct l2cap_chan *chan)
+static inline int l2cap_chan_no_new_connection(struct l2cap_conn *conn,
+					       struct l2cap_chan *chan,
+					       struct l2cap_chan *new_chan)
 {
-	return NULL;
+	return -EOPNOTSUPP;
 }
 
 static inline int l2cap_chan_no_recv(struct l2cap_chan *chan, struct sk_buff *skb)
diff --git a/net/bluetooth/6lowpan.c b/net/bluetooth/6lowpan.c
index cb1e329d66fd..94863af97a44 100644
--- a/net/bluetooth/6lowpan.c
+++ b/net/bluetooth/6lowpan.c
@@ -624,6 +624,15 @@ static bool is_bt_6lowpan(struct hci_conn *hcon)
 	return true;
 }
 
+static void chan_init(struct l2cap_chan *chan)
+{
+	l2cap_chan_set_defaults(chan);
+
+	chan->chan_type = L2CAP_CHAN_CONN_ORIENTED;
+	chan->mode = L2CAP_MODE_LE_FLOWCTL;
+	chan->imtu = 1280;
+}
+
 static struct l2cap_chan *chan_create(void)
 {
 	struct l2cap_chan *chan;
@@ -632,11 +641,7 @@ static struct l2cap_chan *chan_create(void)
 	if (!chan)
 		return NULL;
 
-	l2cap_chan_set_defaults(chan);
-
-	chan->chan_type = L2CAP_CHAN_CONN_ORIENTED;
-	chan->mode = L2CAP_MODE_LE_FLOWCTL;
-	chan->imtu = 1280;
+	chan_init(chan);
 
 	return chan;
 }
@@ -745,19 +750,19 @@ static inline void chan_ready_cb(struct l2cap_chan *chan)
 	ifup(dev->netdev);
 }
 
-static inline struct l2cap_chan *chan_new_conn_cb(struct l2cap_chan *pchan)
+static inline int chan_new_conn_cb(struct l2cap_conn *conn,
+				   struct l2cap_chan *pchan,
+				   struct l2cap_chan *chan)
 {
-	struct l2cap_chan *chan;
-
-	chan = chan_create();
-	if (!chan)
-		return NULL;
-
+	chan_init(chan);
 	chan->ops = pchan->ops;
 
+	/* Take the conn list reference; see l2cap_new_connection(). */
+	__l2cap_chan_add(conn, chan);
+
 	BT_DBG("chan %p pchan %p", chan, pchan);
 
-	return chan;
+	return 0;
 }
 
 static void unregister_dev(struct lowpan_btle_dev *dev)
diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
index c4ccfbda9d78..62acf90837fb 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -4007,6 +4007,31 @@ static inline int l2cap_command_rej(struct l2cap_conn *conn,
 	return 0;
 }
 
+/* Allocate and initialise a channel for an incoming connection.
+ *
+ * ->new_connection() initialises the channel and links it into @conn with
+ * __l2cap_chan_add(). The l2cap_chan_create() reference becomes the one owned
+ * by the parent subsystem (l2cap_pi(sk)->chan, conn->smp or peer->chan) and is
+ * released by its teardown callback; the conn list reference is released by
+ * l2cap_chan_del().
+ */
+static struct l2cap_chan *l2cap_new_connection(struct l2cap_conn *conn,
+					       struct l2cap_chan *pchan)
+{
+	struct l2cap_chan *chan;
+
+	chan = l2cap_chan_create();
+	if (!chan)
+		return NULL;
+
+	if (pchan->ops->new_connection(conn, pchan, chan) < 0) {
+		l2cap_chan_put(chan);
+		return NULL;
+	}
+
+	return chan;
+}
+
 static void l2cap_connect(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd,
 			  u8 *data, u8 rsp_code)
 {
@@ -4053,7 +4078,7 @@ static void l2cap_connect(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd,
 		goto response;
 	}
 
-	chan = pchan->ops->new_connection(pchan);
+	chan = l2cap_new_connection(conn, pchan);
 	if (!chan)
 		goto response;
 
@@ -4071,8 +4096,6 @@ static void l2cap_connect(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd,
 	chan->psm  = psm;
 	chan->dcid = scid;
 
-	__l2cap_chan_add(conn, chan);
-
 	dcid = chan->scid;
 
 	__set_chan_timer(chan, chan->ops->get_sndtimeo(chan));
@@ -4955,7 +4978,7 @@ static int l2cap_le_connect_req(struct l2cap_conn *conn,
 		goto response_unlock;
 	}
 
-	chan = pchan->ops->new_connection(pchan);
+	chan = l2cap_new_connection(conn, pchan);
 	if (!chan) {
 		result = L2CAP_CR_LE_NO_MEM;
 		goto response_unlock;
@@ -4970,8 +4993,6 @@ static int l2cap_le_connect_req(struct l2cap_conn *conn,
 	chan->omtu = mtu;
 	chan->remote_mps = mps;
 
-	__l2cap_chan_add(conn, chan);
-
 	l2cap_le_flowctl_init(chan, __le16_to_cpu(req->credits));
 
 	dcid = chan->scid;
@@ -5179,7 +5200,7 @@ static inline int l2cap_ecred_conn_req(struct l2cap_conn *conn,
 			continue;
 		}
 
-		chan = pchan->ops->new_connection(pchan);
+		chan = l2cap_new_connection(conn, pchan);
 		if (!chan) {
 			result = L2CAP_CR_LE_NO_MEM;
 			continue;
@@ -5194,8 +5215,6 @@ static inline int l2cap_ecred_conn_req(struct l2cap_conn *conn,
 		chan->omtu = mtu;
 		chan->remote_mps = mps;
 
-		__l2cap_chan_add(conn, chan);
-
 		l2cap_ecred_init(chan, __le16_to_cpu(req->credits));
 
 		/* Init response */
@@ -7470,14 +7489,12 @@ static void l2cap_connect_cfm(struct hci_conn *hcon, u8 status)
 			goto next;
 
 		l2cap_chan_lock(pchan);
-		chan = pchan->ops->new_connection(pchan);
+		chan = l2cap_new_connection(conn, pchan);
 		if (chan) {
 			bacpy(&chan->src, &hcon->src);
 			bacpy(&chan->dst, &hcon->dst);
 			chan->src_type = bdaddr_src_type(hcon);
 			chan->dst_type = dst_type;
-
-			__l2cap_chan_add(conn, chan);
 		}
 
 		l2cap_chan_unlock(pchan);
diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c
index 025329636353..87f4c0db5c0c 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)
@@ -1287,6 +1288,23 @@ static int l2cap_sock_recvmsg(struct socket *sock, struct msghdr *msg,
 	return err;
 }
 
+/* Release the sock's ref on chan and clear the pointer so that the ref is
+ * dropped exactly once even if both l2cap_sock_kill() and
+ * l2cap_sock_destruct() run. Setting chan->data to NULL first stops any other
+ * task from dereferencing the now-dead sock pointer.
+ */
+static void l2cap_sock_put_chan(struct sock *sk)
+{
+	struct l2cap_chan *chan = l2cap_pi(sk)->chan;
+
+	if (!chan)
+		return;
+
+	chan->data = NULL;
+	l2cap_pi(sk)->chan = NULL;
+	l2cap_chan_put(chan);
+}
+
 /* Kill socket (only if zapped and orphan)
  * Must be called on unlocked socket, with l2cap channel lock.
  */
@@ -1297,13 +1315,9 @@ static void l2cap_sock_kill(struct sock *sk)
 
 	BT_DBG("sk %p state %s", sk, state_to_string(sk->sk_state));
 
-	/* Sock is dead, so set chan data to NULL, avoid other task use invalid
-	 * sock pointer.
-	 */
-	l2cap_pi(sk)->chan->data = NULL;
-	/* Kill poor orphan */
+	l2cap_sock_put_chan(sk);
 
-	l2cap_chan_put(l2cap_pi(sk)->chan);
+	/* Kill poor orphan */
 	sock_set_flag(sk, SOCK_DEAD);
 	sock_put(sk);
 }
@@ -1546,12 +1560,14 @@ 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_conn *conn,
+					struct l2cap_chan *chan,
+					struct l2cap_chan *new_chan)
 {
 	struct sock *sk, *parent = chan->data;
 
 	if (!parent)
-		return NULL;
+		return -EINVAL;
 
 	lock_sock(parent);
 
@@ -1559,25 +1575,33 @@ 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);
 
 	l2cap_sock_init(sk, parent);
 
+	/* Link the channel into conn before exposing the new socket via the
+	 * accept queue. Once release_sock() below drops the parent lock the
+	 * socket may be freed by another task, dropping its reference on
+	 * new_chan; the conn list reference taken here keeps new_chan alive so
+	 * the caller can safely use it after ->new_connection() returns.
+	 */
+	__l2cap_chan_add(conn, new_chan);
+
 	bt_accept_enqueue(parent, sk, false);
 
 	release_sock(parent);
 
-	return l2cap_pi(sk)->chan;
+	return 0;
 }
 
 static int l2cap_sock_recv_cb(struct l2cap_chan *chan, struct sk_buff *skb)
@@ -1874,10 +1898,7 @@ static void l2cap_sock_destruct(struct sock *sk)
 
 	BT_DBG("sk %p", sk);
 
-	if (l2cap_pi(sk)->chan) {
-		l2cap_pi(sk)->chan->data = NULL;
-		l2cap_chan_put(l2cap_pi(sk)->chan);
-	}
+	l2cap_sock_put_chan(sk);
 
 	list_for_each_entry_safe(rx_busy, next, &l2cap_pi(sk)->rx_busy, list) {
 		kfree_skb(rx_busy->skb);
@@ -1978,10 +1999,10 @@ static struct proto l2cap_proto = {
 };
 
 static struct sock *l2cap_sock_alloc(struct net *net, struct socket *sock,
-				     int proto, gfp_t prio, int kern)
+				     int proto, gfp_t prio, int kern,
+				     struct l2cap_chan *chan)
 {
 	struct sock *sk;
-	struct l2cap_chan *chan;
 
 	sk = bt_sock_alloc(net, sock, &l2cap_proto, proto, prio, kern);
 	if (!sk)
@@ -1992,16 +2013,7 @@ 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;
-	}
-
-	l2cap_chan_hold(chan);
-
+	/* The sock takes ownership of the caller's reference on chan. */
 	l2cap_pi(sk)->chan = chan;
 
 	return sk;
@@ -2011,6 +2023,7 @@ static int l2cap_sock_create(struct net *net, struct socket *sock, int protocol,
 			     int kern)
 {
 	struct sock *sk;
+	struct l2cap_chan *chan;
 
 	BT_DBG("sock %p", sock);
 
@@ -2025,10 +2038,16 @@ 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;
+	}
+
 	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..2d31c3c7bbc0 100644
--- a/net/bluetooth/smp.c
+++ b/net/bluetooth/smp.c
@@ -3204,16 +3204,12 @@ 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_conn *conn,
+				  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 +3225,12 @@ static inline struct l2cap_chan *smp_new_conn_cb(struct l2cap_chan *pchan)
 	 */
 	atomic_set(&chan->nesting, L2CAP_NESTING_SMP);
 
-	BT_DBG("created chan %p", chan);
+	/* Take the conn list reference; see l2cap_new_connection(). */
+	__l2cap_chan_add(conn, chan);
 
-	return chan;
+	BT_DBG("initialised chan %p", chan);
+
+	return 0;
 }
 
 static const struct l2cap_ops smp_root_chan_ops = {
-- 
2.54.0


^ permalink raw reply related

* [PATCH v9 0/1] Bluetooth: L2CAP: Fix use-after-free in l2cap_sock_new_connection_cb()
From: Siwei Zhang @ 2026-06-03 15:06 UTC (permalink / raw)
  To: Marcel Holtmann, Luiz Augusto von Dentz; +Cc: linux-bluetooth, Siwei Zhang

Compared to v2, addresses comments on https://sashiko.dev/#/patchset/20260415204842.2363950-1-oss%40fourdim.xyz .

Compared to v3, rebase against bluetooth-next.

Compared to v4, allocate the channel outside the function and pass it in as an argument to avoid the use-after-free.

Compared to v5, extract the channel init to a separate function.

Compared to v6, balance puts and holds on chans.

Compared to v7, rebase against bluetooth-next and refactor the chan refcounting.

Compared to v8, adopt the philosophy of one assignment one reference. Make refcounting easier to follow.

Siwei Zhang (1):
  Bluetooth: L2CAP: Fix use-after-free in l2cap_sock_new_connection_cb()

 include/net/bluetooth/l2cap.h | 10 +++--
 net/bluetooth/6lowpan.c       | 31 +++++++------
 net/bluetooth/l2cap_core.c    | 41 ++++++++++++-----
 net/bluetooth/l2cap_sock.c    | 83 +++++++++++++++++++++--------------
 net/bluetooth/smp.c           | 17 ++++---
 5 files changed, 113 insertions(+), 69 deletions(-)

-- 
2.54.0


^ permalink raw reply


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