public inbox for linux-bluetooth@vger.kernel.org
 help / color / mirror / Atom feed
* [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-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

* 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

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