All of lore.kernel.org
 help / color / mirror / Atom feed
From: Jeff Layton <jlayton@kernel.org>
To: Chuck Lever <cel@kernel.org>, NeilBrown <neil@brown.name>,
	Olga Kornievskaia <okorniev@redhat.com>,
	Dai Ngo <Dai.Ngo@oracle.com>, Tom Talpey <tom@talpey.com>
Cc: linux-nfs@vger.kernel.org
Subject: Re: [PATCH v4 7/9] NFSD: Prevent client use-after-free during blocked-lock reaping
Date: Thu, 09 Jul 2026 14:36:04 -0400	[thread overview]
Message-ID: <075f2d2acaff6607f507ae1e2a47d1d6bd880dd2.camel@kernel.org> (raw)
In-Reply-To: <20260709-cel-v4-7-1d519d9be0cb@kernel.org>

On Thu, 2026-07-09 at 13:40 -0400, Chuck Lever wrote:
> A bare lock owner -- its only remaining reference a blocked lock on
> nn->blocked_locks_lru -- holds a raw pointer to its nfs4_client but
> no reference keeping the client alive. When the per-net laundromat
> reaps such a lock, freeing the nbl drops the owner reference
> held through flc_owner, and the final nfs4_put_stateowner()
> takes the client's cl_lock. Because the laundromat detaches the
> nbl first, __destroy_client() no longer finds it, so a concurrent
> force_expire_client() can free the client before nfs4_put_stateowner()
> runs, dereferencing cl_lock in freed memory.
> 
> Pin the client with cl_rpc_users before dropping
> nn->blocked_locks_lock, and skip clients already expiring, whose
> blocked locks __destroy_client() frees while holding an owner
> reference. Take nn->client_lock outside nn->blocked_locks_lock.
> Every other site holds nn->blocked_locks_lock as a leaf, acquiring
> no further lock, so placing nn->client_lock outside it cannot form
> a lock-order cycle.
> 
> Fixes: 7919d0a27f1e ("nfsd: add a LRU list for blocked locks")
> Signed-off-by: Chuck Lever <cel@kernel.org>
> ---
>  fs/nfsd/nfs4state.c | 23 ++++++++++++++++++++---
>  1 file changed, 20 insertions(+), 3 deletions(-)
> 
> diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
> index 142ba7d80539..4acd02f1642c 100644
> --- a/fs/nfsd/nfs4state.c
> +++ b/fs/nfsd/nfs4state.c
> @@ -357,6 +357,16 @@ free_blocked_lock(struct nfsd4_blocked_lock *nbl)
>  	kref_put(&nbl->nbl_kref, free_nbl);
>  }
>  
> +/* A blocked lock's flc_owner is its nfs4_lockowner. */
> +static struct nfs4_client *
> +nbl_client(struct nfsd4_blocked_lock *nbl)
> +{
> +	struct nfs4_lockowner *lo;
> +
> +	lo = (struct nfs4_lockowner *)nbl->nbl_lock.c.flc_owner;
> +	return lo->lo_owner.so_client;
> +}
> +
>  static void
>  remove_blocked_locks(struct nfs4_lockowner *lo)
>  {
> @@ -7591,22 +7601,29 @@ nfs4_laundromat(struct nfsd_net *nn)
>  	 * indefinitely once the lock does become free.
>  	 */
>  	BUG_ON(!list_empty(&reaplist));
> +	spin_lock(&nn->client_lock);
>  	spin_lock(&nn->blocked_locks_lock);
> -	while (!list_empty(&nn->blocked_locks_lru)) {
> -		nbl = list_first_entry(&nn->blocked_locks_lru,
> -					struct nfsd4_blocked_lock, nbl_lru);
> +	list_for_each_safe(pos, next, &nn->blocked_locks_lru) {
> +		nbl = list_entry(pos, struct nfsd4_blocked_lock, nbl_lru);
>  		if (!state_expired(&lt, nbl->nbl_time))
>  			break;
> +		clp = nbl_client(nbl);
> +		if (is_client_expired(clp))
> +			continue;
> +		atomic_inc(&clp->cl_rpc_users);
>  		list_move(&nbl->nbl_lru, &reaplist);
>  		list_del_init(&nbl->nbl_list);
>  	}
>  	spin_unlock(&nn->blocked_locks_lock);
> +	spin_unlock(&nn->client_lock);
>  
>  	while (!list_empty(&reaplist)) {
>  		nbl = list_first_entry(&reaplist,
>  					struct nfsd4_blocked_lock, nbl_lru);
> +		clp = nbl_client(nbl);
>  		list_del_init(&nbl->nbl_lru);
>  		free_blocked_lock(nbl);
> +		put_client_no_renew(clp);
>  	}
>  #ifdef CONFIG_NFSD_V4_2_INTER_SSC
>  	/* service the server-to-server copy delayed unmount list */

Reviewed-by: Jeff Layton <jlayton@kernel.org>

  reply	other threads:[~2026-07-09 18:36 UTC|newest]

Thread overview: 14+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-07-09 17:40 [PATCH v4 0/9] NFSD: Fix UAFs in client teardown and state revocation Chuck Lever
2026-07-09 17:40 ` [PATCH v4 1/9] NFSD: Prevent lock owner use-after-free during client teardown Chuck Lever
2026-07-09 17:40 ` [PATCH v4 2/9] NFSD: Prevent client use-after-free during delegation revoke Chuck Lever
2026-07-09 17:40 ` [PATCH v4 3/9] NFSD: Prevent client use-after-free during admin state revocation Chuck Lever
2026-07-09 17:40 ` [PATCH v4 4/9] NFSD: Prevent client use-after-free during export " Chuck Lever
2026-07-09 17:40 ` [PATCH v4 5/9] NFSD: Prevent client use-after-free during NFSv4.0 revoked-state cleanup Chuck Lever
2026-07-09 17:40 ` [PATCH v4 6/9] NFSD: Consolidate the revocation-path client unpin Chuck Lever
2026-07-09 17:40 ` [PATCH v4 7/9] NFSD: Prevent client use-after-free during blocked-lock reaping Chuck Lever
2026-07-09 18:36   ` Jeff Layton [this message]
2026-07-09 17:40 ` [PATCH v4 8/9] NFSD: Prevent client use-after-free during close_lru reaping Chuck Lever
2026-07-09 18:37   ` Jeff Layton
2026-07-09 17:40 ` [PATCH v4 9/9] NFSD: Release the export reference when reaping open stateids Chuck Lever
2026-07-09 18:40   ` Jeff Layton
2026-07-09 19:55     ` Chuck Lever

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=075f2d2acaff6607f507ae1e2a47d1d6bd880dd2.camel@kernel.org \
    --to=jlayton@kernel.org \
    --cc=Dai.Ngo@oracle.com \
    --cc=cel@kernel.org \
    --cc=linux-nfs@vger.kernel.org \
    --cc=neil@brown.name \
    --cc=okorniev@redhat.com \
    --cc=tom@talpey.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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.