FAILED: patch "[PATCH] Bluetooth: mgmt: fix race in read_unconf_index_list()" failed to apply to 5.15-stable tree
Subsystems (2)
[email protected]
maintainerThe patch below does not apply to the 5.15-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-5.15.y
git checkout FETCH_HEAD
git cherry-pick -x b5dbb41b212c50c095a4dbee3017a84fe94f033b
# <resolve conflicts, build, test, etc.>
git commit -s
git send-email --to '<[email protected]>' --in-reply-to '2026092958-cathouse-visiting-7f57@gregkh' --subject-prefix 'PATCH 5.15.y' 'HEAD^..'
Possible dependencies:
thanks,
greg k-h
------------------ original commit in Linus's tree ------------------
From b5dbb41b212c50c095a4dbee3017a84fe94f033b Mon Sep 17 00:00:00 2001
From: Aldo Ariel Panzardo <[email protected]>
Date: Tue, 15 Sep 2026 12:59:52 -0300
Subject: [PATCH] Bluetooth: mgmt: fix race in read_unconf_index_list()
read_unconf_index_list() counts unconfigured controllers before allocating its response, then checks the device flags again while filling it.
hci_dev_list_lock stabilizes list membership, but it does not serialize the per-device flags. During asynchronous controller setup, the worker can set HCI_UNCONFIGURED and clear HCI_SETUP between the two passes. A controller omitted from the allocation count can then become eligible for the fill pass, causing an out-of-bounds write to rp->index[].
Allocate space for every device on hci_dev_list. Since list membership cannot change while hci_dev_list_lock is held, the response remains large enough regardless of flag transitions. The reported count and response length still include only eligible unconfigured controllers.
net/bluetooth/mgmt.c +2 -6
@@ -496,13 +496,9 @@ static int read_unconf_index_list(struct sock *sk, struct hci_dev *hdev,read_lock (&hci_dev_list_lock); - count =0 ; -list_for_each_entry (d, &hci_dev_list, list) { -if (hci_dev_test_flag (d,HCI_UNCONFIGURED )) - count++; - } + count =list_count_nodes (&hci_dev_list); - rp_len =sizeof (*rp) + (2 * count); + rp_len =sizeof (*rp) + (sizeof (__le16) * count); rp =kmalloc (rp_len,GFP_ATOMIC );if (!rp) {read_unlock (&hci_dev_list_lock);
Sasha Levin
maintainerPATCH 1/3 Bluetooth: L2CAP: Fix slab-use-after-free in l2cap_connect()
From: Sungwoo Kim <[email protected]>
[ Upstream commit 4d7b41c0e43995b0e992b9f8903109275744b658 ]
Extend a critical section to prevent chan from early freeing. Also make the l2cap_connect() return type void. Nothing is using the returned value but it is ugly to return a potentially freed pointer. Making it void will help with backports because earlier kernels did use the return value. Now the compile will break for kernels where this patch is not a complete fix.
Call stack summary:
[use]l2cap_bredr_sig_cmd
l2cap_connect
┌ mutex_lock(&conn->chan_lock);
│ chan = pchan->ops->new_connection(pchan); <- alloc chan
│ __l2cap_chan_add(conn, chan);
│ l2cap_chan_hold(chan);
│ list_add(&chan->list, &conn->chan_l); ... (1)
└ mutex_unlock(&conn->chan_lock);
chan->conf_state ... (4) <- use after free[free]l2cap_conn_del
┌ mutex_lock(&conn->chan_lock); │ foreach chan in conn->chan_l: ... (2) │ l2cap_chan_put(chan); │ l2cap_chan_destroy │ kfree(chan) ... (3) <- chan freed └ mutex_unlock(&conn->chan_lock);
==================================================================
BUG: KASAN: slab-use-after-free in instrument_atomic_read include/linux/instrumented.h:68 [inline] BUG: KASAN: slab-use-after-free in _test_bit include/asm-generic/bitops/instrumented-non-atomic.h:141 [inline] BUG: KASAN: slab-use-after-free in l2cap_connect+0xa67/0x11a0 net/bluetooth/l2cap_core.c:4260 Read of size 8 at addr ffff88810bf040a0 by task kworker/u3:1/311
Stable-dep-of: b5dbb41b212c ("Bluetooth: mgmt: fix race in read_unconf_index_list()")
--- net/bluetooth/l2cap_core.c | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-)
net/bluetooth/l2cap_core.c +10 -11
@@ -4201,13 +4201,12 @@ static inline int l2cap_command_rej(struct l2cap_conn *conn,return 0 ; } -static struct l2cap_chan *l2cap_connect (struct l2cap_conn *conn, -struct l2cap_cmd_hdr *cmd, -u8 *data,u8 rsp_code,u8 amp_id) +static void l2cap_connect (struct l2cap_conn *conn,struct l2cap_cmd_hdr *cmd, +u8 *data,u8 rsp_code,u8 amp_id) {struct l2cap_conn_req *req = (struct l2cap_conn_req *) data;struct l2cap_conn_rsp rsp; -struct l2cap_chan *chan =NULL , *pchan; +struct l2cap_chan *chan =NULL , *pchan =NULL ;int result, status =L2CAP_CS_NO_INFO ;u16 dcid =0 , scid =__le16_to_cpu (req->scid);
@@ -4220,7 +4219,7 @@ static struct l2cap_chan *l2cap_connect(struct l2cap_conn *conn, &conn->hcon->dst, ACL_LINK);if (!pchan) { result =L2CAP_CR_BAD_PSM ; - goto sendresp; + goto response; }mutex_lock (&conn->chan_lock);
@@ -4309,17 +4308,15 @@ static struct l2cap_chan *l2cap_connect(struct l2cap_conn *conn, } response: -l2cap_chan_unlock (pchan); -mutex_unlock (&conn->chan_lock); -l2cap_chan_put (pchan); - -sendresp: rsp.scid =cpu_to_le16 (scid); rsp.dcid =cpu_to_le16 (dcid); rsp.result =cpu_to_le16 (result); rsp.status =cpu_to_le16 (status);l2cap_send_cmd (conn, cmd->ident, rsp_code,sizeof (rsp), &rsp); +if (!pchan) +return ; +if (result ==L2CAP_CR_PEND && status ==L2CAP_CS_NO_INFO ) {struct l2cap_info_req info; info.type =cpu_to_le16 (L2CAP_IT_FEAT_MASK );
@@ -4342,7 +4339,9 @@ static struct l2cap_chan *l2cap_connect(struct l2cap_conn *conn, chan->num_conf_req++; } -return chan; +l2cap_chan_unlock (pchan); +mutex_unlock (&conn->chan_lock); +l2cap_chan_put (pchan); } static int l2cap_connect_req(struct l2cap_conn *conn,
Signature · 1 line
2.53.0
Sasha Levin
maintainerPATCH 2/3 Bluetooth: HCI: Remove HCI_AMP support
From: Luiz Augusto von Dentz <[email protected]>
[ Upstream commit 84a4bb6548a29326564f0e659fb8064503ecc1c7 ]
Since BT_HS has been remove HCI_AMP controllers no longer has any use so remove it along with the capability of creating AMP controllers.
Since we no longer need to differentiate between AMP and Primary controllers, as only HCI_PRIMARY is left, this also remove hdev->dev_type altogether.
Stable backport scope: retain only the read_unconf_index_list() allocation-counting change needed by b5dbb41b212c ("Bluetooth: mgmt:
fix race in read_unconf_index_list()"). Drop the HCI_PRIMARY test from that first pass so the target patch applies without conflicts.
Keep the HCI_PRIMARY test in the response-filling pass. Counting an unconfigured AMP controller can only reserve extra space; the returned controller list and response length still include only primary devices. The target subsequently replaces this flag-dependent count with a count of every device on the locked list to fix the race.
Linux 5.15 still has BT_HS/AMP support and lacks hci_bcm4377.c and hci_sync.c. Drop all remaining upstream hunks rather than removing fields, handlers and driver support that this tree still uses.
The preceding l2cap_connect() UAF fix made its return type void, but the 5.15 AMP create-channel caller still consumes that return value, causing an allmodconfig build failure. Pass the referenced AMP device into l2cap_connect() and move the existing AMP channel setup into its locked region. This retains the void return type and protects the channel until AMP setup finishes. The caller retains ownership of the device reference and releases it after l2cap_connect() returns. No new functions are added.
[ sashal: Reduced backport -- upstream 84a4bb6548a29 touches 20 file(s), this
backport carries 2. Not backported here:
drivers/bluetooth/btmrvl_main.c
drivers/bluetooth/btrsi.c
drivers/bluetooth/btsdio.c
drivers/bluetooth/btusb.c
drivers/bluetooth/hci_bcm4377.c
drivers/bluetooth/hci_ldisc.c
drivers/bluetooth/hci_serdev.c
drivers/bluetooth/hci_uart.h
... and 10 more
This note is generated from the file lists only; see the resolution record for the reasoning. ]
Stable-dep-of: b5dbb41b212c ("Bluetooth: mgmt: fix race in read_unconf_index_list()")
--- net/bluetooth/l2cap_core.c | 58 +++++++++++++++++++------------------- net/bluetooth/mgmt.c | 3 +- 2 files changed, 30 insertions(+), 31 deletions(-)
net/bluetooth/l2cap_core.c +29 -29
@@ -58,6 +58,8 @@ static void l2cap_send_cmd(struct l2cap_conn *conn, u8 ident, u8 code, u16 len, void *data);static int l2cap_build_conf_req (struct l2cap_chan *chan,void *data,size_t data_size);static void l2cap_send_disconn_req (struct l2cap_chan *chan,int err); +static void cmd_reject_invalid_cid (struct l2cap_conn *conn,u8 ident, +u16 scid,u16 dcid);static void l2cap_tx (struct l2cap_chan *chan,struct l2cap_ctrl *control,struct sk_buff_head *skbs,u8 event);
@@ -4202,7 +4204,7 @@ static inline int l2cap_command_rej(struct l2cap_conn *conn, }static void l2cap_connect (struct l2cap_conn *conn,struct l2cap_cmd_hdr *cmd, -u8 *data,u8 rsp_code,u8 amp_id) +u8 *data,u8 rsp_code,struct hci_dev *amp_hdev) {struct l2cap_conn_req *req = (struct l2cap_conn_req *) data;struct l2cap_conn_rsp rsp;
@@ -4265,7 +4267,7 @@ static void l2cap_connect(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, chan->dst_type =bdaddr_dst_type (conn->hcon); chan->psm = psm; chan->dcid = scid; - chan->local_amp_id = amp_id; + chan->local_amp_id = amp_hdev ? amp_hdev->id :AMP_ID_BREDR ;__l2cap_chan_add (conn, chan);
@@ -4287,7 +4289,7 @@ static void l2cap_connect(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd,* The connection will succeed after the * physical link is up. */ -if (amp_id ==AMP_ID_BREDR ) { +if (!amp_hdev) {l2cap_state_change (chan,BT_CONFIG ); result =L2CAP_CR_SUCCESS ; }else {
@@ -4339,6 +4341,27 @@ static void l2cap_connect(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, chan->num_conf_req++; } +/* Finish AMP setup while the new channel is protected. */ +if (chan && amp_hdev) { +struct amp_mgr *mgr = conn->hcon->amp_mgr; +struct hci_conn *hs_hcon; + + hs_hcon =hci_conn_hash_lookup_ba (amp_hdev,AMP_LINK , + &conn->hcon->dst); +if (!hs_hcon) { +cmd_reject_invalid_cid (conn, cmd->ident, chan->scid, + chan->dcid); + }else { +BT_DBG ("mgr %p bredr_chan %p hs_hcon %p" , mgr, chan, + hs_hcon); + + mgr->bredr_chan = chan; + chan->hs_hcon = hs_hcon; + chan->fcs =L2CAP_FCS_NONE ; + conn->mtu = amp_hdev->block_mtu; + } + } +l2cap_chan_unlock (pchan);mutex_unlock (&conn->chan_lock);l2cap_chan_put (pchan);
@@ -4350,7 +4373,7 @@ static int l2cap_connect_req(struct l2cap_conn *conn,if (cmd_len <sizeof (struct l2cap_conn_req ))return -EPROTO ; -l2cap_connect (conn, cmd, data,L2CAP_CONN_RSP ,0 ); +l2cap_connect (conn, cmd, data,L2CAP_CONN_RSP ,NULL );return 0 ; }
@@ -4917,7 +4940,6 @@ static int l2cap_create_channel_req(struct l2cap_conn *conn, {struct l2cap_create_chan_req *req = data;struct l2cap_create_chan_rsp rsp; -struct l2cap_chan *chan;struct hci_dev *hdev;u16 psm, scid;
@@ -4934,8 +4956,7 @@ static int l2cap_create_channel_req(struct l2cap_conn *conn,/* For controller id 0 make BR/EDR connection */ if (req->amp_id ==AMP_ID_BREDR ) { -l2cap_connect (conn, cmd, data,L2CAP_CREATE_CHAN_RSP , - req->amp_id); +l2cap_connect (conn, cmd, data,L2CAP_CREATE_CHAN_RSP ,NULL );return 0 ; }
@@ -4949,28 +4970,7 @@ static int l2cap_create_channel_req(struct l2cap_conn *conn, goto error; } - chan =l2cap_connect (conn, cmd, data,L2CAP_CREATE_CHAN_RSP , - req->amp_id); -if (chan) { -struct amp_mgr *mgr = conn->hcon->amp_mgr; -struct hci_conn *hs_hcon; - - hs_hcon =hci_conn_hash_lookup_ba (hdev,AMP_LINK , - &conn->hcon->dst); -if (!hs_hcon) { -hci_dev_put (hdev); -cmd_reject_invalid_cid (conn, cmd->ident, chan->scid, - chan->dcid); -return 0 ; - } - -BT_DBG ("mgr %p bredr_chan %p hs_hcon %p" , mgr, chan, hs_hcon); - - mgr->bredr_chan = chan; - chan->hs_hcon = hs_hcon; - chan->fcs =L2CAP_FCS_NONE ; - conn->mtu = hdev->block_mtu; - } +l2cap_connect (conn, cmd, data,L2CAP_CREATE_CHAN_RSP , hdev);hci_dev_put (hdev);
net/bluetooth/mgmt.c +1 -2
@@ -460,8 +460,7 @@ static int read_unconf_index_list(struct sock *sk, struct hci_dev *hdev, count =0 ;list_for_each_entry (d, &hci_dev_list, list) { -if (d->dev_type ==HCI_PRIMARY && -hci_dev_test_flag (d,HCI_UNCONFIGURED )) +if (hci_dev_test_flag (d,HCI_UNCONFIGURED )) count++; }
Signature · 1 line
2.53.0
Sasha Levin
maintainerPATCH 3/3 Bluetooth: mgmt: fix race in read_unconf_index_list()
In reply to Sasha LevinFrom: Aldo Ariel Panzardo <[email protected]>
[ Upstream commit b5dbb41b212c50c095a4dbee3017a84fe94f033b ]
read_unconf_index_list() counts unconfigured controllers before allocating its response, then checks the device flags again while filling it.
hci_dev_list_lock stabilizes list membership, but it does not serialize the per-device flags. During asynchronous controller setup, the worker can set HCI_UNCONFIGURED and clear HCI_SETUP between the two passes. A controller omitted from the allocation count can then become eligible for the fill pass, causing an out-of-bounds write to rp->index[].
Allocate space for every device on hci_dev_list. Since list membership cannot change while hci_dev_list_lock is held, the response remains large enough regardless of flag transitions. The reported count and response length still include only eligible unconfigured controllers.
--- net/bluetooth/mgmt.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-)
net/bluetooth/mgmt.c +3 -5
@@ -459,12 +459,10 @@ static int read_unconf_index_list(struct sock *sk, struct hci_dev *hdev,read_lock (&hci_dev_list_lock); count =0 ; -list_for_each_entry (d, &hci_dev_list, list) { -if (hci_dev_test_flag (d,HCI_UNCONFIGURED )) - count++; - } +list_for_each_entry (d, &hci_dev_list, list) + count++; - rp_len =sizeof (*rp) + (2 * count); + rp_len =sizeof (*rp) + (sizeof (__le16) * count); rp =kmalloc (rp_len,GFP_ATOMIC );if (!rp) {read_unlock (&hci_dev_list_lock);
Signature · 1 line
2.53.0