Linux bluetooth development
 help / color / mirror / Atom feed
* [PATCH] Bluetooth: RFCOMM: hold listener socket in rfcomm_connect_ind()
@ 2026-05-09 17:37 Zhang Cen
  2026-05-09 18:29 ` bluez.test.bot
  0 siblings, 1 reply; 2+ messages in thread
From: Zhang Cen @ 2026-05-09 17:37 UTC (permalink / raw)
  To: Marcel Holtmann, Luiz Augusto von Dentz
  Cc: linux-bluetooth, linux-kernel, zerocling0077, Zhang Cen

rfcomm_get_sock_by_channel() returns a listener from rfcomm_sk_list
after dropping rfcomm_sk_list.lock, but it does not hold a reference on
that socket. rfcomm_connect_ind() then locks the listener, queues a
child on it, and may still notify it after unlocking it.

rfcomm_connect_ind()              listener close
1. Look up the parent on          1. close() enters
   rfcomm_sk_list.                   rfcomm_sock_release().
2. Drop rfcomm_sk_list.lock       2. rfcomm_sock_shutdown()
   without pinning the listener.     starts tearing the listener down.
3. Later call lock_sock(parent),  3. rfcomm_sock_kill() unlinks the
   bt_accept_enqueue(parent, ...),   listener and drops its last
   or the deferred-setup callback.   reference.

Take a socket reference on the selected listener before leaving
rfcomm_sk_list.lock, re-check that the parent is still in BT_LISTEN
after locking it, cache the deferred-setup bit while the parent is
locked, and drop the extra reference after the last parent use in
rfcomm_connect_ind().

The buggy scenario involves two paths, with each column showing the order within that path:

  rfcomm_connect_ind():                  listener close:
  1. Call                                1. close() enters
     rfcomm_get_sock_by_channel(BT_LISTEN,       rfcomm_sock_release()
     channel, &src)
  2. Return the matched listener         2. rfcomm_sock_shutdown() runs
     after                                  the BT_LISTEN close path and
     read_unlock(&rfcomm_sk_list.lock)       rfcomm_sock_cleanup_listen(parent)
     without sock_hold()                    sets parent->sk_state =
                                            BT_CLOSED and SOCK_ZAPPED
  3. Later call lock_sock(parent)        3. rfcomm_sock_release() calls
     and bt_accept_enqueue(parent,          sock_orphan(parent) and
     sk, true)                              rfcomm_sock_kill(parent)
  4. After release_sock(parent),         4. rfcomm_sock_kill() unlinks
     read bt_sk(parent)->flags and          the listener from
     may call                               rfcomm_sk_list and sock_put()
     parent->sk_state_change(parent)        can free it

The lookup path drops rfcomm_sk_list.lock without a private reference,
so listener close can mark the socket closed, unlink it, and free it
before rfcomm_connect_ind() reaches lock_sock(), bt_accept_enqueue(), or
its deferred-setup callback.

rfcomm_lock serializes RFCOMM core work but does not serialize userspace
close against rfcomm_sock_release() or rfcomm_sock_kill().

Sanitizer validation reported:
BUG: KASAN: slab-use-after-free in lock_sock_nested()
Read of size 1 at addr ffff88810da92250
Call trace:
  dump_stack_lvl() (?:?)
  print_address_description() (mm/kasan/report.c:373)
  lock_sock_nested() (net/core/sock.c:3780)
  print_report() (?:?)
  __virt_addr_valid() (?:?)
  srso_alias_return_thunk() (arch/x86/include/asm/nospec-branch.h:375)
  kasan_addr_to_slab() (mm/kasan/common.c:45)
  kasan_report() (?:?)
  __kasan_check_byte() (mm/kasan/common.c:571)
  lock_acquire() (?:?)
  rcu_is_watching() (?:?)
  rfcomm_connect_ind() (net/bluetooth/rfcomm/sock.c:952)
  rfcomm_recv_pn() (net/bluetooth/rfcomm/core.c:1432)
  trace_clock_x86_tsc() (arch/x86/kernel/trace_clock.c:14)
  __lock_acquire() (kernel/locking/lockdep.c:5077)
  rfcomm_recv_mcc() (net/bluetooth/rfcomm/core.c:1645)
  do_raw_spin_lock() (?:?)
  mark_held_locks() (kernel/locking/lockdep.c:4308)
  rfcomm_recv_frame() (net/bluetooth/rfcomm/core.c:1738)
  rfcomm_process_rx() (net/bluetooth/rfcomm/core.c:1933)
  rfcomm_run() (net/bluetooth/rfcomm/core.c:2114)
  find_held_lock() (kernel/locking/lockdep.c:5340)
  _raw_spin_unlock_irqrestore() (kernel/locking/spinlock.c:196)
  lockdep_hardirqs_on() (?:?)
  __kthread_parkme() (kernel/kthread.c:259)
  kthread() (?:?)
  _raw_spin_unlock_irq() (kernel/locking/spinlock.c:204)
  ret_from_fork() (?:?)
  __switch_to() (?:?)
  ret_from_fork_asm() (?:?)
  kasan_save_stack() (mm/kasan/common.c:52)
  kasan_save_track() (mm/kasan/common.c:74)
  __kasan_kmalloc() (?:?)
  __kmalloc_noprof() (?:?)
  sk_prot_alloc() (net/core/sock.c:2233)
  sk_alloc() (?:?)
  bt_sock_alloc() (?:?)
  rfcomm_sock_alloc() (net/bluetooth/rfcomm/sock.c:271)
  rfcomm_sock_create() (net/bluetooth/rfcomm/sock.c:305)
  bt_sock_create() (net/bluetooth/af_bluetooth.c:116)
  __sock_create() (?:?)
  __sys_socket() (net/socket.c:1801)
  __x64_sys_socket() (?:?)
  do_syscall_64() (arch/x86/entry/syscall_64.c:87)
  entry_SYSCALL_64_after_hwframe() (?:?)
  kasan_save_free_info() (?:?)
  __kasan_slab_free() (?:?)
  kfree() (?:?)
  __sk_destruct() (net/core/sock.c:2345)
  sk_destruct() (net/core/sock.c:2402)
  __sk_free() (net/core/sock.c:2417)
  sk_free() (net/core/sock.c:2428)
  rfcomm_sock_kill() (net/bluetooth/rfcomm/sock.c:192)
  rfcomm_sock_release() (net/bluetooth/rfcomm/sock.c:912)
  __sock_release() (net/socket.c:713)

Signed-off-by: Zhang Cen <rollkingzzc@gmail.com>

---
diff --git a/net/bluetooth/rfcomm/sock.c b/net/bluetooth/rfcomm/sock.c
index be6639cd6f59..677c9cd22fb2 100644
--- a/net/bluetooth/rfcomm/sock.c
+++ b/net/bluetooth/rfcomm/sock.c
@@ -122,7 +122,7 @@ static struct sock *__rfcomm_get_listen_sock_by_addr(u8 channel, bdaddr_t *src)
 }
 
 /* Find socket with channel and source bdaddr.
- * Returns closest match.
+ * Returns closest match with an extra reference held.
  */
 static struct sock *rfcomm_get_sock_by_channel(int state, u8 channel, bdaddr_t *src)
 {
@@ -136,15 +136,25 @@ static struct sock *rfcomm_get_sock_by_channel(int state, u8 channel, bdaddr_t *
 
 		if (rfcomm_pi(sk)->channel == channel) {
 			/* Exact match. */
-			if (!bacmp(&rfcomm_pi(sk)->src, src))
+			if (!bacmp(&rfcomm_pi(sk)->src, src)) {
+				sock_hold(sk);
 				break;
+			}
 
 			/* Closest match */
-			if (!bacmp(&rfcomm_pi(sk)->src, BDADDR_ANY))
+			if (!bacmp(&rfcomm_pi(sk)->src, BDADDR_ANY)) {
+				if (sk1)
+					sock_put(sk1);
+
 				sk1 = sk;
+				sock_hold(sk1);
+			}
 		}
 	}
 
+	if (sk && sk1)
+		sock_put(sk1);
+
 	read_unlock(&rfcomm_sk_list.lock);
 
 	return sk ? sk : sk1;
@@ -934,6 +944,7 @@ int rfcomm_connect_ind(struct rfcomm_session *s, u8 channel, struct rfcomm_dlc *
 {
 	struct sock *sk, *parent;
 	bdaddr_t src, dst;
+	bool defer_setup = false;
 	int result = 0;
 
 	BT_DBG("session %p channel %d", s, channel);
@@ -947,6 +958,11 @@ int rfcomm_connect_ind(struct rfcomm_session *s, u8 channel, struct rfcomm_dlc *
 
 	lock_sock(parent);
 
+	if (parent->sk_state != BT_LISTEN)
+		goto done;
+
+	defer_setup = test_bit(BT_SK_DEFER_SETUP, &bt_sk(parent)->flags);
+
 	/* Check for backlog size */
 	if (sk_acceptq_is_full(parent)) {
 		BT_DBG("backlog full %d", parent->sk_ack_backlog);
@@ -974,9 +990,11 @@ int rfcomm_connect_ind(struct rfcomm_session *s, u8 channel, struct rfcomm_dlc *
 done:
 	release_sock(parent);
 
-	if (test_bit(BT_SK_DEFER_SETUP, &bt_sk(parent)->flags))
+	if (defer_setup)
 		parent->sk_state_change(parent);
 
+	sock_put(parent);
+
 	return result;
 }

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

* RE: Bluetooth: RFCOMM: hold listener socket in rfcomm_connect_ind()
  2026-05-09 17:37 [PATCH] Bluetooth: RFCOMM: hold listener socket in rfcomm_connect_ind() Zhang Cen
@ 2026-05-09 18:29 ` bluez.test.bot
  0 siblings, 0 replies; 2+ messages in thread
From: bluez.test.bot @ 2026-05-09 18:29 UTC (permalink / raw)
  To: linux-bluetooth, rollkingzzc

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

---Test result---

Test Summary:
CheckPatch                    FAIL      0.77 seconds
GitLint                       FAIL      0.34 seconds
SubjectPrefix                 PASS      0.13 seconds
BuildKernel                   PASS      24.98 seconds
CheckAllWarning               PASS      27.45 seconds
CheckSparse                   PASS      26.44 seconds
BuildKernel32                 PASS      24.22 seconds
TestRunnerSetup               PASS      518.00 seconds
TestRunner_rfcomm-tester      PASS      63.49 seconds
IncrementalBuild              PASS      23.77 seconds

Details
##############################
Test: CheckPatch - FAIL
Desc: Run checkpatch.pl script
Output:
Bluetooth: RFCOMM: hold listener socket in rfcomm_connect_ind()
WARNING: Prefer a maximum 75 chars per line (possible unwrapped commit description?)
#119: 
The buggy scenario involves two paths, with each column showing the order within that path:

WARNING: The commit message has 'BUG: KASAN: ', perhaps it also needs a 'Fixes:' tag?

total: 0 errors, 2 warnings, 0 checks, 65 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/14563150.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: RFCOMM: hold listener socket in rfcomm_connect_ind()

WARNING: I3 - ignore-body-lines: gitlint will be switching from using Python regex 'match' (match beginning) to 'search' (match anywhere) semantics. Please review your ignore-body-lines.regex option accordingly. To remove this warning, set general.regex-style-search=True. More details: https://jorisroovers.github.io/gitlint/configuration/#regex-style-search
23: B1 Line exceeds max length (91>80): "The buggy scenario involves two paths, with each column showing the order within that path:"


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

---
Regards,
Linux Bluetooth


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

end of thread, other threads:[~2026-05-09 18:29 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-05-09 17:37 [PATCH] Bluetooth: RFCOMM: hold listener socket in rfcomm_connect_ind() Zhang Cen
2026-05-09 18:29 ` bluez.test.bot

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