All of lore.kernel.org
 help / color / mirror / Atom feed
From: Jeff Layton <jlayton@kernel.org>
To: Olga Kornievskaia <okorniev@redhat.com>, chuck.lever@oracle.com
Cc: linux-nfs@vger.kernel.org, stable@vger.kernel.org
Subject: Re: [PATCH 1/1] nfsd: fix race between laundromat and free_stateid
Date: Fri, 11 Oct 2024 09:04:53 -0400	[thread overview]
Message-ID: <ae0003013659a34279e3666180cd8b730ca3a2d8.camel@kernel.org> (raw)
In-Reply-To: <20241010221801.35462-1-okorniev@redhat.com>

On Thu, 2024-10-10 at 18:18 -0400, Olga Kornievskaia wrote:
> There is a race between laundromat handling of revoked delegations
> and a client sending free_stateid operation. Laundromat thread
> finds that delegation has expired and needs to be revoked so it
> marks the delegation stid revoked and it puts it on a reaper list
> but then it unlock the state lock and the actual delegation revocation
> happens without the lock. Once the stid is marked revoked a racing
> free_stateid processing thread does the following (1) it calls
> list_del_init() which removes it from the reaper list and (2) frees
> the delegation stid structure. The laundromat thread ends up not
> calling the revoke_delegation() function for this particular delegation
> but that means it will no release the lock lease that exists on
> the file.
> 
> Now, a new open for this file comes in and ends up finding that
> lease list isn't empty and calls nfsd_breaker_owns_lease() which ends
> up trying to derefence a freed delegation stateid. Leading to the
> followint use-after-free KASAN warning:
> 
> kernel: ==================================================================
> kernel: BUG: KASAN: slab-use-after-free in nfsd_breaker_owns_lease+0x140/0x160 [nfsd]
> kernel: Read of size 8 at addr ffff0000e73cd0c8 by task nfsd/6205
> kernel:
> kernel: CPU: 2 UID: 0 PID: 6205 Comm: nfsd Kdump: loaded Not tainted 6.11.0-rc7+ #9
> kernel: Hardware name: Apple Inc. Apple Virtualization Generic Platform, BIOS 2069.0.0.0.0 08/03/2024
> kernel: Call trace:
> kernel: dump_backtrace+0x98/0x120
> kernel: show_stack+0x1c/0x30
> kernel: dump_stack_lvl+0x80/0xe8
> kernel: print_address_description.constprop.0+0x84/0x390
> kernel: print_report+0xa4/0x268
> kernel: kasan_report+0xb4/0xf8
> kernel: __asan_report_load8_noabort+0x1c/0x28
> kernel: nfsd_breaker_owns_lease+0x140/0x160 [nfsd]
> kernel: leases_conflict+0x68/0x370
> kernel: __break_lease+0x204/0xc38
> kernel: nfsd_open_break_lease+0x8c/0xf0 [nfsd]
> kernel: nfsd_file_do_acquire+0xb3c/0x11d0 [nfsd]
> kernel: nfsd_file_acquire_opened+0x84/0x110 [nfsd]
> kernel: nfs4_get_vfs_file+0x634/0x958 [nfsd]
> kernel: nfsd4_process_open2+0xa40/0x1a40 [nfsd]
> kernel: nfsd4_open+0xa08/0xe80 [nfsd]
> kernel: nfsd4_proc_compound+0xb8c/0x2130 [nfsd]
> kernel: nfsd_dispatch+0x22c/0x718 [nfsd]
> kernel: svc_process_common+0x8e8/0x1960 [sunrpc]
> kernel: svc_process+0x3d4/0x7e0 [sunrpc]
> kernel: svc_handle_xprt+0x828/0xe10 [sunrpc]
> kernel: svc_recv+0x2cc/0x6a8 [sunrpc]
> kernel: nfsd+0x270/0x400 [nfsd]
> kernel: kthread+0x288/0x310
> kernel: ret_from_fork+0x10/0x20
> 
> Proposing to have laundromat thread hold the state_lock over both
> marking thru revoking the delegation as well as making free_stateid
> acquire state_lock before accessing the list. Making sure that
> revoke_delegation() (ie kernel_setlease(unlock)) is called for
> every delegation that was revoked and added to the reaper list.
> 

Nice detective work!

> CC: stable@vger.kernel.org
> Signed-off-by: Olga Kornievskaia <okorniev@redhat.com>
> 
> --- I can't figure out the Fixes: tag. Laundromat's behaviour has
> been like that forever. But the free_stateid bits wont apply before
> the 1e3577a4521e ("SUNRPC: discard sv_refcnt, and svc_get/svc_put").
> But we used that fixes tag already with a previous fix for a different
> problem.
> ---
>  fs/nfsd/nfs4state.c | 4 +++-
>  1 file changed, 3 insertions(+), 1 deletion(-)
> 
> diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
> index 9c2b1d251ab3..c97907d7fb38 100644
> --- a/fs/nfsd/nfs4state.c
> +++ b/fs/nfsd/nfs4state.c
> @@ -6605,13 +6605,13 @@ nfs4_laundromat(struct nfsd_net *nn)
>  		unhash_delegation_locked(dp, SC_STATUS_REVOKED);
>  		list_add(&dp->dl_recall_lru, &reaplist);
>  	}
> -	spin_unlock(&state_lock);
>  	while (!list_empty(&reaplist)) {
>  		dp = list_first_entry(&reaplist, struct nfs4_delegation,
>  					dl_recall_lru);
>  		list_del_init(&dp->dl_recall_lru);
>  		revoke_delegation(dp);
>  	}
> +	spin_unlock(&state_lock);
>  
>  	spin_lock(&nn->client_lock);
>  	while (!list_empty(&nn->close_lru)) {
> @@ -7213,7 +7213,9 @@ nfsd4_free_stateid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
>  		if (s->sc_status & SC_STATUS_REVOKED) {
>  			spin_unlock(&s->sc_lock);
>  			dp = delegstateid(s);
> +			spin_lock(&state_lock);
>  			list_del_init(&dp->dl_recall_lru);
> +			spin_unlock(&state_lock);
>  			spin_unlock(&cl->cl_lock);
>  			nfs4_put_stid(s);
>  			ret = nfs_ok;


I'm not thrilled with this patch, but it does seem like it would fix
the problem. Long term, I think we need to get rid of the state_lock,
but I don't have a real plan for that just yet as it's not 100% clear
what it still protects.

As far as a Fixes tag, this bug is likely very old. I'd say it probably
got introduced here:

    2d4a532d385f nfsd: ensure that clp->cl_revoked list is protected by clp->cl_lock

In any case, let's go with this patch until we can come up with a
better plan for delegation handling.

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

  reply	other threads:[~2024-10-11 13:04 UTC|newest]

Thread overview: 11+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2024-10-10 22:18 [PATCH 1/1] nfsd: fix race between laundromat and free_stateid Olga Kornievskaia
2024-10-11 13:04 ` Jeff Layton [this message]
2024-10-11 13:14   ` Trond Myklebust
2024-10-11 13:43     ` Olga Kornievskaia
2024-10-11 13:59   ` Olga Kornievskaia
2024-10-11 14:39 ` Chuck Lever
2024-10-11 16:17   ` Jeff Layton
2024-10-11 20:01     ` Olga Kornievskaia
2024-10-11 20:16       ` Jeff Layton
2024-10-11 20:57         ` Olga Kornievskaia
2024-10-11 20:57   ` Trond Myklebust

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=ae0003013659a34279e3666180cd8b730ca3a2d8.camel@kernel.org \
    --to=jlayton@kernel.org \
    --cc=chuck.lever@oracle.com \
    --cc=linux-nfs@vger.kernel.org \
    --cc=okorniev@redhat.com \
    --cc=stable@vger.kernel.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 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.