Re: [PATCH] Bluetooth: RFCOMM: serialize session teardown

Pauli Virtanen <[email protected]>
Newsgroups org.kernel.vger.linux-bluetooth,org.kernel.vger.linux-kernel
Message-ID <[email protected]>
Hi,

la, 2026-08-22 kello 01:45 +0800, Chengfeng Ye kirjoitti:
> rfcomm_kill_listener() walks session_list and deletes every session
> without holding rfcomm_mutex.  A connect task holds that mutex while
> rfcomm_session_create() adds a session and while its error path deletes
> the session, but the unlocked teardown can still observe the object
> between those operations.

Reviewed-by: Pauli Virtanen <[email protected]>

While looking at these locking bugs, please also consider using LLVM
context analysis to globally audit the locking of the structure, to
catch the other related data races:

https://docs.kernel.org/dev-tools/context-analysis.html
https://mirrors.edge.kernel.org/pub/tools/llvm/

I think adding the annotations probably should usually go in separate
patch to make backporting of the fix easier.

For example, adding here:

diff --git a/net/bluetooth/rfcomm/core.c b/net/bluetooth/rfcomm/core.c
index 0e496b85e6ce..6b5c44f0d89a 100644
--- a/net/bluetooth/rfcomm/core.c
+++ b/net/bluetooth/rfcomm/core.c
@@ -47,7 +47,7 @@ static DEFINE_MUTEX(rfcomm_mutex);
 #define rfcomm_unlock()        mutex_unlock(&rfcomm_mutex)
 
 
-static LIST_HEAD(session_list);
+static __guarded_by(&rfcomm_mutex) LIST_HEAD(session_list);
 
 static int rfcomm_send_frame(struct rfcomm_session *s, u8 *data, int len);
 static int rfcomm_send_sabm(struct rfcomm_session *s, u8 dlci);
@@ -676,6 +676,7 @@ int rfcomm_dlc_get_modem_status(struct rfcomm_dlc *d, u8 *v24_sig)
 
 /* ---- RFCOMM sessions ---- */
 static struct rfcomm_session *rfcomm_session_add(struct socket *sock, int state)
+       __must_hold(&rfcomm_mutex)
 {
        struct rfcomm_session *s = kzalloc_obj(*s);
 
plus other __must_hold(&rfcomm_mutex) annotations to functions where
needed, compiler warnings show the session_list is accessed without
holding rfcomm_mutex also from

rfcomm_run() -> rfcomm_session_add()

rfcomm_security_cfm() -> rfcomm_session_get()

Are these reachable? Former is probably theoretical, the latter could
be reachable. Also if unreachable, in my view, taking the lock may be
better than relying on a possibly brittle and hard to understand
invariant to protect the access.

> 
> The race can proceed as follows:
> 
>   connect task                    krfcommd
>   ------------                    --------
>   rfcomm_lock()
>   rfcomm_session_add()
>                                   fetch session from session_list
>   kernel_connect() fails
>   rfcomm_session_del()
>     remove and free session
>                                   rfcomm_session_del(session)
> 
> The final call then reads the freed session and may corrupt the list.
> 
> KASAN reported:
> 
>   BUG: KASAN: slab-use-after-free in rfcomm_session_del+0x15f/0x170
>   Read of size 8 at addr ffff8881019e9b40 by task krfcommd/87
>   Call Trace:
>    rfcomm_session_del+0x15f/0x170
>    rfcomm_run+0x16d5/0x3de0
>    kthread+0x2c6/0x3b0
>    ret_from_fork+0x36e/0x5a0
>   Allocated by task 96:
>    rfcomm_session_add+0x9e/0x300
>    rfcomm_dlc_open+0x8b1/0xdf0
>    rfcomm_sock_connect+0x34c/0x530
>   Freed by task 96:
>    kfree+0x131/0x3c0
>    rfcomm_session_del+0x109/0x170
>    rfcomm_dlc_open+0x9eb/0xdf0
>    rfcomm_sock_connect+0x34c/0x530
> 
> Hold rfcomm_mutex across the teardown traversal, matching the locking
> used by normal session processing and connect error cleanup.
> 
> Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
> Cc: [email protected]
> Signed-off-by: Chengfeng Ye <[email protected]>
> ---
>  net/bluetooth/rfcomm/core.c | 2 ++
>  1 file changed, 2 insertions(+)
> 
> diff --git a/net/bluetooth/rfcomm/core.c b/net/bluetooth/rfcomm/core.c
> index 9cdfea666a2c..5fe2758e8c47 100644
> --- a/net/bluetooth/rfcomm/core.c
> +++ b/net/bluetooth/rfcomm/core.c
> @@ -2178,8 +2178,10 @@ static void rfcomm_kill_listener(void)
>  
>  	BT_DBG("");
>  
> +	rfcomm_lock();
>  	list_for_each_entry_safe(s, n, &session_list, list)
>  		rfcomm_session_del(s);
> +	rfcomm_unlock();
>  }
>  
>  static int rfcomm_run(void *unused)

-- 
Pauli Virtanen
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.