Bluetooth: hci_conn: hold conn references in hci_sync tasks
Subsystems (2)
v5 cover Bluetooth: hci_conn: hold conn references in hci_sync tasks
Have hci_sync tasks hold reference to hci_conn pointer they want to use later.
Avoids UAFs and passing potentially reused (possible even if very unlikely) pointers to hci_conn_valid().
hci_conn_del() dequeues running works for the same connection, but this has no effect if the work is already started running, which is the race condition here.
v5:
- resend
- no need to check hci_conn_valid() in create_big_complete, the bit is safe to clear also if hci_conn_del() has run
v4:
- Check !conn in hci_connect_big_sync() first.
It's probably bug in iso.c that it may call this with NULL, but probably better fixed separately.
v3:
- resending some rebased parts from
https://lore.kernel.org/linux-bluetooth/[email protected]/
https://lore.kernel.org/linux-bluetooth/[email protected]/
Pauli Virtanen (7):
Bluetooth: hci_conn: hold conn reference in abort_conn_sync()
Bluetooth: hci_sync: hold conn in hci_connect_acl/le_sync() callbacks
Bluetooth: hci_sync: hold conn in hci_connect_big_sync() callback
Bluetooth: hci_sync: hold conn in hci_connect_pa_sync() callback
Bluetooth: hci_sync: hold conn in hci_past_sync() callback
Bluetooth: hci_sync: fix hci_conn_del() use in hci_le_create_conn_sync
Bluetooth: hci_sync: remove unnecessary hci_conn_get in
create_conn_sync
net/bluetooth/hci_conn.c | 12 +++++- net/bluetooth/hci_sync.c | 85 +++++++++++++++++++++++++--------------- 2 files changed, 65 insertions(+), 32 deletions(-)
Signature · 1 line
2.55.0
PATCH v5 1/7 Bluetooth: hci_conn: hold conn reference in abort_conn_sync()
There is theoretical UAF if the conn is freed while the hci_sync task is running.
Hold refcount to avoid that.
---
Notes:
v5:
- no change
v4:
- no change
v3:
- split to multiple patches per different Fixes:
net/bluetooth/hci_conn.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-)
net/bluetooth/hci_conn.c +11 -1
@@ -3163,6 +3163,13 @@ static int abort_conn_sync(struct hci_dev *hdev, void *data)return hci_abort_conn_sync (hdev, conn, conn->abort_reason); } +static void abort_conn_destroy (struct hci_dev *hdev,void *data,int err) +{ +struct hci_conn *conn = data; + +hci_conn_put (conn); +} +int hci_abort_conn (struct hci_conn *conn,u8 reason) {struct hci_dev *hdev = conn->hdev;
@@ -3188,7 +3195,10 @@ int hci_abort_conn(struct hci_conn *conn, u8 reason)* as a result to MGMT_OP_DISCONNECT/MGMT_OP_UNPAIR which does * already queue its callback on cmd_sync_work. */ - err =hci_cmd_sync_run_once (hdev, abort_conn_sync, conn,NULL ); + err =hci_cmd_sync_run_once (hdev, abort_conn_sync,hci_conn_get (conn), + abort_conn_destroy); +if (err) +hci_conn_put (conn);return (err == -EEXIST ) ?0 : err; }
Signature · 1 line
2.55.0
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=1134345
---Test result---
Test Summary:
CheckPatch PASS 4.97 seconds VerifyFixes PASS 0.13 seconds VerifySignedoff PASS 0.13 seconds GitLint FAIL 2.26 seconds SubjectPrefix PASS 1.85 seconds BuildKernel PASS 26.83 seconds CheckAllWarning PASS 29.51 seconds CheckSparse PASS 28.39 seconds BuildKernel32 PASS 25.84 seconds CheckKernelLLVM SKIP 0.00 seconds TestRunnerSetup PASS 491.84 seconds TestRunner_l2cap-tester PASS 59.36 seconds TestRunner_iso-tester FAIL 90.00 seconds TestRunner_bnep-tester PASS 19.20 seconds TestRunner_mgmt-tester FAIL 217.48 seconds TestRunner_rfcomm-tester PASS 25.19 seconds TestRunner_sco-tester PASS 31.40 seconds TestRunner_ioctl-tester PASS 26.32 seconds TestRunner_mesh-tester FAIL 25.89 seconds TestRunner_smp-tester PASS 23.55 seconds TestRunner_userchan-tester PASS 20.01 seconds TestRunner_6lowpan-tester PASS 23.23 seconds IncrementalBuild PASS 43.48 seconds
Details
##############################
Test: GitLint - FAIL
Desc: Run gitlint
Output:
[v5,2/7] Bluetooth: hci_sync: hold conn in hci_connect_acl/le_sync() callbacks
18: B2 Line has trailing whitespace: " "
[v5,7/7] Bluetooth: hci_sync: remove unnecessary hci_conn_get in create_conn_sync
1: T1 Title exceeds max length (81>80): "[v5,7/7] Bluetooth: hci_sync: remove unnecessary hci_conn_get in create_conn_sync"
##############################
Test: CheckKernelLLVM - SKIP
Desc: Build kernel with LLVM + context analysis
Output:
Clang not found
##############################
Test: TestRunner_iso-tester - FAIL
Desc: Run iso-tester with test-runner
Output:
Total: 141, Passed: 134 (95.0%), Failed: 7, Not Run: 0
Failed Test Cases
ISO Disconnect - Success Timed out 2.653 seconds ISO Reconnect - Success Timed out 1.995 seconds ISO Reconnect Send and Receive #16 - Success Timed out 1.995 seconds ISO Reconnect AC 6(i) - Success Timed out 2.632 seconds ISO Reconnect AC 6(ii) - Success Timed out 2.004 seconds ISO Broadcaster Reconnect - Success Timed out 1.971 seconds ISO Broadcaster Receiver Defer Reconnect - Success Timed out 2.417 seconds
##############################
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.249 seconds
##############################
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 2.648 seconds Mesh - Send cancel - 2 Timed out 1.988 seconds
https://github.com/bluez/bluetooth-next/pull/493
---
Regards,
Linux Bluetooth
PATCH v5 2/7 Bluetooth: hci_sync: hold conn in hci_connect_acl/le_sync() callbacks
In reply to Pauli VirtanenThere is theoretical UAF if the conn is freed while the hci_sync task is running.
Hold refcount to avoid that.
---
Notes:
v5:
- no change
v4:
- no change
v3:
- split to multiple patches per different Fixes:
hci_conn_get() was added inside hci_le_create_conn_sync() in commit 76c2d047410ba, but it is too late to do there as the hci_conn_get() itself may be UAF.
net/bluetooth/hci_sync.c | 32 ++++++++++++++++++++++++-------- 1 file changed, 24 insertions(+), 8 deletions(-)
net/bluetooth/hci_sync.c +24 -8
@@ -7128,12 +7128,23 @@ static int hci_acl_create_conn_sync(struct hci_dev *hdev, void *data)return err; } +static void hci_acl_create_conn_sync_complete (struct hci_dev *hdev,void *data, +int err) +{ +struct hci_conn *conn = data; + +hci_conn_put (conn); +} +int hci_connect_acl_sync (struct hci_dev *hdev,struct hci_conn *conn) {int err; - err =hci_cmd_sync_queue_once (hdev, hci_acl_create_conn_sync, conn, -NULL ); + err =hci_cmd_sync_queue_once (hdev, hci_acl_create_conn_sync, +hci_conn_get (conn), + hci_acl_create_conn_sync_complete); +if (err) +hci_conn_put (conn);return (err == -EEXIST ) ?0 : err; }
@@ -7144,36 +7155,41 @@ static void create_le_conn_complete(struct hci_dev *hdev, void *data, int err)bt_dev_dbg (hdev,"err %d" , err);if (err == -ECANCELED ) -return ; + goto done;hci_dev_lock (hdev);if (!hci_conn_valid (hdev, conn)) - goto done; + goto unlock;if (!err) {hci_connect_le_scan_cleanup (conn,0x00 ); - goto done; + goto unlock; }/* Check if connection is still pending */ if (conn !=hci_lookup_le_connect (hdev)) - goto done; + goto unlock;/* Flush to make sure we send create conn cancel command if needed */ flush_delayed_work (&conn->le_conn_timeout);hci_conn_failed (conn,bt_status (err)); -done: +unlock:hci_dev_unlock (hdev); +done: +hci_conn_put (conn); }int hci_connect_le_sync (struct hci_dev *hdev,struct hci_conn *conn) {int err; - err =hci_cmd_sync_queue_once (hdev, hci_le_create_conn_sync, conn, + err =hci_cmd_sync_queue_once (hdev, hci_le_create_conn_sync, +hci_conn_get (conn), create_le_conn_complete); +if (err) +hci_conn_put (conn);return (err == -EEXIST ) ?0 : err; }
Signature · 1 line
2.55.0
PATCH v5 3/7 Bluetooth: hci_sync: hold conn in hci_connect_big_sync() callback
In reply to Pauli VirtanenThere is theoretical UAF if the conn is freed while the hci_sync task is running.
Hold refcount to avoid that. Handle NULL hcon, return 0 + do nothing to match the previous behavior.
---
Notes:
v5:
- clear_bit() without hci_conn_valid check, we hold reference v4:
- check for conn == NULL before hci_conn_get(), since it appears iso.c may end up calling this with NULL
v3:
- split to multiple patches per different Fixes:
- hold RCU instead of hdev->lock
net/bluetooth/hci_sync.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-)
net/bluetooth/hci_sync.c +12 -4
@@ -7498,10 +7498,12 @@ static void create_big_complete(struct hci_dev *hdev, void *data, int err)bt_dev_dbg (hdev,"err %d" , err);if (err == -ECANCELED ) -return ; + goto done; -if (hci_conn_valid (hdev, conn)) -clear_bit (HCI_CONN_CREATE_BIG_SYNC , &conn->flags); +clear_bit (HCI_CONN_CREATE_BIG_SYNC , &conn->flags); + +done: +hci_conn_put (conn); }static int hci_le_big_create_sync (struct hci_dev *hdev,void *data)
@@ -7553,8 +7555,14 @@ int hci_connect_big_sync(struct hci_dev *hdev, struct hci_conn *conn) {int err; - err =hci_cmd_sync_queue_once (hdev, hci_le_big_create_sync, conn, +if (!conn) +return 0 ; + + err =hci_cmd_sync_queue_once (hdev, hci_le_big_create_sync, +hci_conn_get (conn), create_big_complete); +if (err) +hci_conn_put (conn);return (err == -EEXIST ) ?0 : err; }
Signature · 1 line
2.55.0
PATCH v5 4/7 Bluetooth: hci_sync: hold conn in hci_connect_pa_sync() callback
In reply to Pauli VirtanenThere is theoretical UAF if the conn is freed while the hci_sync task is running.
Hold refcount to avoid that.
---
Notes:
v5:
- no change
v4:
- no change
v3:
- split to multiple patches per different Fixes:
net/bluetooth/hci_sync.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-)
net/bluetooth/hci_sync.c +7 -2
@@ -7312,7 +7312,7 @@ static void create_pa_complete(struct hci_dev *hdev, void *data, int err)bt_dev_dbg (hdev,"err %d" , err);if (err == -ECANCELED ) -return ; + goto done;hci_dev_lock (hdev);
@@ -7336,6 +7336,8 @@ static void create_pa_complete(struct hci_dev *hdev, void *data, int err) unlock:hci_dev_unlock (hdev); +done: +hci_conn_put (conn); } static int hci_le_past_params_sync(struct hci_dev *hdev, struct hci_conn *conn,
@@ -7486,8 +7488,11 @@ int hci_connect_pa_sync(struct hci_dev *hdev, struct hci_conn *conn) {int err; - err =hci_cmd_sync_queue_once (hdev, hci_le_pa_create_sync, conn, + err =hci_cmd_sync_queue_once (hdev, hci_le_pa_create_sync, +hci_conn_get (conn), create_pa_complete); +if (err) +hci_conn_put (conn);return (err == -EEXIST ) ?0 : err; }
Signature · 1 line
2.55.0
PATCH v5 5/7 Bluetooth: hci_sync: hold conn in hci_past_sync() callback
In reply to Pauli VirtanenAvoids giving freed pointers to hci_conn_valid(), which kmalloc may have reused.
Hold refcount to avoid that.
---
Notes:
v5:
- no change
v4:
- no change
v3:
- split to multiple patches per different Fixes:
net/bluetooth/hci_sync.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-)
net/bluetooth/hci_sync.c +8 -3
@@ -7582,6 +7582,8 @@ static void past_complete(struct hci_dev *hdev, void *data, int err)bt_dev_dbg (hdev,"err %d" , err); +hci_conn_put (past->conn); +hci_conn_put (past->le);kfree (past); }
@@ -7646,8 +7648,8 @@ int hci_past_sync(struct hci_conn *conn, struct hci_conn *le)if (!data)return -ENOMEM ; - data->conn = conn; - data->le = le; + data->conn =hci_conn_get (conn); + data->le =hci_conn_get (le);if (conn->role ==HCI_ROLE_MASTER ) err = hci_cmd_sync_queue_once(conn->hdev,
@@ -7657,8 +7659,11 @@ int hci_past_sync(struct hci_conn *conn, struct hci_conn *le) err =hci_cmd_sync_queue_once (conn->hdev, hci_le_past_sync, data, past_complete); -if (err) +if (err) { +hci_conn_put (data->conn); +hci_conn_put (data->le);kfree (data); + }return (err == -EEXIST ) ?0 : err; }
Signature · 1 line
2.55.0
PATCH v5 6/7 Bluetooth: hci_sync: fix hci_conn_del() use in hci_le_create_conn_sync
In reply to Pauli Virtanenhci_conn_del() caller must hold hdev->lock, check the conn was not concurrently deleted, and usually inform socket the conn is going to be deleted.
Use hci_abort_conn_sync() instead of calling hci_conn_del() without locks etc.
---
Notes:
v5:
- no change
v4:
- no change
v3:
- use hci_abort_conn_sync instead of lock + hci_conn_valid + hci_conn_del
net/bluetooth/hci_sync.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
net/bluetooth/hci_sync.c +3 -1
@@ -6733,7 +6733,9 @@ static int hci_le_create_conn_sync(struct hci_dev *hdev, void *data)if (hci_dev_test_flag (hdev,HCI_LE_SCAN ) && hdev->le_scan_type ==LE_SCAN_ACTIVE && !hci_dev_test_flag (hdev,HCI_LE_SIMULTANEOUS_ROLES )) { -hci_conn_del (conn); + conn->state =BT_OPEN ; +hci_abort_conn_sync (hdev, conn, +HCI_ERROR_REJ_LIMITED_RESOURCES );hci_conn_put (conn);return -EBUSY ; }
Signature · 1 line
2.55.0
PATCH v5 7/7 Bluetooth: hci_sync: remove unnecessary hci_conn_get in create_conn_sync
In reply to Pauli Virtanenhci_conn_get() without already held reference is data race against concurrent deletion.
In previous patches, the refcount has been changed to be taken before starting the hci_sync task, so remove these extra get() + put() as they are not needed.
---
Notes:
v5:
- no change
v4:
- no change
net/bluetooth/hci_sync.c | 13 ------------- 1 file changed, 13 deletions(-)
net/bluetooth/hci_sync.c +0 -13
@@ -6717,11 +6717,6 @@ static int hci_le_create_conn_sync(struct hci_dev *hdev, void *data)bt_dev_dbg (hdev,"conn %p" , conn); -/* Hold a reference so conn stays valid for the HCI_CONN_CREATE -* clear_bit() at done. -*/ -hci_conn_get (conn); -clear_bit (HCI_CONN_SCANNING , &conn->flags); conn->state =BT_CONNECT ;
@@ -6736,7 +6731,6 @@ static int hci_le_create_conn_sync(struct hci_dev *hdev, void *data) conn->state =BT_OPEN ;hci_abort_conn_sync (hdev, conn,HCI_ERROR_REJ_LIMITED_RESOURCES ); -hci_conn_put (conn);return -EBUSY ; }
@@ -6834,7 +6828,6 @@ static int hci_le_create_conn_sync(struct hci_dev *hdev, void *data)/* Re-enable advertising after the connection attempt is finished. */ hci_resume_advertising_sync (hdev); -hci_conn_put (conn);return err; }
@@ -7109,11 +7102,6 @@ static int hci_acl_create_conn_sync(struct hci_dev *hdev, void *data)else cp.role_switch =0x00 ; -/* Hold a reference so conn stays valid for the HCI_CONN_CREATE -* clear_bit() below. -*/ -hci_conn_get (conn); -/* Mark create connection in flight so hci_cancel_connect_sync() can * cancel it while blocking on the connection complete event. */
@@ -7125,7 +7113,6 @@ static int hci_acl_create_conn_sync(struct hci_dev *hdev, void *data) conn->conn_timeout, NULL);clear_bit (HCI_CONN_CREATE , &conn->flags); -hci_conn_put (conn);return err; }
Signature · 1 line
2.55.0
This series was applied to bluetooth/bluetooth-next.git (master) by Luiz Augusto von Dentz <[email protected]>:
Hello:
This series was applied to bluetooth/bluetooth-next.git (master) by Luiz Augusto von Dentz <[email protected]>:
Quoted 11 lines · On Sat, 25 Jul 2026 12:59:16 +0300 you wrote:
Have
hci_synctasks hold reference tohci_connpointer they want to use later.Avoids UAFs and passing potentially reused (possible even if very unlikely) pointers to
hci_conn_valid().
hci_conn_del()dequeues running works for the same connection, but this has no effect if the work is already started running, which is the race condition here.[...]
Here is the summary with links:
- [v5,1/7] Bluetooth: hci_conn: hold conn reference in abort_conn_sync()
https://git.kernel.org/bluetooth/bluetooth-next/c/3bf1394e8868 - [v5,2/7] Bluetooth: hci_sync: hold conn in hci_connect_acl/le_sync() callbacks https://git.kernel.org/bluetooth/bluetooth-next/c/69a694ebe97f - [v5,3/7] Bluetooth: hci_sync: hold conn in hci_connect_big_sync() callback https://git.kernel.org/bluetooth/bluetooth-next/c/b1196afe58a9 - [v5,4/7] Bluetooth: hci_sync: hold conn in hci_connect_pa_sync() callback https://git.kernel.org/bluetooth/bluetooth-next/c/cddfec3618d0 - [v5,5/7] Bluetooth: hci_sync: hold conn in hci_past_sync() callback https://git.kernel.org/bluetooth/bluetooth-next/c/3c5f5c6be878 - [v5,6/7] Bluetooth: hci_sync: fix hci_conn_del() use in hci_le_create_conn_sync https://git.kernel.org/bluetooth/bluetooth-next/c/423e5fc465eb - [v5,7/7] Bluetooth: hci_sync: remove unnecessary hci_conn_get in create_conn_sync https://git.kernel.org/bluetooth/bluetooth-next/c/73b6871b261f
You are awesome, thank you!
Signature · 2 lines
Deet-doot-dot, I am a bot. https://korg.docs.kernel.org/patchwork/pwbot.html