NFS: Don't ignore suid/sgid bit changes after a successful write
If we suspect that the server may have cleared the suid/sgid bit, then mark the inode for revalidation. Reported-by: Kinglong Mee <kinglongmee@gmail.com> Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com>
This commit is contained in:
parent
43b6535e71
commit
1f2edbe3fe
|
@ -1353,6 +1353,30 @@ static const struct rpc_call_ops nfs_write_common_ops = {
|
|||
.rpc_release = nfs_writeback_release_common,
|
||||
};
|
||||
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
|
||||
/*
|
||||
* This function is called when the WRITE call is complete.
|
||||
|
@ -1401,9 +1425,16 @@ void nfs_writeback_done(struct rpc_task *task, struct nfs_write_data *data)
|
|||
}
|
||||
}
|
||||
#endif
|
||||
if (task->tk_status < 0)
|
||||
if (task->tk_status < 0) {
|
||||
nfs_set_pgio_error(data->header, task->tk_status, argp->offset);
|
||||
else if (resp->count < argp->count) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Deal with the suid/sgid bit corner case */
|
||||
if (nfs_should_remove_suid(inode))
|
||||
nfs_mark_for_revalidate(inode);
|
||||
|
||||
if (resp->count < argp->count) {
|
||||
static unsigned long complain;
|
||||
|
||||
/* This a short write! */
|
||||
|
|
Loading…
Reference in New Issue
Block a user