Linux bluetooth development
 help / color / mirror / Atom feed
From: Pauli Virtanen <pav@iki.fi>
To: linux-bluetooth@vger.kernel.org
Cc: marcel@holtmann.org, luiz.dentz@gmail.com, linux-kernel@vger.kernel.org
Subject: Re: [PATCH RESEND] Bluetooth: hci_core: add lockdep check to hci_conn lookups
Date: Sun, 16 Aug 2026 14:19:00 +0300	[thread overview]
Message-ID: <108c76a0ee67b795dee6dccd713ebcd685fe33c7.camel@iki.fi> (raw)
In-Reply-To: <2be38d111362590f45776a0bc114f7890906ead9.1786875148.git.pav@iki.fi>

su, 2026-08-16 kello 13:26 +0300, Pauli Virtanen kirjoitti:
> Add lockdep check for RCU || hdev->lock in hci_conn_hash lookups that
> return hci_conn pointer, as dereferencing that without locks can be
> TOCTOU issue. It used to be several callsites did not hold appropriate
> locks.

https://sashiko.dev/#/patchset/2be38d111362590f45776a0bc114f7890906ead9.1786875148.git.pav%40iki.fi

Sashiko review complains about HCI_CONN_HASH_LOCKDEP_CHECK() added to
wrong functions.

It applied the patch to bluetooth/master, instead of bluetooth-
next/master as intended.

Apparently the patch applies with fuzz also to bluetooth/master, but
some of the added HCI_CONN_HASH_LOCKDEP_CHECK land in wrong functions
there.

> The check is equivalent to removing rcu_read_lock() and doing instead
> list_for_each_entry_rcu(c, &h->list, list, lockdep_is_held(&hdev->lock))
> Although there should not be any remaining callsites without locks,
> don't remove the rcu_read_lock() for now, and just add the warning here.
> 
> Signed-off-by: Pauli Virtanen <pav@iki.fi>
> ---
> 
> Notes:
>     resend:
>     - no changes
> 
>  include/net/bluetooth/hci_core.h | 44 ++++++++++++++++++++++++++++++++
>  1 file changed, 44 insertions(+)
> 
> diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
> index 4105c446ca98..c12cd6873f65 100644
> --- a/include/net/bluetooth/hci_core.h
> +++ b/include/net/bluetooth/hci_core.h
> @@ -1030,6 +1030,9 @@ static inline bool hci_conn_sc_enabled(struct hci_conn *conn)
>  static inline void hci_conn_hash_add(struct hci_dev *hdev, struct hci_conn *c)
>  {
>  	struct hci_conn_hash *h = &hdev->conn_hash;
> +
> +	lockdep_assert_held(&hdev->lock);
> +
>  	list_add_tail_rcu(&c->list, &h->list);
>  	switch (c->type) {
>  	case ACL_LINK:
> @@ -1060,6 +1063,8 @@ static inline void hci_conn_hash_del(struct hci_dev *hdev, struct hci_conn *c)
>  {
>  	struct hci_conn_hash *h = &hdev->conn_hash;
>  
> +	lockdep_assert_held(&hdev->lock);
> +
>  	list_del_rcu(&c->list);
>  	synchronize_rcu();
>  
> @@ -1088,6 +1093,15 @@ static inline void hci_conn_hash_del(struct hci_dev *hdev, struct hci_conn *c)
>  	}
>  }
>  
> +#ifdef CONFIG_PROVE_RCU
> +#define HCI_CONN_HASH_LOCKDEP_CHECK(hdev)				\
> +	RCU_LOCKDEP_WARN(!lockdep_is_held(&(hdev)->lock) &&		\
> +			 !rcu_read_lock_held(),				\
> +			 "suspicious hci_conn locking")
> +#else
> +#define HCI_CONN_HASH_LOCKDEP_CHECK(hdev) do { } while (0 && (hdev))
> +#endif
> +
>  static inline unsigned int hci_conn_num(struct hci_dev *hdev, __u8 type)
>  {
>  	struct hci_conn_hash *h = &hdev->conn_hash;
> @@ -1169,6 +1183,8 @@ static inline struct hci_conn *hci_conn_hash_lookup_bis(struct hci_dev *hdev,
>  	struct hci_conn_hash *h = &hdev->conn_hash;
>  	struct hci_conn  *c;
>  
> +	HCI_CONN_HASH_LOCKDEP_CHECK(hdev);
> +
>  	rcu_read_lock();
>  
>  	list_for_each_entry_rcu(c, &h->list, list) {
> @@ -1191,6 +1207,8 @@ hci_conn_hash_lookup_create_pa_sync(struct hci_dev *hdev)
>  	struct hci_conn_hash *h = &hdev->conn_hash;
>  	struct hci_conn  *c;
>  
> +	HCI_CONN_HASH_LOCKDEP_CHECK(hdev);
> +
>  	rcu_read_lock();
>  
>  	list_for_each_entry_rcu(c, &h->list, list) {
> @@ -1217,6 +1235,8 @@ hci_conn_hash_lookup_per_adv_bis(struct hci_dev *hdev,
>  	struct hci_conn_hash *h = &hdev->conn_hash;
>  	struct hci_conn  *c;
>  
> +	HCI_CONN_HASH_LOCKDEP_CHECK(hdev);
> +
>  	rcu_read_lock();
>  
>  	list_for_each_entry_rcu(c, &h->list, list) {
> @@ -1241,6 +1261,8 @@ static inline struct hci_conn *hci_conn_hash_lookup_handle(struct hci_dev *hdev,
>  	struct hci_conn_hash *h = &hdev->conn_hash;
>  	struct hci_conn  *c;
>  
> +	HCI_CONN_HASH_LOCKDEP_CHECK(hdev);
> +
>  	rcu_read_lock();
>  
>  	list_for_each_entry_rcu(c, &h->list, list) {
> @@ -1260,6 +1282,8 @@ static inline struct hci_conn *hci_conn_hash_lookup_ba(struct hci_dev *hdev,
>  	struct hci_conn_hash *h = &hdev->conn_hash;
>  	struct hci_conn  *c;
>  
> +	HCI_CONN_HASH_LOCKDEP_CHECK(hdev);
> +
>  	rcu_read_lock();
>  
>  	list_for_each_entry_rcu(c, &h->list, list) {
> @@ -1281,6 +1305,8 @@ static inline struct hci_conn *hci_conn_hash_lookup_role(struct hci_dev *hdev,
>  	struct hci_conn_hash *h = &hdev->conn_hash;
>  	struct hci_conn  *c;
>  
> +	HCI_CONN_HASH_LOCKDEP_CHECK(hdev);
> +
>  	rcu_read_lock();
>  
>  	list_for_each_entry_rcu(c, &h->list, list) {
> @@ -1302,6 +1328,8 @@ static inline struct hci_conn *hci_conn_hash_lookup_le(struct hci_dev *hdev,
>  	struct hci_conn_hash *h = &hdev->conn_hash;
>  	struct hci_conn  *c;
>  
> +	HCI_CONN_HASH_LOCKDEP_CHECK(hdev);
> +
>  	rcu_read_lock();
>  
>  	list_for_each_entry_rcu(c, &h->list, list) {
> @@ -1328,6 +1356,8 @@ static inline struct hci_conn *hci_conn_hash_lookup_cis(struct hci_dev *hdev,
>  	struct hci_conn_hash *h = &hdev->conn_hash;
>  	struct hci_conn  *c;
>  
> +	HCI_CONN_HASH_LOCKDEP_CHECK(hdev);
> +
>  	rcu_read_lock();
>  
>  	list_for_each_entry_rcu(c, &h->list, list) {
> @@ -1360,6 +1390,8 @@ static inline struct hci_conn *hci_conn_hash_lookup_cig(struct hci_dev *hdev,
>  	struct hci_conn_hash *h = &hdev->conn_hash;
>  	struct hci_conn  *c;
>  
> +	HCI_CONN_HASH_LOCKDEP_CHECK(hdev);
> +
>  	rcu_read_lock();
>  
>  	list_for_each_entry_rcu(c, &h->list, list) {
> @@ -1383,6 +1415,8 @@ static inline struct hci_conn *hci_conn_hash_lookup_big(struct hci_dev *hdev,
>  	struct hci_conn_hash *h = &hdev->conn_hash;
>  	struct hci_conn  *c;
>  
> +	HCI_CONN_HASH_LOCKDEP_CHECK(hdev);
> +
>  	rcu_read_lock();
>  
>  	list_for_each_entry_rcu(c, &h->list, list) {
> @@ -1407,6 +1441,8 @@ hci_conn_hash_lookup_big_sync_pend(struct hci_dev *hdev,
>  	struct hci_conn_hash *h = &hdev->conn_hash;
>  	struct hci_conn  *c;
>  
> +	HCI_CONN_HASH_LOCKDEP_CHECK(hdev);
> +
>  	rcu_read_lock();
>  
>  	list_for_each_entry_rcu(c, &h->list, list) {
> @@ -1431,6 +1467,8 @@ hci_conn_hash_lookup_big_state(struct hci_dev *hdev, __u8 handle, __u16 state,
>  	struct hci_conn_hash *h = &hdev->conn_hash;
>  	struct hci_conn  *c;
>  
> +	HCI_CONN_HASH_LOCKDEP_CHECK(hdev);
> +
>  	rcu_read_lock();
>  
>  	list_for_each_entry_rcu(c, &h->list, list) {
> @@ -1454,6 +1492,8 @@ hci_conn_hash_lookup_pa_sync_big_handle(struct hci_dev *hdev, __u8 big)
>  	struct hci_conn_hash *h = &hdev->conn_hash;
>  	struct hci_conn  *c;
>  
> +	HCI_CONN_HASH_LOCKDEP_CHECK(hdev);
> +
>  	rcu_read_lock();
>  
>  	list_for_each_entry_rcu(c, &h->list, list) {
> @@ -1477,6 +1517,8 @@ hci_conn_hash_lookup_pa_sync_handle(struct hci_dev *hdev, __u16 sync_handle)
>  	struct hci_conn_hash *h = &hdev->conn_hash;
>  	struct hci_conn  *c;
>  
> +	HCI_CONN_HASH_LOCKDEP_CHECK(hdev);
> +
>  	rcu_read_lock();
>  
>  	list_for_each_entry_rcu(c, &h->list, list) {
> @@ -1546,6 +1588,8 @@ static inline struct hci_conn *hci_lookup_le_connect(struct hci_dev *hdev)
>  	struct hci_conn_hash *h = &hdev->conn_hash;
>  	struct hci_conn  *c;
>  
> +	HCI_CONN_HASH_LOCKDEP_CHECK(hdev);
> +
>  	rcu_read_lock();
>  
>  	list_for_each_entry_rcu(c, &h->list, list) {

-- 
Pauli Virtanen

      parent reply	other threads:[~2026-08-16 11:19 UTC|newest]

Thread overview: 3+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-08-16 10:26 [PATCH RESEND] Bluetooth: hci_core: add lockdep check to hci_conn lookups Pauli Virtanen
2026-08-16 11:15 ` [RESEND] " bluez.test.bot
2026-08-16 11:19 ` Pauli Virtanen [this message]

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=108c76a0ee67b795dee6dccd713ebcd685fe33c7.camel@iki.fi \
    --to=pav@iki.fi \
    --cc=linux-bluetooth@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=luiz.dentz@gmail.com \
    --cc=marcel@holtmann.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox