Skip to content

Commit d7a5118

Browse files
amschuma-ntapTrond Myklebust
authored andcommitted
NFSv4.2: Update mode bits after ALLOCATE and DEALLOCATE
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 <[email protected]> Fixes: 913eca1 ("NFS: Fallocate should use the nfs4_fattr_bitmap") Signed-off-by: Anna Schumaker <[email protected]> Signed-off-by: Trond Myklebust <[email protected]>
1 parent 2a9d683 commit d7a5118

File tree

3 files changed

+32
-27
lines changed

3 files changed

+32
-27
lines changed

fs/nfs/internal.h

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -604,6 +604,31 @@ static inline gfp_t nfs_io_gfp_mask(void)
604604
return GFP_KERNEL;
605605
}
606606

607+
/*
608+
* Special version of should_remove_suid() that ignores capabilities.
609+
*/
610+
static inline int nfs_should_remove_suid(const struct inode *inode)
611+
{
612+
umode_t mode = inode->i_mode;
613+
int kill = 0;
614+
615+
/* suid always must be killed */
616+
if (unlikely(mode & S_ISUID))
617+
kill = ATTR_KILL_SUID;
618+
619+
/*
620+
* sgid without any exec bits is just a mandatory locking mark; leave
621+
* it alone. If some exec bits are set, it's a real sgid; kill it.
622+
*/
623+
if (unlikely((mode & S_ISGID) && (mode & S_IXGRP)))
624+
kill |= ATTR_KILL_SGID;
625+
626+
if (unlikely(kill && S_ISREG(mode)))
627+
return kill;
628+
629+
return 0;
630+
}
631+
607632
/* unlink.c */
608633
extern struct rpc_task *
609634
nfs_async_rename(struct inode *old_dir, struct inode *new_dir,

fs/nfs/nfs42proc.c

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -78,10 +78,15 @@ static int _nfs42_proc_fallocate(struct rpc_message *msg, struct file *filep,
7878

7979
status = nfs4_call_sync(server->client, server, msg,
8080
&args.seq_args, &res.seq_res, 0);
81-
if (status == 0)
81+
if (status == 0) {
82+
if (nfs_should_remove_suid(inode)) {
83+
spin_lock(&inode->i_lock);
84+
nfs_set_cache_invalid(inode, NFS_INO_INVALID_MODE);
85+
spin_unlock(&inode->i_lock);
86+
}
8287
status = nfs_post_op_update_inode_force_wcc(inode,
8388
res.falloc_fattr);
84-
89+
}
8590
if (msg->rpc_proc == &nfs4_procedures[NFSPROC4_CLNT_ALLOCATE])
8691
trace_nfs4_fallocate(inode, &args, status);
8792
else

fs/nfs/write.c

Lines changed: 0 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1496,31 +1496,6 @@ void nfs_commit_prepare(struct rpc_task *task, void *calldata)
14961496
NFS_PROTO(data->inode)->commit_rpc_prepare(task, data);
14971497
}
14981498

1499-
/*
1500-
* Special version of should_remove_suid() that ignores capabilities.
1501-
*/
1502-
static int nfs_should_remove_suid(const struct inode *inode)
1503-
{
1504-
umode_t mode = inode->i_mode;
1505-
int kill = 0;
1506-
1507-
/* suid always must be killed */
1508-
if (unlikely(mode & S_ISUID))
1509-
kill = ATTR_KILL_SUID;
1510-
1511-
/*
1512-
* sgid without any exec bits is just a mandatory locking mark; leave
1513-
* it alone. If some exec bits are set, it's a real sgid; kill it.
1514-
*/
1515-
if (unlikely((mode & S_ISGID) && (mode & S_IXGRP)))
1516-
kill |= ATTR_KILL_SGID;
1517-
1518-
if (unlikely(kill && S_ISREG(mode)))
1519-
return kill;
1520-
1521-
return 0;
1522-
}
1523-
15241499
static void nfs_writeback_check_extend(struct nfs_pgio_header *hdr,
15251500
struct nfs_fattr *fattr)
15261501
{

0 commit comments

Comments
 (0)