summaryrefslogtreecommitdiff
path: root/include
diff options
context:
space:
mode:
authorPauli Virtanen <pav@iki.fi>2026-09-02 00:04:33 +0300
committerLuiz Augusto von Dentz <luiz.von.dentz@intel.com>2026-10-14 13:28:03 -0400
commitdc1ddc65f06df44dfcfe51955c82a132acb3ab8d (patch)
tree447763f5f91fbaf8a9b8425ce75f3d911f778d55 /include
parent6098ed784e2cade6eb39e20254e98cec54084194 (diff)
downloadlinux-dc1ddc65f06df44dfcfe51955c82a132acb3ab8d.tar.gz
linux-dc1ddc65f06df44dfcfe51955c82a132acb3ab8d.zip
Bluetooth: L2CAP: take lock for l2cap_chan_del in l2cap_ecred_rsp_defer
l2cap_ecred_rsp_defer() calls l2cap_chan_del without holding chan->lock, which ends up calling ops->teardown() with wrong lock context. Fix by taking chan->lock in l2cap_ecred_rsp_defer(). AB-BA deadlocks between sibling l2cap_chan are avoided here via requiring l2cap_conn::lock to serialize all nested l2cap_chan locking on same nesting level. In current code, there is no nested l2cap_chan locking on same nesting level, so we can add this new requirement. Also return early from __l2cap_ecred_conn_rsp_defer() if chan did not have FLAG_DEFER_SETUP, as then no RSP shall be sent for it, to make sure SMP channels are excluded. Also hold chan reference over l2cap_chan_del(), in case chan_l reference was the last. Signed-off-by: Pauli Virtanen <pav@iki.fi> Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
Diffstat (limited to 'include')
-rw-r--r--include/net/bluetooth/l2cap.h4
1 files changed, 4 insertions, 0 deletions
diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h
index 2315a3993c7b..c7e642abe404 100644
--- a/include/net/bluetooth/l2cap.h
+++ b/include/net/bluetooth/l2cap.h
@@ -758,6 +758,10 @@ enum {
* otherwise considers all channels equal and will e.g. complain about a
* connection oriented channel triggering SMP procedures or a listening
* channel creating and locking a child channel.
+ *
+ * Lock nesting of channels at the same nesting level is allowed if the channels
+ * have the same l2cap_chan::conn and l2cap_chan::conn.lock is taken before the
+ * nested locks. l2cap_chan_try_sibling_lock() must be used.
*/
enum {
L2CAP_NESTING_SMP,