* Re: [PATCH] Bluetooth: RFCOMM: serialize session teardown
2026-08-21 19:21 ` Ali Ahmet Memis
@ 2026-08-22 7:14 ` Chengfeng Ye
2026-08-22 8:30 ` Ali Ahmet Memis
0 siblings, 1 reply; 6+ messages in thread
From: Chengfeng Ye @ 2026-08-22 7:14 UTC (permalink / raw)
To: Ali Ahmet Memis
Cc: Marcel Holtmann, Luiz Augusto von Dentz, Kees Cook,
Jakub Kicinski, Pengpeng Hou, Jiale Yao, SeungJu Cheon, Tim Bird,
linux-bluetooth, linux-kernel, stable
Hi Ali,
Thanks for taking a close look.
On Sat, Aug 22, 2026 at 3:22 AM Ali Ahmet Memis <ali@iusegentoo.com> wrote:
>
> Hi,
>
> On Sat, Aug 22, 2026 at 01:45:14AM +0800, Chengfeng Ye wrote:
> > rfcomm_kill_listener() walks session_list and deletes every session
> > without holding rfcomm_mutex.
>
> I agree with that observation but I don't think this race is reachable. I
> also could not reproduce the reported splat.
>
> I tested 7.2-rc5 with KASAN and RFCOMM as a module. An open RFCOMM socket
> keeps rfcomm.ko pinned so the module cannot be unloaded while connect() is
> running. Even with forced unloads and a widened add/drop window, I only
> hit execution from freed module text. I never saw a UAF in
> rfcomm_session_del().
You are right that my changelog did not describe the reachability
constraints clearly enough. The reproducer I used relies on forced
module unload via: syscall(SYS_delete_module, "rfcomm", O_TRUNC) so
the path is only reachable by a privileged user with module-unload
capability. Furthermore, to make the race triggering stable, we add
the following kernel-delay log for race reproduction (which is
acceptable approach for demonstrating the bug[1]):
index 2e8c080b4d9e..fb9b4f6d1a86 100644
--- a/net/bluetooth/rfcomm/core.c
+++ b/net/bluetooth/rfcomm/core.c
@@ -25,6 +25,7 @@
#include <linux/module.h>
#include <linux/debugfs.h>
#include <linux/kthread.h>
+#include <linux/delay.h>
#include <linux/unaligned.h>
#include <net/bluetooth/bluetooth.h>
@@ -701,7 +702,12 @@ static struct rfcomm_session
*rfcomm_session_add(struct socket *sock, int state)
return NULL;
}
+ /*
+ * Widen the transient BT_BOUND lifetime after insertion so forced
+ * unload can overlap a live session on session_list.
+ */
list_add(&s->list, &session_list);
+ mdelay(30);
return s;
}
@@ -2160,8 +2166,14 @@ static void rfcomm_kill_listener(void)
BT_DBG("");
- list_for_each_entry_safe(s, n, &session_list, list)
+ list_for_each_entry_safe(s, n, &session_list, list) {
+ /*
+ * Widen the unlocked teardown window so forced module
unload can
+ * overlap a concurrent session teardown on the same list entry.
+ */
+ mdelay(50);
rfcomm_session_del(s);
+ }
}
>
>
> The splat also looks like it came from a built-in RFCOMM build. The
> missing module tag and the way rfcomm_exit() works in that case make the
> reported path unlikely.
>
> Could you send the full report and the reproducer? In particular the
> "buggy address" block and both full stacks would help. faddr2line on your
> vmlinux should also show which traversal the offset points to.
I will send the reproducer as a separate email as the maillist does
not accept an attachment. The full KASAN I reproduced on the current
master branch as following (where the address would be different from
that on the commit message cause that one was reproduced on a kernel
built roughly 2 months ago):
[ 29.867919] ==================================================================
[ 29.868407] BUG: KASAN: slab-use-after-free in
rfcomm_run+0x3802/0x3f00 [rfcomm]
[ 29.868954] Read of size 8 at addr ffff888111058d40 by task krfcommd/79
[ 29.869432]
[ 29.869544] CPU: 0 UID: 0 PID: 79 Comm: krfcommd Tainted: G R
7.2.0-05126-ga4ff2be345d0-dirty #20 PREEMPT(lazy)
[ 29.869550] Tainted: [R]=FORCED_RMMOD
[ 29.869551] Hardware name: QEMU Ubuntu 24.04 PC v2 (i440FX + PIIX,
arch_caps fix, 1996), BIOS 1.16.3-debian-1.16.3-2 04/01/2014
[ 29.869554] Call Trace:
[ 29.869558] <TASK>
[ 29.869559] dump_stack_lvl+0x53/0x70
[ 29.869591] print_report+0xd0/0x630
[ 29.869611] ? __pfx__raw_spin_lock_irqsave+0x10/0x10
[ 29.869620] ? rfcomm_run+0x3802/0x3f00 [rfcomm]
[ 29.869623] kasan_report+0xce/0x100
[ 29.869625] ? rfcomm_run+0x3802/0x3f00 [rfcomm]
[ 29.869629] rfcomm_run+0x3802/0x3f00 [rfcomm]
[ 29.869632] ? __pfx___set_cpus_allowed_ptr+0x10/0x10
[ 29.869643] ? __pfx_rfcomm_run+0x10/0x10 [rfcomm]
[ 29.869647] ? mutex_unlock+0x7b/0xd0
[ 29.869649] ? __pfx_mutex_unlock+0x10/0x10
[ 29.869651] ? __pfx_woken_wake_function+0x10/0x10
[ 29.869655] ? __pfx__raw_spin_lock_irqsave+0x10/0x10
[ 29.869657] ? __pfx_kthread_affine_node+0x10/0x10
[ 29.869661] ? __kthread_parkme+0x88/0x170
[ 29.869666] ? __pfx_rfcomm_run+0x10/0x10 [rfcomm]
[ 29.869669] ? __pfx_rfcomm_run+0x10/0x10 [rfcomm]
[ 29.869672] kthread+0x2c8/0x3b0
[ 29.869674] ? recalc_sigpending+0x15c/0x1e0
[ 29.869678] ? __pfx_kthread+0x10/0x10
[ 29.869680] ret_from_fork+0x36e/0x5a0
[ 29.869690] ? __pfx_ret_from_fork+0x10/0x10
[ 29.869695] ? __switch_to+0x572/0xdd0
[ 29.869699] ? __pfx_kthread+0x10/0x10
[ 29.869701] ret_from_fork_asm+0x1a/0x30
[ 29.869705] </TASK>
[ 29.869706]
[ 29.879688] Allocated by task 86:
[ 29.879947] kasan_save_stack+0x33/0x60
[ 29.880247] kasan_save_track+0x14/0x30
[ 29.880550] __kasan_kmalloc+0x8f/0xa0
[ 29.880846] __kmalloc_cache_noprof+0x15a/0x370
[ 29.881198] rfcomm_session_add+0xa1/0x300 [rfcomm]
[ 29.881555] rfcomm_dlc_open+0x8b2/0xf30 [rfcomm]
[ 29.881908] rfcomm_sock_connect+0x34c/0x530 [rfcomm]
[ 29.882248] __sys_connect+0xfc/0x130
[ 29.882491] __x64_sys_connect+0x6d/0xb0
[ 29.882785] do_syscall_64+0xdd/0x4a0
[ 29.883050] entry_SYSCALL_64_after_hwframe+0x77/0x7f
[ 29.883425]
[ 29.883530] Freed by task 86:
[ 29.883758] kasan_save_stack+0x33/0x60
[ 29.884029] kasan_save_track+0x14/0x30
[ 29.884321] kasan_save_free_info+0x3b/0x60
[ 29.884642] __kasan_slab_free+0x43/0x70
[ 29.884920] kfree+0x121/0x3c0
[ 29.885145] rfcomm_dlc_open+0xab7/0xf30 [rfcomm]
[ 29.885520] rfcomm_sock_connect+0x34c/0x530 [rfcomm]
[ 29.885824] __sys_connect+0xfc/0x130
[ 29.886047] __x64_sys_connect+0x6d/0xb0
[ 29.886286] do_syscall_64+0xdd/0x4a0
[ 29.886508] entry_SYSCALL_64_after_hwframe+0x77/0x7f
[ 29.886808]
[ 29.886906] The buggy address belongs to the object at ffff888111058d00
[ 29.886906] which belongs to the cache kmalloc-part-02-128 of size 128
[ 29.887669] The buggy address is located 64 bytes inside of
[ 29.887669] freed 128-byte region [ffff888111058d00, ffff888111058d80)
[ 29.888371]
[ 29.888470] The buggy address belongs to the physical page:
[ 29.888797] page: refcount:0 mapcount:0 mapping:0000000000000000
index:0x0 pfn:0x111058
[ 29.889270] flags: 0x200000000000000(node=0|zone=2)
[ 29.889563] page_type: f5(slab)
[ 29.889756] raw: 0200000000000000 ffff888100043c80 dead000000000122
0000000000000000
[ 29.890207] raw: 0000000000000000 0000000000100010 00000000f5000000
0000000000000000
[ 29.890660] page dumped because: kasan: bad access detected
[ 29.890987]
[ 29.891086] Memory state around the buggy address:
[ 29.891373] ffff888111058c00: fc fc fc fc fc fc fc fc fc fc fc fc
fc fc fc fc
[ 29.891793] ffff888111058c80: fc fc fc fc fc fc fc fc fc fc fc fc
fc fc fc fc
[ 29.892212] >ffff888111058d00: fa fb fb fb fb fb fb fb fb fb fb fb
fb fb fb fb
[ 29.892636] ^
[ 29.892948] ffff888111058d80: fc fc fc fc fc fc fc fc fc fc fc fc
fc fc fc fc
[ 29.893373] ffff888111058e00: fa fb fb fb fb fb fb fb fb fb fb fb
fb fb fb fb
[ 29.893793] ==================================================================
[ 29.894249] Oops: general protection fault, probably for
non-canonical address 0xe0fd7c116000000a: 0000 [#1] SMP KASAN NOPTI
[ 29.894901] KASAN: maybe wild-memory-access in range
[0x07ec008b00000050-0x07ec008b00000057]
[ 29.895397] CPU: 0 UID: 0 PID: 79 Comm: krfcommd Tainted: G R B
7.2.0-05126-ga4ff2be345d0-dirty #20 PREEMPT(lazy)
[ 29.896068] Tainted: [R]=FORCED_RMMOD, [B]=BAD_PAGE
[ 29.896358] Hardware name: QEMU Ubuntu 24.04 PC v2 (i440FX + PIIX,
arch_caps fix, 1996), BIOS 1.16.3-debian-1.16.3-2 04/01/2014
[ 29.897017] RIP: 0010:rfcomm_run+0x148f/0x3f00 [rfcomm]
[ 29.897331] Code: 08 23 00 00 49 8d 7c 24 08 49 8b 46 08 48 89 f9
48 c1 e9 03 80 3c 29 00 0f 85 da 22 00 00 48 89 c1 49 89 44 24 08 48
c1 e9 03 <80> 3c 29 00 0f 85 ad 22 00 00 4c 89 20 49 8d 7e 18 48 b8 22
01 00
[ 29.898405] RSP: 0018:ffff888111fa7cd0 EFLAGS: 00010207
[ 29.898715] RAX: 07ec008b00000056 RBX: 0000000000000003 RCX: 00fd80116000000a
[ 29.899131] RDX: 0000000000000001 RSI: 0000000000000008 RDI: ffff888111fa7c98
[ 29.899552] RBP: dffffc0000000000 R08: 0000000000000001 R09: fffffbfff4c5b440
[ 29.899970] R10: ffffffffa62da207 R11: 3d3d3d3d3d3d3d3d R12: ffff888111ef9a00
[ 29.900388] R13: ffff888100fd5300 R14: ffff888111058d00 R15: dead000000000100
[ 29.900804] FS: 0000000000000000(0000) GS:ffff88817557e000(0000)
knlGS:0000000000000000
[ 29.901278] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[ 29.901615] CR2: 00007f2f84a69b30 CR3: 0000000111c02002 CR4: 0000000000770ef0
[ 29.902032] PKRU: 55555554
[ 29.902197] Call Trace:
[ 29.902353] <TASK>
[ 29.902486] ? __pfx___set_cpus_allowed_ptr+0x10/0x10
[ 29.902787] ? __pfx_rfcomm_run+0x10/0x10 [rfcomm]
[ 29.903074] ? mutex_unlock+0x7b/0xd0
[ 29.903299] ? __pfx_mutex_unlock+0x10/0x10
[ 29.903549] ? __pfx_woken_wake_function+0x10/0x10
[ 29.903833] ? __pfx__raw_spin_lock_irqsave+0x10/0x10
[ 29.904134] ? __pfx_kthread_affine_node+0x10/0x10
[ 29.904423] ? __kthread_parkme+0x88/0x170
[ 29.904667] ? __pfx_rfcomm_run+0x10/0x10 [rfcomm]
[ 29.904952] ? __pfx_rfcomm_run+0x10/0x10 [rfcomm]
[ 29.905237] kthread+0x2c8/0x3b0
[ 29.905441] ? recalc_sigpending+0x15c/0x1e0
[ 29.905698] ? __pfx_kthread+0x10/0x10
[ 29.905924] ret_from_fork+0x36e/0x5a0
[ 29.906150] ? __pfx_ret_from_fork+0x10/0x10
[ 29.906408] ? __switch_to+0x572/0xdd0
[ 29.906636] ? __pfx_kthread+0x10/0x10
[ 29.906862] ret_from_fork_asm+0x1a/0x30
[ 29.907097] </TASK>
[ 29.907233] Modules linked in: rfcomm(-)
[ 29.907480] ---[ end trace 0000000000000000 ]---
[ 29.907757] RIP: 0010:rfcomm_run+0x148f/0x3f00 [rfcomm]
[ 29.908068] Code: 08 23 00 00 49 8d 7c 24 08 49 8b 46 08 48 89 f9
48 c1 e9 03 80 3c 29 00 0f 85 da 22 00 00 48 89 c1 49 89 44 24 08 48
c1 e9 03 <80> 3c 29 00 0f 85 ad 22 00 00 4c 89 20 49 8d 7e 18 48 b8 22
01 00
[ 29.909139] RSP: 0018:ffff888111fa7cd0 EFLAGS: 00010207
[ 29.909455] RAX: 07ec008b00000056 RBX: 0000000000000003 RCX: 00fd80116000000a
[ 29.909870] RDX: 0000000000000001 RSI: 0000000000000008 RDI: ffff888111fa7c98
[ 29.910295] RBP: dffffc0000000000 R08: 0000000000000001 R09: fffffbfff4c5b440
[ 29.910711] R10: ffffffffa62da207 R11: 3d3d3d3d3d3d3d3d R12: ffff888111ef9a00
[ 29.911128] R13: ffff888100fd5300 R14: ffff888111058d00 R15: dead000000000100
[ 29.911550] FS: 0000000000000000(0000) GS:ffff88817557e000(0000)
knlGS:0000000000000000
[ 29.912019] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[ 29.912364] CR2: 00007f2f84a69b30 CR3: 0000000111c02002 CR4: 0000000000770ef0
[ 29.912782] PKRU: 55555554
[ 29.912948] Kernel panic - not syncing: Fatal exception
[ 29.913315] Kernel Offset: 0x1f400000 from 0xffffffff81000000
(relocation range: 0xffffffff80000000-0xffffffffbfffffff)
The probably useful addr2line information is like:
### `rfcomm_run+0x3802/0x3f00 [rfcomm]`
```text
rfcomm_run+0x3802/0x3f00:
rfcomm_session_del at /home/cyeaa/linux/net/bluetooth/rfcomm/core.c:717
(inlined by) fcomm_kill_listener at
/home/cyeaa/linux/net/bluetooth/rfcomm/core.c:2175
(inlined by) fcomm_run at /home/cyeaa/linux/net/bluetooth/rfcomm/core.c:2198
```
### `rfcomm_run+0x148f/0x3f00 [rfcomm]`
```text
rfcomm_run+0x148f/0x3f00:
__list_del at /home/cyeaa/linux/./include/linux/list.h:227 (discriminator 2)
(inlined by) __list_del_entry at
/home/cyeaa/linux/./include/linux/list.h:249 (discriminator 2)
(inlined by) list_del at /home/cyeaa/linux/./include/linux/list.h:260
(discriminator 2)
(inlined by) fcomm_session_del at
/home/cyeaa/linux/net/bluetooth/rfcomm/core.c:721 (discriminator 2)
(inlined by) fcomm_kill_listener at
/home/cyeaa/linux/net/bluetooth/rfcomm/core.c:2175 (discriminator 2)
(inlined by) fcomm_run at
/home/cyeaa/linux/net/bluetooth/rfcomm/core.c:2198 (discriminator 2)
```
### `__pfx_rfcomm_run+0x10/0x10 [rfcomm]`
```text
__pfx_rfcomm_run+0x10/0x10:
rfcomm_run at /home/cyeaa/linux/net/bluetooth/rfcomm/core.c:2180
```
### `rfcomm_session_add+0xa1/0x300 [rfcomm]`
```text
rfcomm_session_add+0xa1/0x300:
_kmalloc_noprof at /home/cyeaa/linux/./include/linux/slab.h:988
(inlined by) _kzalloc_noprof at /home/cyeaa/linux/./include/linux/slab.h:1309
(inlined by) fcomm_session_add at
/home/cyeaa/linux/net/bluetooth/rfcomm/core.c:681
```
### `rfcomm_dlc_open+0x8b2/0xf30 [rfcomm]`
```text
rfcomm_dlc_open+0x8b2/0xf30:
rfcomm_session_create at /home/cyeaa/linux/net/bluetooth/rfcomm/core.c:801
(inlined by) __rfcomm_dlc_open at
/home/cyeaa/linux/net/bluetooth/rfcomm/core.c:386
(inlined by) fcomm_dlc_open at /home/cyeaa/linux/net/bluetooth/rfcomm/core.c:429
```
### `rfcomm_sock_connect+0x34c/0x530 [rfcomm]`
```text
rfcomm_sock_connect+0x34c/0x530:
lock_sock at /home/cyeaa/linux/./include/net/sock.h:1713
(inlined by) fcomm_sock_connect at
/home/cyeaa/linux/net/bluetooth/rfcomm/sock.c:422
```
### `rfcomm_dlc_open+0xab7/0xf30 [rfcomm]`
```text
rfcomm_dlc_open+0xab7/0xf30:
rfcomm_session_del at /home/cyeaa/linux/net/bluetooth/rfcomm/core.c:727
(inlined by) fcomm_session_create at
/home/cyeaa/linux/net/bluetooth/rfcomm/core.c:818
(inlined by) __rfcomm_dlc_open at
/home/cyeaa/linux/net/bluetooth/rfcomm/core.c:386
(inlined by) fcomm_dlc_open at /home/cyeaa/linux/net/bluetooth/rfcomm/core.c:429
> The locking itself is safe but I don't think the changelog currently
> describes a reachable race. There may be a more relevant unlocked
> session_list access in rfcomm_security_cfm().
Yes the commit message might be not clear enough, I am happy to make
v2 for it if you decide to fix the bug.
Best regards,
Chengfeng
[1] https://lore.kernel.org/netdev/20251128151919.576920-1-jhs@mojatatu.com/T/
^ permalink raw reply related [flat|nested] 6+ messages in thread