Commit 659bfcd6 authored by Trond Myklebust's avatar Trond Myklebust

NFS: Fix the ftruncate() credential problem

ftruncate() access checking is supposed to be performed at open() time,
just like reads and writes.
Signed-off-by: default avatarTrond Myklebust <Trond.Myklebust@netapp.com>
parent a486aeda
...@@ -347,7 +347,7 @@ nfs_fhget(struct super_block *sb, struct nfs_fh *fh, struct nfs_fattr *fattr) ...@@ -347,7 +347,7 @@ nfs_fhget(struct super_block *sb, struct nfs_fh *fh, struct nfs_fattr *fattr)
goto out; goto out;
} }
#define NFS_VALID_ATTRS (ATTR_MODE|ATTR_UID|ATTR_GID|ATTR_SIZE|ATTR_ATIME|ATTR_ATIME_SET|ATTR_MTIME|ATTR_MTIME_SET) #define NFS_VALID_ATTRS (ATTR_MODE|ATTR_UID|ATTR_GID|ATTR_SIZE|ATTR_ATIME|ATTR_ATIME_SET|ATTR_MTIME|ATTR_MTIME_SET|ATTR_FILE)
int int
nfs_setattr(struct dentry *dentry, struct iattr *attr) nfs_setattr(struct dentry *dentry, struct iattr *attr)
...@@ -369,7 +369,7 @@ nfs_setattr(struct dentry *dentry, struct iattr *attr) ...@@ -369,7 +369,7 @@ nfs_setattr(struct dentry *dentry, struct iattr *attr)
/* Optimization: if the end result is no change, don't RPC */ /* Optimization: if the end result is no change, don't RPC */
attr->ia_valid &= NFS_VALID_ATTRS; attr->ia_valid &= NFS_VALID_ATTRS;
if (attr->ia_valid == 0) if ((attr->ia_valid & ~ATTR_FILE) == 0)
return 0; return 0;
lock_kernel(); lock_kernel();
......
...@@ -129,6 +129,8 @@ nfs3_proc_setattr(struct dentry *dentry, struct nfs_fattr *fattr, ...@@ -129,6 +129,8 @@ nfs3_proc_setattr(struct dentry *dentry, struct nfs_fattr *fattr,
int status; int status;
dprintk("NFS call setattr\n"); dprintk("NFS call setattr\n");
if (sattr->ia_valid & ATTR_FILE)
msg.rpc_cred = nfs_file_cred(sattr->ia_file);
nfs_fattr_init(fattr); nfs_fattr_init(fattr);
status = rpc_call_sync(NFS_CLIENT(inode), &msg, 0); status = rpc_call_sync(NFS_CLIENT(inode), &msg, 0);
if (status == 0) if (status == 0)
......
...@@ -1139,8 +1139,9 @@ static struct nfs4_state *nfs4_do_open(struct inode *dir, struct path *path, int ...@@ -1139,8 +1139,9 @@ static struct nfs4_state *nfs4_do_open(struct inode *dir, struct path *path, int
return res; return res;
} }
static int _nfs4_do_setattr(struct inode *inode, struct nfs_fattr *fattr, static int _nfs4_do_setattr(struct inode *inode, struct rpc_cred *cred,
struct iattr *sattr, struct nfs4_state *state) struct nfs_fattr *fattr, struct iattr *sattr,
struct nfs4_state *state)
{ {
struct nfs_server *server = NFS_SERVER(inode); struct nfs_server *server = NFS_SERVER(inode);
struct nfs_setattrargs arg = { struct nfs_setattrargs arg = {
...@@ -1154,9 +1155,10 @@ static int _nfs4_do_setattr(struct inode *inode, struct nfs_fattr *fattr, ...@@ -1154,9 +1155,10 @@ static int _nfs4_do_setattr(struct inode *inode, struct nfs_fattr *fattr,
.server = server, .server = server,
}; };
struct rpc_message msg = { struct rpc_message msg = {
.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_SETATTR], .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_SETATTR],
.rpc_argp = &arg, .rpc_argp = &arg,
.rpc_resp = &res, .rpc_resp = &res,
.rpc_cred = cred,
}; };
unsigned long timestamp = jiffies; unsigned long timestamp = jiffies;
int status; int status;
...@@ -1166,7 +1168,6 @@ static int _nfs4_do_setattr(struct inode *inode, struct nfs_fattr *fattr, ...@@ -1166,7 +1168,6 @@ static int _nfs4_do_setattr(struct inode *inode, struct nfs_fattr *fattr,
if (nfs4_copy_delegation_stateid(&arg.stateid, inode)) { if (nfs4_copy_delegation_stateid(&arg.stateid, inode)) {
/* Use that stateid */ /* Use that stateid */
} else if (state != NULL) { } else if (state != NULL) {
msg.rpc_cred = state->owner->so_cred;
nfs4_copy_stateid(&arg.stateid, state, current->files); nfs4_copy_stateid(&arg.stateid, state, current->files);
} else } else
memcpy(&arg.stateid, &zero_stateid, sizeof(arg.stateid)); memcpy(&arg.stateid, &zero_stateid, sizeof(arg.stateid));
...@@ -1177,15 +1178,16 @@ static int _nfs4_do_setattr(struct inode *inode, struct nfs_fattr *fattr, ...@@ -1177,15 +1178,16 @@ static int _nfs4_do_setattr(struct inode *inode, struct nfs_fattr *fattr,
return status; return status;
} }
static int nfs4_do_setattr(struct inode *inode, struct nfs_fattr *fattr, static int nfs4_do_setattr(struct inode *inode, struct rpc_cred *cred,
struct iattr *sattr, struct nfs4_state *state) struct nfs_fattr *fattr, struct iattr *sattr,
struct nfs4_state *state)
{ {
struct nfs_server *server = NFS_SERVER(inode); struct nfs_server *server = NFS_SERVER(inode);
struct nfs4_exception exception = { }; struct nfs4_exception exception = { };
int err; int err;
do { do {
err = nfs4_handle_exception(server, err = nfs4_handle_exception(server,
_nfs4_do_setattr(inode, fattr, sattr, state), _nfs4_do_setattr(inode, cred, fattr, sattr, state),
&exception); &exception);
} while (exception.retry); } while (exception.retry);
return err; return err;
...@@ -1647,29 +1649,25 @@ static int ...@@ -1647,29 +1649,25 @@ static int
nfs4_proc_setattr(struct dentry *dentry, struct nfs_fattr *fattr, nfs4_proc_setattr(struct dentry *dentry, struct nfs_fattr *fattr,
struct iattr *sattr) struct iattr *sattr)
{ {
struct rpc_cred *cred;
struct inode *inode = dentry->d_inode; struct inode *inode = dentry->d_inode;
struct nfs_open_context *ctx; struct rpc_cred *cred = NULL;
struct nfs4_state *state = NULL; struct nfs4_state *state = NULL;
int status; int status;
nfs_fattr_init(fattr); nfs_fattr_init(fattr);
cred = rpc_lookup_cred();
if (IS_ERR(cred))
return PTR_ERR(cred);
/* Search for an existing open(O_WRITE) file */ /* Search for an existing open(O_WRITE) file */
ctx = nfs_find_open_context(inode, cred, FMODE_WRITE); if (sattr->ia_valid & ATTR_FILE) {
if (ctx != NULL) struct nfs_open_context *ctx;
ctx = nfs_file_open_context(sattr->ia_file);
cred = ctx->cred;
state = ctx->state; state = ctx->state;
}
status = nfs4_do_setattr(inode, fattr, sattr, state); status = nfs4_do_setattr(inode, cred, fattr, sattr, state);
if (status == 0) if (status == 0)
nfs_setattr_update_inode(inode, sattr); nfs_setattr_update_inode(inode, sattr);
if (ctx != NULL)
put_nfs_open_context(ctx);
put_rpccred(cred);
return status; return status;
} }
...@@ -1897,17 +1895,16 @@ nfs4_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr, ...@@ -1897,17 +1895,16 @@ nfs4_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr,
goto out; goto out;
} }
state = nfs4_do_open(dir, &path, flags, sattr, cred); state = nfs4_do_open(dir, &path, flags, sattr, cred);
put_rpccred(cred);
d_drop(dentry); d_drop(dentry);
if (IS_ERR(state)) { if (IS_ERR(state)) {
status = PTR_ERR(state); status = PTR_ERR(state);
goto out; goto out_putcred;
} }
d_add(dentry, igrab(state->inode)); d_add(dentry, igrab(state->inode));
nfs_set_verifier(dentry, nfs_save_change_attribute(dir)); nfs_set_verifier(dentry, nfs_save_change_attribute(dir));
if (flags & O_EXCL) { if (flags & O_EXCL) {
struct nfs_fattr fattr; struct nfs_fattr fattr;
status = nfs4_do_setattr(state->inode, &fattr, sattr, state); status = nfs4_do_setattr(state->inode, cred, &fattr, sattr, state);
if (status == 0) if (status == 0)
nfs_setattr_update_inode(state->inode, sattr); nfs_setattr_update_inode(state->inode, sattr);
nfs_post_op_update_inode(state->inode, &fattr); nfs_post_op_update_inode(state->inode, &fattr);
...@@ -1916,6 +1913,8 @@ nfs4_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr, ...@@ -1916,6 +1913,8 @@ nfs4_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr,
status = nfs4_intent_set_file(nd, &path, state); status = nfs4_intent_set_file(nd, &path, state);
else else
nfs4_close_sync(&path, state, flags); nfs4_close_sync(&path, state, flags);
out_putcred:
put_rpccred(cred);
out: out:
return status; return status;
} }
......
...@@ -129,6 +129,8 @@ nfs_proc_setattr(struct dentry *dentry, struct nfs_fattr *fattr, ...@@ -129,6 +129,8 @@ nfs_proc_setattr(struct dentry *dentry, struct nfs_fattr *fattr,
sattr->ia_mode &= S_IALLUGO; sattr->ia_mode &= S_IALLUGO;
dprintk("NFS call setattr\n"); dprintk("NFS call setattr\n");
if (sattr->ia_valid & ATTR_FILE)
msg.rpc_cred = nfs_file_cred(sattr->ia_file);
nfs_fattr_init(fattr); nfs_fattr_init(fattr);
status = rpc_call_sync(NFS_CLIENT(inode), &msg, 0); status = rpc_call_sync(NFS_CLIENT(inode), &msg, 0);
if (status == 0) if (status == 0)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment