public inbox for linux-bluetooth@vger.kernel.org
 help / color / mirror / Atom feed
From: Paul Menzel <pmenzel@molgen.mpg.de>
To: Ren Wei <n05ec@lzu.edu.cn>
Cc: linux-bluetooth@vger.kernel.org, netdev@vger.kernel.org,
	marcel@holtmann.org, luiz.dentz@gmail.com, davem@davemloft.net,
	edumazet@google.com, kuba@kernel.org, pabeni@redhat.com,
	horms@kernel.org, yifanwucs@gmail.com, tomapufckgml@gmail.com,
	yuantan098@gmail.com, bird@lzu.edu.cn, enjou1224z@gmail.com,
	wangjiexun2025@gmail.com
Subject: Re: [PATCH v2 1/1] Bluetooth: serialize accept_q access
Date: Fri, 3 Apr 2026 11:27:25 +0200	[thread overview]
Message-ID: <fa0cd4e5-33f4-41db-a186-853ea39613cd@molgen.mpg.de> (raw)
In-Reply-To: <06a6b4549acba207847ce532dedbf1c95ab22d13.1774925231.git.wangjiexun2025@gmail.com>

Dear Ren,


Thank you for your patch.

Am 03.04.26 um 10:05 schrieb Ren Wei:
> From: Jiexun Wang <wangjiexun2025@gmail.com>
> 
> bt_sock_poll() walks the accept queue without synchronization, while
> child teardown can unlink the same socket and drop its last reference.
> 
> Protect accept_q with a dedicated lock for queue updates and polling.
> Also rework bt_accept_dequeue() to take temporary child references under
> the queue lock before dropping it and locking the child socket.
> 
> Fixes: 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 ("Linux-2.6.12-rc2")
> Reported-by: Yifan Wu <yifanwucs@gmail.com>
> Reported-by: Juefei Pu <tomapufckgml@gmail.com>
> Co-developed-by: Yuan Tan <yuantan098@gmail.com>
> Signed-off-by: Yuan Tan <yuantan098@gmail.com>
> Suggested-by: Xin Liu <bird@lzu.edu.cn>
> Tested-by: Ren Wei <enjou1224z@gmail.com>
> Signed-off-by: Jiexun Wang <wangjiexun2025@gmail.com>
> Signed-off-by: Ren Wei <n05ec@lzu.edu.cn>
> ---
> Changes in v2:
> - add Tested-by: Ren Wei <enjou1224z@gmail.com>
> - resend to the public Bluetooth/netdev lists
> 
>   include/net/bluetooth/bluetooth.h |  1 +
>   net/bluetooth/af_bluetooth.c      | 85 +++++++++++++++++++++++--------
>   2 files changed, 66 insertions(+), 20 deletions(-)
> 
> diff --git a/include/net/bluetooth/bluetooth.h b/include/net/bluetooth/bluetooth.h
> index 69eed69f7f26..3faea66b1979 100644
> --- a/include/net/bluetooth/bluetooth.h
> +++ b/include/net/bluetooth/bluetooth.h
> @@ -398,6 +398,7 @@ void baswap(bdaddr_t *dst, const bdaddr_t *src);
>   struct bt_sock {
>   	struct sock sk;
>   	struct list_head accept_q;
> +	spinlock_t accept_q_lock; /* protects accept_q */
>   	struct sock *parent;
>   	unsigned long flags;
>   	void (*skb_msg_name)(struct sk_buff *, void *, int *);
> diff --git a/net/bluetooth/af_bluetooth.c b/net/bluetooth/af_bluetooth.c
> index 2b94e2077203..f44e1ecc83d8 100644
> --- a/net/bluetooth/af_bluetooth.c
> +++ b/net/bluetooth/af_bluetooth.c
> @@ -154,6 +154,7 @@ struct sock *bt_sock_alloc(struct net *net, struct socket *sock,
>   
>   	sock_init_data(sock, sk);
>   	INIT_LIST_HEAD(&bt_sk(sk)->accept_q);
> +	spin_lock_init(&bt_sk(sk)->accept_q_lock);
>   
>   	sock_reset_flag(sk, SOCK_ZAPPED);
>   
> @@ -214,6 +215,7 @@ void bt_accept_enqueue(struct sock *parent, struct sock *sk, bool bh)
>   {
>   	const struct cred *old_cred;
>   	struct pid *old_pid;
> +	struct bt_sock *par = bt_sk(parent);
>   
>   	BT_DBG("parent %p, sk %p", parent, sk);
>   
> @@ -224,9 +226,12 @@ void bt_accept_enqueue(struct sock *parent, struct sock *sk, bool bh)
>   	else
>   		lock_sock_nested(sk, SINGLE_DEPTH_NESTING);
>   
> -	list_add_tail(&bt_sk(sk)->accept_q, &bt_sk(parent)->accept_q);
>   	bt_sk(sk)->parent = parent;
>   
> +	spin_lock_bh(&par->accept_q_lock);
> +	list_add_tail(&bt_sk(sk)->accept_q, &par->accept_q);
> +	spin_unlock_bh(&par->accept_q_lock);
> +
>   	/* Copy credentials from parent since for incoming connections the
>   	 * socket is allocated by the kernel.
>   	 */
> @@ -254,45 +259,73 @@ EXPORT_SYMBOL(bt_accept_enqueue);
>    */
>   void bt_accept_unlink(struct sock *sk)
>   {
> +	struct sock *parent = bt_sk(sk)->parent;
> +
>   	BT_DBG("sk %p state %d", sk, sk->sk_state);
>   
> +	spin_lock_bh(&bt_sk(parent)->accept_q_lock);
>   	list_del_init(&bt_sk(sk)->accept_q);
> -	sk_acceptq_removed(bt_sk(sk)->parent);
> +	spin_unlock_bh(&bt_sk(parent)->accept_q_lock);
> +
> +	sk_acceptq_removed(parent);
>   	bt_sk(sk)->parent = NULL;
>   	sock_put(sk);
>   }
>   EXPORT_SYMBOL(bt_accept_unlink);
>   
> +static struct sock *bt_accept_get(struct sock *parent, struct sock *sk)
> +{
> +	struct bt_sock *bt = bt_sk(parent);
> +	struct sock *next = NULL;
> +
> +	/* accept_q is modified from child teardown paths too, so take a
> +	 * temporary reference before dropping the queue lock.
> +	 */
> +	spin_lock_bh(&bt->accept_q_lock);
> +
> +	if (sk) {
> +		if (bt_sk(sk)->parent != parent)
> +			goto out;
> +
> +		if (!list_is_last(&bt_sk(sk)->accept_q, &bt->accept_q)) {
> +			next = &list_next_entry(bt_sk(sk), accept_q)->sk;
> +			sock_hold(next);
> +		}
> +	} else if (!list_empty(&bt->accept_q)) {
> +		next = &list_first_entry(&bt->accept_q,
> +					 struct bt_sock, accept_q)->sk;
> +		sock_hold(next);
> +	}
> +
> +out:
> +	spin_unlock_bh(&bt->accept_q_lock);
> +	return next;
> +}
> +
>   struct sock *bt_accept_dequeue(struct sock *parent, struct socket *newsock)
>   {
> -	struct bt_sock *s, *n;
> -	struct sock *sk;
> +	struct sock *sk, *next;
>   
>   	BT_DBG("parent %p", parent);
>   
>   restart:
> -	list_for_each_entry_safe(s, n, &bt_sk(parent)->accept_q, accept_q) {
> -		sk = (struct sock *)s;
> -
> +	for (sk = bt_accept_get(parent, NULL); sk; sk = next) {
>   		/* Prevent early freeing of sk due to unlink and sock_kill */
> -		sock_hold(sk);
>   		lock_sock(sk);
>   
>   		/* Check sk has not already been unlinked via
>   		 * bt_accept_unlink() due to serialisation caused by sk locking
>   		 */
> -		if (!bt_sk(sk)->parent) {
> +		if (bt_sk(sk)->parent != parent) {
>   			BT_DBG("sk %p, already unlinked", sk);
>   			release_sock(sk);
>   			sock_put(sk);
>   
> -			/* Restart the loop as sk is no longer in the list
> -			 * and also avoid a potential infinite loop because
> -			 * list_for_each_entry_safe() is not thread safe.
> -			 */
>   			goto restart;
>   		}
>   
> +		next = bt_accept_get(parent, sk);
> +
>   		/* sk is safely in the parent list so reduce reference count */
>   		sock_put(sk);
>   
> @@ -310,6 +343,8 @@ struct sock *bt_accept_dequeue(struct sock *parent, struct socket *newsock)
>   				sock_graft(sk, newsock);
>   
>   			release_sock(sk);
> +			if (next)
> +				sock_put(next);
>   			return sk;
>   		}
>   
> @@ -518,18 +553,28 @@ EXPORT_SYMBOL(bt_sock_stream_recvmsg);
>   
>   static inline __poll_t bt_accept_poll(struct sock *parent)
>   {
> -	struct bt_sock *s, *n;
> +	struct bt_sock *bt = bt_sk(parent);
> +	struct bt_sock *s;
>   	struct sock *sk;
> +	__poll_t mask = 0;
> +
> +	spin_lock_bh(&bt->accept_q_lock);
> +	list_for_each_entry(s, &bt->accept_q, accept_q) {
> +		int state;
>   
> -	list_for_each_entry_safe(s, n, &bt_sk(parent)->accept_q, accept_q) {
>   		sk = (struct sock *)s;
> -		if (sk->sk_state == BT_CONNECTED ||
> -		    (test_bit(BT_SK_DEFER_SETUP, &bt_sk(parent)->flags) &&
> -		     sk->sk_state == BT_CONNECT2))
> -			return EPOLLIN | EPOLLRDNORM;
> +		state = READ_ONCE(sk->sk_state);
> +
> +		if (state == BT_CONNECTED ||
> +		    (test_bit(BT_SK_DEFER_SETUP, &bt->flags) &&
> +		     state == BT_CONNECT2)) {
> +			mask = EPOLLIN | EPOLLRDNORM;
> +			break;
> +		}
>   	}
> +	spin_unlock_bh(&bt->accept_q_lock);
>   
> -	return 0;
> +	return mask;
>   }
>   
>   __poll_t bt_sock_poll(struct file *file, struct socket *sock,

Google’s Gemini review service has a comment [1]. Do you think it’s 
valid and related?


Kind regards,

Paul


[1]: 
https://sashiko.dev/#/patchset/06a6b4549acba207847ce532dedbf1c95ab22d13.1774925231.git.wangjiexun2025%40gmail.com

  parent reply	other threads:[~2026-04-03  9:28 UTC|newest]

Thread overview: 7+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
     [not found] <cover.1774454568.git.wangjiexun2025@gmail.com>
2026-04-03  8:05 ` [PATCH v2 1/1] Bluetooth: serialize accept_q access Ren Wei
2026-04-03  9:06   ` [v2,1/1] " bluez.test.bot
2026-04-03  9:27   ` Paul Menzel [this message]
2026-04-03 17:51   ` [PATCH v2 1/1] " Luiz Augusto von Dentz
2026-04-04 16:23 ` [PATCH v3 " Ren Wei
2026-04-04 16:50   ` [v3,1/1] " bluez.test.bot
2026-04-09 20:20   ` bluez.test.bot

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=fa0cd4e5-33f4-41db-a186-853ea39613cd@molgen.mpg.de \
    --to=pmenzel@molgen.mpg.de \
    --cc=bird@lzu.edu.cn \
    --cc=davem@davemloft.net \
    --cc=edumazet@google.com \
    --cc=enjou1224z@gmail.com \
    --cc=horms@kernel.org \
    --cc=kuba@kernel.org \
    --cc=linux-bluetooth@vger.kernel.org \
    --cc=luiz.dentz@gmail.com \
    --cc=marcel@holtmann.org \
    --cc=n05ec@lzu.edu.cn \
    --cc=netdev@vger.kernel.org \
    --cc=pabeni@redhat.com \
    --cc=tomapufckgml@gmail.com \
    --cc=wangjiexun2025@gmail.com \
    --cc=yifanwucs@gmail.com \
    --cc=yuantan098@gmail.com \
    /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