* [PATCH v2] Bluetooth: hci_conn: Fix null ptr deref in hci_abort_conn()
@ 2026-06-10 15:06 Siwei Zhang
2026-06-10 16:43 ` Luiz Augusto von Dentz
2026-06-10 18:28 ` [v2] " bluez.test.bot
0 siblings, 2 replies; 3+ messages in thread
From: Siwei Zhang @ 2026-06-10 15:06 UTC (permalink / raw)
To: Luiz Augusto von Dentz; +Cc: linux-bluetooth, Siwei Zhang
hci_abort_conn() read hci_skb_event(hdev->sent_cmd) when a connection
was pending, but hdev->sent_cmd can be NULL while req_status is still
HCI_REQ_PEND, leading to a NULL pointer dereference and a general
protection fault from the hci_rx_work() receive path.
Instead of inspecting hdev->sent_cmd, track the in-flight create
connection command with a new per-connection HCI_CONN_CREATE_CONN flag
and route all cancellation through hci_cancel_connect_sync(), which
dequeues the command if still queued, or cancels the pending request if
this connection owns the in-flight create command. CIS uses the same
path via the existing HCI_CONN_CREATE_CIS flag.
Fixes: a13f316e90fd ("Bluetooth: hci_conn: Consolidate code for aborting connections")
Cc: stable@vger.kernel.org
Assisted-by: Claude:claude-opus-4-8
Signed-off-by: Siwei Zhang <oss@fourdim.xyz>
---
include/net/bluetooth/hci_core.h | 1 +
net/bluetooth/hci_conn.c | 21 ++----------
net/bluetooth/hci_sync.c | 58 +++++++++++++++++++++++++-------
3 files changed, 50 insertions(+), 30 deletions(-)
diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index aa600fbf9a53..c90ca6173680 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -988,6 +988,7 @@ enum {
HCI_CONN_AUTH_FAILURE,
HCI_CONN_PER_ADV,
HCI_CONN_BIG_CREATED,
+ HCI_CONN_CREATE_CONN,
HCI_CONN_CREATE_CIS,
HCI_CONN_CREATE_BIG_SYNC,
HCI_CONN_BIG_SYNC,
diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c
index 54eabaa46960..eba4a548bef5 100644
--- a/net/bluetooth/hci_conn.c
+++ b/net/bluetooth/hci_conn.c
@@ -3181,26 +3181,11 @@ int hci_abort_conn(struct hci_conn *conn, u8 reason)
conn->abort_reason = reason;
- /* If the connection is pending check the command opcode since that
- * might be blocking on hci_cmd_sync_work while waiting its respective
- * event so we need to hci_cmd_sync_cancel to cancel it.
- *
- * hci_connect_le serializes the connection attempts so only one
- * connection can be in BT_CONNECT at time.
+ /* Cancel the connect attempt. A return of 0 means the create command
+ * was still queued and got dequeued, so there is nothing to disconnect.
*/
- if (conn->state == BT_CONNECT && READ_ONCE(hdev->req_status) == HCI_REQ_PEND) {
- switch (hci_skb_event(hdev->sent_cmd)) {
- case HCI_EV_CONN_COMPLETE:
- case HCI_EV_LE_CONN_COMPLETE:
- case HCI_EV_LE_ENHANCED_CONN_COMPLETE:
- case HCI_EVT_LE_CIS_ESTABLISHED:
- hci_cmd_sync_cancel(hdev, ECANCELED);
- break;
- }
- /* Cancel connect attempt if still queued/pending */
- } else if (!hci_cancel_connect_sync(hdev, conn)) {
+ if (!hci_cancel_connect_sync(hdev, conn))
return 0;
- }
/* Run immediately if on cmd_sync_work since this may be called
* as a result to MGMT_OP_DISCONNECT/MGMT_OP_UNPAIR which does
diff --git a/net/bluetooth/hci_sync.c b/net/bluetooth/hci_sync.c
index df23245d6ccd..08917b8167de 100644
--- a/net/bluetooth/hci_sync.c
+++ b/net/bluetooth/hci_sync.c
@@ -6668,6 +6668,12 @@ static int hci_le_create_conn_sync(struct hci_dev *hdev, void *data)
&own_addr_type);
if (err)
goto done;
+
+ /* Mark create connection in flight so hci_cancel_connect_sync() can
+ * cancel it while blocking on the connection complete event.
+ */
+ set_bit(HCI_CONN_CREATE_CONN, &conn->flags);
+
/* Send command LE Extended Create Connection if supported */
if (use_ext_conn(hdev)) {
err = hci_le_ext_create_conn_sync(hdev, conn, own_addr_type);
@@ -6703,6 +6709,8 @@ static int hci_le_create_conn_sync(struct hci_dev *hdev, void *data)
conn->conn_timeout, NULL);
done:
+ clear_bit(HCI_CONN_CREATE_CONN, &conn->flags);
+
if (err == -ETIMEDOUT)
hci_le_connect_cancel_sync(hdev, conn, 0x00);
@@ -6982,10 +6990,19 @@ static int hci_acl_create_conn_sync(struct hci_dev *hdev, void *data)
else
cp.role_switch = 0x00;
- return __hci_cmd_sync_status_sk(hdev, HCI_OP_CREATE_CONN,
- sizeof(cp), &cp,
- HCI_EV_CONN_COMPLETE,
- conn->conn_timeout, NULL);
+ /* Mark create connection in flight so hci_cancel_connect_sync() can
+ * cancel it while blocking on the connection complete event.
+ */
+ set_bit(HCI_CONN_CREATE_CONN, &conn->flags);
+
+ err = __hci_cmd_sync_status_sk(hdev, HCI_OP_CREATE_CONN,
+ sizeof(cp), &cp,
+ HCI_EV_CONN_COMPLETE,
+ conn->conn_timeout, NULL);
+
+ clear_bit(HCI_CONN_CREATE_CONN, &conn->flags);
+
+ return err;
}
int hci_connect_acl_sync(struct hci_dev *hdev, struct hci_conn *conn)
@@ -7039,20 +7056,37 @@ int hci_connect_le_sync(struct hci_dev *hdev, struct hci_conn *conn)
int hci_cancel_connect_sync(struct hci_dev *hdev, struct hci_conn *conn)
{
- if (conn->state != BT_OPEN)
- return -EINVAL;
+ hci_cmd_sync_work_func_t func = NULL;
+ hci_cmd_sync_work_destroy_t destroy = NULL;
+ int create_flag = -1;
switch (conn->type) {
case ACL_LINK:
- return !hci_cmd_sync_dequeue_once(hdev,
- hci_acl_create_conn_sync,
- conn, NULL);
+ func = hci_acl_create_conn_sync;
+ create_flag = HCI_CONN_CREATE_CONN;
+ break;
case LE_LINK:
- return !hci_cmd_sync_dequeue_once(hdev, hci_le_create_conn_sync,
- conn, create_le_conn_complete);
+ func = hci_le_create_conn_sync;
+ destroy = create_le_conn_complete;
+ create_flag = HCI_CONN_CREATE_CONN;
+ break;
+ case CIS_LINK:
+ /* LE Create CIS is shared by the whole CIG and cannot be
+ * dequeued per-connection; only cancel it in-flight below.
+ */
+ create_flag = HCI_CONN_CREATE_CIS;
+ break;
+ default:
+ return -ENOENT;
}
- return -ENOENT;
+ if (func && hci_cmd_sync_dequeue_once(hdev, func, conn, destroy))
+ return 0;
+
+ if (create_flag >= 0 && test_bit(create_flag, &conn->flags))
+ hci_cmd_sync_cancel(hdev, ECANCELED);
+
+ return -EBUSY;
}
int hci_le_conn_update_sync(struct hci_dev *hdev, struct hci_conn *conn,
--
2.54.0
^ permalink raw reply related [flat|nested] 3+ messages in thread
* Re: [PATCH v2] Bluetooth: hci_conn: Fix null ptr deref in hci_abort_conn()
2026-06-10 15:06 [PATCH v2] Bluetooth: hci_conn: Fix null ptr deref in hci_abort_conn() Siwei Zhang
@ 2026-06-10 16:43 ` Luiz Augusto von Dentz
2026-06-10 18:28 ` [v2] " bluez.test.bot
1 sibling, 0 replies; 3+ messages in thread
From: Luiz Augusto von Dentz @ 2026-06-10 16:43 UTC (permalink / raw)
To: Siwei Zhang; +Cc: linux-bluetooth
Hi Siwei,
On Wed, Jun 10, 2026 at 11:07 AM Siwei Zhang <oss@fourdim.xyz> wrote:
>
> hci_abort_conn() read hci_skb_event(hdev->sent_cmd) when a connection
> was pending, but hdev->sent_cmd can be NULL while req_status is still
> HCI_REQ_PEND, leading to a NULL pointer dereference and a general
> protection fault from the hci_rx_work() receive path.
>
> Instead of inspecting hdev->sent_cmd, track the in-flight create
> connection command with a new per-connection HCI_CONN_CREATE_CONN flag
> and route all cancellation through hci_cancel_connect_sync(), which
> dequeues the command if still queued, or cancels the pending request if
> this connection owns the in-flight create command. CIS uses the same
> path via the existing HCI_CONN_CREATE_CIS flag.
>
> Fixes: a13f316e90fd ("Bluetooth: hci_conn: Consolidate code for aborting connections")
> Cc: stable@vger.kernel.org
> Assisted-by: Claude:claude-opus-4-8
> Signed-off-by: Siwei Zhang <oss@fourdim.xyz>
> ---
> include/net/bluetooth/hci_core.h | 1 +
> net/bluetooth/hci_conn.c | 21 ++----------
> net/bluetooth/hci_sync.c | 58 +++++++++++++++++++++++++-------
> 3 files changed, 50 insertions(+), 30 deletions(-)
>
> diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
> index aa600fbf9a53..c90ca6173680 100644
> --- a/include/net/bluetooth/hci_core.h
> +++ b/include/net/bluetooth/hci_core.h
> @@ -988,6 +988,7 @@ enum {
> HCI_CONN_AUTH_FAILURE,
> HCI_CONN_PER_ADV,
> HCI_CONN_BIG_CREATED,
> + HCI_CONN_CREATE_CONN,
Use just HCI_CONN_CREATE
> HCI_CONN_CREATE_CIS,
> HCI_CONN_CREATE_BIG_SYNC,
> HCI_CONN_BIG_SYNC,
> diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c
> index 54eabaa46960..eba4a548bef5 100644
> --- a/net/bluetooth/hci_conn.c
> +++ b/net/bluetooth/hci_conn.c
> @@ -3181,26 +3181,11 @@ int hci_abort_conn(struct hci_conn *conn, u8 reason)
>
> conn->abort_reason = reason;
>
> - /* If the connection is pending check the command opcode since that
> - * might be blocking on hci_cmd_sync_work while waiting its respective
> - * event so we need to hci_cmd_sync_cancel to cancel it.
> - *
> - * hci_connect_le serializes the connection attempts so only one
> - * connection can be in BT_CONNECT at time.
> + /* Cancel the connect attempt. A return of 0 means the create command
> + * was still queued and got dequeued, so there is nothing to disconnect.
> */
> - if (conn->state == BT_CONNECT && READ_ONCE(hdev->req_status) == HCI_REQ_PEND) {
> - switch (hci_skb_event(hdev->sent_cmd)) {
> - case HCI_EV_CONN_COMPLETE:
> - case HCI_EV_LE_CONN_COMPLETE:
> - case HCI_EV_LE_ENHANCED_CONN_COMPLETE:
> - case HCI_EVT_LE_CIS_ESTABLISHED:
> - hci_cmd_sync_cancel(hdev, ECANCELED);
> - break;
> - }
> - /* Cancel connect attempt if still queued/pending */
> - } else if (!hci_cancel_connect_sync(hdev, conn)) {
> + if (!hci_cancel_connect_sync(hdev, conn))
> return 0;
> - }
>
> /* Run immediately if on cmd_sync_work since this may be called
> * as a result to MGMT_OP_DISCONNECT/MGMT_OP_UNPAIR which does
> diff --git a/net/bluetooth/hci_sync.c b/net/bluetooth/hci_sync.c
> index df23245d6ccd..08917b8167de 100644
> --- a/net/bluetooth/hci_sync.c
> +++ b/net/bluetooth/hci_sync.c
> @@ -6668,6 +6668,12 @@ static int hci_le_create_conn_sync(struct hci_dev *hdev, void *data)
> &own_addr_type);
> if (err)
> goto done;
> +
> + /* Mark create connection in flight so hci_cancel_connect_sync() can
> + * cancel it while blocking on the connection complete event.
> + */
> + set_bit(HCI_CONN_CREATE_CONN, &conn->flags);
> +
> /* Send command LE Extended Create Connection if supported */
> if (use_ext_conn(hdev)) {
> err = hci_le_ext_create_conn_sync(hdev, conn, own_addr_type);
> @@ -6703,6 +6709,8 @@ static int hci_le_create_conn_sync(struct hci_dev *hdev, void *data)
> conn->conn_timeout, NULL);
>
> done:
> + clear_bit(HCI_CONN_CREATE_CONN, &conn->flags);
> +
> if (err == -ETIMEDOUT)
> hci_le_connect_cancel_sync(hdev, conn, 0x00);
>
> @@ -6982,10 +6990,19 @@ static int hci_acl_create_conn_sync(struct hci_dev *hdev, void *data)
> else
> cp.role_switch = 0x00;
>
> - return __hci_cmd_sync_status_sk(hdev, HCI_OP_CREATE_CONN,
> - sizeof(cp), &cp,
> - HCI_EV_CONN_COMPLETE,
> - conn->conn_timeout, NULL);
> + /* Mark create connection in flight so hci_cancel_connect_sync() can
> + * cancel it while blocking on the connection complete event.
> + */
> + set_bit(HCI_CONN_CREATE_CONN, &conn->flags);
> +
> + err = __hci_cmd_sync_status_sk(hdev, HCI_OP_CREATE_CONN,
> + sizeof(cp), &cp,
> + HCI_EV_CONN_COMPLETE,
> + conn->conn_timeout, NULL);
> +
> + clear_bit(HCI_CONN_CREATE_CONN, &conn->flags);
> +
> + return err;
> }
>
> int hci_connect_acl_sync(struct hci_dev *hdev, struct hci_conn *conn)
> @@ -7039,20 +7056,37 @@ int hci_connect_le_sync(struct hci_dev *hdev, struct hci_conn *conn)
>
> int hci_cancel_connect_sync(struct hci_dev *hdev, struct hci_conn *conn)
> {
> - if (conn->state != BT_OPEN)
> - return -EINVAL;
> + hci_cmd_sync_work_func_t func = NULL;
> + hci_cmd_sync_work_destroy_t destroy = NULL;
> + int create_flag = -1;
>
> switch (conn->type) {
> case ACL_LINK:
> - return !hci_cmd_sync_dequeue_once(hdev,
> - hci_acl_create_conn_sync,
> - conn, NULL);
> + func = hci_acl_create_conn_sync;
> + create_flag = HCI_CONN_CREATE_CONN;
> + break;
> case LE_LINK:
> - return !hci_cmd_sync_dequeue_once(hdev, hci_le_create_conn_sync,
> - conn, create_le_conn_complete);
> + func = hci_le_create_conn_sync;
> + destroy = create_le_conn_complete;
> + create_flag = HCI_CONN_CREATE_CONN;
> + break;
> + case CIS_LINK:
> + /* LE Create CIS is shared by the whole CIG and cannot be
> + * dequeued per-connection; only cancel it in-flight below.
> + */
> + create_flag = HCI_CONN_CREATE_CIS;
> + break;
> + default:
> + return -ENOENT;
> }
>
> - return -ENOENT;
> + if (func && hci_cmd_sync_dequeue_once(hdev, func, conn, destroy))
> + return 0;
> +
> + if (create_flag >= 0 && test_bit(create_flag, &conn->flags))
> + hci_cmd_sync_cancel(hdev, ECANCELED);
Hmm, I'm not sure I like how this is done here, it seems to always
attempt to dequeue even if the flag indicates it is pending. If that
is intentional, you should add a comment.
> + return -EBUSY;
> }
>
> int hci_le_conn_update_sync(struct hci_dev *hdev, struct hci_conn *conn,
> --
> 2.54.0
>
--
Luiz Augusto von Dentz
^ permalink raw reply [flat|nested] 3+ messages in thread
* RE: [v2] Bluetooth: hci_conn: Fix null ptr deref in hci_abort_conn()
2026-06-10 15:06 [PATCH v2] Bluetooth: hci_conn: Fix null ptr deref in hci_abort_conn() Siwei Zhang
2026-06-10 16:43 ` Luiz Augusto von Dentz
@ 2026-06-10 18:28 ` bluez.test.bot
1 sibling, 0 replies; 3+ messages in thread
From: bluez.test.bot @ 2026-06-10 18:28 UTC (permalink / raw)
To: linux-bluetooth, oss
[-- Attachment #1: Type: text/plain, Size: 2204 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=1109363
---Test result---
Test Summary:
CheckPatch PASS 1.14 seconds
VerifyFixes PASS 0.11 seconds
VerifySignedoff PASS 0.11 seconds
GitLint PASS 0.29 seconds
SubjectPrefix PASS 0.11 seconds
BuildKernel PASS 27.22 seconds
CheckAllWarning PASS 29.76 seconds
CheckSparse PASS 28.66 seconds
BuildKernel32 PASS 26.45 seconds
TestRunnerSetup PASS 579.03 seconds
TestRunner_l2cap-tester PASS 60.13 seconds
TestRunner_iso-tester PASS 74.99 seconds
TestRunner_bnep-tester PASS 19.60 seconds
TestRunner_mgmt-tester FAIL 214.34 seconds
TestRunner_rfcomm-tester PASS 25.55 seconds
TestRunner_sco-tester PASS 32.90 seconds
TestRunner_ioctl-tester PASS 26.59 seconds
TestRunner_mesh-tester FAIL 26.13 seconds
TestRunner_smp-tester PASS 23.46 seconds
TestRunner_userchan-tester PASS 20.07 seconds
TestRunner_6lowpan-tester PASS 23.57 seconds
IncrementalBuild PASS 26.07 seconds
Details
##############################
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.248 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.228 seconds
Mesh - Send cancel - 2 Timed out 1.988 seconds
https://github.com/bluez/bluetooth-next/pull/302
---
Regards,
Linux Bluetooth
^ permalink raw reply [flat|nested] 3+ messages in thread
end of thread, other threads:[~2026-06-10 18:28 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-06-10 15:06 [PATCH v2] Bluetooth: hci_conn: Fix null ptr deref in hci_abort_conn() Siwei Zhang
2026-06-10 16:43 ` Luiz Augusto von Dentz
2026-06-10 18:28 ` [v2] " bluez.test.bot
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox