* [RESEND] Bluetooth: L2CAP: Fix use-after-free in l2cap_unregister_user
@ 2026-03-06 21:04 Luiz Augusto von Dentz
2026-03-06 21:48 ` bluez.test.bot
` (2 more replies)
0 siblings, 3 replies; 11+ messages in thread
From: Luiz Augusto von Dentz @ 2026-03-06 21:04 UTC (permalink / raw)
To: linux-bluetooth
From: Shaurya Rane <ssrane_b23@ee.vjti.ac.in>
After commit ab4eedb790ca ("Bluetooth: L2CAP: Fix corrupted list in
hci_chan_del"), l2cap_conn_del() uses conn->lock to protect access to
conn->users and conn->hchan. However, l2cap_register_user() and
l2cap_unregister_user() still use hci_dev_lock(), creating a race
condition where these functions can access conn->users and conn->hchan
concurrently with l2cap_conn_del().
This can lead to use-after-free and list corruption bugs, as reported
by syzbot.
Fix this by changing l2cap_register_user() and l2cap_unregister_user()
to use conn->lock instead of hci_dev_lock(), ensuring consistent locking
for the l2cap_conn structure.
Reported-by: syzbot+14b6d57fb728e27ce23c@syzkaller.appspotmail.com
Closes: https://syzkaller.appspot.com/bug?extid=14b6d57fb728e27ce23c
Fixes: ab4eedb790ca ("Bluetooth: L2CAP: Fix corrupted list in hci_chan_del")
Signed-off-by: Shaurya Rane <ssrane_b23@ee.vjti.ac.in>
Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
---
net/bluetooth/l2cap_core.c | 20 ++++++++------------
1 file changed, 8 insertions(+), 12 deletions(-)
diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
index 14131e427efd..6606d7f12534 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -1678,17 +1678,15 @@ static void l2cap_info_timeout(struct work_struct *work)
int l2cap_register_user(struct l2cap_conn *conn, struct l2cap_user *user)
{
- struct hci_dev *hdev = conn->hcon->hdev;
int ret;
/* We need to check whether l2cap_conn is registered. If it is not, we
- * must not register the l2cap_user. l2cap_conn_del() is unregisters
- * l2cap_conn objects, but doesn't provide its own locking. Instead, it
- * relies on the parent hci_conn object to be locked. This itself relies
- * on the hci_dev object to be locked. So we must lock the hci device
- * here, too. */
+ * must not register the l2cap_user. l2cap_conn_del() unregisters
+ * l2cap_conn objects under conn->lock, and we use the same lock here
+ * to protect access to conn->users and conn->hchan.
+ */
- hci_dev_lock(hdev);
+ mutex_lock(&conn->lock);
if (!list_empty(&user->list)) {
ret = -EINVAL;
@@ -1709,16 +1707,14 @@ int l2cap_register_user(struct l2cap_conn *conn, struct l2cap_user *user)
ret = 0;
out_unlock:
- hci_dev_unlock(hdev);
+ mutex_unlock(&conn->lock);
return ret;
}
EXPORT_SYMBOL(l2cap_register_user);
void l2cap_unregister_user(struct l2cap_conn *conn, struct l2cap_user *user)
{
- struct hci_dev *hdev = conn->hcon->hdev;
-
- hci_dev_lock(hdev);
+ mutex_lock(&conn->lock);
if (list_empty(&user->list))
goto out_unlock;
@@ -1727,7 +1723,7 @@ void l2cap_unregister_user(struct l2cap_conn *conn, struct l2cap_user *user)
user->remove(conn, user);
out_unlock:
- hci_dev_unlock(hdev);
+ mutex_unlock(&conn->lock);
}
EXPORT_SYMBOL(l2cap_unregister_user);
--
2.53.0
^ permalink raw reply related [flat|nested] 11+ messages in thread* RE: [RESEND] Bluetooth: L2CAP: Fix use-after-free in l2cap_unregister_user 2026-03-06 21:04 [RESEND] Bluetooth: L2CAP: Fix use-after-free in l2cap_unregister_user Luiz Augusto von Dentz @ 2026-03-06 21:48 ` bluez.test.bot 2026-03-07 8:59 ` Pauli Virtanen 2026-03-09 15:30 ` patchwork-bot+bluetooth 2 siblings, 0 replies; 11+ messages in thread From: bluez.test.bot @ 2026-03-06 21:48 UTC (permalink / raw) To: linux-bluetooth, luiz.dentz [-- Attachment #1: Type: text/plain, Size: 2961 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=1062836 ---Test result--- Test Summary: CheckPatch PENDING 0.51 seconds GitLint PENDING 0.44 seconds SubjectPrefix PASS 0.08 seconds BuildKernel PASS 26.18 seconds CheckAllWarning PASS 29.05 seconds CheckSparse WARNING 32.13 seconds BuildKernel32 PASS 25.48 seconds TestRunnerSetup PASS 565.63 seconds TestRunner_l2cap-tester PASS 28.95 seconds TestRunner_iso-tester PASS 92.74 seconds TestRunner_bnep-tester PASS 6.44 seconds TestRunner_mgmt-tester FAIL 126.51 seconds TestRunner_rfcomm-tester PASS 9.78 seconds TestRunner_sco-tester FAIL 17.73 seconds TestRunner_ioctl-tester PASS 10.34 seconds TestRunner_mesh-tester FAIL 11.69 seconds TestRunner_smp-tester PASS 8.63 seconds TestRunner_userchan-tester PASS 6.67 seconds IncrementalBuild PENDING 0.53 seconds Details ############################## Test: CheckPatch - PENDING Desc: Run checkpatch.pl script Output: ############################## Test: GitLint - PENDING Desc: Run gitlint Output: ############################## Test: CheckSparse - WARNING Desc: Run sparse tool with linux kernel Output: net/bluetooth/l2cap_core.c:7788:1: error: bad constant expressionnet/bluetooth/l2cap_core.c:7789:1: error: bad constant expressionnet/bluetooth/l2cap_core.c:7791:1: error: bad constant expressionnet/bluetooth/l2cap_core.c:7792:1: error: bad constant expression ############################## Test: TestRunner_mgmt-tester - FAIL Desc: Run mgmt-tester with test-runner Output: Total: 494, Passed: 489 (99.0%), Failed: 1, Not Run: 4 Failed Test Cases Read Exp Feature - Success Failed 0.110 seconds ############################## Test: TestRunner_sco-tester - FAIL Desc: Run sco-tester with test-runner Output: WARNING: possible circular locking dependency detected BUG: sleeping function called from invalid context at net/core/sock.c:3782 Total: 30, Passed: 30 (100.0%), Failed: 0, Not Run: 0 ############################## Test: TestRunner_mesh-tester - FAIL Desc: Run mesh-tester with test-runner Output: Total: 10, Passed: 8 (80.0%), Failed: 2, Not Run: 0 Failed Test Cases Mesh - Send cancel - 1 Timed out 1.852 seconds Mesh - Send cancel - 2 Timed out 1.996 seconds ############################## Test: IncrementalBuild - PENDING Desc: Incremental build with the patches in the series Output: --- Regards, Linux Bluetooth ^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [RESEND] Bluetooth: L2CAP: Fix use-after-free in l2cap_unregister_user 2026-03-06 21:04 [RESEND] Bluetooth: L2CAP: Fix use-after-free in l2cap_unregister_user Luiz Augusto von Dentz 2026-03-06 21:48 ` bluez.test.bot @ 2026-03-07 8:59 ` Pauli Virtanen 2026-03-07 9:33 ` [syzbot] [bluetooth?] KASAN: slab-use-after-free Read " syzbot ` (2 more replies) 2026-03-09 15:30 ` patchwork-bot+bluetooth 2 siblings, 3 replies; 11+ messages in thread From: Pauli Virtanen @ 2026-03-07 8:59 UTC (permalink / raw) To: linux-bluetooth; +Cc: syzbot+14b6d57fb728e27ce23c [-- Attachment #1: Type: text/plain, Size: 3794 bytes --] pe, 2026-03-06 kello 16:04 -0500, Luiz Augusto von Dentz kirjoitti: > From: Shaurya Rane <ssrane_b23@ee.vjti.ac.in> > > After commit ab4eedb790ca ("Bluetooth: L2CAP: Fix corrupted list in > hci_chan_del"), l2cap_conn_del() uses conn->lock to protect access to > conn->users and conn->hchan. However, l2cap_register_user() and > l2cap_unregister_user() still use hci_dev_lock(), creating a race > condition where these functions can access conn->users and conn->hchan > concurrently with l2cap_conn_del(). AFAIK the above text from the original submitter is a bit inaccurate, as l2cap_conn_del() is called with hdev lock held, so conn->users/hchan should be safe. However, using conn->mutex should fix the use-after-free in conn->hcon->hdev hci_dev_lock(hdev); hci_dev_unlock(hdev); by making l2cap_unregister_user() safe to call after the hcon/hdev are no longer alive. The change looks OK to me, but probably worth to double check with syzbot it fixes the original issue #syz test git://git.kernel.org/pub/scm/linux/kernel/git/bluetooth/bluetooth-next.git master > This can lead to use-after-free and list corruption bugs, as reported > by syzbot. > > Fix this by changing l2cap_register_user() and l2cap_unregister_user() > to use conn->lock instead of hci_dev_lock(), ensuring consistent locking > for the l2cap_conn structure. > Reported-by: syzbot+14b6d57fb728e27ce23c@syzkaller.appspotmail.com > Closes: https://syzkaller.appspot.com/bug?extid=14b6d57fb728e27ce23c > Fixes: ab4eedb790ca ("Bluetooth: L2CAP: Fix corrupted list in hci_chan_del") > Signed-off-by: Shaurya Rane <ssrane_b23@ee.vjti.ac.in> > Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com> > --- > net/bluetooth/l2cap_core.c | 20 ++++++++------------ > 1 file changed, 8 insertions(+), 12 deletions(-) > > diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c > index 14131e427efd..6606d7f12534 100644 > --- a/net/bluetooth/l2cap_core.c > +++ b/net/bluetooth/l2cap_core.c > @@ -1678,17 +1678,15 @@ static void l2cap_info_timeout(struct work_struct *work) > > int l2cap_register_user(struct l2cap_conn *conn, struct l2cap_user *user) > { > - struct hci_dev *hdev = conn->hcon->hdev; > int ret; > > /* We need to check whether l2cap_conn is registered. If it is not, we > - * must not register the l2cap_user. l2cap_conn_del() is unregisters > - * l2cap_conn objects, but doesn't provide its own locking. Instead, it > - * relies on the parent hci_conn object to be locked. This itself relies > - * on the hci_dev object to be locked. So we must lock the hci device > - * here, too. */ > + * must not register the l2cap_user. l2cap_conn_del() unregisters > + * l2cap_conn objects under conn->lock, and we use the same lock here > + * to protect access to conn->users and conn->hchan. > + */ > > - hci_dev_lock(hdev); > + mutex_lock(&conn->lock); > > if (!list_empty(&user->list)) { > ret = -EINVAL; > @@ -1709,16 +1707,14 @@ int l2cap_register_user(struct l2cap_conn *conn, struct l2cap_user *user) > ret = 0; > > out_unlock: > - hci_dev_unlock(hdev); > + mutex_unlock(&conn->lock); > return ret; > } > EXPORT_SYMBOL(l2cap_register_user); > > void l2cap_unregister_user(struct l2cap_conn *conn, struct l2cap_user *user) > { > - struct hci_dev *hdev = conn->hcon->hdev; > - > - hci_dev_lock(hdev); > + mutex_lock(&conn->lock); > > if (list_empty(&user->list)) > goto out_unlock; > @@ -1727,7 +1723,7 @@ void l2cap_unregister_user(struct l2cap_conn *conn, struct l2cap_user *user) > user->remove(conn, user); > > out_unlock: > - hci_dev_unlock(hdev); > + mutex_unlock(&conn->lock); > } > EXPORT_SYMBOL(l2cap_unregister_user); > [-- Attachment #2: 0001-Bluetooth-L2CAP-Fix-use-after-free-in-l2cap_unregist.patch --] [-- Type: text/x-patch, Size: 3220 bytes --] From 2d0e9ce3888e494c12324c0f682900d9f61d5eb2 Mon Sep 17 00:00:00 2001 Message-ID: <2d0e9ce3888e494c12324c0f682900d9f61d5eb2.1772873329.git.pav@iki.fi> From: Shaurya Rane <ssrane_b23@ee.vjti.ac.in> Date: Fri, 6 Mar 2026 16:04:27 -0500 Subject: [PATCH] Bluetooth: L2CAP: Fix use-after-free in l2cap_unregister_user To: linux-bluetooth@vger.kernel.org After commit ab4eedb790ca ("Bluetooth: L2CAP: Fix corrupted list in hci_chan_del"), l2cap_conn_del() uses conn->lock to protect access to conn->users and conn->hchan. However, l2cap_register_user() and l2cap_unregister_user() still use hci_dev_lock(), creating a race condition where these functions can access conn->users and conn->hchan concurrently with l2cap_conn_del(). This can lead to use-after-free and list corruption bugs, as reported by syzbot. Fix this by changing l2cap_register_user() and l2cap_unregister_user() to use conn->lock instead of hci_dev_lock(), ensuring consistent locking for the l2cap_conn structure. Reported-by: syzbot+14b6d57fb728e27ce23c@syzkaller.appspotmail.com Closes: https://syzkaller.appspot.com/bug?extid=14b6d57fb728e27ce23c Fixes: ab4eedb790ca ("Bluetooth: L2CAP: Fix corrupted list in hci_chan_del") Signed-off-by: Shaurya Rane <ssrane_b23@ee.vjti.ac.in> Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com> --- net/bluetooth/l2cap_core.c | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 14131e427efd..6606d7f12534 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -1678,17 +1678,15 @@ static void l2cap_info_timeout(struct work_struct *work) int l2cap_register_user(struct l2cap_conn *conn, struct l2cap_user *user) { - struct hci_dev *hdev = conn->hcon->hdev; int ret; /* We need to check whether l2cap_conn is registered. If it is not, we - * must not register the l2cap_user. l2cap_conn_del() is unregisters - * l2cap_conn objects, but doesn't provide its own locking. Instead, it - * relies on the parent hci_conn object to be locked. This itself relies - * on the hci_dev object to be locked. So we must lock the hci device - * here, too. */ + * must not register the l2cap_user. l2cap_conn_del() unregisters + * l2cap_conn objects under conn->lock, and we use the same lock here + * to protect access to conn->users and conn->hchan. + */ - hci_dev_lock(hdev); + mutex_lock(&conn->lock); if (!list_empty(&user->list)) { ret = -EINVAL; @@ -1709,16 +1707,14 @@ int l2cap_register_user(struct l2cap_conn *conn, struct l2cap_user *user) ret = 0; out_unlock: - hci_dev_unlock(hdev); + mutex_unlock(&conn->lock); return ret; } EXPORT_SYMBOL(l2cap_register_user); void l2cap_unregister_user(struct l2cap_conn *conn, struct l2cap_user *user) { - struct hci_dev *hdev = conn->hcon->hdev; - - hci_dev_lock(hdev); + mutex_lock(&conn->lock); if (list_empty(&user->list)) goto out_unlock; @@ -1727,7 +1723,7 @@ void l2cap_unregister_user(struct l2cap_conn *conn, struct l2cap_user *user) user->remove(conn, user); out_unlock: - hci_dev_unlock(hdev); + mutex_unlock(&conn->lock); } EXPORT_SYMBOL(l2cap_unregister_user); -- 2.53.0 ^ permalink raw reply related [flat|nested] 11+ messages in thread
* Re: [syzbot] [bluetooth?] KASAN: slab-use-after-free Read in l2cap_unregister_user 2026-03-07 8:59 ` Pauli Virtanen @ 2026-03-07 9:33 ` syzbot 2026-03-07 9:45 ` [RESEND] Bluetooth: L2CAP: Fix use-after-free " Pauli Virtanen 2026-03-09 15:34 ` Luiz Augusto von Dentz 2 siblings, 0 replies; 11+ messages in thread From: syzbot @ 2026-03-07 9:33 UTC (permalink / raw) To: linux-bluetooth, linux-kernel, pav, syzkaller-bugs Hello, syzbot tried to test the proposed patch but the build/boot failed: can't ssh into the instance failed to run ["ssh" "-p" "22" "-F" "/dev/null" "-o" "UserKnownHostsFile=/dev/null" "-o" "IdentitiesOnly=yes" "-o" "BatchMode=yes" "-o" "StrictHostKeyChecking=no" "-o" "ConnectTimeout=10" "root@10.128.1.205" "pwd"]: exit status 255Pseudo-terminal will not be allocated because stdin is not a terminal. Warning: Permanently added '[us-central1-ssh-serialport.googleapis.com]:9600' (ECDSA) to the list of known hosts. UEFI firmware (version built at 09:00:00 on Jan 10 2025) EMU Variable FVB Started EMU Variable invalid PCD sizes Found PL031 RTC @ 0x9010000 InitializeRealTimeClock: using default timezone/daylight settings ^[[2J^[[01;01H^[[=3h^[[2J^[[01;01H^[[2J^[[01;01H^[[=3h^[[2J^[[01;01HBdsDxe: loading Boot0001 "UEFI Misc Device" from PciRoot(0x0)/Pci(0x2,0x0)/NVMe(0x1,00-00-00-00-00-00-00-00) BdsDxe: starting Boot0001 "UEFI Misc Device" from PciRoot(0x0)/Pci(0x2,0x0)/NVMe(0x1,00-00-00-00-00-00-00-00) UEFI: Attempting to start image. Description: UEFI Misc Device FilePath: PciRoot(0x0)/Pci(0x2,0x0)/NVMe(0x1,00-00-00-00-00-00-00-00) OptionNumber: 1. Booting `syzkaller' serialport: Connected to syzkaller.us-central1-a.ci-upstream-gce-arm64-test-job-parallel-1 port 1 (session ID: 0999632978e2591e762757af145c8d34989ebc3ddb04e2e60c08a78fd4beda56, active connections: 1). syzkaller build log: go env (err=<nil>) AR='ar' CC='gcc' CGO_CFLAGS='-O2 -g' CGO_CPPFLAGS='' CGO_CXXFLAGS='-O2 -g' CGO_ENABLED='1' CGO_FFLAGS='-O2 -g' CGO_LDFLAGS='-O2 -g' CXX='g++' GCCGO='gccgo' GO111MODULE='auto' GOAMD64='v1' GOARCH='amd64' GOAUTH='netrc' GOBIN='' GOCACHE='/syzkaller/.cache/go-build' GOCACHEPROG='' GODEBUG='' GOENV='/syzkaller/.config/go/env' GOEXE='' GOEXPERIMENT='' GOFIPS140='off' GOFLAGS='' GOGCCFLAGS='-fPIC -m64 -pthread -Wl,--no-gc-sections -fmessage-length=0 -ffile-prefix-map=/tmp/go-build2562130928=/tmp/go-build -gno-record-gcc-switches' GOHOSTARCH='amd64' GOHOSTOS='linux' GOINSECURE='' GOMOD='/syzkaller/jobs-2/linux/gopath/src/github.com/google/syzkaller/go.mod' GOMODCACHE='/syzkaller/jobs-2/linux/gopath/pkg/mod' GONOPROXY='' GONOSUMDB='' GOOS='linux' GOPATH='/syzkaller/jobs-2/linux/gopath' GOPRIVATE='' GOPROXY='https://proxy.golang.org,direct' GOROOT='/usr/local/go' GOSUMDB='sum.golang.org' GOTELEMETRY='local' GOTELEMETRYDIR='/syzkaller/.config/go/telemetry' GOTMPDIR='' GOTOOLCHAIN='auto' GOTOOLDIR='/usr/local/go/pkg/tool/linux_amd64' GOVCS='' GOVERSION='go1.26.0' GOWORK='' PKG_CONFIG='pkg-config' git status (err=<nil>) HEAD detached at c06e8995d7 nothing to commit, working tree clean tput: No value for $TERM and no -T specified tput: No value for $TERM and no -T specified Makefile:31: run command via tools/syz-env for best compatibility, see: Makefile:32: https://github.com/google/syzkaller/blob/master/docs/contributing.md#using-syz-env go list -f '{{.Stale}}' ./sys/syz-sysgen | grep -q false || go install ./sys/syz-sysgen make .descriptions tput: No value for $TERM and no -T specified tput: No value for $TERM and no -T specified Makefile:31: run command via tools/syz-env for best compatibility, see: Makefile:32: https://github.com/google/syzkaller/blob/master/docs/contributing.md#using-syz-env bin/syz-sysgen touch .descriptions GOOS=linux GOARCH=arm64 go build -ldflags="-s -w -X github.com/google/syzkaller/prog.GitRevision=c06e8995d711b5a8d8fbd771826fcbfdac6f110f -X github.com/google/syzkaller/prog.gitRevisionDate=20250811-165554" -o ./bin/linux_arm64/syz-execprog github.com/google/syzkaller/tools/syz-execprog mkdir -p ./bin/linux_arm64 aarch64-linux-gnu-g++ -o ./bin/linux_arm64/syz-executor executor/executor.cc \ -O2 -pthread -Wall -Werror -Wparentheses -Wunused-const-variable -Wframe-larger-than=16384 -Wno-stringop-overflow -Wno-array-bounds -Wno-format-overflow -Wno-unused-but-set-variable -Wno-unused-command-line-argument -static-pie -std=c++17 -I. -Iexecutor/_include -DGOOS_linux=1 -DGOARCH_arm64=1 \ -DHOSTGOOS_linux=1 -DGIT_REVISION=\"c06e8995d711b5a8d8fbd771826fcbfdac6f110f\" /usr/lib/gcc-cross/aarch64-linux-gnu/14/../../../../aarch64-linux-gnu/bin/ld: /tmp/ccd7e8uY.o: in function `Connection::Connect(char const*, char const*)': executor.cc:(.text._ZN10Connection7ConnectEPKcS1_[_ZN10Connection7ConnectEPKcS1_]+0x2ec): warning: Using 'gethostbyname' in statically linked applications requires at runtime the shared libraries from the glibc version used for linking Tested on: commit: 708efc5f Bluetooth: HIDP: Fix possible UAF git tree: git://git.kernel.org/pub/scm/linux/kernel/git/bluetooth/bluetooth-next.git master kernel config: https://syzkaller.appspot.com/x/.config?x=de187e3c06ea9a2b dashboard link: https://syzkaller.appspot.com/bug?extid=14b6d57fb728e27ce23c compiler: Debian clang version 21.1.8 (++20251221033036+2078da43e25a-1~exp1~20251221153213.50), Debian LLD 21.1.8 userspace arch: arm64 patch: https://syzkaller.appspot.com/x/patch.diff?x=11b8075a580000 ^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [RESEND] Bluetooth: L2CAP: Fix use-after-free in l2cap_unregister_user 2026-03-07 8:59 ` Pauli Virtanen 2026-03-07 9:33 ` [syzbot] [bluetooth?] KASAN: slab-use-after-free Read " syzbot @ 2026-03-07 9:45 ` Pauli Virtanen 2026-03-07 10:22 ` [syzbot] [bluetooth?] KASAN: slab-use-after-free Read " syzbot 2026-03-07 10:32 ` [RESEND] Bluetooth: L2CAP: Fix use-after-free " Pauli Virtanen 2026-03-09 15:34 ` Luiz Augusto von Dentz 2 siblings, 2 replies; 11+ messages in thread From: Pauli Virtanen @ 2026-03-07 9:45 UTC (permalink / raw) To: linux-bluetooth; +Cc: syzbot+14b6d57fb728e27ce23c [-- Attachment #1: Type: text/plain, Size: 4052 bytes --] la, 2026-03-07 kello 10:59 +0200, Pauli Virtanen kirjoitti: > pe, 2026-03-06 kello 16:04 -0500, Luiz Augusto von Dentz kirjoitti: > > From: Shaurya Rane <ssrane_b23@ee.vjti.ac.in> > > > > After commit ab4eedb790ca ("Bluetooth: L2CAP: Fix corrupted list in > > hci_chan_del"), l2cap_conn_del() uses conn->lock to protect access to > > conn->users and conn->hchan. However, l2cap_register_user() and > > l2cap_unregister_user() still use hci_dev_lock(), creating a race > > condition where these functions can access conn->users and conn->hchan > > concurrently with l2cap_conn_del(). > > AFAIK the above text from the original submitter is a bit inaccurate, > as l2cap_conn_del() is called with hdev lock held, so conn->users/hchan > should be safe. > > However, using conn->mutex should fix the use-after-free in > > conn->hcon->hdev > hci_dev_lock(hdev); > hci_dev_unlock(hdev); > > by making l2cap_unregister_user() safe to call after the hcon/hdev are > no longer alive. > > The change looks OK to me, but probably worth to double check with > syzbot it fixes the original issue syzbot seems to have hit some internal error, another try on upstream branch instead #syz test > > This can lead to use-after-free and list corruption bugs, as reported > > by syzbot. > > > > Fix this by changing l2cap_register_user() and l2cap_unregister_user() > > to use conn->lock instead of hci_dev_lock(), ensuring consistent locking > > for the l2cap_conn structure. > > Reported-by: syzbot+14b6d57fb728e27ce23c@syzkaller.appspotmail.com > > Closes: https://syzkaller.appspot.com/bug?extid=14b6d57fb728e27ce23c > > Fixes: ab4eedb790ca ("Bluetooth: L2CAP: Fix corrupted list in hci_chan_del") > > Signed-off-by: Shaurya Rane <ssrane_b23@ee.vjti.ac.in> > > Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com> > > --- > > net/bluetooth/l2cap_core.c | 20 ++++++++------------ > > 1 file changed, 8 insertions(+), 12 deletions(-) > > > > diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c > > index 14131e427efd..6606d7f12534 100644 > > --- a/net/bluetooth/l2cap_core.c > > +++ b/net/bluetooth/l2cap_core.c > > @@ -1678,17 +1678,15 @@ static void l2cap_info_timeout(struct work_struct *work) > > > > int l2cap_register_user(struct l2cap_conn *conn, struct l2cap_user *user) > > { > > - struct hci_dev *hdev = conn->hcon->hdev; > > int ret; > > > > /* We need to check whether l2cap_conn is registered. If it is not, we > > - * must not register the l2cap_user. l2cap_conn_del() is unregisters > > - * l2cap_conn objects, but doesn't provide its own locking. Instead, it > > - * relies on the parent hci_conn object to be locked. This itself relies > > - * on the hci_dev object to be locked. So we must lock the hci device > > - * here, too. */ > > + * must not register the l2cap_user. l2cap_conn_del() unregisters > > + * l2cap_conn objects under conn->lock, and we use the same lock here > > + * to protect access to conn->users and conn->hchan. > > + */ > > > > - hci_dev_lock(hdev); > > + mutex_lock(&conn->lock); > > > > if (!list_empty(&user->list)) { > > ret = -EINVAL; > > @@ -1709,16 +1707,14 @@ int l2cap_register_user(struct l2cap_conn *conn, struct l2cap_user *user) > > ret = 0; > > > > out_unlock: > > - hci_dev_unlock(hdev); > > + mutex_unlock(&conn->lock); > > return ret; > > } > > EXPORT_SYMBOL(l2cap_register_user); > > > > void l2cap_unregister_user(struct l2cap_conn *conn, struct l2cap_user *user) > > { > > - struct hci_dev *hdev = conn->hcon->hdev; > > - > > - hci_dev_lock(hdev); > > + mutex_lock(&conn->lock); > > > > if (list_empty(&user->list)) > > goto out_unlock; > > @@ -1727,7 +1723,7 @@ void l2cap_unregister_user(struct l2cap_conn *conn, struct l2cap_user *user) > > user->remove(conn, user); > > > > out_unlock: > > - hci_dev_unlock(hdev); > > + mutex_unlock(&conn->lock); > > } > > EXPORT_SYMBOL(l2cap_unregister_user); > > [-- Attachment #2: 0001-Bluetooth-L2CAP-Fix-use-after-free-in-l2cap_unregist.patch --] [-- Type: text/x-patch, Size: 3220 bytes --] From 2d0e9ce3888e494c12324c0f682900d9f61d5eb2 Mon Sep 17 00:00:00 2001 Message-ID: <2d0e9ce3888e494c12324c0f682900d9f61d5eb2.1772873329.git.pav@iki.fi> From: Shaurya Rane <ssrane_b23@ee.vjti.ac.in> Date: Fri, 6 Mar 2026 16:04:27 -0500 Subject: [PATCH] Bluetooth: L2CAP: Fix use-after-free in l2cap_unregister_user To: linux-bluetooth@vger.kernel.org After commit ab4eedb790ca ("Bluetooth: L2CAP: Fix corrupted list in hci_chan_del"), l2cap_conn_del() uses conn->lock to protect access to conn->users and conn->hchan. However, l2cap_register_user() and l2cap_unregister_user() still use hci_dev_lock(), creating a race condition where these functions can access conn->users and conn->hchan concurrently with l2cap_conn_del(). This can lead to use-after-free and list corruption bugs, as reported by syzbot. Fix this by changing l2cap_register_user() and l2cap_unregister_user() to use conn->lock instead of hci_dev_lock(), ensuring consistent locking for the l2cap_conn structure. Reported-by: syzbot+14b6d57fb728e27ce23c@syzkaller.appspotmail.com Closes: https://syzkaller.appspot.com/bug?extid=14b6d57fb728e27ce23c Fixes: ab4eedb790ca ("Bluetooth: L2CAP: Fix corrupted list in hci_chan_del") Signed-off-by: Shaurya Rane <ssrane_b23@ee.vjti.ac.in> Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com> --- net/bluetooth/l2cap_core.c | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 14131e427efd..6606d7f12534 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -1678,17 +1678,15 @@ static void l2cap_info_timeout(struct work_struct *work) int l2cap_register_user(struct l2cap_conn *conn, struct l2cap_user *user) { - struct hci_dev *hdev = conn->hcon->hdev; int ret; /* We need to check whether l2cap_conn is registered. If it is not, we - * must not register the l2cap_user. l2cap_conn_del() is unregisters - * l2cap_conn objects, but doesn't provide its own locking. Instead, it - * relies on the parent hci_conn object to be locked. This itself relies - * on the hci_dev object to be locked. So we must lock the hci device - * here, too. */ + * must not register the l2cap_user. l2cap_conn_del() unregisters + * l2cap_conn objects under conn->lock, and we use the same lock here + * to protect access to conn->users and conn->hchan. + */ - hci_dev_lock(hdev); + mutex_lock(&conn->lock); if (!list_empty(&user->list)) { ret = -EINVAL; @@ -1709,16 +1707,14 @@ int l2cap_register_user(struct l2cap_conn *conn, struct l2cap_user *user) ret = 0; out_unlock: - hci_dev_unlock(hdev); + mutex_unlock(&conn->lock); return ret; } EXPORT_SYMBOL(l2cap_register_user); void l2cap_unregister_user(struct l2cap_conn *conn, struct l2cap_user *user) { - struct hci_dev *hdev = conn->hcon->hdev; - - hci_dev_lock(hdev); + mutex_lock(&conn->lock); if (list_empty(&user->list)) goto out_unlock; @@ -1727,7 +1723,7 @@ void l2cap_unregister_user(struct l2cap_conn *conn, struct l2cap_user *user) user->remove(conn, user); out_unlock: - hci_dev_unlock(hdev); + mutex_unlock(&conn->lock); } EXPORT_SYMBOL(l2cap_unregister_user); -- 2.53.0 ^ permalink raw reply related [flat|nested] 11+ messages in thread
* Re: [syzbot] [bluetooth?] KASAN: slab-use-after-free Read in l2cap_unregister_user 2026-03-07 9:45 ` [RESEND] Bluetooth: L2CAP: Fix use-after-free " Pauli Virtanen @ 2026-03-07 10:22 ` syzbot 2026-03-07 10:32 ` [RESEND] Bluetooth: L2CAP: Fix use-after-free " Pauli Virtanen 1 sibling, 0 replies; 11+ messages in thread From: syzbot @ 2026-03-07 10:22 UTC (permalink / raw) To: linux-bluetooth, linux-kernel, pav, syzkaller-bugs Hello, syzbot tried to test the proposed patch but the build/boot failed: can't ssh into the instance failed to run ["ssh" "-p" "22" "-F" "/dev/null" "-o" "UserKnownHostsFile=/dev/null" "-o" "IdentitiesOnly=yes" "-o" "BatchMode=yes" "-o" "StrictHostKeyChecking=no" "-o" "ConnectTimeout=10" "root@10.128.1.197" "pwd"]: exit status 255Pseudo-terminal will not be allocated because stdin is not a terminal. Warning: Permanently added '[us-central1-ssh-serialport.googleapis.com]:9600' (ECDSA) to the list of known hosts. UEFI firmware (version built at 09:00:00 on Jan 10 2025) EMU Variable FVB Started EMU Variable invalid PCD sizes Found PL031 RTC @ 0x9010000 InitializeRealTimeClock: using default timezone/daylight settings ^[[2J^[[01;01H^[[=3h^[[2J^[[01;01H^[[2J^[[01;01H^[[=3h^[[2J^[[01;01HBdsDxe: loading Boot0001 "UEFI Misc Device" from PciRoot(0x0)/Pci(0x2,0x0)/NVMe(0x1,00-00-00-00-00-00-00-00) BdsDxe: starting Boot0001 "UEFI Misc Device" from PciRoot(0x0)/Pci(0x2,0x0)/NVMe(0x1,00-00-00-00-00-00-00-00) UEFI: Attempting to start image. Description: UEFI Misc Device FilePath: PciRoot(0x0)/Pci(0x2,0x0)/NVMe(0x1,00-00-00-00-00-00-00-00) OptionNumber: 1. Booting `syzkaller' serialport: Connected to syzkaller.us-central1-a.ci-upstream-gce-arm64-test-job-parallel-1 port 1 (session ID: 496df2a91bf6754c27cb2596a739f60f4c94c5a4fc85884e1f75d06230ee71eb, active connections: 1). syzkaller build log: go env (err=<nil>) AR='ar' CC='gcc' CGO_CFLAGS='-O2 -g' CGO_CPPFLAGS='' CGO_CXXFLAGS='-O2 -g' CGO_ENABLED='1' CGO_FFLAGS='-O2 -g' CGO_LDFLAGS='-O2 -g' CXX='g++' GCCGO='gccgo' GO111MODULE='auto' GOAMD64='v1' GOARCH='amd64' GOAUTH='netrc' GOBIN='' GOCACHE='/syzkaller/.cache/go-build' GOCACHEPROG='' GODEBUG='' GOENV='/syzkaller/.config/go/env' GOEXE='' GOEXPERIMENT='' GOFIPS140='off' GOFLAGS='' GOGCCFLAGS='-fPIC -m64 -pthread -Wl,--no-gc-sections -fmessage-length=0 -ffile-prefix-map=/tmp/go-build262281762=/tmp/go-build -gno-record-gcc-switches' GOHOSTARCH='amd64' GOHOSTOS='linux' GOINSECURE='' GOMOD='/syzkaller/jobs-2/linux/gopath/src/github.com/google/syzkaller/go.mod' GOMODCACHE='/syzkaller/jobs-2/linux/gopath/pkg/mod' GONOPROXY='' GONOSUMDB='' GOOS='linux' GOPATH='/syzkaller/jobs-2/linux/gopath' GOPRIVATE='' GOPROXY='https://proxy.golang.org,direct' GOROOT='/usr/local/go' GOSUMDB='sum.golang.org' GOTELEMETRY='local' GOTELEMETRYDIR='/syzkaller/.config/go/telemetry' GOTMPDIR='' GOTOOLCHAIN='auto' GOTOOLDIR='/usr/local/go/pkg/tool/linux_amd64' GOVCS='' GOVERSION='go1.26.0' GOWORK='' PKG_CONFIG='pkg-config' git status (err=<nil>) HEAD detached at c06e8995d7 nothing to commit, working tree clean tput: No value for $TERM and no -T specified tput: No value for $TERM and no -T specified Makefile:31: run command via tools/syz-env for best compatibility, see: Makefile:32: https://github.com/google/syzkaller/blob/master/docs/contributing.md#using-syz-env go list -f '{{.Stale}}' ./sys/syz-sysgen | grep -q false || go install ./sys/syz-sysgen make .descriptions tput: No value for $TERM and no -T specified tput: No value for $TERM and no -T specified Makefile:31: run command via tools/syz-env for best compatibility, see: Makefile:32: https://github.com/google/syzkaller/blob/master/docs/contributing.md#using-syz-env bin/syz-sysgen touch .descriptions GOOS=linux GOARCH=arm64 go build -ldflags="-s -w -X github.com/google/syzkaller/prog.GitRevision=c06e8995d711b5a8d8fbd771826fcbfdac6f110f -X github.com/google/syzkaller/prog.gitRevisionDate=20250811-165554" -o ./bin/linux_arm64/syz-execprog github.com/google/syzkaller/tools/syz-execprog mkdir -p ./bin/linux_arm64 aarch64-linux-gnu-g++ -o ./bin/linux_arm64/syz-executor executor/executor.cc \ -O2 -pthread -Wall -Werror -Wparentheses -Wunused-const-variable -Wframe-larger-than=16384 -Wno-stringop-overflow -Wno-array-bounds -Wno-format-overflow -Wno-unused-but-set-variable -Wno-unused-command-line-argument -static-pie -std=c++17 -I. -Iexecutor/_include -DGOOS_linux=1 -DGOARCH_arm64=1 \ -DHOSTGOOS_linux=1 -DGIT_REVISION=\"c06e8995d711b5a8d8fbd771826fcbfdac6f110f\" /usr/lib/gcc-cross/aarch64-linux-gnu/14/../../../../aarch64-linux-gnu/bin/ld: /tmp/ccHQpBys.o: in function `Connection::Connect(char const*, char const*)': executor.cc:(.text._ZN10Connection7ConnectEPKcS1_[_ZN10Connection7ConnectEPKcS1_]+0x2ec): warning: Using 'gethostbyname' in statically linked applications requires at runtime the shared libraries from the glibc version used for linking Tested on: commit: 1e0a8362 Merge branches 'for-next/core' and 'for-next/.. git tree: git://git.kernel.org/pub/scm/linux/kernel/git/arm64/linux.git for-kernelci kernel config: https://syzkaller.appspot.com/x/.config?x=1aef92cd87e68b9f dashboard link: https://syzkaller.appspot.com/bug?extid=14b6d57fb728e27ce23c compiler: Debian clang version 21.1.8 (++20251221033036+2078da43e25a-1~exp1~20251221153213.50), Debian LLD 21.1.8 userspace arch: arm64 patch: https://syzkaller.appspot.com/x/patch.diff?x=10e4075a580000 ^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [RESEND] Bluetooth: L2CAP: Fix use-after-free in l2cap_unregister_user 2026-03-07 9:45 ` [RESEND] Bluetooth: L2CAP: Fix use-after-free " Pauli Virtanen 2026-03-07 10:22 ` [syzbot] [bluetooth?] KASAN: slab-use-after-free Read " syzbot @ 2026-03-07 10:32 ` Pauli Virtanen 2026-03-07 11:00 ` [syzbot] [bluetooth?] KASAN: slab-use-after-free Read " syzbot 2026-03-07 11:14 ` [RESEND] Bluetooth: L2CAP: Fix use-after-free " Pauli Virtanen 1 sibling, 2 replies; 11+ messages in thread From: Pauli Virtanen @ 2026-03-07 10:32 UTC (permalink / raw) To: linux-bluetooth; +Cc: syzbot+14b6d57fb728e27ce23c [-- Attachment #1: Type: text/plain, Size: 4508 bytes --] la, 2026-03-07 kello 11:45 +0200, Pauli Virtanen kirjoitti: > la, 2026-03-07 kello 10:59 +0200, Pauli Virtanen kirjoitti: > > pe, 2026-03-06 kello 16:04 -0500, Luiz Augusto von Dentz kirjoitti: > > > From: Shaurya Rane <ssrane_b23@ee.vjti.ac.in> > > > > > > After commit ab4eedb790ca ("Bluetooth: L2CAP: Fix corrupted list in > > > hci_chan_del"), l2cap_conn_del() uses conn->lock to protect access to > > > conn->users and conn->hchan. However, l2cap_register_user() and > > > l2cap_unregister_user() still use hci_dev_lock(), creating a race > > > condition where these functions can access conn->users and conn->hchan > > > concurrently with l2cap_conn_del(). > > > > AFAIK the above text from the original submitter is a bit inaccurate, > > as l2cap_conn_del() is called with hdev lock held, so conn->users/hchan > > should be safe. > > > > However, using conn->mutex should fix the use-after-free in > > > > conn->hcon->hdev > > hci_dev_lock(hdev); > > hci_dev_unlock(hdev); > > > > by making l2cap_unregister_user() safe to call after the hcon/hdev are > > no longer alive. > > > > The change looks OK to me, but probably worth to double check with > > syzbot it fixes the original issue > > syzbot seems to have hit some internal error, another try on upstream > branch instead > No luck, test the patch setting session->conn = NULL; in case it fixes the syzcaller failure. If that passes, maybe the conn->mutex locking overlooks something that I don't see right now, #syz test > > > This can lead to use-after-free and list corruption bugs, as reported > > > by syzbot. > > > > > > Fix this by changing l2cap_register_user() and l2cap_unregister_user() > > > to use conn->lock instead of hci_dev_lock(), ensuring consistent locking > > > for the l2cap_conn structure. > > > Reported-by: syzbot+14b6d57fb728e27ce23c@syzkaller.appspotmail.com > > > Closes: https://syzkaller.appspot.com/bug?extid=14b6d57fb728e27ce23c > > > Fixes: ab4eedb790ca ("Bluetooth: L2CAP: Fix corrupted list in hci_chan_del") > > > Signed-off-by: Shaurya Rane <ssrane_b23@ee.vjti.ac.in> > > > Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com> > > > --- > > > net/bluetooth/l2cap_core.c | 20 ++++++++------------ > > > 1 file changed, 8 insertions(+), 12 deletions(-) > > > > > > diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c > > > index 14131e427efd..6606d7f12534 100644 > > > --- a/net/bluetooth/l2cap_core.c > > > +++ b/net/bluetooth/l2cap_core.c > > > @@ -1678,17 +1678,15 @@ static void l2cap_info_timeout(struct work_struct *work) > > > > > > int l2cap_register_user(struct l2cap_conn *conn, struct l2cap_user *user) > > > { > > > - struct hci_dev *hdev = conn->hcon->hdev; > > > int ret; > > > > > > /* We need to check whether l2cap_conn is registered. If it is not, we > > > - * must not register the l2cap_user. l2cap_conn_del() is unregisters > > > - * l2cap_conn objects, but doesn't provide its own locking. Instead, it > > > - * relies on the parent hci_conn object to be locked. This itself relies > > > - * on the hci_dev object to be locked. So we must lock the hci device > > > - * here, too. */ > > > + * must not register the l2cap_user. l2cap_conn_del() unregisters > > > + * l2cap_conn objects under conn->lock, and we use the same lock here > > > + * to protect access to conn->users and conn->hchan. > > > + */ > > > > > > - hci_dev_lock(hdev); > > > + mutex_lock(&conn->lock); > > > > > > if (!list_empty(&user->list)) { > > > ret = -EINVAL; > > > @@ -1709,16 +1707,14 @@ int l2cap_register_user(struct l2cap_conn *conn, struct l2cap_user *user) > > > ret = 0; > > > > > > out_unlock: > > > - hci_dev_unlock(hdev); > > > + mutex_unlock(&conn->lock); > > > return ret; > > > } > > > EXPORT_SYMBOL(l2cap_register_user); > > > > > > void l2cap_unregister_user(struct l2cap_conn *conn, struct l2cap_user *user) > > > { > > > - struct hci_dev *hdev = conn->hcon->hdev; > > > - > > > - hci_dev_lock(hdev); > > > + mutex_lock(&conn->lock); > > > > > > if (list_empty(&user->list)) > > > goto out_unlock; > > > @@ -1727,7 +1723,7 @@ void l2cap_unregister_user(struct l2cap_conn *conn, struct l2cap_user *user) > > > user->remove(conn, user); > > > > > > out_unlock: > > > - hci_dev_unlock(hdev); > > > + mutex_unlock(&conn->lock); > > > } > > > EXPORT_SYMBOL(l2cap_unregister_user); > > > [-- Attachment #2: 0001-Bluetooth-HIDP-Fix-possible-UAF.patch --] [-- Type: text/x-patch, Size: 15843 bytes --] From 9d7d765a35c2385fe0c387199e484f486e6f2257 Mon Sep 17 00:00:00 2001 Message-ID: <9d7d765a35c2385fe0c387199e484f486e6f2257.1772879270.git.pav@iki.fi> From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com> Date: Thu, 5 Mar 2026 10:17:47 -0500 Subject: [PATCH] Bluetooth: HIDP: Fix possible UAF To: linux-bluetooth@vger.kernel.org This fixes the following trace caused by not dropping l2cap_conn reference when user->remove callback is called: [ 97.809249] l2cap_conn_free: freeing conn ffff88810a171c00 [ 97.809907] CPU: 1 UID: 0 PID: 1419 Comm: repro_standalon Not tainted 7.0.0-rc1-dirty #14 PREEMPT(lazy) [ 97.809935] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.17.0-debian-1.17.0-1 04/01/2014 [ 97.809947] Call Trace: [ 97.809954] <TASK> [ 97.809961] dump_stack_lvl (lib/dump_stack.c:122) [ 97.809990] l2cap_conn_free (net/bluetooth/l2cap_core.c:1808) [ 97.810017] l2cap_conn_del (./include/linux/kref.h:66 net/bluetooth/l2cap_core.c:1821 net/bluetooth/l2cap_core.c:1798) [ 97.810055] l2cap_disconn_cfm (net/bluetooth/l2cap_core.c:7347 (discriminator 1) net/bluetooth/l2cap_core.c:7340 (discriminator 1)) [ 97.810086] ? __pfx_l2cap_disconn_cfm (net/bluetooth/l2cap_core.c:7341) [ 97.810117] hci_conn_hash_flush (./include/net/bluetooth/hci_core.h:2152 (discriminator 2) net/bluetooth/hci_conn.c:2644 (discriminator 2)) [ 97.810148] hci_dev_close_sync (net/bluetooth/hci_sync.c:5360) [ 97.810180] ? __pfx_hci_dev_close_sync (net/bluetooth/hci_sync.c:5285) [ 97.810212] ? srso_alias_return_thunk (arch/x86/lib/retpoline.S:221) [ 97.810242] ? up_write (./arch/x86/include/asm/atomic64_64.h:87 (discriminator 5) ./include/linux/atomic/atomic-arch-fallback.h:2852 (discriminator 5) ./include/linux/atomic/atomic-long.h:268 (discriminator 5) ./include/linux/atomic/atomic-instrumented.h:3391 (discriminator 5) kernel/locking/rwsem.c:1385 (discriminator 5) kernel/locking/rwsem.c:1643 (discriminator 5)) [ 97.810267] ? srso_alias_return_thunk (arch/x86/lib/retpoline.S:221) [ 97.810290] ? rcu_is_watching (./arch/x86/include/asm/atomic.h:23 ./include/linux/atomic/atomic-arch-fallback.h:457 ./include/linux/context_tracking.h:128 kernel/rcu/tree.c:752) [ 97.810320] hci_unregister_dev (net/bluetooth/hci_core.c:504 net/bluetooth/hci_core.c:2716) [ 97.810346] vhci_release (drivers/bluetooth/hci_vhci.c:691) [ 97.810375] ? __pfx_vhci_release (drivers/bluetooth/hci_vhci.c:678) [ 97.810404] __fput (fs/file_table.c:470) [ 97.810430] task_work_run (kernel/task_work.c:235) [ 97.810451] ? __pfx_task_work_run (kernel/task_work.c:201) [ 97.810472] ? srso_alias_return_thunk (arch/x86/lib/retpoline.S:221) [ 97.810495] ? do_raw_spin_unlock (./include/asm-generic/qspinlock.h:128 (discriminator 5) kernel/locking/spinlock_debug.c:142 (discriminator 5)) [ 97.810527] do_exit (kernel/exit.c:972) [ 97.810547] ? srso_alias_return_thunk (arch/x86/lib/retpoline.S:221) [ 97.810574] ? __pfx_do_exit (kernel/exit.c:897) [ 97.810594] ? lock_acquire (kernel/locking/lockdep.c:470 (discriminator 6) kernel/locking/lockdep.c:5870 (discriminator 6) kernel/locking/lockdep.c:5825 (discriminator 6)) [ 97.810616] ? srso_alias_return_thunk (arch/x86/lib/retpoline.S:221) [ 97.810639] ? do_raw_spin_lock (kernel/locking/spinlock_debug.c:95 (discriminator 4) kernel/locking/spinlock_debug.c:118 (discriminator 4)) [ 97.810664] ? srso_alias_return_thunk (arch/x86/lib/retpoline.S:221) [ 97.810688] ? find_held_lock (kernel/locking/lockdep.c:5350 (discriminator 1)) [ 97.810721] do_group_exit (kernel/exit.c:1093) [ 97.810745] get_signal (kernel/signal.c:3007 (discriminator 1)) [ 97.810772] ? security_file_permission (./arch/x86/include/asm/jump_label.h:37 security/security.c:2366) [ 97.810803] ? srso_alias_return_thunk (arch/x86/lib/retpoline.S:221) [ 97.810826] ? vfs_read (fs/read_write.c:555) [ 97.810854] ? __pfx_get_signal (kernel/signal.c:2800) [ 97.810880] ? srso_alias_return_thunk (arch/x86/lib/retpoline.S:221) [ 97.810905] ? __pfx_vfs_read (fs/read_write.c:555) [ 97.810932] ? srso_alias_return_thunk (arch/x86/lib/retpoline.S:221) [ 97.810960] arch_do_signal_or_restart (arch/x86/kernel/signal.c:337 (discriminator 1)) [ 97.810990] ? __pfx_arch_do_signal_or_restart (arch/x86/kernel/signal.c:334) [ 97.811021] ? srso_alias_return_thunk (arch/x86/lib/retpoline.S:221) [ 97.811055] ? srso_alias_return_thunk (arch/x86/lib/retpoline.S:221) [ 97.811078] ? ksys_read (fs/read_write.c:707) [ 97.811106] ? __pfx_ksys_read (fs/read_write.c:707) [ 97.811137] exit_to_user_mode_loop (kernel/entry/common.c:66 kernel/entry/common.c:98) [ 97.811169] ? rcu_is_watching (./arch/x86/include/asm/atomic.h:23 ./include/linux/atomic/atomic-arch-fallback.h:457 ./include/linux/context_tracking.h:128 kernel/rcu/tree.c:752) [ 97.811192] ? srso_alias_return_thunk (arch/x86/lib/retpoline.S:221) [ 97.811215] ? trace_hardirqs_off (./include/trace/events/preemptirq.h:36 (discriminator 33) kernel/trace/trace_preemptirq.c:95 (discriminator 33) kernel/trace/trace_preemptirq.c:90 (discriminator 33)) [ 97.811240] do_syscall_64 (./include/linux/irq-entry-common.h:226 ./include/linux/irq-entry-common.h:256 ./include/linux/entry-common.h:325 arch/x86/entry/syscall_64.c:100) [ 97.811268] ? srso_alias_return_thunk (arch/x86/lib/retpoline.S:221) [ 97.811292] ? exc_page_fault (arch/x86/mm/fault.c:1480 (discriminator 3) arch/x86/mm/fault.c:1527 (discriminator 3)) [ 97.811318] entry_SYSCALL_64_after_hwframe (arch/x86/entry/entry_64.S:130) [ 97.811338] RIP: 0033:0x445cfe [ 97.811352] Code: Unable to access opcode bytes at 0x445cd4. Code starting with the faulting instruction =========================================== [ 97.811360] RSP: 002b:00007f65c41c6dc8 EFLAGS: 00000246 ORIG_RAX: 0000000000000000 [ 97.811378] RAX: fffffffffffffe00 RBX: 00007f65c41c76c0 RCX: 0000000000445cfe [ 97.811391] RDX: 0000000000000400 RSI: 00007f65c41c6e40 RDI: 0000000000000004 [ 97.811403] RBP: 00007f65c41c7250 R08: 0000000000000000 R09: 0000000000000000 [ 97.811415] R10: 0000000000000000 R11: 0000000000000246 R12: ffffffffffffffe8 [ 97.811428] R13: 0000000000000000 R14: 00007fff780a8c00 R15: 00007f65c41c76c0 [ 97.811453] </TASK> [ 98.402453] ================================================================== [ 98.403560] BUG: KASAN: use-after-free in __mutex_lock (kernel/locking/mutex.c:199 kernel/locking/mutex.c:694 kernel/locking/mutex.c:776) [ 98.404541] Read of size 8 at addr ffff888113ee40a8 by task khidpd_00050004/1430 [ 98.405361] [ 98.405563] CPU: 1 UID: 0 PID: 1430 Comm: khidpd_00050004 Not tainted 7.0.0-rc1-dirty #14 PREEMPT(lazy) [ 98.405588] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.17.0-debian-1.17.0-1 04/01/2014 [ 98.405600] Call Trace: [ 98.405607] <TASK> [ 98.405614] dump_stack_lvl (lib/dump_stack.c:122) [ 98.405641] print_report (mm/kasan/report.c:379 mm/kasan/report.c:482) [ 98.405667] ? srso_alias_return_thunk (arch/x86/lib/retpoline.S:221) [ 98.405691] ? __virt_addr_valid (arch/x86/mm/physaddr.c:55) [ 98.405724] ? __mutex_lock (kernel/locking/mutex.c:199 kernel/locking/mutex.c:694 kernel/locking/mutex.c:776) [ 98.405748] kasan_report (mm/kasan/report.c:221 mm/kasan/report.c:597) [ 98.405778] ? __mutex_lock (kernel/locking/mutex.c:199 kernel/locking/mutex.c:694 kernel/locking/mutex.c:776) [ 98.405807] __mutex_lock (kernel/locking/mutex.c:199 kernel/locking/mutex.c:694 kernel/locking/mutex.c:776) [ 98.405832] ? do_raw_spin_lock (kernel/locking/spinlock_debug.c:95 (discriminator 4) kernel/locking/spinlock_debug.c:118 (discriminator 4)) [ 98.405859] ? l2cap_unregister_user (./include/linux/list.h:381 (discriminator 2) net/bluetooth/l2cap_core.c:1723 (discriminator 2)) [ 98.405888] ? __pfx_do_raw_spin_lock (kernel/locking/spinlock_debug.c:114) [ 98.405915] ? __pfx___mutex_lock (kernel/locking/mutex.c:775) [ 98.405939] ? srso_alias_return_thunk (arch/x86/lib/retpoline.S:221) [ 98.405963] ? lock_acquire (kernel/locking/lockdep.c:470 (discriminator 6) kernel/locking/lockdep.c:5870 (discriminator 6) kernel/locking/lockdep.c:5825 (discriminator 6)) [ 98.405984] ? find_held_lock (kernel/locking/lockdep.c:5350 (discriminator 1)) [ 98.406015] ? srso_alias_return_thunk (arch/x86/lib/retpoline.S:221) [ 98.406038] ? lock_release (kernel/locking/lockdep.c:5536 kernel/locking/lockdep.c:5889 kernel/locking/lockdep.c:5875) [ 98.406061] ? srso_alias_return_thunk (arch/x86/lib/retpoline.S:221) [ 98.406085] ? _raw_spin_unlock_irqrestore (./arch/x86/include/asm/irqflags.h:42 ./arch/x86/include/asm/irqflags.h:119 ./arch/x86/include/asm/irqflags.h:159 ./include/linux/spinlock_api_smp.h:178 kernel/locking/spinlock.c:194) [ 98.406107] ? srso_alias_return_thunk (arch/x86/lib/retpoline.S:221) [ 98.406130] ? __timer_delete_sync (kernel/time/timer.c:1592) [ 98.406158] ? l2cap_unregister_user (./include/linux/list.h:381 (discriminator 2) net/bluetooth/l2cap_core.c:1723 (discriminator 2)) [ 98.406186] ? srso_alias_return_thunk (arch/x86/lib/retpoline.S:221) [ 98.406210] l2cap_unregister_user (./include/linux/list.h:381 (discriminator 2) net/bluetooth/l2cap_core.c:1723 (discriminator 2)) [ 98.406263] hidp_session_thread (./include/linux/instrumented.h:112 ./include/linux/atomic/atomic-instrumented.h:400 ./include/linux/refcount.h:389 ./include/linux/refcount.h:432 ./include/linux/refcount.h:450 ./include/linux/kref.h:64 net/bluetooth/hidp/core.c:996 net/bluetooth/hidp/core.c:1305) [ 98.406293] ? __pfx_hidp_session_thread (net/bluetooth/hidp/core.c:1264) [ 98.406323] ? kthread (kernel/kthread.c:433) [ 98.406340] ? __pfx_hidp_session_wake_function (net/bluetooth/hidp/core.c:1251) [ 98.406370] ? srso_alias_return_thunk (arch/x86/lib/retpoline.S:221) [ 98.406393] ? find_held_lock (kernel/locking/lockdep.c:5350 (discriminator 1)) [ 98.406424] ? __pfx_hidp_session_wake_function (net/bluetooth/hidp/core.c:1251) [ 98.406453] ? srso_alias_return_thunk (arch/x86/lib/retpoline.S:221) [ 98.406476] ? trace_hardirqs_on (kernel/trace/trace_preemptirq.c:79 (discriminator 1)) [ 98.406499] ? srso_alias_return_thunk (arch/x86/lib/retpoline.S:221) [ 98.406523] ? kthread (kernel/kthread.c:433) [ 98.406539] ? srso_alias_return_thunk (arch/x86/lib/retpoline.S:221) [ 98.406565] ? kthread (kernel/kthread.c:433) [ 98.406581] ? __pfx_hidp_session_thread (net/bluetooth/hidp/core.c:1264) [ 98.406610] kthread (kernel/kthread.c:467) [ 98.406627] ? __pfx_kthread (kernel/kthread.c:412) [ 98.406645] ret_from_fork (arch/x86/kernel/process.c:164) [ 98.406674] ? __pfx_ret_from_fork (arch/x86/kernel/process.c:153) [ 98.406704] ? srso_alias_return_thunk (arch/x86/lib/retpoline.S:221) [ 98.406728] ? __pfx_kthread (kernel/kthread.c:412) [ 98.406747] ret_from_fork_asm (arch/x86/entry/entry_64.S:258) [ 98.406774] </TASK> [ 98.406780] [ 98.433693] The buggy address belongs to the physical page: [ 98.434405] page: refcount:0 mapcount:0 mapping:0000000000000000 index:0xffff888113ee7c40 pfn:0x113ee4 [ 98.435557] flags: 0x200000000000000(node=0|zone=2) [ 98.436198] raw: 0200000000000000 ffffea0004244308 ffff8881f6f3ebc0 0000000000000000 [ 98.437195] raw: ffff888113ee7c40 0000000000000000 00000000ffffffff 0000000000000000 [ 98.438115] page dumped because: kasan: bad access detected [ 98.438951] [ 98.439211] Memory state around the buggy address: [ 98.439871] ffff888113ee3f80: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc [ 98.440714] ffff888113ee4000: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff [ 98.441580] >ffff888113ee4080: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff [ 98.442458] ^ [ 98.443011] ffff888113ee4100: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff [ 98.443889] ffff888113ee4180: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff [ 98.444768] ================================================================== [ 98.445719] Disabling lock debugging due to kernel taint [ 98.448074] l2cap_conn_free: freeing conn ffff88810c22b400 [ 98.450012] CPU: 1 UID: 0 PID: 1430 Comm: khidpd_00050004 Tainted: G B 7.0.0-rc1-dirty #14 PREEMPT(lazy) [ 98.450040] Tainted: [B]=BAD_PAGE [ 98.450047] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.17.0-debian-1.17.0-1 04/01/2014 [ 98.450059] Call Trace: [ 98.450065] <TASK> [ 98.450071] dump_stack_lvl (lib/dump_stack.c:122) [ 98.450099] l2cap_conn_free (net/bluetooth/l2cap_core.c:1808) [ 98.450125] l2cap_conn_put (net/bluetooth/l2cap_core.c:1822) [ 98.450154] session_free (net/bluetooth/hidp/core.c:990) [ 98.450181] hidp_session_thread (net/bluetooth/hidp/core.c:1307) [ 98.450213] ? __pfx_hidp_session_thread (net/bluetooth/hidp/core.c:1264) [ 98.450271] ? kthread (kernel/kthread.c:433) [ 98.450293] ? __pfx_hidp_session_wake_function (net/bluetooth/hidp/core.c:1251) [ 98.450339] ? srso_alias_return_thunk (arch/x86/lib/retpoline.S:221) [ 98.450368] ? find_held_lock (kernel/locking/lockdep.c:5350 (discriminator 1)) [ 98.450406] ? __pfx_hidp_session_wake_function (net/bluetooth/hidp/core.c:1251) [ 98.450442] ? srso_alias_return_thunk (arch/x86/lib/retpoline.S:221) [ 98.450471] ? trace_hardirqs_on (kernel/trace/trace_preemptirq.c:79 (discriminator 1)) [ 98.450499] ? srso_alias_return_thunk (arch/x86/lib/retpoline.S:221) [ 98.450528] ? kthread (kernel/kthread.c:433) [ 98.450547] ? srso_alias_return_thunk (arch/x86/lib/retpoline.S:221) [ 98.450578] ? kthread (kernel/kthread.c:433) [ 98.450598] ? __pfx_hidp_session_thread (net/bluetooth/hidp/core.c:1264) [ 98.450637] kthread (kernel/kthread.c:467) [ 98.450657] ? __pfx_kthread (kernel/kthread.c:412) [ 98.450680] ret_from_fork (arch/x86/kernel/process.c:164) [ 98.450715] ? __pfx_ret_from_fork (arch/x86/kernel/process.c:153) [ 98.450752] ? srso_alias_return_thunk (arch/x86/lib/retpoline.S:221) [ 98.450782] ? __pfx_kthread (kernel/kthread.c:412) [ 98.450804] ret_from_fork_asm (arch/x86/entry/entry_64.S:258) [ 98.450836] </TASK> Fixes: b4f34d8d9d26 ("Bluetooth: hidp: add new session-management helpers") Reported-by: soufiane el hachmi <kilwa10@gmail.com> Tested-by: soufiane el hachmi <kilwa10@gmail.com> Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com> --- net/bluetooth/hidp/core.c | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/net/bluetooth/hidp/core.c b/net/bluetooth/hidp/core.c index 6fe815241b01..7bcf8c5ceaee 100644 --- a/net/bluetooth/hidp/core.c +++ b/net/bluetooth/hidp/core.c @@ -986,7 +986,8 @@ static void session_free(struct kref *ref) skb_queue_purge(&session->intr_transmit); fput(session->intr_sock->file); fput(session->ctrl_sock->file); - l2cap_conn_put(session->conn); + if (session->conn) + l2cap_conn_put(session->conn); kfree(session); } @@ -1164,6 +1165,15 @@ static void hidp_session_remove(struct l2cap_conn *conn, down_write(&hidp_session_sem); + /* Drop L2CAP reference immediately to indicate that + * l2cap_unregister_user() shall not be called as it is already + * considered removed. + */ + if (session->conn) { + l2cap_conn_put(session->conn); + session->conn = NULL; + } + hidp_session_terminate(session); cancel_work_sync(&session->dev_init); @@ -1301,7 +1311,9 @@ static int hidp_session_thread(void *arg) * Instead, this call has the same semantics as if user-space tried to * delete the session. */ - l2cap_unregister_user(session->conn, &session->user); + if (session->conn) + l2cap_unregister_user(session->conn, &session->user); + hidp_session_put(session); module_put_and_kthread_exit(0); -- 2.53.0 ^ permalink raw reply related [flat|nested] 11+ messages in thread
* Re: [syzbot] [bluetooth?] KASAN: slab-use-after-free Read in l2cap_unregister_user 2026-03-07 10:32 ` [RESEND] Bluetooth: L2CAP: Fix use-after-free " Pauli Virtanen @ 2026-03-07 11:00 ` syzbot 2026-03-07 11:14 ` [RESEND] Bluetooth: L2CAP: Fix use-after-free " Pauli Virtanen 1 sibling, 0 replies; 11+ messages in thread From: syzbot @ 2026-03-07 11:00 UTC (permalink / raw) To: linux-bluetooth, linux-kernel, pav, syzkaller-bugs Hello, syzbot tried to test the proposed patch but the build/boot failed: can't ssh into the instance failed to run ["ssh" "-p" "22" "-F" "/dev/null" "-o" "UserKnownHostsFile=/dev/null" "-o" "IdentitiesOnly=yes" "-o" "BatchMode=yes" "-o" "StrictHostKeyChecking=no" "-o" "ConnectTimeout=10" "root@10.128.0.96" "pwd"]: exit status 255Pseudo-terminal will not be allocated because stdin is not a terminal. Warning: Permanently added '[us-central1-ssh-serialport.googleapis.com]:9600' (ECDSA) to the list of known hosts. UEFI firmware (version built at 09:00:00 on Jan 10 2025) EMU Variable FVB Started EMU Variable invalid PCD sizes Found PL031 RTC @ 0x9010000 InitializeRealTimeClock: using default timezone/daylight settings ^[[2J^[[01;01H^[[=3h^[[2J^[[01;01H^[[2J^[[01;01H^[[=3h^[[2J^[[01;01HBdsDxe: loading Boot0001 "UEFI Misc Device" from PciRoot(0x0)/Pci(0x2,0x0)/NVMe(0x1,00-00-00-00-00-00-00-00) BdsDxe: starting Boot0001 "UEFI Misc Device" from PciRoot(0x0)/Pci(0x2,0x0)/NVMe(0x1,00-00-00-00-00-00-00-00) UEFI: Attempting to start image. Description: UEFI Misc Device FilePath: PciRoot(0x0)/Pci(0x2,0x0)/NVMe(0x1,00-00-00-00-00-00-00-00) OptionNumber: 1. Booting `syzkaller' serialport: Connected to syzkaller.us-central1-a.ci-upstream-gce-arm64-test-job-2 port 1 (session ID: bb7bd93cd4db56d08e3e26793aff3031016e820757ae311fc18736e74b75bf59, active connections: 1). syzkaller build log: go env (err=<nil>) AR='ar' CC='gcc' CGO_CFLAGS='-O2 -g' CGO_CPPFLAGS='' CGO_CXXFLAGS='-O2 -g' CGO_ENABLED='1' CGO_FFLAGS='-O2 -g' CGO_LDFLAGS='-O2 -g' CXX='g++' GCCGO='gccgo' GO111MODULE='auto' GOAMD64='v1' GOARCH='amd64' GOAUTH='netrc' GOBIN='' GOCACHE='/syzkaller/.cache/go-build' GOCACHEPROG='' GODEBUG='' GOENV='/syzkaller/.config/go/env' GOEXE='' GOEXPERIMENT='' GOFIPS140='off' GOFLAGS='' GOGCCFLAGS='-fPIC -m64 -pthread -Wl,--no-gc-sections -fmessage-length=0 -ffile-prefix-map=/tmp/go-build165225799=/tmp/go-build -gno-record-gcc-switches' GOHOSTARCH='amd64' GOHOSTOS='linux' GOINSECURE='' GOMOD='/syzkaller/jobs/linux/gopath/src/github.com/google/syzkaller/go.mod' GOMODCACHE='/syzkaller/jobs/linux/gopath/pkg/mod' GONOPROXY='' GONOSUMDB='' GOOS='linux' GOPATH='/syzkaller/jobs/linux/gopath' GOPRIVATE='' GOPROXY='https://proxy.golang.org,direct' GOROOT='/usr/local/go' GOSUMDB='sum.golang.org' GOTELEMETRY='local' GOTELEMETRYDIR='/syzkaller/.config/go/telemetry' GOTMPDIR='' GOTOOLCHAIN='auto' GOTOOLDIR='/usr/local/go/pkg/tool/linux_amd64' GOVCS='' GOVERSION='go1.26.0' GOWORK='' PKG_CONFIG='pkg-config' git status (err=<nil>) HEAD detached at c06e8995d71 nothing to commit, working tree clean tput: No value for $TERM and no -T specified tput: No value for $TERM and no -T specified Makefile:31: run command via tools/syz-env for best compatibility, see: Makefile:32: https://github.com/google/syzkaller/blob/master/docs/contributing.md#using-syz-env go list -f '{{.Stale}}' ./sys/syz-sysgen | grep -q false || go install ./sys/syz-sysgen make .descriptions tput: No value for $TERM and no -T specified tput: No value for $TERM and no -T specified Makefile:31: run command via tools/syz-env for best compatibility, see: Makefile:32: https://github.com/google/syzkaller/blob/master/docs/contributing.md#using-syz-env bin/syz-sysgen touch .descriptions GOOS=linux GOARCH=arm64 go build -ldflags="-s -w -X github.com/google/syzkaller/prog.GitRevision=c06e8995d711b5a8d8fbd771826fcbfdac6f110f -X github.com/google/syzkaller/prog.gitRevisionDate=20250811-165554" -o ./bin/linux_arm64/syz-execprog github.com/google/syzkaller/tools/syz-execprog mkdir -p ./bin/linux_arm64 aarch64-linux-gnu-g++ -o ./bin/linux_arm64/syz-executor executor/executor.cc \ -O2 -pthread -Wall -Werror -Wparentheses -Wunused-const-variable -Wframe-larger-than=16384 -Wno-stringop-overflow -Wno-array-bounds -Wno-format-overflow -Wno-unused-but-set-variable -Wno-unused-command-line-argument -static-pie -std=c++17 -I. -Iexecutor/_include -DGOOS_linux=1 -DGOARCH_arm64=1 \ -DHOSTGOOS_linux=1 -DGIT_REVISION=\"c06e8995d711b5a8d8fbd771826fcbfdac6f110f\" /usr/lib/gcc-cross/aarch64-linux-gnu/14/../../../../aarch64-linux-gnu/bin/ld: /tmp/ccHZ4d27.o: in function `Connection::Connect(char const*, char const*)': executor.cc:(.text._ZN10Connection7ConnectEPKcS1_[_ZN10Connection7ConnectEPKcS1_]+0x2ec): warning: Using 'gethostbyname' in statically linked applications requires at runtime the shared libraries from the glibc version used for linking Tested on: commit: 1e0a8362 Merge branches 'for-next/core' and 'for-next/.. git tree: git://git.kernel.org/pub/scm/linux/kernel/git/arm64/linux.git for-kernelci kernel config: https://syzkaller.appspot.com/x/.config?x=1aef92cd87e68b9f dashboard link: https://syzkaller.appspot.com/bug?extid=14b6d57fb728e27ce23c compiler: Debian clang version 21.1.8 (++20251221033036+2078da43e25a-1~exp1~20251221153213.50), Debian LLD 21.1.8 userspace arch: arm64 patch: https://syzkaller.appspot.com/x/patch.diff?x=1242ca02580000 ^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [RESEND] Bluetooth: L2CAP: Fix use-after-free in l2cap_unregister_user 2026-03-07 10:32 ` [RESEND] Bluetooth: L2CAP: Fix use-after-free " Pauli Virtanen 2026-03-07 11:00 ` [syzbot] [bluetooth?] KASAN: slab-use-after-free Read " syzbot @ 2026-03-07 11:14 ` Pauli Virtanen 1 sibling, 0 replies; 11+ messages in thread From: Pauli Virtanen @ 2026-03-07 11:14 UTC (permalink / raw) To: linux-bluetooth la, 2026-03-07 kello 12:32 +0200, Pauli Virtanen kirjoitti: > la, 2026-03-07 kello 11:45 +0200, Pauli Virtanen kirjoitti: > > la, 2026-03-07 kello 10:59 +0200, Pauli Virtanen kirjoitti: > > > pe, 2026-03-06 kello 16:04 -0500, Luiz Augusto von Dentz kirjoitti: > > > > From: Shaurya Rane <ssrane_b23@ee.vjti.ac.in> > > > > > > > > After commit ab4eedb790ca ("Bluetooth: L2CAP: Fix corrupted list in > > > > hci_chan_del"), l2cap_conn_del() uses conn->lock to protect access to > > > > conn->users and conn->hchan. However, l2cap_register_user() and > > > > l2cap_unregister_user() still use hci_dev_lock(), creating a race > > > > condition where these functions can access conn->users and conn->hchan > > > > concurrently with l2cap_conn_del(). > > > > > > AFAIK the above text from the original submitter is a bit inaccurate, > > > as l2cap_conn_del() is called with hdev lock held, so conn->users/hchan > > > should be safe. > > > > > > However, using conn->mutex should fix the use-after-free in > > > > > > conn->hcon->hdev > > > hci_dev_lock(hdev); > > > hci_dev_unlock(hdev); > > > > > > by making l2cap_unregister_user() safe to call after the hcon/hdev are > > > no longer alive. > > > > > > The change looks OK to me, but probably worth to double check with > > > syzbot it fixes the original issue > > > > syzbot seems to have hit some internal error, another try on upstream > > branch instead > > > > No luck, test the patch setting session->conn = NULL; in case it fixes > the syzcaller failure. If that passes, maybe the conn->mutex locking > overlooks something that I don't see right now, > > #syz test Looks like I can't get syzbot to test either patch. Probably this has nothing to do with the patch content, and is instead some other syzbot internal issue. > > > > This can lead to use-after-free and list corruption bugs, as reported > > > > by syzbot. > > > > > > > > Fix this by changing l2cap_register_user() and l2cap_unregister_user() > > > > to use conn->lock instead of hci_dev_lock(), ensuring consistent locking > > > > for the l2cap_conn structure. > > > > Reported-by: syzbot+14b6d57fb728e27ce23c@syzkaller.appspotmail.com > > > > Closes: https://syzkaller.appspot.com/bug?extid=14b6d57fb728e27ce23c > > > > Fixes: ab4eedb790ca ("Bluetooth: L2CAP: Fix corrupted list in hci_chan_del") > > > > Signed-off-by: Shaurya Rane <ssrane_b23@ee.vjti.ac.in> > > > > Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com> > > > > --- > > > > net/bluetooth/l2cap_core.c | 20 ++++++++------------ > > > > 1 file changed, 8 insertions(+), 12 deletions(-) > > > > > > > > diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c > > > > index 14131e427efd..6606d7f12534 100644 > > > > --- a/net/bluetooth/l2cap_core.c > > > > +++ b/net/bluetooth/l2cap_core.c > > > > @@ -1678,17 +1678,15 @@ static void l2cap_info_timeout(struct work_struct *work) > > > > > > > > int l2cap_register_user(struct l2cap_conn *conn, struct l2cap_user *user) > > > > { > > > > - struct hci_dev *hdev = conn->hcon->hdev; > > > > int ret; > > > > > > > > /* We need to check whether l2cap_conn is registered. If it is not, we > > > > - * must not register the l2cap_user. l2cap_conn_del() is unregisters > > > > - * l2cap_conn objects, but doesn't provide its own locking. Instead, it > > > > - * relies on the parent hci_conn object to be locked. This itself relies > > > > - * on the hci_dev object to be locked. So we must lock the hci device > > > > - * here, too. */ > > > > + * must not register the l2cap_user. l2cap_conn_del() unregisters > > > > + * l2cap_conn objects under conn->lock, and we use the same lock here > > > > + * to protect access to conn->users and conn->hchan. > > > > + */ > > > > > > > > - hci_dev_lock(hdev); > > > > + mutex_lock(&conn->lock); > > > > > > > > if (!list_empty(&user->list)) { > > > > ret = -EINVAL; > > > > @@ -1709,16 +1707,14 @@ int l2cap_register_user(struct l2cap_conn *conn, struct l2cap_user *user) > > > > ret = 0; > > > > > > > > out_unlock: > > > > - hci_dev_unlock(hdev); > > > > + mutex_unlock(&conn->lock); > > > > return ret; > > > > } > > > > EXPORT_SYMBOL(l2cap_register_user); > > > > > > > > void l2cap_unregister_user(struct l2cap_conn *conn, struct l2cap_user *user) > > > > { > > > > - struct hci_dev *hdev = conn->hcon->hdev; > > > > - > > > > - hci_dev_lock(hdev); > > > > + mutex_lock(&conn->lock); > > > > > > > > if (list_empty(&user->list)) > > > > goto out_unlock; > > > > @@ -1727,7 +1723,7 @@ void l2cap_unregister_user(struct l2cap_conn *conn, struct l2cap_user *user) > > > > user->remove(conn, user); > > > > > > > > out_unlock: > > > > - hci_dev_unlock(hdev); > > > > + mutex_unlock(&conn->lock); > > > > } > > > > EXPORT_SYMBOL(l2cap_unregister_user); > > > > -- Pauli Virtanen ^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [RESEND] Bluetooth: L2CAP: Fix use-after-free in l2cap_unregister_user 2026-03-07 8:59 ` Pauli Virtanen 2026-03-07 9:33 ` [syzbot] [bluetooth?] KASAN: slab-use-after-free Read " syzbot 2026-03-07 9:45 ` [RESEND] Bluetooth: L2CAP: Fix use-after-free " Pauli Virtanen @ 2026-03-09 15:34 ` Luiz Augusto von Dentz 2 siblings, 0 replies; 11+ messages in thread From: Luiz Augusto von Dentz @ 2026-03-09 15:34 UTC (permalink / raw) To: Pauli Virtanen; +Cc: linux-bluetooth, syzbot+14b6d57fb728e27ce23c Hi Pauli, On Sat, Mar 7, 2026 at 3:59 AM Pauli Virtanen <pav@iki.fi> wrote: > > pe, 2026-03-06 kello 16:04 -0500, Luiz Augusto von Dentz kirjoitti: > > From: Shaurya Rane <ssrane_b23@ee.vjti.ac.in> > > > > After commit ab4eedb790ca ("Bluetooth: L2CAP: Fix corrupted list in > > hci_chan_del"), l2cap_conn_del() uses conn->lock to protect access to > > conn->users and conn->hchan. However, l2cap_register_user() and > > l2cap_unregister_user() still use hci_dev_lock(), creating a race > > condition where these functions can access conn->users and conn->hchan > > concurrently with l2cap_conn_del(). > > AFAIK the above text from the original submitter is a bit inaccurate, > as l2cap_conn_del() is called with hdev lock held, so conn->users/hchan > should be safe. Yeah, I did amend the commit message since I don't think the hchan and hci_dev_lock are relevant here, so it only keeps the information conn->lock must be used to protect the l2cap_conn and l2cap_user. > However, using conn->mutex should fix the use-after-free in > > conn->hcon->hdev > hci_dev_lock(hdev); > hci_dev_unlock(hdev); > > by making l2cap_unregister_user() safe to call after the hcon/hdev are > no longer alive. > > The change looks OK to me, but probably worth to double check with > syzbot it fixes the original issue > > #syz test git://git.kernel.org/pub/scm/linux/kernel/git/bluetooth/bluetooth-next.git master > > > This can lead to use-after-free and list corruption bugs, as reported > > by syzbot. > > > > Fix this by changing l2cap_register_user() and l2cap_unregister_user() > > to use conn->lock instead of hci_dev_lock(), ensuring consistent locking > > for the l2cap_conn structure. > > Reported-by: syzbot+14b6d57fb728e27ce23c@syzkaller.appspotmail.com > > Closes: https://syzkaller.appspot.com/bug?extid=14b6d57fb728e27ce23c > > Fixes: ab4eedb790ca ("Bluetooth: L2CAP: Fix corrupted list in hci_chan_del") > > Signed-off-by: Shaurya Rane <ssrane_b23@ee.vjti.ac.in> > > Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com> > > --- > > net/bluetooth/l2cap_core.c | 20 ++++++++------------ > > 1 file changed, 8 insertions(+), 12 deletions(-) > > > > diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c > > index 14131e427efd..6606d7f12534 100644 > > --- a/net/bluetooth/l2cap_core.c > > +++ b/net/bluetooth/l2cap_core.c > > @@ -1678,17 +1678,15 @@ static void l2cap_info_timeout(struct work_struct *work) > > > > int l2cap_register_user(struct l2cap_conn *conn, struct l2cap_user *user) > > { > > - struct hci_dev *hdev = conn->hcon->hdev; > > int ret; > > > > /* We need to check whether l2cap_conn is registered. If it is not, we > > - * must not register the l2cap_user. l2cap_conn_del() is unregisters > > - * l2cap_conn objects, but doesn't provide its own locking. Instead, it > > - * relies on the parent hci_conn object to be locked. This itself relies > > - * on the hci_dev object to be locked. So we must lock the hci device > > - * here, too. */ > > + * must not register the l2cap_user. l2cap_conn_del() unregisters > > + * l2cap_conn objects under conn->lock, and we use the same lock here > > + * to protect access to conn->users and conn->hchan. > > + */ > > > > - hci_dev_lock(hdev); > > + mutex_lock(&conn->lock); > > > > if (!list_empty(&user->list)) { > > ret = -EINVAL; > > @@ -1709,16 +1707,14 @@ int l2cap_register_user(struct l2cap_conn *conn, struct l2cap_user *user) > > ret = 0; > > > > out_unlock: > > - hci_dev_unlock(hdev); > > + mutex_unlock(&conn->lock); > > return ret; > > } > > EXPORT_SYMBOL(l2cap_register_user); > > > > void l2cap_unregister_user(struct l2cap_conn *conn, struct l2cap_user *user) > > { > > - struct hci_dev *hdev = conn->hcon->hdev; > > - > > - hci_dev_lock(hdev); > > + mutex_lock(&conn->lock); > > > > if (list_empty(&user->list)) > > goto out_unlock; > > @@ -1727,7 +1723,7 @@ void l2cap_unregister_user(struct l2cap_conn *conn, struct l2cap_user *user) > > user->remove(conn, user); > > > > out_unlock: > > - hci_dev_unlock(hdev); > > + mutex_unlock(&conn->lock); > > } > > EXPORT_SYMBOL(l2cap_unregister_user); > > -- Luiz Augusto von Dentz ^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [RESEND] Bluetooth: L2CAP: Fix use-after-free in l2cap_unregister_user 2026-03-06 21:04 [RESEND] Bluetooth: L2CAP: Fix use-after-free in l2cap_unregister_user Luiz Augusto von Dentz 2026-03-06 21:48 ` bluez.test.bot 2026-03-07 8:59 ` Pauli Virtanen @ 2026-03-09 15:30 ` patchwork-bot+bluetooth 2 siblings, 0 replies; 11+ messages in thread From: patchwork-bot+bluetooth @ 2026-03-09 15:30 UTC (permalink / raw) To: Luiz Augusto von Dentz; +Cc: linux-bluetooth Hello: This patch was applied to bluetooth/bluetooth-next.git (master) by Luiz Augusto von Dentz <luiz.von.dentz@intel.com>: On Fri, 6 Mar 2026 16:04:27 -0500 you wrote: > From: Shaurya Rane <ssrane_b23@ee.vjti.ac.in> > > After commit ab4eedb790ca ("Bluetooth: L2CAP: Fix corrupted list in > hci_chan_del"), l2cap_conn_del() uses conn->lock to protect access to > conn->users and conn->hchan. However, l2cap_register_user() and > l2cap_unregister_user() still use hci_dev_lock(), creating a race > condition where these functions can access conn->users and conn->hchan > concurrently with l2cap_conn_del(). > > [...] Here is the summary with links: - [RESEND] Bluetooth: L2CAP: Fix use-after-free in l2cap_unregister_user https://git.kernel.org/bluetooth/bluetooth-next/c/99940a6c1ebe You are awesome, thank you! -- Deet-doot-dot, I am a bot. https://korg.docs.kernel.org/patchwork/pwbot.html ^ permalink raw reply [flat|nested] 11+ messages in thread
end of thread, other threads:[~2026-03-09 15:34 UTC | newest] Thread overview: 11+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2026-03-06 21:04 [RESEND] Bluetooth: L2CAP: Fix use-after-free in l2cap_unregister_user Luiz Augusto von Dentz 2026-03-06 21:48 ` bluez.test.bot 2026-03-07 8:59 ` Pauli Virtanen 2026-03-07 9:33 ` [syzbot] [bluetooth?] KASAN: slab-use-after-free Read " syzbot 2026-03-07 9:45 ` [RESEND] Bluetooth: L2CAP: Fix use-after-free " Pauli Virtanen 2026-03-07 10:22 ` [syzbot] [bluetooth?] KASAN: slab-use-after-free Read " syzbot 2026-03-07 10:32 ` [RESEND] Bluetooth: L2CAP: Fix use-after-free " Pauli Virtanen 2026-03-07 11:00 ` [syzbot] [bluetooth?] KASAN: slab-use-after-free Read " syzbot 2026-03-07 11:14 ` [RESEND] Bluetooth: L2CAP: Fix use-after-free " Pauli Virtanen 2026-03-09 15:34 ` Luiz Augusto von Dentz 2026-03-09 15:30 ` patchwork-bot+bluetooth
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox