* [PATCH] Bluetooth: 6LoWPAN: Serialize multicast sends with peer removal
@ 2026-10-08 4:27 Cen Zhang
0 siblings, 0 replies; only message in thread
From: Cen Zhang @ 2026-10-08 4:27 UTC (permalink / raw)
To: marcel, luiz.dentz
Cc: linux-bluetooth, linux-kernel, baijiaju1990, jjzuming, zzzccc427
A peer's channel must remain alive until send_mcast_pkt() finishes using
it. The multicast walk protects the lowpan_peer with RCU, but peer_del()
defers only the peer allocation. On disconnect, l2cap_chan_del() drops
the connection-list reference, chan_close_cb() removes the peer and drops
the original channel reference, and l2cap_conn_del() drops its temporary
reference. A ready channel can then be freed while multicast transmit
still holds the peer, causing send_pkt() to write chan->data after free.
Another peer can keep the interface up, so the last-peer shutdown does
not drain this transmission.
Hold devices_lock across the multicast walk and send_pkt() calls so that
peer removal cannot release the channel reference until the send finishes.
Use the bottom-half-safe variants for all devices_lock critical sections
because transmit runs in softirq context. This prevents transmit from
interrupting a process-context lock holder on the same CPU and deadlocking.
The LE send path uses atomic allocations and does not acquire the channel
or connection mutexes, preserving the existing lock order and teardown
sequence.
The reported access and release path were:
[Thu Oct 1 11:52:32 2026] BUG: KASAN: slab-use-after-free in
send_pkt+0x2c5/0x300
[Thu Oct 1 11:52:32 2026] Write of size 8 at addr ffff88810be0f4a0
by task python3/535
[...]
[Thu Oct 1 11:52:32 2026] Freed by task 502:
[...]
[Thu Oct 1 11:52:32 2026] l2cap_chan_put+0x273/0x3a0
[Thu Oct 1 11:52:32 2026] l2cap_conn_del+0x36d/0x770
[Thu Oct 1 11:52:32 2026] l2cap_disconn_cfm+0x87/0xd0
[Thu Oct 1 11:52:32 2026] hci_disconn_complete_evt+0x319/0xa30
[...]
Fixes: 90305829635d ("Bluetooth: 6lowpan: Converting rwlocks to use RCU")
Assisted-by: LLM
Signed-off-by: Cen Zhang <zzzccc427@gmail.com>
---
diff --git a/net/bluetooth/6lowpan.c b/net/bluetooth/6lowpan.c
index 836add41f5..8732132c47 100644
--- a/net/bluetooth/6lowpan.c
+++ b/net/bluetooth/6lowpan.c
@@ -471,6 +471,11 @@
struct lowpan_btle_dev *entry;
int err = 0;
+ /*
+ * Peer removal drops the channel reference, so RCU alone is not
+ * enough.
+ */
+ spin_lock_bh(&devices_lock);
rcu_read_lock();
list_for_each_entry_rcu(entry, &bt_6lowpan_devices, list) {
@@ -502,6 +507,7 @@
}
rcu_read_unlock();
+ spin_unlock_bh(&devices_lock);
return err;
}
@@ -657,10 +663,10 @@
lowpan_iphc_uncompress_eui48_lladdr(&peer->peer_addr, peer->lladdr);
- spin_lock(&devices_lock);
+ spin_lock_bh(&devices_lock);
INIT_LIST_HEAD(&peer->list);
peer_add(dev, peer);
- spin_unlock(&devices_lock);
+ spin_unlock_bh(&devices_lock);
/* Notifying peers about us needs to be done without locks held */
if (new_netdev)
@@ -695,17 +701,17 @@
(*dev)->hdev = chan->conn->hcon->hdev;
INIT_LIST_HEAD(&(*dev)->peers);
- spin_lock(&devices_lock);
+ spin_lock_bh(&devices_lock);
INIT_LIST_HEAD(&(*dev)->list);
list_add_rcu(&(*dev)->list, &bt_6lowpan_devices);
- spin_unlock(&devices_lock);
+ spin_unlock_bh(&devices_lock);
err = lowpan_register_netdev(netdev, LOWPAN_LLTYPE_BTLE);
if (err < 0) {
BT_INFO("register_netdev failed %d", err);
- spin_lock(&devices_lock);
+ spin_lock_bh(&devices_lock);
list_del_rcu(&(*dev)->list);
- spin_unlock(&devices_lock);
+ spin_unlock_bh(&devices_lock);
free_netdev(netdev);
goto out;
}
@@ -788,7 +794,7 @@
BT_DBG("chan %p conn %p", chan, chan->conn);
- spin_lock(&devices_lock);
+ spin_lock_bh(&devices_lock);
list_for_each_entry_rcu(entry, &bt_6lowpan_devices, list) {
dev = lowpan_btle_dev(entry->netdev);
@@ -808,7 +814,7 @@
}
if (!err && last && dev && !atomic_read(&dev->peer_count)) {
- spin_unlock(&devices_lock);
+ spin_unlock_bh(&devices_lock);
cancel_delayed_work_sync(&dev->notify_peers);
@@ -817,7 +823,7 @@
INIT_WORK(&entry->delete_netdev, delete_netdev);
schedule_work(&entry->delete_netdev);
} else {
- spin_unlock(&devices_lock);
+ spin_unlock_bh(&devices_lock);
}
}
@@ -918,18 +924,18 @@
BT_DBG("conn %p dst type %u", conn, dst_type);
- spin_lock(&devices_lock);
+ spin_lock_bh(&devices_lock);
peer = lookup_peer(conn);
if (!peer) {
- spin_unlock(&devices_lock);
+ spin_unlock_bh(&devices_lock);
return -ENOENT;
}
chan = peer->chan;
l2cap_chan_hold(chan);
- spin_unlock(&devices_lock);
+ spin_unlock_bh(&devices_lock);
BT_DBG("peer %p chan %p", peer, chan);
@@ -1053,7 +1059,7 @@
nchans = 0;
- spin_lock(&devices_lock);
+ spin_lock_bh(&devices_lock);
list_for_each_entry_rcu(entry, &bt_6lowpan_devices, list) {
list_for_each_entry_rcu(peer, &entry->peers, list) {
@@ -1070,7 +1076,7 @@
}
done:
- spin_unlock(&devices_lock);
+ spin_unlock_bh(&devices_lock);
for (i = 0; i < nchans; ++i) {
l2cap_chan_close_unlocked(chans[i], ENOENT);
@@ -1195,7 +1201,7 @@
struct lowpan_btle_dev *entry;
struct lowpan_peer *peer;
- spin_lock(&devices_lock);
+ spin_lock_bh(&devices_lock);
list_for_each_entry(entry, &bt_6lowpan_devices, list) {
list_for_each_entry(peer, &entry->peers, list)
@@ -1203,7 +1209,7 @@
&peer->chan->dst, peer->chan->dst_type);
}
- spin_unlock(&devices_lock);
+ spin_unlock_bh(&devices_lock);
return 0;
}
@@ -1269,7 +1275,7 @@
switch (event) {
case NETDEV_UNREGISTER:
- spin_lock(&devices_lock);
+ spin_lock_bh(&devices_lock);
list_for_each_entry(entry, &bt_6lowpan_devices, list) {
if (entry->netdev == netdev) {
BT_DBG("Unregistered netdev %s %p",
@@ -1278,7 +1284,7 @@
break;
}
}
- spin_unlock(&devices_lock);
+ spin_unlock_bh(&devices_lock);
break;
}
^ permalink raw reply [flat|nested] only message in thread
only message in thread, other threads:[~2026-10-08 4:28 UTC | newest]
Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-10-08 4:27 [PATCH] Bluetooth: 6LoWPAN: Serialize multicast sends with peer removal Cen Zhang
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®