[PATCH 14/16] Bluetooth: L2CAP: make concurrent l2cap_set_timer() refcounting safe
From: Pauli Virtanen
Date: Sat Aug 29 2026 - 10:23:31 EST
Since l2cap_set_timer() does not check return value of
schedule_delayed_work(), two concurrent calls may result to l2cap_chan
refcount leak.
Change the refcounting by using mod_delayed_work() and checking its
return value.
Code paths aside from l2cap_chan_busy() hold chan->lock, so this has
little correctness impact.
Signed-off-by: Pauli Virtanen <pav@xxxxxx>
---
include/net/bluetooth/l2cap.h | 9 ++++-----
1 file changed, 4 insertions(+), 5 deletions(-)
diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h
index 3d00ffb66cc9..efb9b7f422d1 100644
--- a/include/net/bluetooth/l2cap.h
+++ b/include/net/bluetooth/l2cap.h
@@ -859,12 +859,11 @@ static inline void l2cap_set_timer(struct l2cap_chan *chan,
BT_DBG("chan %p state %s timeout %ld", chan,
state_to_string(chan->state), timeout);
- /* If delayed work cancelled do not hold(chan)
- since it is already done with previous set_timer */
- if (!cancel_delayed_work(work))
- l2cap_chan_hold(chan);
+ l2cap_chan_hold(chan);
- schedule_delayed_work(work, timeout);
+ /* put(chan) if timer was already queued so it already has a ref */
+ if (mod_delayed_work(system_percpu_wq, work, timeout))
+ l2cap_chan_put(chan);
}
static inline bool l2cap_clear_timer(struct l2cap_chan *chan,
--
2.55.0