FAILED: patch "[PATCH] Bluetooth: hci_conn: Fix null ptr deref in hci_abort_conn()" failed to apply to 6.12-stable tree
Subsystems (2)
[email protected]
maintainerThe patch below does not apply to the 6.12-stable tree.
If someone wants it applied there, or to any other stable or longterm tree, then please email the backport, including the original git commit id to <[email protected]>.
To reproduce the conflict and resubmit, you may use the following commands:
git fetch https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/ linux-6.12.y
git checkout FETCH_HEAD
git cherry-pick -x 12917f591cea1af36087dba5b9ec888652f0b42a
# <resolve conflicts, build, test, etc.>
git commit -s
git send-email --to '<[email protected]>' --in-reply-to '2026071353-angular-magical-b4f5@gregkh' --subject-prefix 'PATCH 6.12.y' 'HEAD^..'
Possible dependencies:
thanks,
greg k-h
------------------ original commit in Linus's tree ------------------
From 12917f591cea1af36087dba5b9ec888652f0b42a Mon Sep 17 00:00:00 2001
From: Siwei Zhang <[email protected]>
Date: Mon, 15 Jun 2026 11:33:05 -0400
Subject: [PATCH] Bluetooth: hci_conn: Fix null ptr deref in hci_abort_conn()
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 flag and route all cancellation through hci_cancel_connect_sync(), which dispatches to a dedicated per-type cancel function. The create command is in exactly one of two states: still queued, or in flight. The cancel function holds cmd_sync_work_lock across the whole decision: the worker takes this lock to dequeue every entry, so while it is held a queued command cannot start running and an in-flight command cannot complete and let the next command become pending. This keeps the flag test and hci_cmd_sync_cancel() atomic with respect to the worker, so a queued command is simply dequeued, and an in-flight command owned by this connection is cancelled without the risk of cancelling an unrelated command that became pending in the meantime. CIS uses the same flag mechanism via HCI_CONN_CREATE_CIS but cannot be dequeued per-connection.
hci_acl_create_conn_sync() and hci_le_create_conn_sync() clear HCI_CONN_CREATE after the create command completes, but the command status handler can free conn via hci_conn_del() (for example when the controller rejects the connection) while the worker is still blocked on the connection complete event. Hold a reference on conn across the create command so the flag can be cleared without a use-after-free.
include/net/bluetooth/hci_core.h +1 -0
@@ -985,6 +985,7 @@ enum {HCI_CONN_AUTH_FAILURE ,HCI_CONN_PER_ADV ,HCI_CONN_BIG_CREATED , +HCI_CONN_CREATE ,HCI_CONN_CREATE_CIS ,HCI_CONN_CREATE_BIG_SYNC , HCI_CONN_BIG_SYNC,
net/bluetooth/hci_conn.c +3 -18
@@ -3178,26 +3178,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
net/bluetooth/hci_sync.c +121 -16
182 lines not on this page · raw message
Sasha Levin
maintainerPATCH 1/3 Bluetooth: hci_core: Enable buffer flow control for SCO/eSCO
From: Luiz Augusto von Dentz <[email protected]>
[ Upstream commit 13218453521d75916dfed55efb8e809bfc03cb4b ]
This enables buffer flow control for SCO/eSCO
(see: Bluetooth Core 6.0 spec: 6.22. Synchronous Flow Control Enable), recently this has caused the following problem and is actually a nice addition for the likes of Socket TX complete:
< HCI Command: Read Buffer Size (0x04|0x0005) plen 0
Quoted 1 line
HCI Event: Command Complete (
0x0e) plen 11
Read Buffer Size (0x04|0x0005) ncmd 1
Status: Success (0x00)
ACL MTU: 1021 ACL max packet: 5
SCO MTU: 240 SCO max packet: 8
...
< SCO Data TX: Handle 257 flags 0x00 dlen 120
< SCO Data TX: Handle 257 flags 0x00 dlen 120
< SCO Data TX: Handle 257 flags 0x00 dlen 120
< SCO Data TX: Handle 257 flags 0x00 dlen 120
< SCO Data TX: Handle 257 flags 0x00 dlen 120
< SCO Data TX: Handle 257 flags 0x00 dlen 120
< SCO Data TX: Handle 257 flags 0x00 dlen 120
< SCO Data TX: Handle 257 flags 0x00 dlen 120
< SCO Data TX: Handle 257 flags 0x00 dlen 120
Quoted 1 line
HCI Event: Hardware Error (
0x10) plen 1
Code: 0x0a
To fix the code will now attempt to enable buffer flow control when HCI_QUIRK_SYNC_FLOWCTL_SUPPORTED is set by the driver:
< HCI Command: Write Sync Fl.. (0x03|0x002f) plen 1
Flow control: Enabled (0x01)
Quoted 1 line
HCI Event: Command Complete (
0x0e) plen 4
Write Sync Flow Control Enable (0x03|0x002f) ncmd 1
Status: Success (0x00)On success then HCI_SCO_FLOWCTL would be set which indicates sco_cnt shall be used for flow contro.
Stable-dep-of: 12917f591cea ("Bluetooth: hci_conn: Fix null ptr deref in hci_abort_conn()")
--- include/net/bluetooth/hci.h | 13 +++++++ include/net/bluetooth/hci_core.h | 1 + net/bluetooth/hci_core.c | 62 +++++++++++++++----------------- net/bluetooth/hci_event.c | 2 ++ net/bluetooth/hci_sync.c | 24 +++++++++++++ 5 files changed, 68 insertions(+), 34 deletions(-)
include/net/bluetooth/hci.h +13 -0
@@ -207,6 +207,13 @@ enum {*/ HCI_QUIRK_WIDEBAND_SPEECH_SUPPORTED , +/* When this quirk is set consider Sync Flow Control as supported by +* the driver. +* +* This quirk must be set before hci_register_dev is called. +*/ + HCI_QUIRK_SYNC_FLOWCTL_SUPPORTED, +/* When this quirk is set, the LE states reported through the * HCI_LE_READ_SUPPORTED_STATES are invalid/broken. *
@@ -448,6 +455,7 @@ enum {HCI_WIDEBAND_SPEECH_ENABLED ,HCI_EVENT_FILTER_CONFIGURED ,HCI_PA_SYNC , +HCI_SCO_FLOWCTL ,HCI_DUT_MODE , HCI_VENDOR_DIAG,
@@ -1545,6 +1553,11 @@ struct hci_rp_read_tx_power {__s8 tx_power; } __packed; +#define HCI_OP_WRITE_SYNC_FLOWCTL 0x0c2f +struct hci_cp_write_sync_flowctl { +__u8 enable; +} __packed; +#define HCI_OP_READ_PAGE_SCAN_TYPE 0x0c46struct hci_rp_read_page_scan_type {__u8 status;
include/net/bluetooth/hci_core.h +1 -0
@@ -1891,6 +1891,7 @@ void hci_conn_del_sysfs(struct hci_conn *conn);#define lmp_hold_capable (dev) ((dev)->features[0][0] & LMP_HOLD)#define lmp_sniff_capable (dev) ((dev)->features[0][0] & LMP_SNIFF)#define lmp_park_capable (dev) ((dev)->features[0][1] & LMP_PARK) +#define lmp_sco_capable (dev) ((dev)->features[0][1] & LMP_SCO)#define lmp_inq_rssi_capable (dev) ((dev)->features[0][3] & LMP_RSSI_INQ)#define lmp_esco_capable (dev) ((dev)->features[0][3] & LMP_ESCO)#define lmp_bredr_capable (dev) (!((dev)->features[0][4] & LMP_NO_BREDR))
net/bluetooth/hci_core.c +28 -34
102 lines not on this page · raw message
net/bluetooth/hci_event.c +2 -0
@@ -4448,9 +4448,11 @@ static void hci_num_comp_pkts_evt(struct hci_dev *hdev, void *data,break ;case SCO_LINK : +case ESCO_LINK : hdev->sco_cnt += count;if (hdev->sco_cnt > hdev->sco_pkts) hdev->sco_cnt = hdev->sco_pkts; +break ;case ISO_LINK :
net/bluetooth/hci_sync.c +24 -0
@@ -3888,6 +3888,28 @@ static int hci_write_ca_timeout_sync(struct hci_dev *hdev) sizeof(param), ¶m, HCI_CMD_TIMEOUT); } +/* Enable SCO flow control if supported */ +static int hci_write_sync_flowctl_sync (struct hci_dev *hdev) +{ +struct hci_cp_write_sync_flowctl cp; +int err; + +/* Check if the controller supports SCO and HCI_OP_WRITE_SYNC_FLOWCTL */ +if (!lmp_sco_capable (hdev) || !(hdev->commands[10 ] &BIT (4 )) || + !test_bit (HCI_QUIRK_SYNC_FLOWCTL_SUPPORTED , &hdev->quirks)) +return 0 ; + +memset (&cp,0 ,sizeof (cp)); + cp.enable =0x01 ; + + err =__hci_cmd_sync_status (hdev,HCI_OP_WRITE_SYNC_FLOWCTL , +sizeof (cp), &cp,HCI_CMD_TIMEOUT ); +if (!err) +hci_dev_set_flag (hdev,HCI_SCO_FLOWCTL ); + +return err; +} +/* BR Controller init stage 2 command sequence */ static const struct hci_init_stage br_init2[] = {/* HCI_OP_READ_BUFFER_SIZE */
@@ -3906,6 +3928,8 @@ static const struct hci_init_stage br_init2[] = {HCI_INIT (hci_clear_event_filter_sync),/* HCI_OP_WRITE_CA_TIMEOUT */ HCI_INIT (hci_write_ca_timeout_sync), +/* HCI_OP_WRITE_SYNC_FLOWCTL */ + HCI_INIT(hci_write_sync_flowctl_sync), {} };
Signature · 1 line
2.53.0
Sasha Levin
maintainerPATCH 2/3 Bluetooth: separate CIS_LINK and BIS_LINK link types
From: Pauli Virtanen <[email protected]>
[ Upstream commit 23205562ffc8de20f57afdd984858cab29e77968 ]
Use separate link type id for unicast and broadcast ISO connections. These connection types are handled with separate HCI commands, socket API is different, and hci_conn has union fields that are different in the two cases, so they shall not be mixed up.
Currently in most places it is attempted to distinguish ucast by bacmp(&c->dst, BDADDR_ANY) but it is wrong as dst is set for bcast sink hci_conn in iso_conn_ready(). Additionally checking sync_handle might be OK, but depends on details of bcast conn configuration flow.
To avoid complicating it, use separate link types.
Stable-dep-of: 12917f591cea ("Bluetooth: hci_conn: Fix null ptr deref in hci_abort_conn()")
--- include/net/bluetooth/hci.h | 3 +- include/net/bluetooth/hci_core.h | 48 ++++++++++++++------------------ net/bluetooth/hci_conn.c | 41 ++++++++++++++++----------- net/bluetooth/hci_core.c | 21 ++++++++------ net/bluetooth/hci_event.c | 24 ++++++++-------- net/bluetooth/hci_sync.c | 16 +++++++---- net/bluetooth/iso.c | 4 +-- net/bluetooth/mgmt.c | 3 +- 8 files changed, 87 insertions(+), 73 deletions(-)
include/net/bluetooth/hci.h +2 -1
@@ -558,7 +558,8 @@ enum {#define ESCO_LINK 0x02/* Low Energy links do not have defined link type. Use invented one */ #define LE_LINK 0x80 -#define ISO_LINK 0x82 +#define CIS_LINK 0x82 +#define BIS_LINK 0x83#define INVALID_LINK 0xff/* LMP features */
include/net/bluetooth/hci_core.h +21 -27
132 lines not on this page · raw message
net/bluetooth/hci_conn.c +24 -17
129 lines not on this page · raw message
net/bluetooth/hci_core.c +13 -8
@@ -2957,12 +2957,13 @@ int hci_recv_frame(struct hci_dev *hdev, struct sk_buff *skb)break ;case HCI_ACLDATA_PKT :/* Detect if ISO packet has been sent as ACL */ -if (hci_conn_num (hdev,ISO_LINK )) { +if (hci_conn_num (hdev,CIS_LINK ) || +hci_conn_num (hdev,BIS_LINK )) {__u16 handle =__le16_to_cpu (hci_acl_hdr (skb)->handle);__u8 type; type =hci_conn_lookup_type (hdev,hci_handle (handle)); -if (type ==ISO_LINK ) +if (type ==CIS_LINK || type ==BIS_LINK )hci_skb_pkt_type (skb) =HCI_ISODATA_PKT ; }break ;
@@ -3397,7 +3398,8 @@ static inline void hci_quote_sent(struct hci_conn *conn, int num, int *quote)case LE_LINK : cnt = hdev->le_mtu ? hdev->le_cnt : hdev->acl_cnt;break ; -case ISO_LINK : +case CIS_LINK : +case BIS_LINK : cnt = hdev->iso_mtu ? hdev->iso_cnt : hdev->le_mtu ? hdev->le_cnt : hdev->acl_cnt;break ;
@@ -3411,7 +3413,7 @@ static inline void hci_quote_sent(struct hci_conn *conn, int num, int *quote) }static struct hci_conn *hci_low_sent (struct hci_dev *hdev,__u8 type, -int *quote) +__u8 type2,int *quote) {struct hci_conn_hash *h = &hdev->conn_hash;struct hci_conn *conn =NULL , *c;
@@ -3423,7 +3425,8 @@ static struct hci_conn *hci_low_sent(struct hci_dev *hdev, __u8 type,rcu_read_lock ();list_for_each_entry_rcu (c, &h->list, list) { -if (c->type != type ||skb_queue_empty (&c->data_q)) +if ((c->type != type && c->type != type2) || +skb_queue_empty (&c->data_q))continue ;if (c->state !=BT_CONNECTED && c->state !=BT_CONFIG )
@@ -3626,7 +3629,7 @@ static void hci_sched_sco(struct hci_dev *hdev, __u8 type)else cnt = &hdev->sco_cnt; -while (*cnt && (conn =hci_low_sent (hdev, type, "e))) { +while (*cnt && (conn =hci_low_sent (hdev, type, type, "e))) {while (quote-- && (skb =skb_dequeue (&conn->data_q))) {BT_DBG ("skb %p len %d" , skb, skb->len);hci_send_frame (hdev, skb);
@@ -3754,12 +3757,14 @@ static void hci_sched_iso(struct hci_dev *hdev)BT_DBG ("%s" , hdev->name); -if (!hci_conn_num (hdev,ISO_LINK )) +if (!hci_conn_num (hdev,CIS_LINK ) && + !hci_conn_num (hdev,BIS_LINK ))return ; cnt = hdev->iso_pkts ? &hdev->iso_cnt : hdev->le_pkts ? &hdev->le_cnt : &hdev->acl_cnt; -while (*cnt && (conn =hci_low_sent (hdev,ISO_LINK , "e))) { +while (*cnt && (conn =hci_low_sent (hdev,CIS_LINK ,BIS_LINK , + "e))) {while (quote-- && (skb =skb_dequeue (&conn->data_q))) {BT_DBG ("skb %p len %d" , skb, skb->len);hci_send_frame (hdev, skb);
net/bluetooth/hci_event.c +13 -11
@@ -3778,7 +3778,7 @@ static void hci_unbound_cis_failed(struct hci_dev *hdev, u8 cig, u8 status)lockdep_assert_held (&hdev->lock);list_for_each_entry_safe (conn, tmp, &hdev->conn_hash.list, list) { -if (conn->type !=ISO_LINK || !bacmp (&conn->dst,BDADDR_ANY ) || +if (conn->type !=CIS_LINK || conn->state ==BT_OPEN || conn->iso_qos.ucast.cig != cig)continue ;
@@ -4455,7 +4455,8 @@ static void hci_num_comp_pkts_evt(struct hci_dev *hdev, void *data,break ; -case ISO_LINK : +case CIS_LINK : +case BIS_LINK :if (hdev->iso_pkts) { hdev->iso_cnt += count;if (hdev->iso_cnt > hdev->iso_pkts)
@@ -6422,7 +6423,8 @@ static void hci_le_pa_sync_estabilished_evt(struct hci_dev *hdev, void *data, conn->sync_handle =le16_to_cpu (ev->handle); conn->sid =HCI_SID_INVALID ; - mask |=hci_proto_connect_ind (hdev, &ev->bdaddr,ISO_LINK , &flags); + mask |=hci_proto_connect_ind (hdev, &ev->bdaddr,BIS_LINK , + &flags);if (!(mask &HCI_LM_ACCEPT )) {hci_le_pa_term_sync (hdev, ev->handle); goto unlock;
@@ -6432,7 +6434,7 @@ static void hci_le_pa_sync_estabilished_evt(struct hci_dev *hdev, void *data, goto unlock;/* Add connection to indicate PA sync event */ - pa_sync =hci_conn_add_unset (hdev,ISO_LINK ,BDADDR_ANY , + pa_sync =hci_conn_add_unset (hdev,BIS_LINK ,BDADDR_ANY ,HCI_ROLE_SLAVE );if (IS_ERR (pa_sync))
@@ -6463,7 +6465,7 @@ static void hci_le_per_adv_report_evt(struct hci_dev *hdev, void *data,hci_dev_lock (hdev); - mask |=hci_proto_connect_ind (hdev,BDADDR_ANY ,ISO_LINK , &flags); + mask |=hci_proto_connect_ind (hdev,BDADDR_ANY ,BIS_LINK , &flags);if (!(mask &HCI_LM_ACCEPT )) goto unlock;
@@ -6754,7 +6756,7 @@ static void hci_le_cis_estabilished_evt(struct hci_dev *hdev, void *data, goto unlock; } -if (conn->type !=ISO_LINK ) { +if (conn->type !=CIS_LINK ) {bt_dev_err (hdev,"Invalid connection link type handle 0x%4.4x" , handle);
@@ -6872,7 +6874,7 @@ static void hci_le_cis_req_evt(struct hci_dev *hdev, void *data,if (!acl) goto unlock; - mask =hci_proto_connect_ind (hdev, &acl->dst,ISO_LINK , &flags); + mask =hci_proto_connect_ind (hdev, &acl->dst,CIS_LINK , &flags);if (!(mask &HCI_LM_ACCEPT )) {hci_le_reject_cis (hdev, ev->cis_handle); goto unlock;
@@ -6880,8 +6882,8 @@ static void hci_le_cis_req_evt(struct hci_dev *hdev, void *data, cis =hci_conn_hash_lookup_handle (hdev, cis_handle);if (!cis) { - cis =hci_conn_add (hdev,ISO_LINK , &acl->dst,HCI_ROLE_SLAVE , - cis_handle); + cis =hci_conn_add (hdev,CIS_LINK , &acl->dst, +HCI_ROLE_SLAVE , cis_handle);if (IS_ERR (cis)) {hci_le_reject_cis (hdev, ev->cis_handle); goto unlock;
@@ -7019,7 +7021,7 @@ static void hci_le_big_sync_established_evt(struct hci_dev *hdev, void *data,bt_dev_dbg (hdev,"ignore too large handle %u" , handle);continue ; } - bis =hci_conn_add (hdev,ISO_LINK ,BDADDR_ANY , + bis =hci_conn_add (hdev,BIS_LINK ,BDADDR_ANY ,HCI_ROLE_SLAVE , handle);if (IS_ERR (bis))continue ;
@@ -7078,7 +7080,7 @@ static void hci_le_big_info_adv_report_evt(struct hci_dev *hdev, void *data,hci_dev_lock (hdev); - mask |=hci_proto_connect_ind (hdev,BDADDR_ANY ,ISO_LINK , &flags); + mask |=hci_proto_connect_ind (hdev,BDADDR_ANY ,BIS_LINK , &flags);if (!(mask &HCI_LM_ACCEPT )) goto unlock;
net/bluetooth/hci_sync.c +10 -6
@@ -2979,7 +2979,7 @@ static int hci_le_set_ext_scan_param_sync(struct hci_dev *hdev, u8 type,if (sent) {struct hci_conn *conn; - conn =hci_conn_hash_lookup_ba (hdev,ISO_LINK , + conn =hci_conn_hash_lookup_ba (hdev,BIS_LINK , &sent->bdaddr);if (conn) {struct bt_iso_qos *qos = &conn->iso_qos;
@@ -5596,7 +5596,7 @@ static int hci_connect_cancel_sync(struct hci_dev *hdev, struct hci_conn *conn,if (conn->type ==LE_LINK )return hci_le_connect_cancel_sync (hdev, conn, reason); -if (conn->type ==ISO_LINK ) { +if (conn->type ==CIS_LINK ) {/* BLUETOOTH CORE SPECIFICATION Version 5.3 | Vol 4, Part E * page 1857: *
@@ -5609,9 +5609,10 @@ static int hci_connect_cancel_sync(struct hci_dev *hdev, struct hci_conn *conn,return hci_disconnect_sync (hdev, conn, reason);/* CIS with no Create CIS sent have nothing to cancel */ -if (bacmp (&conn->dst,BDADDR_ANY )) -return HCI_ERROR_LOCAL_HOST_TERM ; +return HCI_ERROR_LOCAL_HOST_TERM ; + } +if (conn->type ==BIS_LINK ) {/* There is no way to cancel a BIS without terminating the BIG * which is done later on connection cleanup. */
@@ -5673,9 +5674,12 @@ static int hci_reject_conn_sync(struct hci_dev *hdev, struct hci_conn *conn, {struct hci_cp_reject_conn_req cp; -if (conn->type ==ISO_LINK ) +if (conn->type ==CIS_LINK )return hci_le_reject_cis_sync (hdev, conn, reason); +if (conn->type ==BIS_LINK ) +return -EINVAL ; +if (conn->type ==SCO_LINK || conn->type ==ESCO_LINK )return hci_reject_sco_sync (hdev, conn, reason);
@@ -7039,7 +7043,7 @@ static void create_pa_complete(struct hci_dev *hdev, void *data, int err) goto unlock;/* Add connection to indicate PA sync error */ - pa_sync =hci_conn_add_unset (hdev,ISO_LINK ,BDADDR_ANY , + pa_sync =hci_conn_add_unset (hdev,BIS_LINK ,BDADDR_ANY ,HCI_ROLE_SLAVE );if (IS_ERR (pa_sync))
net/bluetooth/iso.c +2 -2
@@ -2200,7 +2200,7 @@ int iso_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr, __u8 *flags)static void iso_connect_cfm (struct hci_conn *hcon,__u8 status) { -if (hcon->type !=ISO_LINK ) { +if (hcon->type !=CIS_LINK && hcon->type !=BIS_LINK ) {if (hcon->type !=LE_LINK )return ;
@@ -2241,7 +2241,7 @@ static void iso_connect_cfm(struct hci_conn *hcon, __u8 status)static void iso_disconn_cfm (struct hci_conn *hcon,__u8 reason) { -if (hcon->type !=ISO_LINK ) +if (hcon->type !=CIS_LINK && hcon->type !=BIS_LINK )return ;BT_DBG ("hcon %p reason %d" , hcon, reason);
net/bluetooth/mgmt.c +2 -1
@@ -3240,7 +3240,8 @@ static int disconnect(struct sock *sk, struct hci_dev *hdev, void *data,static u8 link_to_bdaddr (u8 link_type,u8 addr_type) {switch (link_type) { -case ISO_LINK : +case CIS_LINK : +case BIS_LINK :case LE_LINK :switch (addr_type) {case ADDR_LE_DEV_PUBLIC :
Signature · 1 line
2.53.0
Sasha Levin
maintainerPATCH 3/3 Bluetooth: hci_conn: Fix null ptr deref in hci_abort_conn()
In reply to Sasha LevinFrom: Siwei Zhang <[email protected]>
[ Upstream commit 12917f591cea1af36087dba5b9ec888652f0b42a ]
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 flag and route all cancellation through hci_cancel_connect_sync(), which dispatches to a dedicated per-type cancel function. The create command is in exactly one of two states: still queued, or in flight. The cancel function holds cmd_sync_work_lock across the whole decision: the worker takes this lock to dequeue every entry, so while it is held a queued command cannot start running and an in-flight command cannot complete and let the next command become pending. This keeps the flag test and hci_cmd_sync_cancel() atomic with respect to the worker, so a queued command is simply dequeued, and an in-flight command owned by this connection is cancelled without the risk of cancelling an unrelated command that became pending in the meantime. CIS uses the same flag mechanism via HCI_CONN_CREATE_CIS but cannot be dequeued per-connection.
hci_acl_create_conn_sync() and hci_le_create_conn_sync() clear HCI_CONN_CREATE after the create command completes, but the command status handler can free conn via hci_conn_del() (for example when the controller rejects the connection) while the worker is still blocked on the connection complete event. Hold a reference on conn across the create command so the flag can be cleared without a use-after-free.
--- include/net/bluetooth/hci_core.h | 1 + net/bluetooth/hci_conn.c | 21 +---- net/bluetooth/hci_sync.c | 133 +++++++++++++++++++++++++++---- 3 files changed, 123 insertions(+), 32 deletions(-)
include/net/bluetooth/hci_core.h +1 -0
@@ -958,6 +958,7 @@ enum {HCI_CONN_AUTH_FAILURE ,HCI_CONN_PER_ADV ,HCI_CONN_BIG_CREATED , +HCI_CONN_CREATE ,HCI_CONN_CREATE_CIS ,HCI_CONN_CREATE_BIG_SYNC , HCI_CONN_BIG_SYNC,
net/bluetooth/hci_conn.c +3 -18
@@ -2921,26 +2921,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
net/bluetooth/hci_sync.c +119 -14
180 lines not on this page · raw message
Signature · 1 line
2.53.0