From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mail-pl1-f195.google.com (mail-pl1-f195.google.com [209.85.214.195]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id D204239C00A for ; Sat, 9 May 2026 17:37:42 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.214.195 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1778348264; cv=none; b=ISGwR2xfsLbvKEe8Bh0X2n8u+w5m5NjeGWO1jSQfIGn5pjQnz7Z9xzKtML5+GSMozOndQLokPj3Dh5+gjx3C+cWAMWVAtVZbnzYddlRWA18I6TgN+Vcf5IziU5NGm5zqMCkln+E0/LNP1XlpCkdddsT4SfZhFRzLB13likavHcU= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1778348264; c=relaxed/simple; bh=I7t5q5hv4eMLevE6KOcpV5PBeoi1BPFTA3lfTL1x0R8=; h=From:To:Cc:Subject:Date:Message-Id:MIME-Version; b=u3RORJH370yDHuOEkRP3AHyF0PgkaStZpuJMeXqDincP0orhV+2XJd+quwPGZFJMBUYgkCTFTB3YWOo7HR9nws95WXUSskER4skxYm4M/Z/znj0tfdEAFVmE5w5ET8/dEYOfHga4oEEvXbzN/9LFrpBpQSol6x6zU7Mg/I3FHDM= ARC-Authentication-Results:i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=QOGlVw/y; arc=none smtp.client-ip=209.85.214.195 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="QOGlVw/y" Received: by mail-pl1-f195.google.com with SMTP id d9443c01a7336-2baef9f5ecdso13159645ad.1 for ; Sat, 09 May 2026 10:37:42 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1778348262; x=1778953062; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:message-id:date:subject:cc :to:from:from:to:cc:subject:date:message-id:reply-to; bh=mw3B+YxDKfj8tFV2xTgPlRdOE16ht898X2ckp1lDjzQ=; b=QOGlVw/yH2Ga4v2Aa1v3BLqy8v9BAEFe2VMttCytfKEB9JhkB/wF8FwP3O1Fvb6rHs wu59q+sjgClY0c4q7OVPLlODWLCdRFiILy5cUXs1KPGg9ldpxJCJAp1ksalzaWZpoDm8 hpboFW9cw3cR/kdc9NzEaja8fEIoITXET4MGq+AzAvt6fJ06RAy0JqGSi9zJTLbRoWM7 FnOOriJ0LB6AJ5AhIekIHO/HN6RF9lg2/DZdmDDaeN2pKArK/FAeuvxeDd0wZq8DO6kU bhnNOukJ4x/9cjcKiDiwWgGVHaVlRV6HfVum9WH3VY1QtkdbPvjLkFAlQU2XbFW5jZfc w8VQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1778348262; x=1778953062; h=content-transfer-encoding:mime-version:message-id:date:subject:cc :to:from:x-gm-gg:x-gm-message-state:from:to:cc:subject:date :message-id:reply-to; bh=mw3B+YxDKfj8tFV2xTgPlRdOE16ht898X2ckp1lDjzQ=; b=GimVfcOxn+/e5uVOP3Qjc9YOWHhmcSkJqiA7LzLvjSQCIDIkZ8UM3wxznyfg2/to2s wLnLV7S+3aIx+YOg8Q+o7zocYyXPnR+vwfFj9w/D0eGTPkEuH61NaYOrYsFvlzFBJ2W/ vWx8ZwE3dzBr+3hYzIK00lDF5uOXi4heAs68P7yoT3EtAOIUpX6wdCQwfGPhgmj3e3GE pCe5vdMNjdSQ04NvbcSESlsK7Xr2vhTBt2n8VCBklEKpaPE63kkPr0a+RueS2EHoFusX JDIbMx5RqcGCkrd3jBr7gCivD80xO9qyZa9qI9vchJQ2cLm6TL9bYgtE+DjCnDWy3lT1 l57A== X-Forwarded-Encrypted: i=1; AFNElJ/y9QfLpWcaHvTH4cwPJvYl1Mpx8CAd+ukkmYRAprj0jaxLnNzH6Nnr6J/WoVrnQEMyG+2+nWAVdYsVuN4=@vger.kernel.org X-Gm-Message-State: AOJu0Yzrod/Mo8Otx1+IlRdsk6xyOPHlncmVIHgrdd5NWImim9Shl0FX RsoFwfPEWZ41jg7B4axLKnhOEe+B/9Txm/mKd/zuveAGvEELubYBwTOE X-Gm-Gg: Acq92OHVYtU5G5cMfGPO8sXc/i6qQbly71OmXxm3xeSNjDe5zCruFxGhtEaqi+P9GBX /88zrRNW14NGKPmLVnnk4CpapFvny9I6239vr5QH96H4mJTBy+UUlcoQuutqihyNzjVWZmM3xVP rX9wOHs0QU8jQchqD6SILo3uIXs2Y0VxQ2xOe1OfJHPuVY7Qk70b6P2/pW/xoViQ34546OM4gyb jcvX5bbxp+JlciQu8HPBpHIkx22CAd9qhIjxCv86gsasrRT7j5Yyfavh32PoeUcGcK7jaNGr5Xx EcWu9uo9aqAeyULKS7W0au4DUGau0chgAcZ7Gm5ZJU+3vuk3Hc8knVvs1vRw/XRwYPilBAicEnL Io4So1tMxOjVestyLw5JJqzDrVhfvKozQ1ajuB2GCysHO8Jcqvlh3Vnb/TA8DmLa2dojK96UTfR VmWmVZL6rJZGNjW08UqO4zOlP3XMKKRY7sIqosCZFJjw== X-Received: by 2002:a17:903:1446:b0:2b7:aba0:ac10 with SMTP id d9443c01a7336-2bc7a99c150mr28136335ad.11.1778348261984; Sat, 09 May 2026 10:37:41 -0700 (PDT) Received: from localhost ([111.228.63.84]) by smtp.gmail.com with ESMTPSA id d9443c01a7336-2baf1ec232esm58010745ad.81.2026.05.09.10.37.35 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sat, 09 May 2026 10:37:41 -0700 (PDT) From: Zhang Cen To: Marcel Holtmann , Luiz Augusto von Dentz Cc: linux-bluetooth@vger.kernel.org, linux-kernel@vger.kernel.org, zerocling0077@gmail.com, Zhang Cen Subject: [PATCH] Bluetooth: RFCOMM: hold listener socket in rfcomm_connect_ind() Date: Sun, 10 May 2026 01:37:27 +0800 Message-Id: <20260509173727.412674-1-rollkingzzc@gmail.com> X-Mailer: git-send-email 2.34.1 Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: 8bit 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 --- 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; }