From aba67d585b993a5a2d6c93181bd2ec50a25cf4c7 Mon Sep 17 00:00:00 2001 From: Pauli Virtanen Date: Sat, 29 Aug 2026 17:20:09 +0300 Subject: [PATCH] Bluetooth: L2CAP: make concurrent l2cap_set_timer() refcounting safe 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 Signed-off-by: Luiz Augusto von Dentz --- 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 a991fc07515c..2315a3993c7b 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h @@ -847,12 +847,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,