From nobody Sat Sep 26 21:59:26 2026 Received: from meesny.iki.fi (meesny.iki.fi [195.140.195.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 1798F3AB5C3; Sat, 29 Aug 2026 14:20:57 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=pass smtp.client-ip=195.140.195.201 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788013260; cv=pass; b=eTiMwEq+IrWBTJAK2wEHmHgVOKnkC0zqKaNJBk5j5E6wFIZI+iGtp/z1DjDikVXAgFFvROgZZ4qGjNq9QNSCoon7lbHxQOaeFYOSNcI2AwGDQVzMaIgq4o4iRbgT+27XwCFJpbx18r4cVjPidixsr/ZyaTAjBh/In6MG2XC87og= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788013260; c=relaxed/simple; bh=TOcMXFWykundmx7U0oKPgaPN+mEeO3jj/UL7vY7+MnQ=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=Fti2R9gSzcTAA3K0qh/r13SKLmUEvGYgs0H8hIzRTlfqHCd2xfsKvdUUnKkHwhrEDvUks6wwqHswqvseJkizJxfTME9SJLffrv7Ys0FRV/gYeZyB7zKwJ2OeUDcVJC7sEUcsTKjPDw5mCy29LcxH5HiJ0akfdciygaweCCInykY= ARC-Authentication-Results: i=2; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=iki.fi; spf=pass smtp.mailfrom=iki.fi; dkim=pass (1024-bit key) header.d=iki.fi header.i=@iki.fi header.b=flZrJKuj; arc=pass smtp.client-ip=195.140.195.201 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=iki.fi Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=iki.fi Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=iki.fi header.i=@iki.fi header.b="flZrJKuj" Received: from monolith.lan (unknown [IPv6:2a03:1b20:1:e011::d701]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange x25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) (Authenticated sender: pav) by meesny.iki.fi (Postfix) with ESMTPSA id 4hXHV510YWzyvj; Sat, 29 Aug 2026 17:20:45 +0300 (EEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=iki.fi; s=meesny; t=1788013246; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=tPdRZk6OTj7U1aLWdMJRRce2Ve5/w20Ues9PzuebYnQ=; b=flZrJKujqxKokr0Fys2eLi3eAZkrgah38wr5P1PPKUBcgJIt4UP9BCAe/gOJ8aA5qQ+1Sj X+tc3/7WnaTdcc3SFETvSqHwzGBSnNhFHbsN0tGpzPaIyq84qwdVkogjEeDALkAOzQdrIi yQ/t9PW81Veurt0P9g1tclUzivBFlfc= ARC-Seal: i=1; a=rsa-sha256; d=iki.fi; s=meesny; cv=none; t=1788013246; b=Py9UX8y+9n9+CkaCRXbPRzYN6aKSwDZ6h2nwsak3AWF+F4oazrUaZEuhXvbrXDoaV3IKHs tvtCKBSGAtYBq10HbXoE5/1EG92Rwy7BHSa48qurnz4oAVe+x8q6zYnUGCfXcRpCuoPsp4 5IBJKiLj4TslHuet4kEP2O2K5NPySNE= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=iki.fi; s=meesny; t=1788013246; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=tPdRZk6OTj7U1aLWdMJRRce2Ve5/w20Ues9PzuebYnQ=; b=QEZ9/meAgOmC1gaH1crUBgprnkoTUwXdqAEBsMYQbd096AS0N0S36uCHx6x6E+YKXnvuJB MtFcYDSEBn1tobamJYRGRpASeS/gvrSqQWfgBAZo5iOqSSoDbsazyq0RfiZ52gIFnVjsK7 2RvvZaM1Njbje5Z4xHYUy0MjgZOdUek= ARC-Authentication-Results: i=1; ORIGINATING; auth=pass smtp.auth=pav smtp.mailfrom=pav@iki.fi From: Pauli Virtanen To: linux-bluetooth@vger.kernel.org Cc: Pauli Virtanen , marcel@holtmann.org, luiz.dentz@gmail.com, oss@fourdim.xyz, error27@gmail.com, elver@google.com, linux-kernel@vger.kernel.org Subject: [PATCH 01/16] Bluetooth: L2CAP: take chan->lock for l2cap_chan_add/ready/del Date: Sat, 29 Aug 2026 17:19:56 +0300 Message-ID: X-Mailer: git-send-email 2.55.0 In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" chan->lock must be held for __l2cap_chan_add as eg. calls to l2cap_chan_close assume chan->conn writes are guarded by it. It must be held for l2cap_chan_del() due to l2cap_sock.c:l2cap_chan_conn, l2cap_monitor_timeout, etc. Similarly it should be held for l2cap_ops::ready (assumed in 6lowpan.c). Also teardown usually has chan->lock held, it should always have it held to have the same locking context. The lock is not correctly held by l2cap_core in several places. Add the missing locks for l2cap_chan_del/add/ready(), except in l2cap_ecred_rsp_defer() which needs separate fix as it needs lock nesting. Fixes: 6fef032af009 ("Bluetooth: L2CAP: Fix use-after-free in l2cap_sock_ne= w_connection_cb()") Signed-off-by: Pauli Virtanen --- include/net/bluetooth/l2cap.h | 3 ++- net/bluetooth/l2cap_core.c | 15 +++++++++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index 69d193fee351..43a67562b238 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h @@ -973,7 +973,8 @@ int l2cap_chan_check_security(struct l2cap_chan *chan, = bool initiator); void l2cap_chan_set_defaults(struct l2cap_chan *chan, struct l2cap_chan *p= chan); int l2cap_ertm_init(struct l2cap_chan *chan); void l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan); -void __l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan); +void __l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan) + __must_hold(&chan->lock); typedef void (*l2cap_chan_func_t)(struct l2cap_chan *chan, void *data); void l2cap_chan_list(struct l2cap_conn *conn, l2cap_chan_func_t func, void *data); diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 358b11eabd4f..adcf714ec1ed 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -665,7 +665,9 @@ void __l2cap_chan_add(struct l2cap_conn *conn, struct l= 2cap_chan *chan) void l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan) { mutex_lock(&conn->lock); + l2cap_chan_lock(chan); __l2cap_chan_add(conn, chan); + l2cap_chan_unlock(chan); mutex_unlock(&conn->lock); } =20 @@ -4065,6 +4067,8 @@ static struct l2cap_chan *l2cap_new_connection(struct= l2cap_conn *conn, if (!chan) return NULL; =20 + l2cap_chan_lock(chan); + l2cap_chan_set_defaults(chan, pchan); chan->ops =3D pchan->ops; =20 @@ -4073,10 +4077,13 @@ static struct l2cap_chan *l2cap_new_connection(stru= ct l2cap_conn *conn, if (pchan->ops->new_connection && pchan->ops->new_connection(pchan, chan) < 0) { l2cap_chan_del(chan, 0); + l2cap_chan_unlock(chan); l2cap_chan_put(chan); return NULL; } =20 + l2cap_chan_unlock(chan); + return chan; } =20 @@ -5047,6 +5054,8 @@ static int l2cap_le_connect_req(struct l2cap_conn *co= nn, goto response_unlock; } =20 + l2cap_chan_lock(chan); + bacpy(&chan->src, &conn->hcon->src); bacpy(&chan->dst, &conn->hcon->dst); chan->src_type =3D bdaddr_src_type(conn->hcon); @@ -5079,6 +5088,8 @@ static int l2cap_le_connect_req(struct l2cap_conn *co= nn, result =3D L2CAP_CR_LE_SUCCESS; } =20 + l2cap_chan_unlock(chan); + response_unlock: l2cap_chan_unlock(pchan); l2cap_chan_put(pchan); @@ -5271,6 +5282,8 @@ static inline int l2cap_ecred_conn_req(struct l2cap_c= onn *conn, continue; } =20 + l2cap_chan_lock(chan); + bacpy(&chan->src, &conn->hcon->src); bacpy(&chan->dst, &conn->hcon->dst); chan->src_type =3D bdaddr_src_type(conn->hcon); @@ -5303,6 +5316,8 @@ static inline int l2cap_ecred_conn_req(struct l2cap_c= onn *conn, } else { l2cap_chan_ready(chan); } + + l2cap_chan_unlock(chan); } =20 unlock: --=20 2.55.0 From nobody Sat Sep 26 21:59:26 2026 Received: from meesny.iki.fi (meesny.iki.fi [195.140.195.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 32C553ABD80; Sat, 29 Aug 2026 14:20:58 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=pass smtp.client-ip=195.140.195.201 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788013260; cv=pass; b=TyMWNDe5mD1DLoBmU9+tzSNzs/FcnFU8+JNNqWgEPs6f9cq9NKInLJeWd8FywaSvHp6TSRAKuuIl+k9LRM+PLjy3UEPfOnbE7lXCH6XvNsgyhfoKHi8lk83aXhcqGzC32lJJgvcksAh32YqYUoG75Lv8jrOW/9pFUbXRdcXno6w= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788013260; c=relaxed/simple; bh=y1mmnI7DF7MHoYSEhAOGbWaboreUA8FXN+9Yen71T6Q=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=QX8hGWWAmC2ykq9YdatbJuTbH3inMFzJdnI2Xqytc5pD8lOkff3Dk1tcSJu9c98UI76yGX6s7+kyzi/HSb4TOZ7n6aNa/Yg9T8E79bLyTvS7gMTfS59QeUzYUZBqJpV9iXnR8V9X9WwUPZ+A4jZdk2+CClqMth0bH1I4ncrGD0o= ARC-Authentication-Results: i=2; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=iki.fi; spf=pass smtp.mailfrom=iki.fi; dkim=pass (1024-bit key) header.d=iki.fi header.i=@iki.fi header.b=loNRmo1y; arc=pass smtp.client-ip=195.140.195.201 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=iki.fi Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=iki.fi Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=iki.fi header.i=@iki.fi header.b="loNRmo1y" Received: from monolith.lan (unknown [IPv6:2a03:1b20:1:e011::d701]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange x25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) (Authenticated sender: pav) by meesny.iki.fi (Postfix) with ESMTPSA id 4hXHVB6DXvz11Fv; Sat, 29 Aug 2026 17:20:50 +0300 (EEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=iki.fi; s=meesny; t=1788013251; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=sHRCViVmqRUSwDuzHIJl4IxoLCXvYL46WleLf0VR724=; b=loNRmo1y2QmWduo0hASO+y/gRfUzx1HiKrWLtPOzrBlc0fYVV7V99rcZtNh3mO0RRByvn4 6iPPAuJKXAfKPcoUa45id3em49q1Id8PnM+Wcxb1VA9uFWmM9ly69d0GvjOi282OQil4i/ bHibXWsEkua5zt0oaYHVWmMqB0JigPQ= ARC-Seal: i=1; a=rsa-sha256; d=iki.fi; s=meesny; cv=none; t=1788013251; b=ZLy9edeVTHphIZAEekQ79bPzmF8jM91+hmKA22w699BcW0NizKsWeeaFwtjz8EE54wJGtn QzvCBjkPNzqkdFD3HaOZ+94Al/2Es18TCPXJ8Hu+9Uht+dGjOar4CUEXPN3XmGn+9lfdWQ nu3BLKwNbJ60le8GtlWmjHcKpcpvg+k= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=iki.fi; s=meesny; t=1788013251; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=sHRCViVmqRUSwDuzHIJl4IxoLCXvYL46WleLf0VR724=; b=c0m4m8ZpM2pRiaWqlkwuvPYiGMXWKnUsQ/qdyjJ3/aqtKLdS/m7M3elBmSMDBYqgBaRI9B WqudSeOzQWz2xvJTwWFXNSPomhaGmFRWcN5B5JV8ZEmTSMSpTF0SLDnJn5Gn8T5xY1IX6O AcV6YoVQQJbv+4auR2mOz8iM1BaO9bQ= ARC-Authentication-Results: i=1; ORIGINATING; auth=pass smtp.auth=pav smtp.mailfrom=pav@iki.fi From: Pauli Virtanen To: linux-bluetooth@vger.kernel.org Cc: Pauli Virtanen , marcel@holtmann.org, luiz.dentz@gmail.com, oss@fourdim.xyz, error27@gmail.com, elver@google.com, linux-kernel@vger.kernel.org Subject: [PATCH 02/16] Bluetooth: L2CAP: add l2cap_chan_close_unlocked() and locking helpers Date: Sat, 29 Aug 2026 17:19:57 +0300 Message-ID: X-Mailer: git-send-email 2.55.0 In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" l2cap_chan_close() requires holding chan->lock and chan->conn->lock if associated chan->conn exists, to guard eg. conn->chan_l. Taking the locks with right ordering requires handling a race condition. Add helper function l2cap_chan_(un)lock_conn that do the locking right. Add l2cap_chan_close_unlocked() that does not require locks to be held, as all callsites do this lock -> close -> unlock pattern. Link: https://syzkaller.appspot.com/bug?extid=3D0e4ebcc970728e056324 Signed-off-by: Pauli Virtanen --- include/net/bluetooth/l2cap.h | 17 ++++++++++ net/bluetooth/l2cap_core.c | 61 ++++++++++++++++++++++++++++++++--- 2 files changed, 73 insertions(+), 5 deletions(-) diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index 43a67562b238..84f557d354ca 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h @@ -962,6 +962,8 @@ int l2cap_add_scid(struct l2cap_chan *chan, __u16 scid= ); =20 struct l2cap_chan *l2cap_chan_create(void); void l2cap_chan_close(struct l2cap_chan *chan, int reason); +void l2cap_chan_close_unlocked(struct l2cap_chan *chan, int reason) + __must_not_hold(&chan->lock); int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid, bdaddr_t *dst, u8 dst_type, u16 timeout); int l2cap_chan_reconfigure(struct l2cap_chan *chan, __u16 mtu); @@ -988,4 +990,19 @@ void l2cap_conn_put(struct l2cap_conn *conn); int l2cap_register_user(struct l2cap_conn *conn, struct l2cap_user *user); void l2cap_unregister_user(struct l2cap_conn *conn, struct l2cap_user *use= r); =20 +bool l2cap_chan_lock_conn(struct l2cap_chan *chan) + __acquires(&chan->lock) __cond_acquires(true, &chan->conn->lock); + +/* Release macro for l2cap_chan_lock_conn, so context analysis understands= it */ +#define l2cap_chan_unlock_conn(chan, conn_locked) \ + ({ \ + struct l2cap_chan *__chan =3D (chan); \ + struct l2cap_conn *__conn =3D __chan->conn; \ + l2cap_chan_unlock(__chan); \ + if (conn_locked) { \ + mutex_unlock(&__conn->lock); \ + l2cap_conn_put(__conn); \ + } \ + }) + #endif /* __L2CAP_H */ diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index adcf714ec1ed..58c88e116ddc 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -59,6 +59,7 @@ static void l2cap_tx(struct l2cap_chan *chan, struct l2ca= p_ctrl *control, static void l2cap_retrans_timeout(struct work_struct *work); static void l2cap_monitor_timeout(struct work_struct *work); static void l2cap_ack_timeout(struct work_struct *work); +static void __l2cap_chan_close(struct l2cap_chan *chan, int reason); =20 static inline u8 bdaddr_type(u8 link_type, u8 bdaddr_type) { @@ -422,7 +423,7 @@ static void l2cap_chan_timeout(struct work_struct *work) else reason =3D ETIMEDOUT; =20 - l2cap_chan_close(chan, reason); + __l2cap_chan_close(chan, reason); =20 chan->ops->close(chan); =20 @@ -829,7 +830,7 @@ static void l2cap_chan_connect_reject(struct l2cap_chan= *chan) l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_RSP, sizeof(rsp), &rsp); } =20 -void l2cap_chan_close(struct l2cap_chan *chan, int reason) +static void __l2cap_chan_close(struct l2cap_chan *chan, int reason) { struct l2cap_conn *conn =3D chan->conn; =20 @@ -878,8 +879,58 @@ void l2cap_chan_close(struct l2cap_chan *chan, int rea= son) break; } } + +void l2cap_chan_close(struct l2cap_chan *chan, int reason) +{ + __l2cap_chan_close(chan, reason); +} EXPORT_SYMBOL(l2cap_chan_close); =20 +/* Take chan->lock. If chan->conn is non-NULL, take new reference on it, t= ake + * chan->conn->lock, and return true. Otherwise return false. + */ +bool l2cap_chan_lock_conn(struct l2cap_chan *chan) + __context_unsafe(/* conditional locking */) +{ + /* Handle conn->lock > chan->lock ordering + race on chan->conn */ + for (;;) { + struct l2cap_conn *conn; + + l2cap_chan_lock(chan); + conn =3D chan->conn; + if (conn) + l2cap_conn_get(conn); + l2cap_chan_unlock(chan); + + if (conn) + mutex_lock(&conn->lock); + + l2cap_chan_lock(chan); + + if (chan->conn !=3D conn) { + l2cap_chan_unlock(chan); + if (conn) { + mutex_unlock(&conn->lock); + l2cap_conn_put(conn); + } + schedule(); + continue; + } + + return chan->conn; + } +} + +void l2cap_chan_close_unlocked(struct l2cap_chan *chan, int reason) +{ + bool have_conn; + + have_conn =3D l2cap_chan_lock_conn(chan); + __l2cap_chan_close(chan, reason); + l2cap_chan_unlock_conn(chan, have_conn); +} +EXPORT_SYMBOL(l2cap_chan_close_unlocked); + static inline u8 l2cap_get_auth_type(struct l2cap_chan *chan) { switch (chan->chan_type) { @@ -1563,7 +1614,7 @@ static void l2cap_conn_start(struct l2cap_conn *conn) if (!l2cap_mode_supported(chan->mode, conn->feat_mask) && test_bit(CONF_STATE2_DEVICE, &chan->conf_state)) { - l2cap_chan_close(chan, ECONNRESET); + __l2cap_chan_close(chan, ECONNRESET); l2cap_chan_unlock(chan); continue; } @@ -1571,7 +1622,7 @@ static void l2cap_conn_start(struct l2cap_conn *conn) if (l2cap_check_enc_key_size(conn->hcon, chan)) l2cap_start_connection(chan); else - l2cap_chan_close(chan, ECONNREFUSED); + __l2cap_chan_close(chan, ECONNREFUSED); =20 } else if (chan->state =3D=3D BT_CONNECT2) { struct l2cap_conn_rsp rsp; @@ -7648,7 +7699,7 @@ static inline void l2cap_check_encryption(struct l2ca= p_chan *chan, u8 encrypt) __set_chan_timer(chan, L2CAP_ENC_TIMEOUT); } else if (chan->sec_level =3D=3D BT_SECURITY_HIGH || chan->sec_level =3D=3D BT_SECURITY_FIPS) - l2cap_chan_close(chan, ECONNREFUSED); + __l2cap_chan_close(chan, ECONNREFUSED); } else { if (chan->sec_level =3D=3D BT_SECURITY_MEDIUM) __clear_chan_timer(chan); --=20 2.55.0 From nobody Sat Sep 26 21:59:26 2026 Received: from meesny.iki.fi (meesny.iki.fi [195.140.195.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id BCB54214812; Sat, 29 Aug 2026 14:21:04 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=pass smtp.client-ip=195.140.195.201 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788013266; cv=pass; b=Ob9EDeGUuiRbRTDpZv7zOpxojjO03ci6gP28Cvh8ywtKz7d46onTFUWxoPjNqK+kqKTz/MPDMBCrC3gSPmm3K8ORlkHC22eId9RVLSan+eW6Btrty/VNW4Eemmhn/2Dq3zaJYUkW6e/NhFTkXPfQTKeGqbx3XTkkc7SZ01tMP28= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788013266; c=relaxed/simple; bh=Ip8ewKHJCDXXqOktL5ZD05PV0I70Yt777as68Mwsgew=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=OBjeEOGy3Sk/kL+i03N5whM6rZZwsygtEAuNuo3OzMj56oXFnQPfST+66GIMxL0uFAhCAhV/EesWlK7VoMNMu/I+kZfh2fCVnqzWrSyo/cRct6W/l+uUKrrsmki3+81kS7VlEPlJJGA0CEOcD/5ucuxwRQhfLSFywRXxrgsbn7c= ARC-Authentication-Results: i=2; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=iki.fi; spf=pass smtp.mailfrom=iki.fi; dkim=pass (1024-bit key) header.d=iki.fi header.i=@iki.fi header.b=eMUiw3Lk; arc=pass smtp.client-ip=195.140.195.201 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=iki.fi Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=iki.fi Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=iki.fi header.i=@iki.fi header.b="eMUiw3Lk" Received: from monolith.lan (unknown [IPv6:2a03:1b20:1:e011::d701]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange x25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) (Authenticated sender: pav) by meesny.iki.fi (Postfix) with ESMTPSA id 4hXHVJ4hKdz11GQ; Sat, 29 Aug 2026 17:20:56 +0300 (EEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=iki.fi; s=meesny; t=1788013258; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=2PRgG5uGRLGPkDBo1Znpwxxc2dMsweTnD+4NI02S4Gs=; b=eMUiw3Lkw82W8YCPUdONCd47durk0Jq3MLJKiogMBq+j0YMk144fZ3aMbG985PrG/00KFv 91vYwe71jJnvROnRgzgSiAsJ0E6t1fPRe392hf8W2OgXQ39YNslMa1gmUgzqDpATdQsPXs rHqP+KjG7j7AIBKUUAJv4OddLjxR37I= ARC-Seal: i=1; a=rsa-sha256; d=iki.fi; s=meesny; cv=none; t=1788013258; b=p8bFDu3BNNKdeJZxxkhNlOPtUrnob1T5chezo+rathQ+ai6+G/HsycV4NJwrUf+g1DQZt8 fs5XcFBE76ZnELC1y1IEtIqQ8+6Z/aBoJCLL8lZxXyvvoEivezhD2B/wlLXA7UEz6q4/CA kE0i1bfnD67WSwSjCyYyPI+reXUKLJQ= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=iki.fi; s=meesny; t=1788013258; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=2PRgG5uGRLGPkDBo1Znpwxxc2dMsweTnD+4NI02S4Gs=; b=I2t2BAtl8jYnwJHFfMg3/oeNeFZq27A9ariC3jB4rihy4rGeZtfJRLRNZnY2f88Rs9yVlf oYnKT1hrs33qGG4KP56olML7cifoVBR9X+QeKJ2T/1rfy33BqJH1jLryUi1fPwpHHEnDJP 1WHRuJXlYeA/fW11bDswKGbMUBPs4ZU= ARC-Authentication-Results: i=1; ORIGINATING; auth=pass smtp.auth=pav smtp.mailfrom=pav@iki.fi From: Pauli Virtanen To: linux-bluetooth@vger.kernel.org Cc: Pauli Virtanen , marcel@holtmann.org, luiz.dentz@gmail.com, oss@fourdim.xyz, error27@gmail.com, elver@google.com, linux-kernel@vger.kernel.org, Eulgyu Kim , Jaeyoung Chung Subject: [PATCH 03/16] Bluetooth: L2CAP: fix race condition in l2cap_sock_shutdown() Date: Sat, 29 Aug 2026 17:19:58 +0300 Message-ID: X-Mailer: git-send-email 2.55.0 In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" l2cap_sock_shutdown() has the race condition [Task 1] [Task 2] l2cap_sock_shutdown l2cap_sock_connect l2cap_chan_lock l2cap_chan_connect conn =3D ... /* =3D=3D NULL*/ l2cap_chan_unlock ------------> l2cap_chan_lock if (conn) /* false */ __l2cap_chan_add(conn, chan) l2cap_chan_lock <-------------- l2cap_chan_unlock l2cap_chan_close /* chan->conn->lock not held! */ conn->lock protects conn->chan_l and is not properly held here. Use the l2cap_chan_close_unlocked() helper that ensures conn->lock is held for l2cap_chan_close(). Fixes: ab4eedb790ca ("Bluetooth: L2CAP: Fix corrupted list in hci_chan_del") Reported-by: Eulgyu Kim Reported-by: Jaeyoung Chung Link: https://lore.kernel.org/linux-bluetooth/20260824153908.2327306-1-jjy6= 00901@snu.ac.kr/ Link: https://syzkaller.appspot.com/bug?extid=3D0e4ebcc970728e056324 Signed-off-by: Pauli Virtanen --- net/bluetooth/l2cap_sock.c | 19 +------------------ 1 file changed, 1 insertion(+), 18 deletions(-) diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c index b553b6356af8..0265b6508682 100644 --- a/net/bluetooth/l2cap_sock.c +++ b/net/bluetooth/l2cap_sock.c @@ -1406,7 +1406,6 @@ static int l2cap_sock_shutdown(struct socket *sock, i= nt how) { struct sock *sk =3D sock->sk; struct l2cap_chan *chan; - struct l2cap_conn *conn; int err =3D 0; =20 BT_DBG("sock %p, sk %p, how %d", sock, sk, how); @@ -1463,23 +1462,7 @@ static int l2cap_sock_shutdown(struct socket *sock, = int how) sk->sk_shutdown |=3D SEND_SHUTDOWN; release_sock(sk); =20 - l2cap_chan_lock(chan); - /* prevent conn structure from being freed */ - conn =3D l2cap_conn_hold_unless_zero(chan->conn); - l2cap_chan_unlock(chan); - - if (conn) - /* mutex lock must be taken before l2cap_chan_lock() */ - mutex_lock(&conn->lock); - - l2cap_chan_lock(chan); - l2cap_chan_close(chan, 0); - l2cap_chan_unlock(chan); - - if (conn) { - mutex_unlock(&conn->lock); - l2cap_conn_put(conn); - } + l2cap_chan_close_unlocked(chan, 0); =20 lock_sock(sk); =20 --=20 2.55.0 From nobody Sat Sep 26 21:59:26 2026 Received: from meesny.iki.fi (meesny.iki.fi [195.140.195.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 0073042A96; Sat, 29 Aug 2026 14:21:09 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=pass smtp.client-ip=195.140.195.201 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788013271; cv=pass; b=IPrgsZX43flNqOwDmDPswdB8CvOEIp4gvkyi5p86h+81B8Xj2WgR2rzJa8M99EYayQ8AY6vRGj4xsk1ws0nmJxfSPYhq+0sWQrwAil/ccJAtr62SLK2PV1+6SuGPq/MYr7HGaLTQ+i6vCagbl95ORnpEOqWvQGUYh6v71onfADM= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788013271; c=relaxed/simple; bh=h6XrQILfwOax1K7ARvNpappOhb59PN4VV5J9P0/3+GI=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=DewD1+sBphpwLanx7jndRn6WTUr5OsJ2SmJCXowwh+xpZuf7tF1Va67jrcGjqcShACbPpMZVjZ6W/zxbrzM/Sqaa/hYFqIBXdAebJCludywQ+DLfN8Pp0D0jg6+2N6Ms3dE0sCJxmtZvIMcYJCVUTzUyS5ndEgkCfQ8To3hy2Oc= ARC-Authentication-Results: i=2; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=iki.fi; spf=pass smtp.mailfrom=iki.fi; dkim=pass (1024-bit key) header.d=iki.fi header.i=@iki.fi header.b=eTQWbKJS; arc=pass smtp.client-ip=195.140.195.201 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=iki.fi Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=iki.fi Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=iki.fi header.i=@iki.fi header.b="eTQWbKJS" Received: from monolith.lan (unknown [IPv6:2a03:1b20:1:e011::d701]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange x25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) (Authenticated sender: pav) by meesny.iki.fi (Postfix) with ESMTPSA id 4hXHVQ72QHzyhS; Sat, 29 Aug 2026 17:21:02 +0300 (EEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=iki.fi; s=meesny; t=1788013264; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=zBhlXhEpcZVXBOByrLQzkXc88TtYCblpBHZ6pmcoSVA=; b=eTQWbKJS9JyX18t/2xz/OpYDNfc+2V1/xAJ8NB7spKUhj9cFJhTe2KEQKxTCFUjn07HbRt N6VWYygs/NfmX8OJSTpI2xqdG101Zr4zF3fZ5BgVxfSsyLA4iRR3TurbLpIINAUJ0KFDe/ //ENK+dhwmjoVmb5cxNGbutuLZs6lJk= ARC-Seal: i=1; a=rsa-sha256; d=iki.fi; s=meesny; cv=none; t=1788013264; b=zPxTnlg69ZBgVn0ohpZaAUDmxPaW6mYamU54klxDIHFstAH+F89Vxmm/63NIxJ2KrXuIa4 VCKud1TxO9aCrgeuVMcjFdTv2LNFlh8VLXW6nMNyk7Ivi3qqabZk82g6GYkdkaCDXJb6AJ 37e7NHm/P4pdSmxmxti+Oo8y+p/SDl4= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=iki.fi; s=meesny; t=1788013264; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=zBhlXhEpcZVXBOByrLQzkXc88TtYCblpBHZ6pmcoSVA=; b=uGFFM4fMZY9OzuKSJNWKwH1ARlNEDhAnIkwebsQF1lL0hSuplrba/ZHBN+baNKzUTiOYdQ 5uVjmUVX7TOZY3d9RyayljwtlpvO++LGDf5uDWI5vbA6mVo2Fr03OpCR6r9Xp2lrr1yimZ pNXjLEt0BBk0aBodN1i/EbPXgQ8GH14= ARC-Authentication-Results: i=1; ORIGINATING; auth=pass smtp.auth=pav smtp.mailfrom=pav@iki.fi From: Pauli Virtanen To: linux-bluetooth@vger.kernel.org Cc: Pauli Virtanen , marcel@holtmann.org, luiz.dentz@gmail.com, oss@fourdim.xyz, error27@gmail.com, elver@google.com, linux-kernel@vger.kernel.org Subject: [PATCH 04/16] Bluetooth: 6lowpan: use l2cap_chan_close_unlocked() Date: Sat, 29 Aug 2026 17:19:59 +0300 Message-ID: X-Mailer: git-send-email 2.55.0 In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" 6lowpan.c is using l2cap_chan_close() without taking chan->conn->lock, so it may modify conn->chan_l without holding the guarding lock. Fix the locking by using the l2cap_chan_close_unlocked() helper that acquires the necessary locks. Fixes: 15f32cabf426 ("Bluetooth: 6lowpan: add missing l2cap_chan_lock()") Link: https://syzkaller.appspot.com/bug?extid=3D0e4ebcc970728e056324 Signed-off-by: Pauli Virtanen --- net/bluetooth/6lowpan.c | 27 +++++++++------------------ 1 file changed, 9 insertions(+), 18 deletions(-) diff --git a/net/bluetooth/6lowpan.c b/net/bluetooth/6lowpan.c index 30f4afa18bc8..4ea55950e599 100644 --- a/net/bluetooth/6lowpan.c +++ b/net/bluetooth/6lowpan.c @@ -921,9 +921,7 @@ static int bt_6lowpan_disconnect(struct l2cap_conn *con= n, u8 dst_type) =20 BT_DBG("peer %p chan %p", peer, peer->chan); =20 - l2cap_chan_lock(peer->chan); - l2cap_chan_close(peer->chan, ENOENT); - l2cap_chan_unlock(peer->chan); + l2cap_chan_close_unlocked(peer->chan, ENOENT); =20 return 0; } @@ -1025,9 +1023,9 @@ static void disconnect_all_peers(void) struct lowpan_peer *peer; int nchans; =20 - /* l2cap_chan_close() cannot be called from RCU, and lock ordering - * chan->lock > devices_lock prevents taking write side lock, so copy - * then close. + /* l2cap_chan_close_unlocked() cannot be called from RCU, and lock + * ordering chan->lock > devices_lock prevents taking write side lock, + * so copy then close. */ =20 rcu_read_lock(); @@ -1062,9 +1060,7 @@ static void disconnect_all_peers(void) spin_unlock(&devices_lock); =20 for (i =3D 0; i < nchans; ++i) { - l2cap_chan_lock(chans[i]); - l2cap_chan_close(chans[i], ENOENT); - l2cap_chan_unlock(chans[i]); + l2cap_chan_close_unlocked(chans[i], ENOENT); l2cap_chan_put(chans[i]); } } while (nchans); @@ -1082,9 +1078,7 @@ static void do_enable_set(bool flag) =20 mutex_lock(&set_lock); if (listen_chan) { - l2cap_chan_lock(listen_chan); - l2cap_chan_close(listen_chan, 0); - l2cap_chan_unlock(listen_chan); + l2cap_chan_close_unlocked(listen_chan, 0); l2cap_chan_put(listen_chan); } =20 @@ -1132,9 +1126,7 @@ static ssize_t lowpan_control_write(struct file *fp, =20 mutex_lock(&set_lock); if (listen_chan) { - l2cap_chan_lock(listen_chan); - l2cap_chan_close(listen_chan, 0); - l2cap_chan_unlock(listen_chan); + l2cap_chan_close_unlocked(listen_chan, 0); l2cap_chan_put(listen_chan); listen_chan =3D NULL; } @@ -1303,10 +1295,9 @@ static void __exit bt_6lowpan_exit(void) debugfs_remove(lowpan_control_debugfs); =20 if (listen_chan) { - l2cap_chan_lock(listen_chan); - l2cap_chan_close(listen_chan, 0); - l2cap_chan_unlock(listen_chan); + l2cap_chan_close_unlocked(listen_chan, 0); l2cap_chan_put(listen_chan); + listen_chan =3D NULL; } =20 disconnect_devices(); --=20 2.55.0 From nobody Sat Sep 26 21:59:26 2026 Received: from meesny.iki.fi (meesny.iki.fi [195.140.195.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id BD3C6214812; Sat, 29 Aug 2026 14:21:15 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=pass smtp.client-ip=195.140.195.201 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788013277; cv=pass; b=utNvXazjkamhtQHYuNGZVG65Mf0IJnnBkv5Z/fDl3pd/WRnBg8nJx6Lejph6AC57AtifS712sMAwf5VCZEqQGsR+H+dolWKsjaIqcH41J9sV4aluoiF4Q+tTWqfqAv/Jy9zle4jXCjHeu4kMo3n1XBDHlMWjg/M5wT/BKvcQDsQ= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788013277; c=relaxed/simple; bh=op78QQZtGTeyMDhLgHzUcodAjobHlPaCPwDpOIpAZVo=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=uGaDp3TBCsEIbaY/0Tbu/7Oyo5G8aU0huFl/oTxAJewyw8/C4AYfp6GGQntgcARneejW09VXjFft5+M31gb0I6MYd9u/ogPgbuDeqGyTpx/xSZ67jnOWjaDKKmqmrUDD7LoyfdOBTo+ozsJdsj2rigCcLQXUEc5qOqHUHgOaT1c= ARC-Authentication-Results: i=2; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=iki.fi; spf=pass smtp.mailfrom=iki.fi; dkim=pass (1024-bit key) header.d=iki.fi header.i=@iki.fi header.b=ZGuh664Q; arc=pass smtp.client-ip=195.140.195.201 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=iki.fi Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=iki.fi Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=iki.fi header.i=@iki.fi header.b="ZGuh664Q" Received: from monolith.lan (unknown [IPv6:2a03:1b20:1:e011::d701]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange x25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) (Authenticated sender: pav) by meesny.iki.fi (Postfix) with ESMTPSA id 4hXHVX3QnJzyvj; Sat, 29 Aug 2026 17:21:08 +0300 (EEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=iki.fi; s=meesny; t=1788013269; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=P9qAXeGSbzvkrAu179qZnN8YI/+hurMqJgOUWHWSjoM=; b=ZGuh664QQwg7StBG9iUYxRpjze8Oko2bPkmIgZfJYIP5GRHxF+8BLLvJsG1MTss2VA+Xza 7fTH5kwfD8Etk9SNQIwJP4/KWgXaWIvqwRpbtm/riSYz/rQ8RlnGh3KpDOYQm7ttlIHYN1 kaIXefR5nwBhG0cSr3Bw8jAybCMzUAg= ARC-Seal: i=1; a=rsa-sha256; d=iki.fi; s=meesny; cv=none; t=1788013269; b=xOhd5iC7Pqn3R69RU9qrKaDijKDCJt02l1iHrm7LZ37+iA978gSdDLJ7F9+l8OM6iQD4MV 3eGL0kV9LibozmE7jhQle7Ty0cqnXesdUUQ4YTHf9Ezd+7Myh9fim225bek9Yf2UpjlWUe bT+se5i57IqFq/ypu6rJEX4uv8gMuMc= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=iki.fi; s=meesny; t=1788013269; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=P9qAXeGSbzvkrAu179qZnN8YI/+hurMqJgOUWHWSjoM=; b=yWnt6fsp715hlf2WtLyM+Wj3huqvXU9kPuSN/jAK8OSSvDxHFwFRAvDflB2qL/XnuhOav0 EDDTuHvTb7+fua+BblkNgFhHi80Ifyq7SP/dSixvmOxHN4urMHPJTDlnO2zI+9TYlKuGkc 9sRanRvsTlcgejr698IVt4N9Ogab06k= ARC-Authentication-Results: i=1; ORIGINATING; auth=pass smtp.auth=pav smtp.mailfrom=pav@iki.fi From: Pauli Virtanen To: linux-bluetooth@vger.kernel.org Cc: Pauli Virtanen , marcel@holtmann.org, luiz.dentz@gmail.com, oss@fourdim.xyz, error27@gmail.com, elver@google.com, linux-kernel@vger.kernel.org Subject: [PATCH 05/16] Bluetooth: L2CAP: remove unused l2cap_chan_close() Date: Sat, 29 Aug 2026 17:20:00 +0300 Message-ID: X-Mailer: git-send-email 2.55.0 In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" l2cap_chan_close() is now unused, and l2cap_chan_close_unlocked() should be used instead. Remove l2cap_chan_close(). Signed-off-by: Pauli Virtanen --- include/net/bluetooth/l2cap.h | 1 - net/bluetooth/l2cap_core.c | 6 ------ 2 files changed, 7 deletions(-) diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index 84f557d354ca..e395ab5493f7 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h @@ -961,7 +961,6 @@ int l2cap_add_psm(struct l2cap_chan *chan, bdaddr_t *sr= c, __le16 psm); int l2cap_add_scid(struct l2cap_chan *chan, __u16 scid); =20 struct l2cap_chan *l2cap_chan_create(void); -void l2cap_chan_close(struct l2cap_chan *chan, int reason); void l2cap_chan_close_unlocked(struct l2cap_chan *chan, int reason) __must_not_hold(&chan->lock); int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid, diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 58c88e116ddc..c9b3321f7f90 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -880,12 +880,6 @@ static void __l2cap_chan_close(struct l2cap_chan *chan= , int reason) } } =20 -void l2cap_chan_close(struct l2cap_chan *chan, int reason) -{ - __l2cap_chan_close(chan, reason); -} -EXPORT_SYMBOL(l2cap_chan_close); - /* Take chan->lock. If chan->conn is non-NULL, take new reference on it, t= ake * chan->conn->lock, and return true. Otherwise return false. */ --=20 2.55.0 From nobody Sat Sep 26 21:59:26 2026 Received: from meesny.iki.fi (meesny.iki.fi [195.140.195.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id DFFF842A96; Sat, 29 Aug 2026 14:21:20 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=pass smtp.client-ip=195.140.195.201 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788013282; cv=pass; b=I/rhoch+jtN6OPNnXBExaWEc1Rq838t3lt5ti9yizVGr5QECgfJFMwwMIYzIxCBh+efPquMkkes0I3qHU9xK63J+fhSacCwzZ7FPzPv+SyesuMAESifQoUh7JOqvr8ggSY/bCXd7Svz+P7yVlNIb4HbgwNc6EgF2ajwwNrzXL4M= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788013282; c=relaxed/simple; bh=QdBBRlhHamIErJyEgdDWKQJ4g/jiKHKA1kE82VRzDGk=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=W714O/EWtd3tZ8iS7lEF26RFDFZVlScz+CDMy8kgi6M1A/gcdOKy7CfLGyDGLeKMrxhXfagYI3kdcWJlgkOmpeW5ok+5Rue8N8sm0+hfGLL7KVab8YuKPptBiQpnJ2k7i2qwYkN38GfNz8dlFCFOWY3xKtsceSou6bMtdgRFf5w= ARC-Authentication-Results: i=2; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=iki.fi; spf=pass smtp.mailfrom=iki.fi; dkim=pass (1024-bit key) header.d=iki.fi header.i=@iki.fi header.b=tSs4XaKX; arc=pass smtp.client-ip=195.140.195.201 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=iki.fi Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=iki.fi Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=iki.fi header.i=@iki.fi header.b="tSs4XaKX" Received: from monolith.lan (unknown [IPv6:2a03:1b20:1:e011::d701]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange x25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) (Authenticated sender: pav) by meesny.iki.fi (Postfix) with ESMTPSA id 4hXHVd6WVLzyWl; Sat, 29 Aug 2026 17:21:13 +0300 (EEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=iki.fi; s=meesny; t=1788013274; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=29nBADU74ZrC5xPAbw987SaaBfsEBjMitjT7ZQbjhIQ=; b=tSs4XaKXNP5qgH5o2aFG2xrJ94li0z2OI/vk9/oI7Ecv7ZJa5LHvPKZVlmtJmYxLCncPXa uv2VYle013AHlVrL0NFGyQk+yjs+dHJmfKkV6vogTKcbxTw0Fa+OSL3LbO8VjtOLcScJJv /PBqZHy2NDMtHOuh28icmXPNVEpSkSc= ARC-Seal: i=1; a=rsa-sha256; d=iki.fi; s=meesny; cv=none; t=1788013274; b=oM+IMMcb79s1ng7EXrfYz+viIwoGchMQB0hvWnGWBmjz06BD1rFaUh/9ybuJSryV26FtZT eNnEYBRv6vFv2zKwBp5gAG9IFzVigfh8hExPfd6/LHkmzUtd0zYeQeNpYTXnR/f0KTsDQV 7qsxwj9hje3csO3FNEu4TXdVWK4Lzbg= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=iki.fi; s=meesny; t=1788013274; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=29nBADU74ZrC5xPAbw987SaaBfsEBjMitjT7ZQbjhIQ=; b=c8l3vleegRpJk3nT7SbSxoECB6g0cKL599+nCsc2aQkO0OPIMJdNce7v2b8ZN73phoplWF 42IbAztNGwp3G42ruVoTWrqOydGSv26BWOWqGcqQXfGjduDlYvyt8fSec9misdj00w/kwF pZTbHcNx+AwURh7ACqyjSay/KRvZcSo= ARC-Authentication-Results: i=1; ORIGINATING; auth=pass smtp.auth=pav smtp.mailfrom=pav@iki.fi From: Pauli Virtanen To: linux-bluetooth@vger.kernel.org Cc: Pauli Virtanen , marcel@holtmann.org, luiz.dentz@gmail.com, oss@fourdim.xyz, error27@gmail.com, elver@google.com, linux-kernel@vger.kernel.org Subject: [PATCH 06/16] Bluetooth: 6lowpan: avoid concurrent peer_del() in bt_6lowpan_disconnect Date: Sat, 29 Aug 2026 17:20:01 +0300 Message-ID: <35b69716d9516c19662d5615a962ceb6be34ffe3.1788013041.git.pav@iki.fi> X-Mailer: git-send-email 2.55.0 In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" bt_6lowpan_disconnect() looks up and accesses peer->chan, without holding locks guaranteeing peer_del() cannot free the peer concurrently. Take devices_lock to ensure peer can be dereferenced safely. Fixes: 15f32cabf426 ("Bluetooth: 6lowpan: add missing l2cap_chan_lock()") Signed-off-by: Pauli Virtanen --- net/bluetooth/6lowpan.c | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/net/bluetooth/6lowpan.c b/net/bluetooth/6lowpan.c index 4ea55950e599..ddcdd2aff91f 100644 --- a/net/bluetooth/6lowpan.c +++ b/net/bluetooth/6lowpan.c @@ -912,16 +912,27 @@ static int bt_6lowpan_connect(bdaddr_t *addr, u8 dst_= type) static int bt_6lowpan_disconnect(struct l2cap_conn *conn, u8 dst_type) { struct lowpan_peer *peer; + struct l2cap_chan *chan; =20 BT_DBG("conn %p dst type %u", conn, dst_type); =20 + spin_lock(&devices_lock); + peer =3D lookup_peer(conn); - if (!peer) + if (!peer) { + spin_unlock(&devices_lock); return -ENOENT; + } =20 - BT_DBG("peer %p chan %p", peer, peer->chan); + chan =3D peer->chan; + l2cap_chan_hold(chan); =20 - l2cap_chan_close_unlocked(peer->chan, ENOENT); + spin_unlock(&devices_lock); + + BT_DBG("peer %p chan %p", peer, chan); + + l2cap_chan_close_unlocked(chan, ENOENT); + l2cap_chan_put(chan); =20 return 0; } --=20 2.55.0 From nobody Sat Sep 26 21:59:26 2026 Received: from meesny.iki.fi (meesny.iki.fi [195.140.195.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 5EBED214812; Sat, 29 Aug 2026 14:21:26 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=pass smtp.client-ip=195.140.195.201 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788013287; cv=pass; b=ncLlJffHwjF9moWo5Tpz7XHqxUAqyzzPPv1t8YMeLTtiXoHKf39XGxOVBbQpJwcIE2pGQjyw3XsYh4qomB1sbl5t8xXv8zWO3mv2YnjRBZOXxnBsGpU5mpPI9rVHCOIUcXeN+JDbXnofddIx9YJdbSOGGbmerADOvPIcJzUhyzM= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788013287; c=relaxed/simple; bh=mJyWPnf3mukEpytt9jrKB9d88tqOXExoMm5/++P1FOs=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=kgDxac0pvCOT/MkUwBoEzBin+jOIpcQhTgyAXdZ9bzek3eKhO/NLk2bt0nzF5rkAILDJpysHrHLIXruh+ZdLzbzSCTV6jTgnCF2wQglWD+EyUdnvOCnQxXHbnVEBcfI/uHqPoDKNCZtKIDFlGbBnXDsOCxgBVsRXaeqh+jXxFY4= ARC-Authentication-Results: i=2; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=iki.fi; spf=pass smtp.mailfrom=iki.fi; dkim=pass (1024-bit key) header.d=iki.fi header.i=@iki.fi header.b=q7leeduz; arc=pass smtp.client-ip=195.140.195.201 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=iki.fi Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=iki.fi Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=iki.fi header.i=@iki.fi header.b="q7leeduz" Received: from monolith.lan (unknown [IPv6:2a03:1b20:1:e011::d701]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange x25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) (Authenticated sender: pav) by meesny.iki.fi (Postfix) with ESMTPSA id 4hXHVl2RgpzyhS; Sat, 29 Aug 2026 17:21:19 +0300 (EEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=iki.fi; s=meesny; t=1788013280; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=rHOeFN2Nn/zpxM8hYq1DsEbcNGI3ZrDw7lT0DfGxc80=; b=q7leeduz5fClqIsIVbwU81UesvzP62F1r9s+T20MXPeZNJtsJI/5IUb3qN/mchxd3kCn8v 9E8y/Dqt6mZKgYZKYNai7YjDfk/pKGR+JCG6MgSirJLv5JghLIbLfVvtk9zaWVFBSXivv5 4a4et+E1HtgRCOcwwrsCtFh3HxDMhzc= ARC-Seal: i=1; a=rsa-sha256; d=iki.fi; s=meesny; cv=none; t=1788013280; b=clzlIpIMPz3PmTdzOTUA2yVFfNUoBF0s6ni21XZF7yI/IiMafpaCzuvpXmGRCo4s6kL+Ci gO+oY5BZ0jrSSPgr6kaMvVesKH+vgwRNnP4Vqm2vbs+v0uk+bk9b68KkiE/Gd6lrv1RQoG Q+KwvMrlnR+5gP0g9HakwyKcw1wmGWg= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=iki.fi; s=meesny; t=1788013280; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=rHOeFN2Nn/zpxM8hYq1DsEbcNGI3ZrDw7lT0DfGxc80=; b=LL4dpy0GrIjX58ZzjydGZspsBlWrmQMKsQaXY3rkKgoMRyR8ZfSaIvr5i3TPMkWXTzPCqa uuhU4b4fWVMY4mxBlMXmycT3quItXaCcyuXCigkD1qj6hFPiFL37Hdk4aZ8/a6sT5ukfx3 TaaE6DU2t9ATVlz4Brno7lFvEhlAKP0= ARC-Authentication-Results: i=1; ORIGINATING; auth=pass smtp.auth=pav smtp.mailfrom=pav@iki.fi From: Pauli Virtanen To: linux-bluetooth@vger.kernel.org Cc: Pauli Virtanen , marcel@holtmann.org, luiz.dentz@gmail.com, oss@fourdim.xyz, error27@gmail.com, elver@google.com, linux-kernel@vger.kernel.org Subject: [PATCH 07/16] Bluetooth: L2CAP: hold conn->lock for __l2cap_ecred_conn_rsp_defer Date: Sat, 29 Aug 2026 17:20:02 +0300 Message-ID: <3213ea451b4db947b3333c002ab19678431781eb.1788013041.git.pav@iki.fi> X-Mailer: git-send-email 2.55.0 In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" __l2cap_ecred_conn_rsp_defer() > __l2cap_chan_list_id() accesses conn->chan_l which is guarded by conn->lock. The lock fails to be held when calling from l2cap_sock.c. Fix by using l2cap_chan_conn_lock(), and taking the locks in required order l2cap_conn::lock > l2cap_chan::lock > sk. Leave fast path with sk->sk_state precheck. Move the L2CAP defer handling to l2cap_sock_defer(). The code should also take l2cap_chan_lock() for sibling channels, but that needs separate fix due to lock nesting. Fixes: ab4eedb790ca ("Bluetooth: L2CAP: Fix corrupted list in hci_chan_del") Signed-off-by: Pauli Virtanen --- net/bluetooth/l2cap_sock.c | 74 ++++++++++++++++++++++++++------------ 1 file changed, 51 insertions(+), 23 deletions(-) diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c index 0265b6508682..dee3025f0ec2 100644 --- a/net/bluetooth/l2cap_sock.c +++ b/net/bluetooth/l2cap_sock.c @@ -1243,6 +1243,54 @@ static void l2cap_publish_rx_avail(struct l2cap_chan= *chan) l2cap_chan_rx_avail(chan, -1); } =20 +static int l2cap_sock_defer(struct sock *sk) +{ + struct l2cap_chan *chan =3D l2cap_pi(sk)->chan; + bool have_conn; + int err =3D 0; + + /* Fast path check */ + lock_sock(sk); + if (sk->sk_state !=3D BT_CONNECT2) { + release_sock(sk); + return 0; + } + release_sock(sk); + + have_conn =3D l2cap_chan_lock_conn(chan); + lock_sock(sk); + + if (sk->sk_state =3D=3D BT_CONNECT2 && test_bit(BT_SK_DEFER_SETUP, + &bt_sk(sk)->flags)) { + err =3D 1; + + if (!have_conn) { + release_sock(sk); + err =3D -ENOTCONN; + } else if (chan->mode =3D=3D L2CAP_MODE_EXT_FLOWCTL) { + sk->sk_state =3D BT_CONNECTED; + chan->state =3D BT_CONNECTED; + release_sock(sk); + __l2cap_ecred_conn_rsp_defer(chan); + } else if (bdaddr_type_is_le(chan->src_type)) { + sk->sk_state =3D BT_CONNECTED; + chan->state =3D BT_CONNECTED; + release_sock(sk); + __l2cap_le_connect_rsp_defer(chan); + } else { + sk->sk_state =3D BT_CONFIG; + chan->state =3D BT_CONFIG; + release_sock(sk); + __l2cap_connect_rsp_defer(chan); + } + } else { + release_sock(sk); + } + + l2cap_chan_unlock_conn(chan, have_conn); + return err; +} + static int l2cap_sock_recvmsg(struct socket *sock, struct msghdr *msg, size_t len, int flags) { @@ -1254,29 +1302,9 @@ static int l2cap_sock_recvmsg(struct socket *sock, s= truct msghdr *msg, return sock_recv_errqueue(sk, msg, len, SOL_BLUETOOTH, BT_SCM_ERROR); =20 - lock_sock(sk); - - if (sk->sk_state =3D=3D BT_CONNECT2 && test_bit(BT_SK_DEFER_SETUP, - &bt_sk(sk)->flags)) { - if (pi->chan->mode =3D=3D L2CAP_MODE_EXT_FLOWCTL) { - sk->sk_state =3D BT_CONNECTED; - pi->chan->state =3D BT_CONNECTED; - __l2cap_ecred_conn_rsp_defer(pi->chan); - } else if (bdaddr_type_is_le(pi->chan->src_type)) { - sk->sk_state =3D BT_CONNECTED; - pi->chan->state =3D BT_CONNECTED; - __l2cap_le_connect_rsp_defer(pi->chan); - } else { - sk->sk_state =3D BT_CONFIG; - pi->chan->state =3D BT_CONFIG; - __l2cap_connect_rsp_defer(pi->chan); - } - - err =3D 0; - goto done; - } - - release_sock(sk); + err =3D l2cap_sock_defer(sk); + if (err) + return err < 0 ? err : 0; =20 if (sock->type =3D=3D SOCK_STREAM) err =3D bt_sock_stream_recvmsg(sock, msg, len, flags); --=20 2.55.0 From nobody Sat Sep 26 21:59:26 2026 Received: from meesny.iki.fi (meesny.iki.fi [195.140.195.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id BFAF62E6CB8; Sat, 29 Aug 2026 14:21:31 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=pass smtp.client-ip=195.140.195.201 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788013294; cv=pass; b=qC6cUuUXa4aN7bRvRmwsmFnimqhNs016gbmlX8SElIBoiu1uNmr7bxt4ajjpe/BTMoyo8iNRKN22cvJZTg9YbPQg7gNTZO7H1WUlcRmH6zG2kie7TQ8c4UBTnfVQGLk5GoAbkpw5IvHEVfT0RL8LAzDklrT6ctxbj1D4S3OFu9Q= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788013294; c=relaxed/simple; bh=tWAgw3HXpFii7LKIcFQkL/4ElS6g1HAO79+W6K6c2vU=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=an0aKIN9DAXfe+ENtkvrIczShQDGmSlmQoTwV+3El2S/hKk6xcauB6ag6QXj2c5Wv9LCwrK52pP0sIfdAYM4w5h73rDgynixjKRuw0sC1BQ3dSigJKBSbew41prmPz5DbsonDswAvV72fEE7+RD3/1357CWyQBqVrYpdmZRIZ3A= ARC-Authentication-Results: i=2; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=iki.fi; spf=pass smtp.mailfrom=iki.fi; dkim=pass (1024-bit key) header.d=iki.fi header.i=@iki.fi header.b=HwlBApxn; arc=pass smtp.client-ip=195.140.195.201 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=iki.fi Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=iki.fi Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=iki.fi header.i=@iki.fi header.b="HwlBApxn" Received: from monolith.lan (unknown [IPv6:2a03:1b20:1:e011::d701]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange x25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) (Authenticated sender: pav) by meesny.iki.fi (Postfix) with ESMTPSA id 4hXHVr5YSSzyWl; Sat, 29 Aug 2026 17:21:24 +0300 (EEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=iki.fi; s=meesny; t=1788013285; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=z3L4ynMGaxqDanS5fOd/Ak0IGdfv0KKsAUltWgJvwXI=; b=HwlBApxnrFv2Z7GmjMxVQWQXCUQob6Rkug06ZYtxpd2EY9MLfMTvvySOmhdO85AM/PQp+m MUczDbroQ+UkRUHEg9rrjoK/7wVmVGtQTfJsZmlPqQgCjLRSntURi0Dhd8LBvsOV/s06fV 14xyqt/ItcU0jbEZLes9FbAEdOyl7ls= ARC-Seal: i=1; a=rsa-sha256; d=iki.fi; s=meesny; cv=none; t=1788013285; b=KzSPN9kElxJpcy7X17al1s5/O0oFbIBCJBXXM7k+sLf77V1Kt0HY/qkw4lDhIKyCW4ta/+ l1PXtspmt+ntVhPghssUDXxJol1Gm04IIbLxYUa+EokPl08Ot/4tQpvP/l5KVIQkxBWhTl EZB26Whh8A/NaHoO5kr9NDtQlprytMA= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=iki.fi; s=meesny; t=1788013285; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=z3L4ynMGaxqDanS5fOd/Ak0IGdfv0KKsAUltWgJvwXI=; b=zM88in/FNNqFvWf7rPGkifgnCSH8j3zMXx8YpqswCPIROfClD5bTfHca5EYY1yijQv07HO lXLacUkYD1Xx0Ubd2nwmh/cI15lS4gk/Q6M6EcCPVZnjnm8cVM/AqWf1OJQwumD6gVdOui MGf5A+Hb5/TV0eEa8b1VHBo6o3UDtO8= ARC-Authentication-Results: i=1; ORIGINATING; auth=pass smtp.auth=pav smtp.mailfrom=pav@iki.fi From: Pauli Virtanen To: linux-bluetooth@vger.kernel.org Cc: Pauli Virtanen , marcel@holtmann.org, luiz.dentz@gmail.com, oss@fourdim.xyz, error27@gmail.com, elver@google.com, linux-kernel@vger.kernel.org Subject: [PATCH 08/16] Bluetooth: L2CAP: hold l2cap_conn::lock in l2cap_connect_cfm() Date: Sat, 29 Aug 2026 17:20:03 +0300 Message-ID: <19f7e8e2dc1b168dcbb848628333cb892c296d86.1788013041.git.pav@iki.fi> X-Mailer: git-send-email 2.55.0 In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" l2cap_new_connection() -> __l2cap_chan_add() modifies l2cap_conn::chan_l, which is guarded by l2cap_conn::lock. The lock is not held in l2cap_connect_cfm(). Fix by holding conn->lock in l2cap_connect_cfm() to make the locking systematic. Fixes: ab4eedb790ca ("Bluetooth: L2CAP: Fix corrupted list in hci_chan_del") Signed-off-by: Pauli Virtanen --- net/bluetooth/l2cap_core.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index c9b3321f7f90..44077e3d1e2d 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -7629,6 +7629,8 @@ static void l2cap_connect_cfm(struct hci_conn *hcon, = u8 status) * we left off, because the list lock would prevent calling the * potentially sleeping l2cap_chan_lock() function. */ + mutex_lock(&conn->lock); + pchan =3D l2cap_global_fixed_chan(NULL, hcon); while (pchan) { struct l2cap_chan *chan, *next; @@ -7653,6 +7655,8 @@ static void l2cap_connect_cfm(struct hci_conn *hcon, = u8 status) pchan =3D next; } =20 + mutex_unlock(&conn->lock); + l2cap_conn_ready(conn); } =20 --=20 2.55.0 From nobody Sat Sep 26 21:59:26 2026 Received: from meesny.iki.fi (meesny.iki.fi [195.140.195.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 1A1213AC0C7; Sat, 29 Aug 2026 14:21:36 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=pass smtp.client-ip=195.140.195.201 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788013299; cv=pass; b=apTLLMDtBqaB4NglEF5lME2Stxz07pjDQHExLFx9hlT4aZCe1DbeGHj6pdmw91M2Z/bfHX9ppNkli/k8rRdXcOpBiKtuokS/d0O0TuVcgepnh10Pgrwrz9i/9fv0BJdEiCSfzo9wXsaBc3R/PWubweoy+p5fN/WyWsGfFfgcivY= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788013299; c=relaxed/simple; bh=4A80eD5xwidok+58mtUypsm2Iw2a5DyAk8v6yteLOfk=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=DjX7nE0WF119DbKEEfQcb78FA55eGryVSFfJ79ijSC2KBwgcOu6yltc3yDzHxCFslp1i9Vc2Q4JM3BgH1CcbV/uKHzVK8jISV1ly2r0MgxOqEoCFjJL4LEuMFZaSVGHBk5SxL0ArRfS8qhX1X6j1wqnG2X7zBs5U87l/eLxFTaQ= ARC-Authentication-Results: i=2; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=iki.fi; spf=pass smtp.mailfrom=iki.fi; dkim=pass (1024-bit key) header.d=iki.fi header.i=@iki.fi header.b=KWuunrqx; arc=pass smtp.client-ip=195.140.195.201 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=iki.fi Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=iki.fi Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=iki.fi header.i=@iki.fi header.b="KWuunrqx" Received: from monolith.lan (unknown [IPv6:2a03:1b20:1:e011::d701]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange x25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) (Authenticated sender: pav) by meesny.iki.fi (Postfix) with ESMTPSA id 4hXHVy1FgrzyhS; Sat, 29 Aug 2026 17:21:30 +0300 (EEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=iki.fi; s=meesny; t=1788013291; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=vjOIMhVLC+nsWWzCfKDzi3jjGsGTOBHVGZxo+sRUpzM=; b=KWuunrqxmks8bf1rqNjBq9BoI8qM2uJgiop/dCNQNHgj0if54tDoPmONMiZ+b+BLJsmw29 gBPcFtfkOZ7ZvG4PjcJakilXgvNbOnt9oznYegs9gS6vvSJkR05Hd1fjTrSWlaFowUC6FD 8CkVSDDC19gfI1Z+IDr4qW8IlZJxCT8= ARC-Seal: i=1; a=rsa-sha256; d=iki.fi; s=meesny; cv=none; t=1788013291; b=Y8mnAmcffBczekWmdieVQ7PAnpzWCHvLkhWrZ2TIpyDGz4UyNlofn9D0gCu/6JeGuHkDUJ q9PAgkuCD2GI1K0+s9iJ9c2J+QCaYitTp6ZwW69jpS/WVfKq7scGOvJ3coM91jdjZt0hTk Sw9Di6gsN6NkNGDLJ9YOjmaUZTHsybA= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=iki.fi; s=meesny; t=1788013291; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=vjOIMhVLC+nsWWzCfKDzi3jjGsGTOBHVGZxo+sRUpzM=; b=NVw8ad2zWA1o7wvjXxTqu3NrnkVqGXo8KvVh5z26rvilsphlgTm9ZKJYUiGs3vaIw39/cI JjtlpQGXT9whA0qmKAo9lvbyCr9mvIwvX//ZeB4kuY3ZlCwdWCg95JLVosbMqRlPWZWnYE dVPn5k3ghHXIPOViR/c5YMxzGQdY/PQ= ARC-Authentication-Results: i=1; ORIGINATING; auth=pass smtp.auth=pav smtp.mailfrom=pav@iki.fi From: Pauli Virtanen To: linux-bluetooth@vger.kernel.org Cc: Pauli Virtanen , marcel@holtmann.org, luiz.dentz@gmail.com, oss@fourdim.xyz, error27@gmail.com, elver@google.com, linux-kernel@vger.kernel.org Subject: [PATCH 09/16] Bluetooth: L2CAP: add annotations for l2cap_chan list locking Date: Sat, 29 Aug 2026 17:20:04 +0300 Message-ID: <8fbc346b0cd372f35b0ab6e348b8034263f84a08.1788013041.git.pav@iki.fi> X-Mailer: git-send-email 2.55.0 In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Add context analysis annotations for l2cap_conn::chan_l and chan_list locking. Add corresponding required annotations to accessors and callers. This is not complete chan_l annotation, l2cap_chan::list and l2cap_chan_del() locking is currently not fully correct, and needs separate fix + annotations. Signed-off-by: Pauli Virtanen --- include/net/bluetooth/l2cap.h | 7 ++-- net/bluetooth/l2cap_core.c | 61 ++++++++++++++++++++++++++++++++--- 2 files changed, 61 insertions(+), 7 deletions(-) diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index e395ab5493f7..a991fc07515c 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h @@ -668,7 +668,7 @@ struct l2cap_conn { =20 struct l2cap_chan *smp; =20 - struct list_head chan_l; + struct list_head chan_l __guarded_by(&lock); struct mutex lock; struct kref ref; struct list_head users; @@ -954,7 +954,8 @@ void l2cap_cleanup_sockets(void); bool l2cap_is_socket(struct socket *sock); =20 void __l2cap_le_connect_rsp_defer(struct l2cap_chan *chan); -void __l2cap_ecred_conn_rsp_defer(struct l2cap_chan *chan); +void __l2cap_ecred_conn_rsp_defer(struct l2cap_chan *chan) + __must_hold(&chan->lock) __must_hold(&chan->conn->lock); void __l2cap_connect_rsp_defer(struct l2cap_chan *chan); =20 int l2cap_add_psm(struct l2cap_chan *chan, bdaddr_t *src, __le16 psm); @@ -975,7 +976,7 @@ void l2cap_chan_set_defaults(struct l2cap_chan *chan, s= truct l2cap_chan *pchan); int l2cap_ertm_init(struct l2cap_chan *chan); void l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan); void __l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan) - __must_hold(&chan->lock); + __must_hold(&conn->lock) __must_hold(&chan->lock); typedef void (*l2cap_chan_func_t)(struct l2cap_chan *chan, void *data); void l2cap_chan_list(struct l2cap_conn *conn, l2cap_chan_func_t func, void *data); diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 44077e3d1e2d..ce51b0b0b37d 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -44,8 +44,8 @@ bool enable_ecred =3D IS_ENABLED(CONFIG_BT_LE_L2CAP_ECRED= ); =20 static u32 l2cap_feat_mask =3D L2CAP_FEAT_FIXED_CHAN | L2CAP_FEAT_UCD; =20 -static LIST_HEAD(chan_list); static DEFINE_RWLOCK(chan_list_lock); +static __guarded_by(&chan_list_lock) LIST_HEAD(chan_list); =20 static struct sk_buff *l2cap_build_cmd(struct l2cap_conn *conn, u8 code, u8 ident, u16 dlen, void *data); @@ -87,6 +87,7 @@ static inline u8 bdaddr_dst_type(struct hci_conn *hcon) =20 static struct l2cap_chan *__l2cap_get_chan_by_dcid(struct l2cap_conn *conn, u16 cid) + __must_hold(&conn->lock) { struct l2cap_chan *c; =20 @@ -99,6 +100,7 @@ static struct l2cap_chan *__l2cap_get_chan_by_dcid(struc= t l2cap_conn *conn, =20 static struct l2cap_chan *__l2cap_get_chan_by_scid(struct l2cap_conn *conn, u16 cid) + __must_hold(&conn->lock) { struct l2cap_chan *c; =20 @@ -114,6 +116,7 @@ static struct l2cap_chan *__l2cap_get_chan_by_scid(stru= ct l2cap_conn *conn, */ static struct l2cap_chan *l2cap_get_chan_by_scid(struct l2cap_conn *conn, u16 cid) + __must_hold(&conn->lock) { struct l2cap_chan *c; =20 @@ -129,6 +132,7 @@ static struct l2cap_chan *l2cap_get_chan_by_scid(struct= l2cap_conn *conn, */ static struct l2cap_chan *l2cap_get_chan_by_dcid(struct l2cap_conn *conn, u16 cid) + __must_hold(&conn->lock) { struct l2cap_chan *c; =20 @@ -141,6 +145,7 @@ static struct l2cap_chan *l2cap_get_chan_by_dcid(struct= l2cap_conn *conn, =20 static struct l2cap_chan *__l2cap_get_chan_by_ident(struct l2cap_conn *con= n, u8 ident) + __must_hold(&conn->lock) { struct l2cap_chan *c; =20 @@ -153,6 +158,7 @@ static struct l2cap_chan *__l2cap_get_chan_by_ident(str= uct l2cap_conn *conn, =20 static struct l2cap_chan *__l2cap_global_chan_by_addr(__le16 psm, bdaddr_t= *src, u8 src_type) + __must_hold_shared(&chan_list_lock) { struct l2cap_chan *c; =20 @@ -230,6 +236,7 @@ int l2cap_add_scid(struct l2cap_chan *chan, __u16 scid) } =20 static u16 l2cap_alloc_cid(struct l2cap_conn *conn) + __must_hold(&conn->lock) { u16 cid, dyn_end; =20 @@ -728,6 +735,7 @@ EXPORT_SYMBOL_GPL(l2cap_chan_del); =20 static void __l2cap_chan_list_id(struct l2cap_conn *conn, u16 id, l2cap_chan_func_t func, void *data) + __must_hold(&conn->lock) { struct l2cap_chan *chan, *l; =20 @@ -739,6 +747,7 @@ static void __l2cap_chan_list_id(struct l2cap_conn *con= n, u16 id, =20 static void __l2cap_chan_list(struct l2cap_conn *conn, l2cap_chan_func_t f= unc, void *data) + __must_hold(&conn->lock) { struct l2cap_chan *chan; =20 @@ -806,6 +815,9 @@ static void l2cap_chan_ecred_connect_reject(struct l2ca= p_chan *chan) { l2cap_state_change(chan, BT_DISCONN); =20 + lockdep_assert_held(&chan->lock); + lockdep_assert_held(&chan->conn->lock); + __l2cap_ecred_conn_rsp_defer(chan); } =20 @@ -1416,6 +1428,7 @@ static void l2cap_ecred_defer_connect(struct l2cap_ch= an *chan, void *data) } =20 static void l2cap_ecred_connect(struct l2cap_chan *chan) + __must_hold(&chan->conn->lock) { struct l2cap_conn *conn =3D chan->conn; struct l2cap_ecred_conn_data data; @@ -1449,6 +1462,7 @@ static void l2cap_ecred_connect(struct l2cap_chan *ch= an) } =20 static void l2cap_le_start(struct l2cap_chan *chan) + __must_hold(&chan->conn->lock) { struct l2cap_conn *conn =3D chan->conn; =20 @@ -1469,6 +1483,7 @@ static void l2cap_le_start(struct l2cap_chan *chan) } =20 static void l2cap_start_connection(struct l2cap_chan *chan) + __must_hold(&chan->conn->lock) { if (chan->conn->hcon->type =3D=3D LE_LINK) { l2cap_le_start(chan); @@ -1518,6 +1533,7 @@ static bool l2cap_check_enc_key_size(struct hci_conn = *hcon, } =20 static void l2cap_do_start(struct l2cap_chan *chan) + __must_hold(&chan->conn->lock) { struct l2cap_conn *conn =3D chan->conn; =20 @@ -1584,6 +1600,7 @@ static void l2cap_send_disconn_req(struct l2cap_chan = *chan, int err) =20 /* ---- L2CAP connections ---- */ static void l2cap_conn_start(struct l2cap_conn *conn) + __must_hold(&conn->lock) { struct l2cap_chan *chan, *tmp; =20 @@ -1592,6 +1609,8 @@ static void l2cap_conn_start(struct l2cap_conn *conn) list_for_each_entry_safe(chan, tmp, &conn->chan_l, list) { l2cap_chan_lock(chan); =20 + lockdep_assert_held(&chan->conn->lock); + if (chan->chan_type !=3D L2CAP_CHAN_CONN_ORIENTED) { l2cap_chan_ready(chan); l2cap_chan_unlock(chan); @@ -1708,6 +1727,8 @@ static void l2cap_conn_ready(struct l2cap_conn *conn) =20 l2cap_chan_lock(chan); =20 + lockdep_assert_held(&chan->conn->lock); + if (hcon->type =3D=3D LE_LINK) { l2cap_le_start(chan); } else if (chan->chan_type !=3D L2CAP_CHAN_CONN_ORIENTED) { @@ -1730,6 +1751,7 @@ static void l2cap_conn_ready(struct l2cap_conn *conn) =20 /* Notify sockets that we cannot guaranty reliability anymore */ static void l2cap_conn_unreliable(struct l2cap_conn *conn, int err) + __must_hold(&conn->lock) { struct l2cap_chan *chan; =20 @@ -3027,6 +3049,7 @@ static void l2cap_pass_to_tx_fbit(struct l2cap_chan *= chan, =20 /* Copy frame to all raw sockets on that connection */ static void l2cap_raw_recv(struct l2cap_conn *conn, struct sk_buff *skb) + __must_hold(&conn->lock) { struct sk_buff *nskb; struct l2cap_chan *chan; @@ -4073,6 +4096,7 @@ static void l2cap_conf_rfc_get(struct l2cap_chan *cha= n, void *rsp, int len) static inline int l2cap_command_rej(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u16 cmd_len, u8 *data) + __must_hold(&conn->lock) { struct l2cap_cmd_rej_unk *rej =3D (struct l2cap_cmd_rej_unk *) data; =20 @@ -4105,6 +4129,7 @@ static inline int l2cap_command_rej(struct l2cap_conn= *conn, */ static struct l2cap_chan *l2cap_new_connection(struct l2cap_conn *conn, struct l2cap_chan *pchan) + __must_hold(&conn->lock) { struct l2cap_chan *chan; =20 @@ -4134,6 +4159,7 @@ static struct l2cap_chan *l2cap_new_connection(struct= l2cap_conn *conn, =20 static void l2cap_connect(struct l2cap_conn *conn, struct l2cap_cmd_hdr *c= md, u8 *data, u8 rsp_code) + __must_hold(&conn->lock) __context_unsafe(/* conditional locking */) { struct l2cap_conn_req *req =3D (struct l2cap_conn_req *) data; @@ -4264,6 +4290,7 @@ static void l2cap_connect(struct l2cap_conn *conn, st= ruct l2cap_cmd_hdr *cmd, =20 static int l2cap_connect_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u16 cmd_len, u8 *data) + __must_hold(&conn->lock) { if (cmd_len < sizeof(struct l2cap_conn_req)) return -EPROTO; @@ -4275,6 +4302,7 @@ static int l2cap_connect_req(struct l2cap_conn *conn, static int l2cap_connect_create_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u16 cmd_len, u8 *data) + __must_hold(&conn->lock) { struct l2cap_conn_rsp *rsp =3D (struct l2cap_conn_rsp *) data; u16 scid, dcid, result, status; @@ -4392,6 +4420,7 @@ static void cmd_reject_invalid_cid(struct l2cap_conn = *conn, u8 ident, static inline int l2cap_config_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u16 cmd_len, u8 *data) + __must_hold(&conn->lock) { struct l2cap_conf_req *req =3D (struct l2cap_conf_req *) data; u16 dcid, flags; @@ -4505,6 +4534,7 @@ static inline int l2cap_config_req(struct l2cap_conn = *conn, static inline int l2cap_config_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u16 cmd_len, u8 *data) + __must_hold(&conn->lock) { struct l2cap_conf_rsp *rsp =3D (struct l2cap_conf_rsp *)data; u16 scid, flags, result; @@ -4614,6 +4644,7 @@ static inline int l2cap_config_rsp(struct l2cap_conn = *conn, static inline int l2cap_disconnect_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u16 cmd_len, u8 *data) + __must_hold(&conn->lock) { struct l2cap_disconn_req *req =3D (struct l2cap_disconn_req *) data; struct l2cap_disconn_rsp rsp; @@ -4655,6 +4686,7 @@ static inline int l2cap_disconnect_req(struct l2cap_c= onn *conn, static inline int l2cap_disconnect_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u16 cmd_len, u8 *data) + __must_hold(&conn->lock) { struct l2cap_disconn_rsp *rsp =3D (struct l2cap_disconn_rsp *) data; u16 dcid, scid; @@ -4742,6 +4774,7 @@ static inline int l2cap_information_req(struct l2cap_= conn *conn, static inline int l2cap_information_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u16 cmd_len, u8 *data) + __must_hold(&conn->lock) { struct l2cap_info_rsp *rsp =3D (struct l2cap_info_rsp *) data; u16 type, result; @@ -4849,6 +4882,7 @@ static inline int l2cap_conn_param_update_req(struct = l2cap_conn *conn, static int l2cap_le_connect_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u16 cmd_len, u8 *data) + __must_hold(&conn->lock) { struct l2cap_le_conn_rsp *rsp =3D (struct l2cap_le_conn_rsp *) data; struct hci_conn *hcon =3D conn->hcon; @@ -4955,6 +4989,7 @@ static void l2cap_put_ident(struct l2cap_conn *conn, = u8 code, u8 id) static inline int l2cap_bredr_sig_cmd(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u16 cmd_len, u8 *data) + __must_hold(&conn->lock) { int err =3D 0; =20 @@ -5016,6 +5051,7 @@ static inline int l2cap_bredr_sig_cmd(struct l2cap_co= nn *conn, static int l2cap_le_connect_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u16 cmd_len, u8 *data) + __must_hold(&conn->lock) { struct l2cap_le_conn_req *req =3D (struct l2cap_le_conn_req *) data; struct l2cap_le_conn_rsp rsp; @@ -5163,6 +5199,7 @@ static int l2cap_le_connect_req(struct l2cap_conn *co= nn, static inline int l2cap_le_credits(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u16 cmd_len, u8 *data) + __must_hold(&conn->lock) { struct l2cap_le_credits *pkt; struct l2cap_chan *chan; @@ -5212,6 +5249,7 @@ static inline int l2cap_le_credits(struct l2cap_conn = *conn, static inline int l2cap_ecred_conn_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u16 cmd_len, u8 *data) + __must_hold(&conn->lock) { struct l2cap_ecred_conn_req *req =3D (void *) data; DEFINE_RAW_FLEX(struct l2cap_ecred_conn_rsp, pdu, dcid, L2CAP_ECRED_MAX_C= ID); @@ -5384,6 +5422,7 @@ static inline int l2cap_ecred_conn_req(struct l2cap_c= onn *conn, static inline int l2cap_ecred_conn_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u16 cmd_len, u8 *data) + __must_hold(&conn->lock) { struct l2cap_ecred_conn_rsp *rsp =3D (void *) data; struct hci_conn *hcon =3D conn->hcon; @@ -5511,6 +5550,7 @@ static inline int l2cap_ecred_conn_rsp(struct l2cap_c= onn *conn, static inline int l2cap_ecred_reconf_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u16 cmd_len, u8 *data) + __must_hold(&conn->lock) { struct l2cap_ecred_reconf_req *req =3D (void *) data; struct l2cap_ecred_reconf_rsp rsp; @@ -5609,6 +5649,7 @@ static inline int l2cap_ecred_reconf_req(struct l2cap= _conn *conn, static inline int l2cap_ecred_reconf_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u16 cmd_len, u8 *data) + __must_hold(&conn->lock) { struct l2cap_chan *chan, *tmp; struct l2cap_ecred_reconf_rsp *rsp =3D (void *)data; @@ -5649,6 +5690,7 @@ static inline int l2cap_ecred_reconf_rsp(struct l2cap= _conn *conn, static inline int l2cap_le_command_rej(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u16 cmd_len, u8 *data) + __must_hold(&conn->lock) { struct l2cap_cmd_rej_unk *rej =3D (struct l2cap_cmd_rej_unk *) data; struct l2cap_chan *chan; @@ -5676,6 +5718,7 @@ static inline int l2cap_le_command_rej(struct l2cap_c= onn *conn, static inline int l2cap_le_sig_cmd(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u16 cmd_len, u8 *data) + __must_hold(&conn->lock) { int err =3D 0; =20 @@ -5740,6 +5783,7 @@ static inline int l2cap_le_sig_cmd(struct l2cap_conn = *conn, =20 static inline void l2cap_le_sig_channel(struct l2cap_conn *conn, struct sk_buff *skb) + __must_hold(&conn->lock) { struct hci_conn *hcon =3D conn->hcon; struct l2cap_cmd_hdr *cmd; @@ -5798,6 +5842,7 @@ static inline void l2cap_sig_send_mtu_rej(struct l2ca= p_conn *conn, u8 ident) =20 static inline void l2cap_sig_channel(struct l2cap_conn *conn, struct sk_buff *skb) + __must_hold(&conn->lock) { struct hci_conn *hcon =3D conn->hcon; struct l2cap_cmd_hdr *cmd; @@ -7035,6 +7080,7 @@ static int l2cap_ecred_data_rcv(struct l2cap_chan *ch= an, struct sk_buff *skb) =20 static void l2cap_data_channel(struct l2cap_conn *conn, u16 cid, struct sk_buff *skb) + __must_hold(&conn->lock) { struct l2cap_chan *chan; =20 @@ -7143,6 +7189,7 @@ static void l2cap_conless_channel(struct l2cap_conn *= conn, __le16 psm, } =20 static void l2cap_recv_frame(struct l2cap_conn *conn, struct sk_buff *skb) + __must_hold(&conn->lock) { struct l2cap_hdr *lh =3D (void *) skb->data; struct hci_conn *hcon =3D conn->hcon; @@ -7252,9 +7299,9 @@ static struct l2cap_conn *l2cap_conn_add(struct hci_c= onn *hcon) hci_dev_test_flag(hcon->hdev, HCI_FORCE_BREDR_SMP))) conn->local_fixed_chan |=3D L2CAP_FC_SMP_BREDR; =20 - mutex_init(&conn->lock); - - INIT_LIST_HEAD(&conn->chan_l); + scoped_guard(mutex_init, &conn->lock) { + INIT_LIST_HEAD(&conn->chan_l); + } INIT_LIST_HEAD(&conn->users); =20 INIT_DELAYED_WORK(&conn->info_timer, l2cap_info_timeout); @@ -7466,6 +7513,8 @@ int l2cap_chan_connect(struct l2cap_chan *chan, __le1= 6 psm, u16 cid, =20 __l2cap_chan_add(conn, chan); =20 + lockdep_assert_held(&chan->conn->lock); + /* l2cap_chan_add takes its own ref so we can drop this one */ hci_conn_drop(hcon); =20 @@ -7688,6 +7737,8 @@ static void l2cap_disconn_cfm(struct hci_conn *hcon, = u8 reason) } =20 static inline void l2cap_check_encryption(struct l2cap_chan *chan, u8 encr= ypt) + __must_hold(&chan->lock) + __must_hold(&chan->conn->lock) { if (chan->chan_type !=3D L2CAP_CHAN_CONN_ORIENTED) return; @@ -7720,6 +7771,8 @@ static void l2cap_security_cfm(struct hci_conn *hcon,= u8 status, u8 encrypt) list_for_each_entry(chan, &conn->chan_l, list) { l2cap_chan_lock(chan); =20 + lockdep_assert_held(&chan->conn->lock); + BT_DBG("chan %p scid 0x%4.4x state %s", chan, chan->scid, state_to_string(chan->state)); =20 --=20 2.55.0 From nobody Sat Sep 26 21:59:26 2026 Received: from meesny.iki.fi (meesny.iki.fi [195.140.195.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id C6BD836F8E5; Sat, 29 Aug 2026 14:22:46 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=pass smtp.client-ip=195.140.195.201 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788013368; cv=pass; b=QRnRH8VJyuMLPs1BhNVxJAUkEJxeT/6MLMFz9D0nQlwZXzNNFcDZCFif3PQJ6gi8br5GW2LG+qF15BsK8DwZX4FqvPwNxZSJBTYlmnsehdfSlmxigWk639LZWSJp6+wrn6AF+BAYtd04EfkztfTPMoWYL4jFsIKHMoN95atrUFg= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788013368; c=relaxed/simple; bh=6f2/T2YdPWk825/l6BZ6NR8rusH1doGXtU/ILb4FGy4=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=cTvPWzL3JMfmvFayAXn4FKAZBkHQxkCz22C+SgbG60sp02x6VvMmVdJN7gtnPQYfM5KrPnGiEewMNZRE5St16gtOm64sJuUVo4wGtPoRK4C+Z0inq02J+qCPCD3AIoRiLJtg71hfL/eo8+MPExwZqC5MXUaEnYXrctL3ez+c1II= ARC-Authentication-Results: i=2; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=iki.fi; spf=pass smtp.mailfrom=iki.fi; dkim=pass (1024-bit key) header.d=iki.fi header.i=@iki.fi header.b=Z3l1zB+F; arc=pass smtp.client-ip=195.140.195.201 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=iki.fi Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=iki.fi Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=iki.fi header.i=@iki.fi header.b="Z3l1zB+F" Received: from monolith.lan (unknown [IPv6:2a03:1b20:1:e011::d701]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange x25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) (Authenticated sender: pav) by meesny.iki.fi (Postfix) with ESMTPSA id 4hXHXJ0LmXzyWl; Sat, 29 Aug 2026 17:22:39 +0300 (EEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=iki.fi; s=meesny; t=1788013361; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=/v1dQ0w80RABszAytoWbBxYusHWM3N5fTPq2MCPDXvg=; b=Z3l1zB+FcdEC0prICJY3qKs5iheo5A6wGzQYGrazN/3AciG62AwUsE7lLTrWmK4Db1elbg UTTgbWBVSrlROz9ELl/NNOb5GhdZmFmp8HssOdozNf4tW3KfE9RzVjmeTbIOJqimbAX2kx pEkv6GuONhjxWZ6HShz0uPn+YmggqlY= ARC-Seal: i=1; a=rsa-sha256; d=iki.fi; s=meesny; cv=none; t=1788013361; b=wAzLmHEezlRFnJIZiEKhvbkl28H9knCxlTUYFaXxHhPCwADUXkToDcvAjcGX0rjbhRTjUR 41iBcmt9yGF6Rit2eUi3mpe/xDT+wg64QNKutf/w++Y8WYrzcAkKMfnGAsskQE14Jm6rOb fIcfh/tY6C1b4TyDRZKRhMhTDgfgE2k= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=iki.fi; s=meesny; t=1788013361; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=/v1dQ0w80RABszAytoWbBxYusHWM3N5fTPq2MCPDXvg=; b=ozTEao5ZALs/IhLhUUt61sM3HC+rIgWzUpl62q08yt2Gzp9CeTrDzeRXLggsya/16KnDmE 2dj8q8NT2t40E2ZzOAWjFtmYP2nGtJ/8JM5KaSx4Bln4CGUVX4BuVCACTnNmNG4icFEN6r HwT9LijVotUQ0tE8W98EcXRKC8cuAT8= ARC-Authentication-Results: i=1; ORIGINATING; auth=pass smtp.auth=pav smtp.mailfrom=pav@iki.fi From: Pauli Virtanen To: linux-bluetooth@vger.kernel.org Cc: Pauli Virtanen , marcel@holtmann.org, luiz.dentz@gmail.com, oss@fourdim.xyz, error27@gmail.com, elver@google.com, linux-kernel@vger.kernel.org Subject: [PATCH 10/16] Bluetooth: L2CAP: take lock for l2cap_chan_del in l2cap_ecred_rsp_defer Date: Sat, 29 Aug 2026 17:20:05 +0300 Message-ID: X-Mailer: git-send-email 2.55.0 In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" 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 --- include/net/bluetooth/l2cap.h | 4 +++ net/bluetooth/l2cap_core.c | 60 +++++++++++++++++++++++++++++++++++ 2 files changed, 64 insertions(+) diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index a991fc07515c..efd59b6f8afd 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 ch= annels + * have the same l2cap_chan::conn and l2cap_chan::conn.lock is taken befor= e the + * nested locks. l2cap_chan_try_sibling_lock() must be used. */ enum { L2CAP_NESTING_SMP, diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index ce51b0b0b37d..750b13f76203 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -848,6 +848,8 @@ static void __l2cap_chan_close(struct l2cap_chan *chan,= int reason) =20 BT_DBG("chan %p state %s", chan, state_to_string(chan->state)); =20 + lockdep_assert_held(&chan->lock); + switch (chan->state) { case BT_LISTEN: chan->ops->teardown(chan, 0); @@ -3943,6 +3945,7 @@ static void l2cap_ecred_list_defer(struct l2cap_chan = *chan, void *data) } =20 struct l2cap_ecred_rsp_data { + struct l2cap_chan *locked_chan; struct { struct l2cap_ecred_conn_rsp_hdr rsp; __le16 scid[L2CAP_ECRED_MAX_CID]; @@ -3950,11 +3953,42 @@ struct l2cap_ecred_rsp_data { int count; }; =20 +/* Lock @chan if it is not @locked_chan, and has same or lower nesting lev= el. + * + * They must have the same chan->conn, and conn->lock must be held. + * + * Caller must ensure @chan has lock nesting level <=3D that of @locked_ch= an, as + * nested locking of l2cap_chan of different levels is allowed also without + * holding conn->lock. + * + * See l2cap.h for the global l2cap_chan locking rules. + */ +static bool l2cap_chan_try_sibling_lock(struct l2cap_chan *chan, + struct l2cap_chan *locked_chan) + __must_hold(&locked_chan->lock) + __must_hold(&locked_chan->conn->lock) + __cond_acquires(true, &chan->lock) +{ + if (chan =3D=3D locked_chan) + return false; + + if (WARN_ON_ONCE(locked_chan->conn !=3D chan->conn)) + return false; + + if (WARN_ON_ONCE(atomic_read(&locked_chan->nesting) + < atomic_read(&chan->nesting))) + return false; + + mutex_lock_nest_lock(&chan->lock, &locked_chan->conn->lock); + return true; +} + static void l2cap_ecred_rsp_defer(struct l2cap_chan *chan, void *data) { struct l2cap_ecred_rsp_data *rsp =3D data; struct l2cap_ecred_conn_rsp *rsp_flex =3D container_of(&rsp->pdu.rsp, struct l2cap_ecred_conn_rsp, hdr); + bool locked; =20 /* Check if channel for outgoing connection or if it wasn't deferred * since in those cases it must be skipped. @@ -3963,6 +3997,22 @@ static void l2cap_ecred_rsp_defer(struct l2cap_chan = *chan, void *data) !test_and_clear_bit(FLAG_DEFER_SETUP, &chan->flags)) return; =20 + lockdep_assert_held(&rsp->locked_chan->lock); + lockdep_assert_held(&rsp->locked_chan->conn->lock); + + l2cap_chan_hold(chan); + + locked =3D l2cap_chan_try_sibling_lock(chan, rsp->locked_chan); + + /* Cannot occur: PARENT channels do not appear in chan_l, and SMP + * channels never have FLAG_DEFER_SETUP. + */ + if (context_unsafe(!locked && chan !=3D rsp->locked_chan)) + goto done; + + lockdep_assert_held(&chan->lock); + lockdep_assert_held(&chan->conn->lock); + /* Reset ident so only one response is sent */ chan->ident =3D 0; =20 @@ -3971,6 +4021,12 @@ static void l2cap_ecred_rsp_defer(struct l2cap_chan = *chan, void *data) rsp_flex->dcid[rsp->count++] =3D cpu_to_le16(chan->scid); else l2cap_chan_del(chan, ECONNRESET); + +done: + if (locked) + l2cap_chan_unlock(chan); + + l2cap_chan_put(chan); } =20 void __l2cap_ecred_conn_rsp_defer(struct l2cap_chan *chan) @@ -3982,11 +4038,15 @@ void __l2cap_ecred_conn_rsp_defer(struct l2cap_chan= *chan) =20 if (!id) return; + if (!test_bit(FLAG_DEFER_SETUP, &chan->flags)) + return; =20 BT_DBG("chan %p id %d", chan, id); =20 memset(&data, 0, sizeof(data)); =20 + data.locked_chan =3D chan; + data.pdu.rsp.mtu =3D cpu_to_le16(chan->imtu); data.pdu.rsp.mps =3D cpu_to_le16(chan->mps); data.pdu.rsp.credits =3D cpu_to_le16(chan->rx_credits); --=20 2.55.0 From nobody Sat Sep 26 21:59:26 2026 Received: from meesny.iki.fi (meesny.iki.fi [195.140.195.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 698ED3AB27B; Sat, 29 Aug 2026 14:22:52 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=pass smtp.client-ip=195.140.195.201 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788013375; cv=pass; b=QweBDYh0rqDH1IhUBEz1vHJZMnIJ0ztJZlDdu4N44jfMGmxhFX08iETAQUW1AsYqIhmPufT28KF9CzP8NsbFkdBJsWolQH8aC/iZdtv8aH30PZIl1aLEIxKheVhHjdb9go3nq39OO+IH5MmFHWr2qJPsTHBMugbkw6mg2ihyyfU= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788013375; c=relaxed/simple; bh=hmDjBOCGtFpW7PfYZu+2E/XC/CAovDyrq81e/lF6Cws=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=PEPN408fC+L88mQBFwt51NK9BbRUrqrg9RboLCa/e5ZJ4SiOLTWbIyjb8IoKWgzwsQXW9QeXg8o3WNz75phzv3V4+7ZfXM1QT3Nuzne11FLimfqUxUL0pAoMrhn7qjF6PwRFxMKnYQ7H+CyDfhABRZMG5MGUn8AUzLjqZhRe6nE= ARC-Authentication-Results: i=2; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=iki.fi; spf=pass smtp.mailfrom=iki.fi; dkim=pass (1024-bit key) header.d=iki.fi header.i=@iki.fi header.b=LEGzGQ7r; arc=pass smtp.client-ip=195.140.195.201 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=iki.fi Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=iki.fi Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=iki.fi header.i=@iki.fi header.b="LEGzGQ7r" Received: from monolith.lan (unknown [IPv6:2a03:1b20:1:e011::d701]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange x25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) (Authenticated sender: pav) by meesny.iki.fi (Postfix) with ESMTPSA id 4hXHXP3JB5zyvj; Sat, 29 Aug 2026 17:22:45 +0300 (EEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=iki.fi; s=meesny; t=1788013366; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=8k4JThe8kY96BoHqze5PbKpWjvfft1Dino9tH73u91o=; b=LEGzGQ7rVWEClF2UjRNV0LbA5xyexfQsTAqGWvIWb06PX3DbwDpbSh1t75BrznMAYl4NrC zoPEhxbZcqi1XvLXnK7u6wr3P6W0dVhE4fC2zQDqTRqWFZ2YjzMOQz7biWK2HAt49VzSbI LyhzugV+eFyv1qKBXojD/Qe39+uHGNI= ARC-Seal: i=1; a=rsa-sha256; d=iki.fi; s=meesny; cv=none; t=1788013366; b=gxYpDG3HsKc3qEOh6anNfpiXq71sLmTLJWwc69pP4dPheUw25DRTcgqvPF6ClQOrdGzVpx S21TsPG59Ulb2Xkpa+IosAdLI93m0wPIzeKUcTzF9yYM2cXj6G9zBx4fH5V8xO8NgPKWWO l+u0xr5a9hZJvvsNfR1BkAxgQMIz0IA= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=iki.fi; s=meesny; t=1788013366; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=8k4JThe8kY96BoHqze5PbKpWjvfft1Dino9tH73u91o=; b=Ubr6JO1+qHPtiu/t7Pn6FsGk+ZO0z2Q1fLldBTOx9n3otdVXPIE5zhkjt6+AQJYEjKPsb1 rVzI/BYvYw1O4SHGVe8TBPvjU83/5mMW7lM7361EDUgwOYyhUQy5alAWYM5GN/+1pJEZGP QknxfZFD2r3Xt8fhnLHG8YC2Bq1w9OQ= ARC-Authentication-Results: i=1; ORIGINATING; auth=pass smtp.auth=pav smtp.mailfrom=pav@iki.fi From: Pauli Virtanen To: linux-bluetooth@vger.kernel.org Cc: Pauli Virtanen , marcel@holtmann.org, luiz.dentz@gmail.com, oss@fourdim.xyz, error27@gmail.com, elver@google.com, linux-kernel@vger.kernel.org Subject: [PATCH 11/16] Bluetooth: L2CAP: hold chan in l2cap_ecred_conn_rsp() Date: Sat, 29 Aug 2026 17:20:06 +0300 Message-ID: <6ad9b23ab2f5e3b0abcbadad91f9a667f426a596.1788013041.git.pav@iki.fi> X-Mailer: git-send-email 2.55.0 In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" l2cap_chan_del() calls l2cap_chan_put() to drop the conn->chan_l reference. If this was the last reference, UAF follows. l2cap_ecred_conn_rsp() iterates chan_l list and calls l2cap_chan_del() on some members, without holding chan reference. Fix by holding refcount while using chan after l2cap_chan_del(). Since orig is looked up by dcid provided by remote, it's also possible orig =3D=3D chan, so reference needs to be held also after orig use. Fixes: 41c2713b204e ("Bluetooth: L2CAP: Fix possible crash on l2cap_ecred_c= onn_rsp") Assisted-by: deepseek-v4-flash Signed-off-by: Pauli Virtanen --- net/bluetooth/l2cap_core.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 750b13f76203..cc86399ef0f5 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -5513,12 +5513,14 @@ static inline int l2cap_ecred_conn_rsp(struct l2cap= _conn *conn, chan->state =3D=3D BT_CONNECTED) continue; =20 + l2cap_chan_hold(chan); l2cap_chan_lock(chan); =20 /* Check that there is a dcid for each pending channel */ if (cmd_len < sizeof(dcid)) { l2cap_chan_del(chan, ECONNREFUSED); l2cap_chan_unlock(chan); + l2cap_chan_put(chan); continue; } =20 @@ -5557,6 +5559,8 @@ static inline int l2cap_ecred_conn_rsp(struct l2cap_c= onn *conn, __set_chan_timer(orig, 0); l2cap_chan_unlock(orig); } + + l2cap_chan_put(chan); continue; } =20 @@ -5602,6 +5606,7 @@ static inline int l2cap_ecred_conn_rsp(struct l2cap_c= onn *conn, } =20 l2cap_chan_unlock(chan); + l2cap_chan_put(chan); } =20 return err; --=20 2.55.0 From nobody Sat Sep 26 21:59:26 2026 Received: from meesny.iki.fi (meesny.iki.fi [195.140.195.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 12C3F3A9852; Sat, 29 Aug 2026 14:22:58 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=pass smtp.client-ip=195.140.195.201 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788013380; cv=pass; b=KfWy5BbuOjbqsTAIQi5j3ZuEpaYns/KfAZLRPSbwCmO2FI2xPsuXi/WQPElv8Tk+Fx/BCTfgiZOV5ViSSr/QBjyM0BScv8ar/zYs5/QxAlOuow059/wBEOpyuO/KVTsXNrT/js24X96v9gV1XYVSRbZsxoEG7Ds1prELR4u5aCA= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788013380; c=relaxed/simple; bh=pTHzh4eQ8mCTR6dt5vGwye1R30GzARfdXxaG6bd7vGc=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=pJBdejeghptN1QEa3KXumnMm27stDW5ynyWVIiAcX4LEos6bcxnzC5wZ85U7dv8REcuTjQFkTigCXlvGstVoMybTWPQJaRQRrnokriJdHU5xIZ6bnG0gNRWEUcOayojc7x3gZeKSBUfAygpzWTN9FOkrQNCQoJ/XUinxm9TqZXY= ARC-Authentication-Results: i=2; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=iki.fi; spf=pass smtp.mailfrom=iki.fi; dkim=pass (1024-bit key) header.d=iki.fi header.i=@iki.fi header.b=dASPUpoQ; arc=pass smtp.client-ip=195.140.195.201 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=iki.fi Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=iki.fi Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=iki.fi header.i=@iki.fi header.b="dASPUpoQ" Received: from monolith.lan (unknown [IPv6:2a03:1b20:1:e011::d701]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange x25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) (Authenticated sender: pav) by meesny.iki.fi (Postfix) with ESMTPSA id 4hXHXV6ZrHzyhS; Sat, 29 Aug 2026 17:22:50 +0300 (EEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=iki.fi; s=meesny; t=1788013371; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=smDW8/X0qUSSTi8iK3Yh7F62eVeKdDWtA4TFlSKr6rQ=; b=dASPUpoQS+NfHRDgH2LKcNPdBkueewyvSx0KK0sj+hBrtQVycJlrInZdJqvZHgoFFqaQYF NVl1GsaQBur3QJxgNcMLi9vZFvNq9iN6HRrkK8c+74u8RuRJTH1E6uuMXhwDiVO0bi3bnH 0uXnlvR8ktwu7s6qQyfjkRoVebcZhzA= ARC-Seal: i=1; a=rsa-sha256; d=iki.fi; s=meesny; cv=none; t=1788013371; b=jqcflGs7zkFKIoeA28+SzwJlGQ3FVPZFgZAqedPc7px666kY9viNjS19YIoTUkWtk6yRoh axxtdJrFyu3aXAy7EuJrGVaj2UT7qOFGZWqX/jWMZgp2w1bWGzcsLH05XKuaohRhbl5VCr iB9946Le3kwCXzdfBN9I2K+7MPuin9o= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=iki.fi; s=meesny; t=1788013371; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=smDW8/X0qUSSTi8iK3Yh7F62eVeKdDWtA4TFlSKr6rQ=; b=H7/S5VfBQpFQyS1tEsburkDlDJtOmgMut2BIfoBMDLhJE+jLUwzUK9EVJmjgawn7M/7TmO XigozMLshbArbUSTudCWUvKRtAaY+oXY+PjQ57r/hV3hWsT9XU1BTV0OXnMGh3pCSEzWWe MnQIxgAUU2KyzzExdIHiZ9Lg3xaQlmE= ARC-Authentication-Results: i=1; ORIGINATING; auth=pass smtp.auth=pav smtp.mailfrom=pav@iki.fi From: Pauli Virtanen To: linux-bluetooth@vger.kernel.org Cc: Pauli Virtanen , marcel@holtmann.org, luiz.dentz@gmail.com, oss@fourdim.xyz, error27@gmail.com, elver@google.com, linux-kernel@vger.kernel.org Subject: [PATCH 12/16] Bluetooth: L2CAP: annotate locking for l2cap_chan_del() Date: Sat, 29 Aug 2026 17:20:07 +0300 Message-ID: <74b398ab221cfefe33a4ddf850da6ad5570bbe76.1788013041.git.pav@iki.fi> X-Mailer: git-send-email 2.55.0 In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Add context analysis annotations for chan->lock and chan->conn->lock involving l2cap_chan_del() usage. Add necessary annotations and related lockdep_assert_held to callers. Move struct l2cap_ops definition after struct l2cap_conn, so that the callbacks can be annotated. In l2cap_chan_close_unlocked() we consider chan->conn->lock as locked even if chan->conn =3D=3D NULL, to avoid needing to define separate __l2cap_chan_close/del for this NULL case. Signed-off-by: Pauli Virtanen --- include/net/bluetooth/l2cap.h | 56 +++++++++++++++++++---------------- net/bluetooth/6lowpan.c | 2 ++ net/bluetooth/l2cap_core.c | 49 +++++++++++++++++++++++++----- 3 files changed, 74 insertions(+), 33 deletions(-) diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index efd59b6f8afd..f612c9f884d1 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h @@ -614,31 +614,6 @@ struct l2cap_chan { struct mutex lock; }; =20 -struct l2cap_ops { - char *name; - - int (*new_connection)(struct l2cap_chan *chan, - struct l2cap_chan *new_chan); - int (*recv) (struct l2cap_chan * chan, - struct sk_buff *skb); - void (*teardown) (struct l2cap_chan *chan, int err); - void (*close) (struct l2cap_chan *chan); - void (*state_change) (struct l2cap_chan *chan, - int state, int err); - void (*ready) (struct l2cap_chan *chan); - void (*defer) (struct l2cap_chan *chan); - void (*resume) (struct l2cap_chan *chan); - void (*suspend) (struct l2cap_chan *chan); - void (*set_shutdown) (struct l2cap_chan *chan); - long (*get_sndtimeo) (struct l2cap_chan *chan); - struct pid *(*get_peer_pid) (struct l2cap_chan *chan); - struct sk_buff *(*alloc_skb) (struct l2cap_chan *chan, - unsigned long hdr_len, - unsigned long len, int nb); - int (*filter) (struct l2cap_chan * chan, - struct sk_buff *skb); -}; - struct l2cap_conn { struct hci_conn *hcon; struct hci_chan *hchan; @@ -674,6 +649,34 @@ struct l2cap_conn { struct list_head users; }; =20 +struct l2cap_ops { + char *name; + + int (*new_connection)(struct l2cap_chan *chan, + struct l2cap_chan *new_chan); + int (*recv) (struct l2cap_chan * chan, + struct sk_buff *skb); + void (*teardown) (struct l2cap_chan *chan, int err) + __must_hold(&chan->lock); + void (*close) (struct l2cap_chan *chan); + void (*state_change) (struct l2cap_chan *chan, + int state, int err); + void (*ready) (struct l2cap_chan *chan) + __must_hold(&chan->lock) + __must_hold(&chan->conn->lock); + void (*defer) (struct l2cap_chan *chan); + void (*resume) (struct l2cap_chan *chan); + void (*suspend) (struct l2cap_chan *chan); + void (*set_shutdown) (struct l2cap_chan *chan); + long (*get_sndtimeo) (struct l2cap_chan *chan); + struct pid *(*get_peer_pid) (struct l2cap_chan *chan); + struct sk_buff *(*alloc_skb) (struct l2cap_chan *chan, + unsigned long hdr_len, + unsigned long len, int nb); + int (*filter) (struct l2cap_chan * chan, + struct sk_buff *skb); +}; + struct l2cap_user { struct list_head list; int (*probe) (struct l2cap_conn *conn, struct l2cap_user *user); @@ -984,7 +987,8 @@ void __l2cap_chan_add(struct l2cap_conn *conn, struct l= 2cap_chan *chan) typedef void (*l2cap_chan_func_t)(struct l2cap_chan *chan, void *data); void l2cap_chan_list(struct l2cap_conn *conn, l2cap_chan_func_t func, void *data); -void l2cap_chan_del(struct l2cap_chan *chan, int err); +void l2cap_chan_del(struct l2cap_chan *chan, int err) + __must_hold(&chan->lock) __must_hold(&chan->conn->lock); void l2cap_send_conn_req(struct l2cap_chan *chan); =20 struct l2cap_conn *l2cap_conn_get(struct l2cap_conn *conn); diff --git a/net/bluetooth/6lowpan.c b/net/bluetooth/6lowpan.c index ddcdd2aff91f..836add41f5d1 100644 --- a/net/bluetooth/6lowpan.c +++ b/net/bluetooth/6lowpan.c @@ -722,6 +722,8 @@ static int setup_netdev(struct l2cap_chan *chan, struct= lowpan_btle_dev **dev) } =20 static inline void chan_ready_cb(struct l2cap_chan *chan) + __must_hold(&chan->lock) + __must_hold(&chan->conn->lock) { struct lowpan_btle_dev *dev; bool new_netdev =3D false; diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index cc86399ef0f5..88a9596e4801 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -59,7 +59,8 @@ static void l2cap_tx(struct l2cap_chan *chan, struct l2ca= p_ctrl *control, static void l2cap_retrans_timeout(struct work_struct *work); static void l2cap_monitor_timeout(struct work_struct *work); static void l2cap_ack_timeout(struct work_struct *work); -static void __l2cap_chan_close(struct l2cap_chan *chan, int reason); +static void __l2cap_chan_close(struct l2cap_chan *chan, int reason) + __must_hold(&chan->lock) __must_hold(&chan->conn->lock); =20 static inline u8 bdaddr_type(u8 link_type, u8 bdaddr_type) { @@ -681,6 +682,8 @@ void l2cap_chan_add(struct l2cap_conn *conn, struct l2c= ap_chan *chan) =20 void l2cap_chan_del(struct l2cap_chan *chan, int err) { + lockdep_assert(!chan->conn || lockdep_is_held(&chan->conn->lock)); + __clear_chan_timer(chan); =20 BT_DBG("chan %p, err %d, state %s", chan, err, @@ -812,12 +815,11 @@ static void l2cap_chan_le_connect_reject(struct l2cap= _chan *chan) } =20 static void l2cap_chan_ecred_connect_reject(struct l2cap_chan *chan) + __must_hold(&chan->lock) + __must_hold(&chan->conn->lock) { l2cap_state_change(chan, BT_DISCONN); =20 - lockdep_assert_held(&chan->lock); - lockdep_assert_held(&chan->conn->lock); - __l2cap_ecred_conn_rsp_defer(chan); } =20 @@ -848,8 +850,6 @@ static void __l2cap_chan_close(struct l2cap_chan *chan,= int reason) =20 BT_DBG("chan %p state %s", chan, state_to_string(chan->state)); =20 - lockdep_assert_held(&chan->lock); - switch (chan->state) { case BT_LISTEN: chan->ops->teardown(chan, 0); @@ -934,7 +934,10 @@ void l2cap_chan_close_unlocked(struct l2cap_chan *chan= , int reason) bool have_conn; =20 have_conn =3D l2cap_chan_lock_conn(chan); - __l2cap_chan_close(chan, reason); + + /* Context analysis: consider chan->conn->lock held also if conn NULL */ + context_unsafe(__l2cap_chan_close(chan, reason)); + l2cap_chan_unlock_conn(chan, have_conn); } EXPORT_SYMBOL(l2cap_chan_close_unlocked); @@ -1336,6 +1339,8 @@ void l2cap_send_conn_req(struct l2cap_chan *chan) } =20 static void l2cap_chan_ready(struct l2cap_chan *chan) + __must_hold(&chan->lock) + __must_hold(&chan->conn->lock) { /* The channel may have already been flagged as connected in * case of receiving data before the L2CAP info req/rsp @@ -1464,6 +1469,7 @@ static void l2cap_ecred_connect(struct l2cap_chan *ch= an) } =20 static void l2cap_le_start(struct l2cap_chan *chan) + __must_hold(&chan->lock) __must_hold(&chan->conn->lock) { struct l2cap_conn *conn =3D chan->conn; @@ -1485,6 +1491,7 @@ static void l2cap_le_start(struct l2cap_chan *chan) } =20 static void l2cap_start_connection(struct l2cap_chan *chan) + __must_hold(&chan->lock) __must_hold(&chan->conn->lock) { if (chan->conn->hcon->type =3D=3D LE_LINK) { @@ -1535,6 +1542,7 @@ static bool l2cap_check_enc_key_size(struct hci_conn = *hcon, } =20 static void l2cap_do_start(struct l2cap_chan *chan) + __must_hold(&chan->lock) __must_hold(&chan->conn->lock) { struct l2cap_conn *conn =3D chan->conn; @@ -1886,6 +1894,8 @@ static void l2cap_conn_del(struct hci_conn *hcon, int= err) l2cap_chan_hold(chan); l2cap_chan_lock(chan); =20 + lockdep_assert_held(&chan->conn->lock); + l2cap_chan_del(chan, err); =20 chan->ops->close(chan); @@ -4204,6 +4214,8 @@ static struct l2cap_chan *l2cap_new_connection(struct= l2cap_conn *conn, =20 __l2cap_chan_add(conn, chan); =20 + lockdep_assert_held(&chan->conn->lock); + if (pchan->ops->new_connection && pchan->ops->new_connection(pchan, chan) < 0) { l2cap_chan_del(chan, 0); @@ -4403,6 +4415,8 @@ static int l2cap_connect_create_rsp(struct l2cap_conn= *conn, =20 l2cap_chan_lock(chan); =20 + lockdep_assert_held(&chan->conn->lock); + switch (result) { case L2CAP_CR_SUCCESS: if (__l2cap_get_chan_by_dcid(conn, dcid)) { @@ -4504,6 +4518,8 @@ static inline int l2cap_config_req(struct l2cap_conn = *conn, =20 l2cap_chan_lock(chan); =20 + lockdep_assert_held(&chan->conn->lock); + if (chan->state !=3D BT_CONFIG && chan->state !=3D BT_CONNECT2 && chan->state !=3D BT_CONNECTED) { cmd_reject_invalid_cid(conn, cmd->ident, chan->scid, @@ -4618,6 +4634,8 @@ static inline int l2cap_config_rsp(struct l2cap_conn = *conn, =20 l2cap_chan_lock(chan); =20 + lockdep_assert_held(&chan->conn->lock); + switch (result) { case L2CAP_CONF_SUCCESS: l2cap_conf_rfc_get(chan, rsp->data, len); @@ -4727,6 +4745,8 @@ static inline int l2cap_disconnect_req(struct l2cap_c= onn *conn, =20 l2cap_chan_lock(chan); =20 + lockdep_assert_held(&chan->conn->lock); + rsp.dcid =3D cpu_to_le16(chan->scid); rsp.scid =3D cpu_to_le16(chan->dcid); l2cap_send_cmd(conn, cmd->ident, L2CAP_DISCONN_RSP, sizeof(rsp), &rsp); @@ -4767,6 +4787,8 @@ static inline int l2cap_disconnect_rsp(struct l2cap_c= onn *conn, =20 l2cap_chan_lock(chan); =20 + lockdep_assert_held(&chan->conn->lock); + if (chan->state !=3D BT_DISCONN) { l2cap_chan_unlock(chan); l2cap_chan_put(chan); @@ -4979,6 +5001,8 @@ static int l2cap_le_connect_rsp(struct l2cap_conn *co= nn, =20 l2cap_chan_lock(chan); =20 + lockdep_assert_held(&chan->conn->lock); + switch (result) { case L2CAP_CR_LE_SUCCESS: if (__l2cap_get_chan_by_dcid(conn, dcid)) { @@ -5197,6 +5221,8 @@ static int l2cap_le_connect_req(struct l2cap_conn *co= nn, =20 l2cap_chan_lock(chan); =20 + lockdep_assert_held(&chan->conn->lock); + bacpy(&chan->src, &conn->hcon->src); bacpy(&chan->dst, &conn->hcon->dst); chan->src_type =3D bdaddr_src_type(conn->hcon); @@ -5427,6 +5453,8 @@ static inline int l2cap_ecred_conn_req(struct l2cap_c= onn *conn, =20 l2cap_chan_lock(chan); =20 + lockdep_assert_held(&chan->conn->lock); + bacpy(&chan->src, &conn->hcon->src); bacpy(&chan->dst, &conn->hcon->dst); chan->src_type =3D bdaddr_src_type(conn->hcon); @@ -5516,6 +5544,8 @@ static inline int l2cap_ecred_conn_rsp(struct l2cap_c= onn *conn, l2cap_chan_hold(chan); l2cap_chan_lock(chan); =20 + lockdep_assert_held(&chan->conn->lock); + /* Check that there is a dcid for each pending channel */ if (cmd_len < sizeof(dcid)) { l2cap_chan_del(chan, ECONNREFUSED); @@ -5743,6 +5773,8 @@ static inline int l2cap_ecred_reconf_rsp(struct l2cap= _conn *conn, continue; l2cap_chan_lock(chan); =20 + lockdep_assert_held(&chan->conn->lock); + l2cap_chan_del(chan, ECONNRESET); =20 l2cap_chan_unlock(chan); @@ -5772,6 +5804,7 @@ static inline int l2cap_le_command_rej(struct l2cap_c= onn *conn, goto done; =20 l2cap_chan_lock(chan); + lockdep_assert_held(&chan->conn->lock); l2cap_chan_del(chan, ECONNREFUSED); l2cap_chan_unlock(chan); l2cap_chan_put(chan); @@ -7159,6 +7192,8 @@ static void l2cap_data_channel(struct l2cap_conn *con= n, u16 cid, =20 l2cap_chan_lock(chan); =20 + lockdep_assert_held(&chan->conn->lock); + BT_DBG("chan %p, len %d", chan, skb->len); =20 /* If we receive data on a fixed channel before the info req/rsp --=20 2.55.0 From nobody Sat Sep 26 21:59:26 2026 Received: from meesny.iki.fi (meesny.iki.fi [195.140.195.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 1A5943976A0; Sat, 29 Aug 2026 14:23:03 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=pass smtp.client-ip=195.140.195.201 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788013385; cv=pass; b=CXAW3yZuSBzD5NeynZJ5WajrfM0CxrHVhaIAOpdJ97EiMxnyYz6FR+4RjdAwy8UmaU18fr4VsnxYIkMvSV0vLesB/Jspj8vAOne+HaOgfbXP0gXQbhzNJ1njcjiS/FtyFQT00fYLnCVJLlTtvaB8Xp3wWBmj/hduSzLkFHDBiOI= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788013385; c=relaxed/simple; bh=XyN5NjZUEUM9+dBFPwGVFU/jX/V94wkLAxY8T2tWdzQ=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=BLzH9L3B0yD85QpK25YLKXnKmLc8He4Bpl3Vz+iedbevSV6zHLoPcPFdPdn7uLgkM2xIAWMPyPJSQThr74ZEGN8cUwSoNtFe7jz/VFJB+MSlpsTuRyZCM0j2kjt78hLqRDbCA4byom+Oqia+e23Kp+eil29F1JAMnX7wM4AfLIA= ARC-Authentication-Results: i=2; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=iki.fi; spf=pass smtp.mailfrom=iki.fi; dkim=pass (1024-bit key) header.d=iki.fi header.i=@iki.fi header.b=Os9YX4pm; arc=pass smtp.client-ip=195.140.195.201 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=iki.fi Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=iki.fi Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=iki.fi header.i=@iki.fi header.b="Os9YX4pm" Received: from monolith.lan (unknown [IPv6:2a03:1b20:1:e011::d701]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange x25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) (Authenticated sender: pav) by meesny.iki.fi (Postfix) with ESMTPSA id 4hXHXd0SvJzyvj; Sat, 29 Aug 2026 17:22:56 +0300 (EEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=iki.fi; s=meesny; t=1788013378; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=mmFd3M5blw19vh8W/w2YzpOm5wkFPxgwIPhzOZGqPDY=; b=Os9YX4pmfjfqqmgv19z4mHHT53XElBq1xalZDzQEQozKHwDCNpzrUenfqAU8IlAMs2kHRP CPkg6//hbVzcBrtInQTh7WFIwnJrhwMjxU3lc9BDcT/nyxIVOXv29mD16BRoVlXg0StcVH bof7tIThj/6sEF0YfLo6zoo9v3oKPNM= ARC-Seal: i=1; a=rsa-sha256; d=iki.fi; s=meesny; cv=none; t=1788013378; b=l3dmWC6VRCJbQzd9a8SmzALV7hwP7v44FUzsi/uLNuaeNvKPOtXS1CovOciu8hR/ttsfl7 JXvi7xmW4RqIzErgftr+C0FyR40MzdSPRVBEGeJV+SzpoDEwmypAWu396KPA2Jn/Bj4Sqx l6D5vXeLwIq+d4F/g4v+Y+LAAYGcFDk= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=iki.fi; s=meesny; t=1788013378; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=mmFd3M5blw19vh8W/w2YzpOm5wkFPxgwIPhzOZGqPDY=; b=D1IOyawMTN+OEFwu05/3+BNWgywu8Orzep9NZCWARzbDeL8AhA1C8XznzALYu+D8de++c3 cuoch5Di2JUxuXsJMJC2Dr9MJGbNJS2o92jf1AzIPbwy6atMmpdffMsmq8v3Bbbme1iZWv IGCcawVhV8sqcOJ2vJBMu5XvtCjd4VU= ARC-Authentication-Results: i=1; ORIGINATING; auth=pass smtp.auth=pav smtp.mailfrom=pav@iki.fi From: Pauli Virtanen To: linux-bluetooth@vger.kernel.org Cc: Pauli Virtanen , marcel@holtmann.org, luiz.dentz@gmail.com, oss@fourdim.xyz, error27@gmail.com, elver@google.com, linux-kernel@vger.kernel.org Subject: [PATCH 13/16] Bluetooth: L2CAP: annotate locking for l2cap_ops callbacks Date: Sat, 29 Aug 2026 17:20:08 +0300 Message-ID: X-Mailer: git-send-email 2.55.0 In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Annotate current locking context for l2cap_ops callbacks. Signed-off-by: Pauli Virtanen --- include/net/bluetooth/l2cap.h | 13 +++++++++---- net/bluetooth/l2cap_core.c | 1 + 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index f612c9f884d1..3d00ffb66cc9 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h @@ -653,21 +653,26 @@ struct l2cap_ops { char *name; =20 int (*new_connection)(struct l2cap_chan *chan, - struct l2cap_chan *new_chan); + struct l2cap_chan *new_chan) + __must_hold(&chan->lock) + __must_hold(&new_chan->lock); int (*recv) (struct l2cap_chan * chan, struct sk_buff *skb); void (*teardown) (struct l2cap_chan *chan, int err) __must_hold(&chan->lock); - void (*close) (struct l2cap_chan *chan); + void (*close) (struct l2cap_chan *chan) + __must_hold(&chan->lock); void (*state_change) (struct l2cap_chan *chan, int state, int err); void (*ready) (struct l2cap_chan *chan) __must_hold(&chan->lock) __must_hold(&chan->conn->lock); void (*defer) (struct l2cap_chan *chan); - void (*resume) (struct l2cap_chan *chan); + void (*resume) (struct l2cap_chan *chan) + __must_hold(&chan->lock); void (*suspend) (struct l2cap_chan *chan); - void (*set_shutdown) (struct l2cap_chan *chan); + void (*set_shutdown) (struct l2cap_chan *chan) + __must_hold(&chan->lock); long (*get_sndtimeo) (struct l2cap_chan *chan); struct pid *(*get_peer_pid) (struct l2cap_chan *chan); struct sk_buff *(*alloc_skb) (struct l2cap_chan *chan, diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 88a9596e4801..ff9529f2eb15 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -4200,6 +4200,7 @@ static inline int l2cap_command_rej(struct l2cap_conn= *conn, static struct l2cap_chan *l2cap_new_connection(struct l2cap_conn *conn, struct l2cap_chan *pchan) __must_hold(&conn->lock) + __must_hold(&pchan->lock) { struct l2cap_chan *chan; =20 --=20 2.55.0 From nobody Sat Sep 26 21:59:26 2026 Received: from meesny.iki.fi (meesny.iki.fi [195.140.195.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id B805D3ACEE3; Sat, 29 Aug 2026 14:23:09 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=pass smtp.client-ip=195.140.195.201 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788013392; cv=pass; b=od/2utLbCVf85h+0qyJWvqDoikRHjPkL0mpqr4ueCKUrgjuDMC+VWRyGnY28+NTAz3t/RUwVu+kz29lpJCxO3eTdGtrVv8hVzYmz/CIaIeSznpUc+VnxWpA6v4Qa+qmmUaWnZvald3iQOo7TtD/wV/nWNM+il+AMbk1RwcG18ck= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788013392; c=relaxed/simple; bh=XgZgRJaCP8RbAxF2F6wwlCNm2i4NZfHfXxO5tbt+JDE=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=oukzFYZjYirqkm4fYzw6IieN+3IXPrRcUXHQVx7v+rhQmnEFDt9la+7hlWo4X6wrJdee8RSMk3NyDWj7KLSQeFPA2GKciqq53UDqyL7WSp76sVCWsuXmS+Zncgu1yKaIurao1QqupJ7H9KCOlosjt8EtX3JPun+Oy3y+a7Mw958= ARC-Authentication-Results: i=2; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=iki.fi; spf=pass smtp.mailfrom=iki.fi; dkim=pass (1024-bit key) header.d=iki.fi header.i=@iki.fi header.b=cs4pl9v5; arc=pass smtp.client-ip=195.140.195.201 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=iki.fi Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=iki.fi Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=iki.fi header.i=@iki.fi header.b="cs4pl9v5" Received: from monolith.lan (unknown [IPv6:2a03:1b20:1:e011::d701]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange x25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) (Authenticated sender: pav) by meesny.iki.fi (Postfix) with ESMTPSA id 4hXHXk3YQrzyhS; Sat, 29 Aug 2026 17:23:02 +0300 (EEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=iki.fi; s=meesny; t=1788013383; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=qbD+jA3FjbPdP0383wROCsVf5CmDmabv7/udhP8xkLM=; b=cs4pl9v5TgY5b0d2Q1jAeGjVHzY0gkFC0KmfCBq7aEXyLeqjOXHAqOWYbFmC4z+tEH8KMp vhGpuuqqIvQKfzvD9ghfHqQqwg1LWpmQoSonAbB0KbJdbkucFp5oRsMed2zqra/T/PAjRc xQ8lhtMqaRcnMFNEn400LVrWZFpKoLk= ARC-Seal: i=1; a=rsa-sha256; d=iki.fi; s=meesny; cv=none; t=1788013383; b=qRueV036TwZB1hTlcmmH7QS94jRf7OoB0PXKmI4VL+xk9558bwEdd8285iyKDKJyMV06ga e4Tzyo8z197DQYvRArf/OYw+xDeuyaqMTsnQpYkpFgl70siwzAvQKB7VLF5WnXgX86MNZ6 3oAaEOXmWNLr6ewL9QMF55n9NxBK8T8= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=iki.fi; s=meesny; t=1788013383; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=qbD+jA3FjbPdP0383wROCsVf5CmDmabv7/udhP8xkLM=; b=TNEGXl8Z7Zi95Re/Txs0rMpRB9aAh+VoLxHEN3Jz/H7qoLt3u1oeHS7DtLZrEE2VJJZ5BW yAonZQwuLyINkW9IVCGqaCybEzluUbIz6HBjGtQSmQ6ocbjywwztWL6AqZ6dXsZpnyg71h dT9JIplv0rhc2yUx6FTqpnGCopa9v8c= ARC-Authentication-Results: i=1; ORIGINATING; auth=pass smtp.auth=pav smtp.mailfrom=pav@iki.fi From: Pauli Virtanen To: linux-bluetooth@vger.kernel.org Cc: Pauli Virtanen , marcel@holtmann.org, luiz.dentz@gmail.com, oss@fourdim.xyz, error27@gmail.com, elver@google.com, linux-kernel@vger.kernel.org Subject: [PATCH 14/16] Bluetooth: L2CAP: make concurrent l2cap_set_timer() refcounting safe Date: Sat, 29 Aug 2026 17:20:09 +0300 Message-ID: X-Mailer: git-send-email 2.55.0 In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" 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 --- 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); =20 - /* 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); =20 - 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); } =20 static inline bool l2cap_clear_timer(struct l2cap_chan *chan, --=20 2.55.0 From nobody Sat Sep 26 21:59:26 2026 Received: from meesny.iki.fi (meesny.iki.fi [195.140.195.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 5DAA53ACEEA; Sat, 29 Aug 2026 14:23:14 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=pass smtp.client-ip=195.140.195.201 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788013397; cv=pass; b=oAhLjpWf5dZeqndPp2DQjSruLfvzxZsspy1HcQX/RJNBLa8TTuCBIH+BxpyU7qJOqx6Rjahut02oNlCC+mjYrYOCC+Em21u40BFvavNSrcWOL+HSWVWk89Yrw7CULLGVGz92C7Fsme30snpXeVi6KQjN0vGHMQ19OV1t14rHvB0= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788013397; c=relaxed/simple; bh=DglAwIBDAOZtI7fLjCYTm3hxn4xxQs2GY6xnNw09kqk=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=HCWGwfDcR/xADcFxfI1WDbMU+R5QoFb5V541nN19PGbhsRM6ODaxwgt6+rWgkbNKTRw/rVNb/04O0EbjXDglSgnpWZ4AoTsiG8FW/PR/WzTvATNSCkQiUDf/UbTu92E8231Yo8z1P/rhrflspZusi18X8oMB4GFOEndVWU4ZmqU= ARC-Authentication-Results: i=2; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=iki.fi; spf=pass smtp.mailfrom=iki.fi; dkim=pass (1024-bit key) header.d=iki.fi header.i=@iki.fi header.b=wEnbTAIu; arc=pass smtp.client-ip=195.140.195.201 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=iki.fi Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=iki.fi Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=iki.fi header.i=@iki.fi header.b="wEnbTAIu" Received: from monolith.lan (unknown [IPv6:2a03:1b20:1:e011::d701]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange x25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) (Authenticated sender: pav) by meesny.iki.fi (Postfix) with ESMTPSA id 4hXHXq6Sglzyvj; Sat, 29 Aug 2026 17:23:07 +0300 (EEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=iki.fi; s=meesny; t=1788013388; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=EJOLdi5PhAwA5XQVJ1o6Hxg+qLS/nkP9SPXADUScm+s=; b=wEnbTAIu9YZUg0V5gA7+y09Ik/FP7Y0HWZMLTBck+qlnLjCmfaU5RreBKNFd44IkwS5oEi YIIQp9DgSDTzvFi+AxA9PGqHZGRnijYogUICqKsfH3IK1Y5ND5YJtHUtUicJzZbIlTCz6/ 7hbYJPCav8HFuSinYxTbN5Sj69S8hsc= ARC-Seal: i=1; a=rsa-sha256; d=iki.fi; s=meesny; cv=none; t=1788013388; b=kw32CZ5FPGZ5f1pK6lbMIjfGDLehBEtEJnNTgr71WfM3ltWPXp9go7SpXHQ7+QnCxXPi7+ nPKKL9C5jRCkYWFCUaWx/gtxvfJ1aznV/XCsDUaVq+XJlfwTmURp9VsH64i46lfY6s6OV9 OEjFiFRbsJj4W3v5D6Smdm6NoS6PHts= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=iki.fi; s=meesny; t=1788013388; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=EJOLdi5PhAwA5XQVJ1o6Hxg+qLS/nkP9SPXADUScm+s=; b=TB8vvLZ8AMNXBJOMSBewW4j5zfa19XK1Jbnv6PK0572dfvzgaD2zonqE9MTEEHCQ8xz7Yj QpJTU5/r5seZZTbLqPb/dmwJK5NkNgireIX2GcoTC09+il4VfDZdyCsMr7qxhIIc8521CM unP7832JXQf/PAw32JmmpUZ/oQgUDgM= ARC-Authentication-Results: i=1; ORIGINATING; auth=pass smtp.auth=pav smtp.mailfrom=pav@iki.fi From: Pauli Virtanen To: linux-bluetooth@vger.kernel.org Cc: Pauli Virtanen , marcel@holtmann.org, luiz.dentz@gmail.com, oss@fourdim.xyz, error27@gmail.com, elver@google.com, linux-kernel@vger.kernel.org Subject: [PATCH 15/16] Bluetooth: L2CAP: remove conditional locking from l2cap_connect() Date: Sat, 29 Aug 2026 17:20:10 +0300 Message-ID: <7d3474153c2b1f3f820c75ff98148ca5238706c3.1788013041.git.pav@iki.fi> X-Mailer: git-send-email 2.55.0 In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Context analysis does not understand conditional locking. Restructure l2cap_connect() by removing conditional locking at the cost of some code duplication, so that static analysis can see its content. Signed-off-by: Pauli Virtanen --- net/bluetooth/l2cap_core.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index ff9529f2eb15..a4299bc10c2f 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -4233,7 +4233,6 @@ static struct l2cap_chan *l2cap_new_connection(struct= l2cap_conn *conn, static void l2cap_connect(struct l2cap_conn *conn, struct l2cap_cmd_hdr *c= md, u8 *data, u8 rsp_code) __must_hold(&conn->lock) - __context_unsafe(/* conditional locking */) { struct l2cap_conn_req *req =3D (struct l2cap_conn_req *) data; struct l2cap_conn_rsp rsp; @@ -4250,7 +4249,13 @@ static void l2cap_connect(struct l2cap_conn *conn, s= truct l2cap_cmd_hdr *cmd, &conn->hcon->dst, ACL_LINK); if (!pchan) { result =3D L2CAP_CR_BAD_PSM; - goto response; + + rsp.scid =3D cpu_to_le16(scid); + rsp.dcid =3D cpu_to_le16(dcid); + rsp.result =3D cpu_to_le16(result); + rsp.status =3D cpu_to_le16(status); + l2cap_send_cmd(conn, cmd->ident, rsp_code, sizeof(rsp), &rsp); + return; } =20 l2cap_chan_lock(pchan); @@ -4332,9 +4337,6 @@ static void l2cap_connect(struct l2cap_conn *conn, st= ruct l2cap_cmd_hdr *cmd, rsp.status =3D cpu_to_le16(status); l2cap_send_cmd(conn, cmd->ident, rsp_code, sizeof(rsp), &rsp); =20 - if (!pchan) - return; - if (result =3D=3D L2CAP_CR_PEND && status =3D=3D L2CAP_CS_NO_INFO) { struct l2cap_info_req info; info.type =3D cpu_to_le16(L2CAP_IT_FEAT_MASK); --=20 2.55.0 From nobody Sat Sep 26 21:59:26 2026 Received: from meesny.iki.fi (meesny.iki.fi [195.140.195.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 5AB8A3B2D0A; Sat, 29 Aug 2026 14:23:20 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=pass smtp.client-ip=195.140.195.201 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788013401; cv=pass; b=JfzLJMpIIRm4EXgpyCAcuoqrtcIZ8sEKfsvkrGGS4x4Mex26/NWBolG6pdS1H73R1IeiG2dK3jR1CHUguBehzGid0Mz+O3aVkFVX6QZJ5OZcYmnvDC+h6vs2ZN4U/R2NJTEGxgR1zT9Z4yxfKJkR3cFCR9KDONKPe6uXDb8TpWo= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788013401; c=relaxed/simple; bh=OlOrHU6Kcyn0daQj6H9bGgE+0JhY5QStHNTKee3VeCY=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=p2+iRgSHqaksdVSYb6866rYw49N2K4hluMEiGggNjr1coi2U9oT6S5KYKNKBpKQGqXSOATI4l7TiTEtDtcjaOtnWH3bp+b0URy4+lbcKhGpfRe9pd6azMHjrEZffLsjQFRef41tvgOorgHhd8Tcnaah6k9+V9UPfNDSwcQOCHTI= ARC-Authentication-Results: i=2; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=iki.fi; spf=pass smtp.mailfrom=iki.fi; dkim=pass (1024-bit key) header.d=iki.fi header.i=@iki.fi header.b=Kb+V5Ir/; arc=pass smtp.client-ip=195.140.195.201 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=iki.fi Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=iki.fi Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=iki.fi header.i=@iki.fi header.b="Kb+V5Ir/" Received: from monolith.lan (unknown [IPv6:2a03:1b20:1:e011::d701]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange x25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) (Authenticated sender: pav) by meesny.iki.fi (Postfix) with ESMTPSA id 4hXHXx2ZKJzyhS; Sat, 29 Aug 2026 17:23:13 +0300 (EEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=iki.fi; s=meesny; t=1788013394; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=hF4A8wUQ9tYT3NtMOI6k9jJyNs1GZ1ugtGxRJQwRLkY=; b=Kb+V5Ir/6lSYcc5F4eJXLNqm7mQz/z7XoFSFzT6INqGgN8uan+ee+P/SkgGfPhsXqUZ1Ai 4Tah4n3NlsOBhG4RHRYcip3kUnmgis6Yt9yKFdNICxVdT6NOLhv5pTAmkkiOwKQPescYvv jCgBbqLg3tDSsLpTQnylOp7n84Ms4w8= ARC-Seal: i=1; a=rsa-sha256; d=iki.fi; s=meesny; cv=none; t=1788013394; b=TEoG5RGxBnrPdBj1AjSMrtSKKX7lrhsacVTVgWtYMUXIfxHYTQEzgYlMzUWVCzZlF1InWq MtDZMADbVmr6xBUh5V+xxfMFZRFvDNRs7raCTNW9CZ4gXlh7WiiCPtXd+fuY7Ugv8H+gv5 uvBs3Asye3YfuUtvBNhXx8YMndWkEP8= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=iki.fi; s=meesny; t=1788013394; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=hF4A8wUQ9tYT3NtMOI6k9jJyNs1GZ1ugtGxRJQwRLkY=; b=Lvx/r0MR9QxTVKJ0F6fnCL7Ji1+49n1pH0ViBRSlxYcgJGI0HBAlxA8YMJSAVavMeHilI5 Jlvn7tTEKQY1OyUeyycESwJqD4WE1mxhvg+AFkVe3AH2R7bMZmYszBosKu/3i5MC71WBHd Qm0a4rBOpVbu8BGt8s30X5c9iFJ2Juw= ARC-Authentication-Results: i=1; ORIGINATING; auth=pass smtp.auth=pav smtp.mailfrom=pav@iki.fi From: Pauli Virtanen To: linux-bluetooth@vger.kernel.org Cc: Pauli Virtanen , marcel@holtmann.org, luiz.dentz@gmail.com, oss@fourdim.xyz, error27@gmail.com, elver@google.com, linux-kernel@vger.kernel.org Subject: [PATCH 16/16] Bluetooth: L2CAP: refuse __l2cap_chan_add if chan already has conn Date: Sat, 29 Aug 2026 17:20:11 +0300 Message-ID: <12da72b4d0ec8c2bba425d37ebaab0fde0937075.1788013041.git.pav@iki.fi> X-Mailer: git-send-email 2.55.0 In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" l2cap_chan may be linked to l2cap_conn at most once. This is assumed in several places, eg l2cap_chan_del cleanup. There is a TOCTOU race where the invariant is violated: [Task 1] [Task 2] l2cap_chan_connect l2cap_sock_bind l2cap_chan_lock lock_sock l2cap_state_change if (sk->sk_state !=3D BT_OPEN) chan->state =3D BT_CONNECT l2cap_sock_state_change_cb chan->state =3D BT_BOUND sk->sk_state =3D BT_BOUND lock_sock <------------------ release_sock sk->sk_state =3D BT_CONNECT l2cap_sock_connect() does not check sk->sk_state, so since chan->state is now BT_BOUND, subsequent connect() ends up with second __l2cap_chan_add. Explicitly document and check the invariant in __l2cap_chan_add with WARN_ON_ONCE. The only callsite where it could be hit is l2cap_chan_connect, so add pre-check there to avoid relying on chan->state. chan->state read/write is not properly guarded currently so there can be other TOCTOUC problems. Add l2cap_lock_chan in l2cap_sock_bind() to guard chan->state write. Fixes: b66774b48dd9 ("Bluetooth: L2CAP: Fix UAF in channel timeout by holdi= ng conn ref") Assisted-by: deepseek-4-flash # finding the race condition Signed-off-by: Pauli Virtanen --- net/bluetooth/l2cap_core.c | 7 ++++++- net/bluetooth/l2cap_sock.c | 2 ++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index a4299bc10c2f..a86c154d4a9a 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -623,6 +623,10 @@ void __l2cap_chan_add(struct l2cap_conn *conn, struct = l2cap_chan *chan) BT_DBG("conn %p, psm 0x%2.2x, dcid 0x%4.4x", conn, __le16_to_cpu(chan->psm), chan->dcid); =20 + /* Caller must ensure l2cap_chan is linked to l2cap_conn only once */ + if (WARN_ON_ONCE(chan->conn || test_bit(FLAG_DEL, &chan->flags))) + return; + conn->disc_reason =3D HCI_ERROR_REMOTE_USER_TERM; =20 chan->conn =3D l2cap_conn_get(conn); @@ -7604,7 +7608,8 @@ int l2cap_chan_connect(struct l2cap_chan *chan, __le1= 6 psm, u16 cid, mutex_lock(&conn->lock); l2cap_chan_lock(chan); =20 - if (cid && __l2cap_get_chan_by_dcid(conn, cid)) { + if ((cid && __l2cap_get_chan_by_dcid(conn, cid)) || chan->conn || + test_bit(FLAG_DEL, &chan->flags)) { hci_conn_drop(hcon); err =3D -EBUSY; goto chan_unlock; diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c index dee3025f0ec2..278adb05c4c9 100644 --- a/net/bluetooth/l2cap_sock.c +++ b/net/bluetooth/l2cap_sock.c @@ -109,6 +109,7 @@ static int l2cap_sock_bind(struct socket *sock, struct = sockaddr_unsized *addr, i return -EINVAL; } =20 + l2cap_chan_lock(chan); lock_sock(sk); =20 if (sk->sk_state !=3D BT_OPEN) { @@ -174,6 +175,7 @@ static int l2cap_sock_bind(struct socket *sock, struct = sockaddr_unsized *addr, i =20 done: release_sock(sk); + l2cap_chan_unlock(chan); return err; } =20 --=20 2.55.0