* [PATCH] Bluetooth: L2CAP: Fix reject-list lookup UAF
@ 2026-08-21 17:40 Chengfeng Ye
0 siblings, 0 replies; only message in thread
From: Chengfeng Ye @ 2026-08-21 17:40 UTC (permalink / raw)
To: Marcel Holtmann, Luiz Augusto von Dentz, Johan Hedberg
Cc: linux-bluetooth, linux-kernel, Chengfeng Ye, stable
l2cap_recv_frame() walks hdev->reject_list while holding conn->lock,
but reject-list updates are serialized by hdev->lock. Consequently,
block_device() or unblock_device() can mutate and free the current list
entry while the receive path is examining it.
The following interleaving causes the use-after-free:
l2cap_recv_frame() unblock_device()
fetch reject-list entry
hci_dev_lock()
list_del()
kfree()
hci_dev_unlock()
read entry->bdaddr_type
KASAN reported:
BUG: KASAN: slab-use-after-free in hci_bdaddr_list_lookup
Read of size 1 by task kworker/u17:1/88
Workqueue: hci0 hci_rx_work
Call Trace:
hci_bdaddr_list_lookup+0xee/0x100
l2cap_recv_frame+0x8a4/0x8e50
l2cap_recv_acldata+0xa64/0xd40
hci_rx_work+0x4ca/0x730
Allocated by task 92:
hci_bdaddr_list_add+0x12a/0x300
block_device+0x94/0x1a0
hci_sock_sendmsg+0x1033/0x1ea0
Freed by task 92:
hci_bdaddr_list_del+0x182/0x230
unblock_device+0xa0/0x1b0
hci_sock_sendmsg+0x1033/0x1ea0
Taking hdev->lock from l2cap_recv_frame() would invert the established
hdev->lock to conn->lock order. Instead, walk the reject list under RCU,
publish and remove address-list entries with the RCU list primitives, and
defer their freeing until readers have left their critical sections.
The address-list helpers are shared with other lists. RCU publication
and deferred freeing preserve their existing locked lookup and matching
behavior while making reject-list traversal safe without changing lock
order.
Fixes: e493150e3639 ("Bluetooth: Centralize looking up blocked devices to l2cap_recv_frame")
Cc: stable@vger.kernel.org
Signed-off-by: Chengfeng Ye <nicoyip.dev@gmail.com>
---
net/bluetooth/hci_core.c | 10 +++++-----
net/bluetooth/l2cap_core.c | 23 ++++++++++++++++++++---
2 files changed, 25 insertions(+), 8 deletions(-)
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
index 509c820a693d..69bcc820d22d 100644
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -2055,8 +2055,8 @@ void hci_bdaddr_list_clear(struct list_head *bdaddr_list)
struct bdaddr_list *b, *n;
list_for_each_entry_safe(b, n, bdaddr_list, list) {
- list_del(&b->list);
- kfree(b);
+ list_del_rcu(&b->list);
+ kfree_rcu_mightsleep(b);
}
}
@@ -2077,7 +2077,7 @@ int hci_bdaddr_list_add(struct list_head *list, bdaddr_t *bdaddr, u8 type)
bacpy(&entry->bdaddr, bdaddr);
entry->bdaddr_type = type;
- list_add(&entry->list, list);
+ list_add_rcu(&entry->list, list);
return 0;
}
@@ -2148,8 +2148,8 @@ int hci_bdaddr_list_del(struct list_head *list, bdaddr_t *bdaddr, u8 type)
if (!entry)
return -ENOENT;
- list_del(&entry->list);
- kfree(entry);
+ list_del_rcu(&entry->list);
+ kfree_rcu_mightsleep(entry);
return 0;
}
diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
index ee459dd411f5..f2e741b25cfd 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -7077,6 +7077,25 @@ static void l2cap_conless_channel(struct l2cap_conn *conn, __le16 psm,
kfree_skb(skb);
}
+static bool l2cap_is_rejected(struct hci_conn *hcon)
+{
+ struct bdaddr_list *b;
+ u8 type;
+
+ type = bdaddr_dst_type(hcon);
+
+ rcu_read_lock();
+ list_for_each_entry_rcu(b, &hcon->hdev->reject_list, list) {
+ if (!bacmp(&b->bdaddr, &hcon->dst) && b->bdaddr_type == type) {
+ rcu_read_unlock();
+ return true;
+ }
+ }
+ rcu_read_unlock();
+
+ return false;
+}
+
static void l2cap_recv_frame(struct l2cap_conn *conn, struct sk_buff *skb)
{
struct l2cap_hdr *lh = (void *) skb->data;
@@ -7102,9 +7121,7 @@ static void l2cap_recv_frame(struct l2cap_conn *conn, struct sk_buff *skb)
/* Since we can't actively block incoming LE connections we must
* at least ensure that we ignore incoming data from them.
*/
- if (hcon->type == LE_LINK &&
- hci_bdaddr_list_lookup(&hcon->hdev->reject_list, &hcon->dst,
- bdaddr_dst_type(hcon))) {
+ if (hcon->type == LE_LINK && l2cap_is_rejected(hcon)) {
kfree_skb(skb);
return;
}
--
2.43.0
^ permalink raw reply related [flat|nested] only message in thread
only message in thread, other threads:[~2026-08-21 17:40 UTC | newest]
Thread overview: (only message) (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-08-21 17:40 [PATCH] Bluetooth: L2CAP: Fix reject-list lookup UAF Chengfeng Ye
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox