Patch "nfsd: don't hand out delegation on setuid files being opened for write" has been added to the 5.15-stable tree

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



This is a note to let you know that I've just added the patch titled

    nfsd: don't hand out delegation on setuid files being opened for write

to the 5.15-stable tree which can be found at:
    http://www.kernel.org/git/?p=linux/kernel/git/stable/stable-queue.git;a=summary

The filename of the patch is:
     nfsd-don-t-hand-out-delegation-on-setuid-files-being.patch
and it can be found in the queue-5.15 subdirectory.

If you, or anyone else, feels it should not be added to the stable tree,
please let <stable@xxxxxxxxxxxxxxx> know about it.



commit e751e3ff63fbe7ec09358c4583b75400afc612f2
Author: Jeff Layton <jlayton@xxxxxxxxxx>
Date:   Fri Jan 27 07:09:33 2023 -0500

    nfsd: don't hand out delegation on setuid files being opened for write
    
    [ Upstream commit 826b67e6376c2a788e3a62c4860dcd79500a27d5 ]
    
    We had a bug report that xfstest generic/355 was failing on NFSv4.0.
    This test sets various combinations of setuid/setgid modes and tests
    whether DIO writes will cause them to be stripped.
    
    What I found was that the server did properly strip those bits, but
    the client didn't notice because it held a delegation that was not
    recalled. The recall didn't occur because the client itself was the
    one generating the activity and we avoid recalls in that case.
    
    Clearing setuid bits is an "implicit" activity. The client didn't
    specifically request that we do that, so we need the server to issue a
    CB_RECALL, or avoid the situation entirely by not issuing a delegation.
    
    The easiest fix here is to simply not give out a delegation if the file
    is being opened for write, and the mode has the setuid and/or setgid bit
    set. Note that there is a potential race between the mode and lease
    being set, so we test for this condition both before and after setting
    the lease.
    
    This patch fixes generic/355, generic/683 and generic/684 for me. (Note
    that 355 fails only on v4.0, and 683 and 684 require NFSv4.2 to run and
    fail).
    
    Reported-by: Boyang Xue <bxue@xxxxxxxxxx>
    Signed-off-by: Jeff Layton <jlayton@xxxxxxxxxx>
    Signed-off-by: Chuck Lever <chuck.lever@xxxxxxxxxx>

diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index 628e564e530bf..773971a75b62d 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -5439,6 +5439,23 @@ nfsd4_verify_deleg_dentry(struct nfsd4_open *open, struct nfs4_file *fp,
 	return 0;
 }
 
+/*
+ * We avoid breaking delegations held by a client due to its own activity, but
+ * clearing setuid/setgid bits on a write is an implicit activity and the client
+ * may not notice and continue using the old mode. Avoid giving out a delegation
+ * on setuid/setgid files when the client is requesting an open for write.
+ */
+static int
+nfsd4_verify_setuid_write(struct nfsd4_open *open, struct nfsd_file *nf)
+{
+	struct inode *inode = file_inode(nf->nf_file);
+
+	if ((open->op_share_access & NFS4_SHARE_ACCESS_WRITE) &&
+	    (inode->i_mode & (S_ISUID|S_ISGID)))
+		return -EAGAIN;
+	return 0;
+}
+
 static struct nfs4_delegation *
 nfs4_set_delegation(struct nfsd4_open *open, struct nfs4_ol_stateid *stp,
 		    struct svc_fh *parent)
@@ -5472,6 +5489,8 @@ nfs4_set_delegation(struct nfsd4_open *open, struct nfs4_ol_stateid *stp,
 	spin_lock(&fp->fi_lock);
 	if (nfs4_delegation_exists(clp, fp))
 		status = -EAGAIN;
+	else if (nfsd4_verify_setuid_write(open, nf))
+		status = -EAGAIN;
 	else if (!fp->fi_deleg_file) {
 		fp->fi_deleg_file = nf;
 		/* increment early to prevent fi_deleg_file from being
@@ -5512,6 +5531,14 @@ nfs4_set_delegation(struct nfsd4_open *open, struct nfs4_ol_stateid *stp,
 	if (status)
 		goto out_unlock;
 
+	/*
+	 * Now that the deleg is set, check again to ensure that nothing
+	 * raced in and changed the mode while we weren't lookng.
+	 */
+	status = nfsd4_verify_setuid_write(open, fp->fi_deleg_file);
+	if (status)
+		goto out_unlock;
+
 	spin_lock(&state_lock);
 	spin_lock(&fp->fi_lock);
 	if (fp->fi_had_conflict)




[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Index of Archives]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux