]> git.itanic.dy.fi Git - linux-stable/commitdiff
NFSv4.2: Update mode bits after ALLOCATE and DEALLOCATE
authorAnna Schumaker <Anna.Schumaker@Netapp.com>
Wed, 7 Sep 2022 20:34:21 +0000 (16:34 -0400)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Fri, 23 Sep 2022 12:14:02 +0000 (14:14 +0200)
[ Upstream commit d7a5118635e725d195843bda80cc5c964d93ef31 ]

The fallocate call invalidates suid and sgid bits as part of normal
operation. We need to mark the mode bits as invalid when using fallocate
with an suid so these will be updated the next time the user looks at them.

This fixes xfstests generic/683 and generic/684.

Reported-by: Yue Cui <cuiyue-fnst@fujitsu.com>
Fixes: 913eca1aea87 ("NFS: Fallocate should use the nfs4_fattr_bitmap")
Signed-off-by: Anna Schumaker <Anna.Schumaker@Netapp.com>
Signed-off-by: Trond Myklebust <trond.myklebust@hammerspace.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
fs/nfs/internal.h
fs/nfs/nfs42proc.c
fs/nfs/write.c

index 8f8cd6e2d4dbcb83223cc95d575daf652a056836..597e3ce3f148aec1fe56d2a852f7580907fe0308 100644 (file)
@@ -604,6 +604,31 @@ static inline gfp_t nfs_io_gfp_mask(void)
        return GFP_KERNEL;
 }
 
+/*
+ * Special version of should_remove_suid() that ignores capabilities.
+ */
+static inline int nfs_should_remove_suid(const struct inode *inode)
+{
+       umode_t mode = inode->i_mode;
+       int kill = 0;
+
+       /* suid always must be killed */
+       if (unlikely(mode & S_ISUID))
+               kill = ATTR_KILL_SUID;
+
+       /*
+        * sgid without any exec bits is just a mandatory locking mark; leave
+        * it alone.  If some exec bits are set, it's a real sgid; kill it.
+        */
+       if (unlikely((mode & S_ISGID) && (mode & S_IXGRP)))
+               kill |= ATTR_KILL_SGID;
+
+       if (unlikely(kill && S_ISREG(mode)))
+               return kill;
+
+       return 0;
+}
+
 /* unlink.c */
 extern struct rpc_task *
 nfs_async_rename(struct inode *old_dir, struct inode *new_dir,
index 068c45b3bc1ab19593441cc5b336e5e50a5e4322..6dab9e40837298405f98617b64076f7a6ce79f90 100644 (file)
@@ -78,10 +78,15 @@ static int _nfs42_proc_fallocate(struct rpc_message *msg, struct file *filep,
 
        status = nfs4_call_sync(server->client, server, msg,
                                &args.seq_args, &res.seq_res, 0);
-       if (status == 0)
+       if (status == 0) {
+               if (nfs_should_remove_suid(inode)) {
+                       spin_lock(&inode->i_lock);
+                       nfs_set_cache_invalid(inode, NFS_INO_INVALID_MODE);
+                       spin_unlock(&inode->i_lock);
+               }
                status = nfs_post_op_update_inode_force_wcc(inode,
                                                            res.falloc_fattr);
-
+       }
        if (msg->rpc_proc == &nfs4_procedures[NFSPROC4_CLNT_ALLOCATE])
                trace_nfs4_fallocate(inode, &args, status);
        else
index 5d7e1c2061842b113c188ecd90333699830b3eaa..4212473c69ee92e0f4fe295f309c2c13d4ae3aa4 100644 (file)
@@ -1497,31 +1497,6 @@ void nfs_commit_prepare(struct rpc_task *task, void *calldata)
        NFS_PROTO(data->inode)->commit_rpc_prepare(task, data);
 }
 
-/*
- * Special version of should_remove_suid() that ignores capabilities.
- */
-static int nfs_should_remove_suid(const struct inode *inode)
-{
-       umode_t mode = inode->i_mode;
-       int kill = 0;
-
-       /* suid always must be killed */
-       if (unlikely(mode & S_ISUID))
-               kill = ATTR_KILL_SUID;
-
-       /*
-        * sgid without any exec bits is just a mandatory locking mark; leave
-        * it alone.  If some exec bits are set, it's a real sgid; kill it.
-        */
-       if (unlikely((mode & S_ISGID) && (mode & S_IXGRP)))
-               kill |= ATTR_KILL_SGID;
-
-       if (unlikely(kill && S_ISREG(mode)))
-               return kill;
-
-       return 0;
-}
-
 static void nfs_writeback_check_extend(struct nfs_pgio_header *hdr,
                struct nfs_fattr *fattr)
 {