diff options
author | Trond Myklebust <Trond.Myklebust@netapp.com> | 2005-08-16 11:49:44 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2005-08-16 12:30:58 -0400 |
commit | 65e4308d2500e7daf60c3dccc202c61ffb066c63 (patch) | |
tree | 76a2e00004f645d09b2e59b485fb2aea0af45234 /fs/nfs | |
parent | 367ae3cd74bdc2ad32d71293427fec570b14ddcd (diff) |
[PATCH] NFS: Ensure we always update inode->i_mode when doing O_EXCL creates
When the client performs an exclusive create and opens the file for writing,
a Netapp filer will first create the file using the mode 01777. It does this
since an NFSv3/v4 exclusive create cannot immediately set the mode bits.
The 01777 mode then gets put into the inode->i_mode. After the file creation
is successful, we then do a setattr to change the mode to the correct value
(as per the NFS spec).
The problem is that nfs_refresh_inode() no longer updates inode->i_mode, so
the latter retains the 01777 mode. A bit later, the VFS notices this, and calls
remove_suid(). This of course now resets the file mode to inode->i_mode & 0777.
Hey presto, the file mode on the server is now magically changed to 0777. Duh...
Fixes http://bugzilla.linux-nfs.org/show_bug.cgi?id=32
Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'fs/nfs')
-rw-r--r-- | fs/nfs/inode.c | 37 | ||||
-rw-r--r-- | fs/nfs/nfs3proc.c | 4 | ||||
-rw-r--r-- | fs/nfs/nfs4proc.c | 10 | ||||
-rw-r--r-- | fs/nfs/proc.c | 2 |
4 files changed, 38 insertions, 15 deletions
diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c index 4845911f1c63..bb7ca022bcb2 100644 --- a/fs/nfs/inode.c +++ b/fs/nfs/inode.c | |||
@@ -814,28 +814,39 @@ nfs_setattr(struct dentry *dentry, struct iattr *attr) | |||
814 | nfs_wb_all(inode); | 814 | nfs_wb_all(inode); |
815 | } | 815 | } |
816 | error = NFS_PROTO(inode)->setattr(dentry, &fattr, attr); | 816 | error = NFS_PROTO(inode)->setattr(dentry, &fattr, attr); |
817 | if (error == 0) { | 817 | if (error == 0) |
818 | nfs_refresh_inode(inode, &fattr); | 818 | nfs_refresh_inode(inode, &fattr); |
819 | nfs_end_data_update(inode); | ||
820 | unlock_kernel(); | ||
821 | return error; | ||
822 | } | ||
823 | |||
824 | /** | ||
825 | * nfs_setattr_update_inode - Update inode metadata after a setattr call. | ||
826 | * @inode: pointer to struct inode | ||
827 | * @attr: pointer to struct iattr | ||
828 | * | ||
829 | * Note: we do this in the *proc.c in order to ensure that | ||
830 | * it works for things like exclusive creates too. | ||
831 | */ | ||
832 | void nfs_setattr_update_inode(struct inode *inode, struct iattr *attr) | ||
833 | { | ||
834 | if ((attr->ia_valid & (ATTR_MODE|ATTR_UID|ATTR_GID)) != 0) { | ||
819 | if ((attr->ia_valid & ATTR_MODE) != 0) { | 835 | if ((attr->ia_valid & ATTR_MODE) != 0) { |
820 | int mode; | 836 | int mode = attr->ia_mode & S_IALLUGO; |
821 | mode = inode->i_mode & ~S_IALLUGO; | 837 | mode |= inode->i_mode & ~S_IALLUGO; |
822 | mode |= attr->ia_mode & S_IALLUGO; | ||
823 | inode->i_mode = mode; | 838 | inode->i_mode = mode; |
824 | } | 839 | } |
825 | if ((attr->ia_valid & ATTR_UID) != 0) | 840 | if ((attr->ia_valid & ATTR_UID) != 0) |
826 | inode->i_uid = attr->ia_uid; | 841 | inode->i_uid = attr->ia_uid; |
827 | if ((attr->ia_valid & ATTR_GID) != 0) | 842 | if ((attr->ia_valid & ATTR_GID) != 0) |
828 | inode->i_gid = attr->ia_gid; | 843 | inode->i_gid = attr->ia_gid; |
829 | if ((attr->ia_valid & ATTR_SIZE) != 0) { | ||
830 | inode->i_size = attr->ia_size; | ||
831 | vmtruncate(inode, attr->ia_size); | ||
832 | } | ||
833 | } | ||
834 | if ((attr->ia_valid & (ATTR_MODE|ATTR_UID|ATTR_GID)) != 0) | ||
835 | NFS_FLAGS(inode) |= NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ACL; | 844 | NFS_FLAGS(inode) |= NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ACL; |
836 | nfs_end_data_update(inode); | 845 | } |
837 | unlock_kernel(); | 846 | if ((attr->ia_valid & ATTR_SIZE) != 0) { |
838 | return error; | 847 | inode->i_size = attr->ia_size; |
848 | vmtruncate(inode, attr->ia_size); | ||
849 | } | ||
839 | } | 850 | } |
840 | 851 | ||
841 | /* | 852 | /* |
diff --git a/fs/nfs/nfs3proc.c b/fs/nfs/nfs3proc.c index 7851569b31c6..2681485cf2d0 100644 --- a/fs/nfs/nfs3proc.c +++ b/fs/nfs/nfs3proc.c | |||
@@ -120,6 +120,8 @@ nfs3_proc_setattr(struct dentry *dentry, struct nfs_fattr *fattr, | |||
120 | dprintk("NFS call setattr\n"); | 120 | dprintk("NFS call setattr\n"); |
121 | fattr->valid = 0; | 121 | fattr->valid = 0; |
122 | status = rpc_call(NFS_CLIENT(inode), NFS3PROC_SETATTR, &arg, fattr, 0); | 122 | status = rpc_call(NFS_CLIENT(inode), NFS3PROC_SETATTR, &arg, fattr, 0); |
123 | if (status == 0) | ||
124 | nfs_setattr_update_inode(inode, sattr); | ||
123 | dprintk("NFS reply setattr: %d\n", status); | 125 | dprintk("NFS reply setattr: %d\n", status); |
124 | return status; | 126 | return status; |
125 | } | 127 | } |
@@ -370,6 +372,8 @@ again: | |||
370 | * not sure this buys us anything (and I'd have | 372 | * not sure this buys us anything (and I'd have |
371 | * to revamp the NFSv3 XDR code) */ | 373 | * to revamp the NFSv3 XDR code) */ |
372 | status = nfs3_proc_setattr(dentry, &fattr, sattr); | 374 | status = nfs3_proc_setattr(dentry, &fattr, sattr); |
375 | if (status == 0) | ||
376 | nfs_setattr_update_inode(dentry->d_inode, sattr); | ||
373 | nfs_refresh_inode(dentry->d_inode, &fattr); | 377 | nfs_refresh_inode(dentry->d_inode, &fattr); |
374 | dprintk("NFS reply setattr (post-create): %d\n", status); | 378 | dprintk("NFS reply setattr (post-create): %d\n", status); |
375 | } | 379 | } |
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 1b76f80aedb9..0c5a308e4963 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c | |||
@@ -753,6 +753,7 @@ static int _nfs4_do_setattr(struct nfs_server *server, struct nfs_fattr *fattr, | |||
753 | .rpc_argp = &arg, | 753 | .rpc_argp = &arg, |
754 | .rpc_resp = &res, | 754 | .rpc_resp = &res, |
755 | }; | 755 | }; |
756 | int status; | ||
756 | 757 | ||
757 | fattr->valid = 0; | 758 | fattr->valid = 0; |
758 | 759 | ||
@@ -762,7 +763,8 @@ static int _nfs4_do_setattr(struct nfs_server *server, struct nfs_fattr *fattr, | |||
762 | } else | 763 | } else |
763 | memcpy(&arg.stateid, &zero_stateid, sizeof(arg.stateid)); | 764 | memcpy(&arg.stateid, &zero_stateid, sizeof(arg.stateid)); |
764 | 765 | ||
765 | return rpc_call_sync(server->client, &msg, 0); | 766 | status = rpc_call_sync(server->client, &msg, 0); |
767 | return status; | ||
766 | } | 768 | } |
767 | 769 | ||
768 | static int nfs4_do_setattr(struct nfs_server *server, struct nfs_fattr *fattr, | 770 | static int nfs4_do_setattr(struct nfs_server *server, struct nfs_fattr *fattr, |
@@ -1145,6 +1147,8 @@ nfs4_proc_setattr(struct dentry *dentry, struct nfs_fattr *fattr, | |||
1145 | 1147 | ||
1146 | status = nfs4_do_setattr(NFS_SERVER(inode), fattr, | 1148 | status = nfs4_do_setattr(NFS_SERVER(inode), fattr, |
1147 | NFS_FH(inode), sattr, state); | 1149 | NFS_FH(inode), sattr, state); |
1150 | if (status == 0) | ||
1151 | nfs_setattr_update_inode(inode, sattr); | ||
1148 | if (state != NULL) | 1152 | if (state != NULL) |
1149 | nfs4_close_state(state, FMODE_WRITE); | 1153 | nfs4_close_state(state, FMODE_WRITE); |
1150 | put_rpccred(cred); | 1154 | put_rpccred(cred); |
@@ -1449,8 +1453,10 @@ nfs4_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr, | |||
1449 | struct nfs_fattr fattr; | 1453 | struct nfs_fattr fattr; |
1450 | status = nfs4_do_setattr(NFS_SERVER(dir), &fattr, | 1454 | status = nfs4_do_setattr(NFS_SERVER(dir), &fattr, |
1451 | NFS_FH(state->inode), sattr, state); | 1455 | NFS_FH(state->inode), sattr, state); |
1452 | if (status == 0) | 1456 | if (status == 0) { |
1457 | nfs_setattr_update_inode(state->inode, sattr); | ||
1453 | goto out; | 1458 | goto out; |
1459 | } | ||
1454 | } else if (flags != 0) | 1460 | } else if (flags != 0) |
1455 | goto out; | 1461 | goto out; |
1456 | nfs4_close_state(state, flags); | 1462 | nfs4_close_state(state, flags); |
diff --git a/fs/nfs/proc.c b/fs/nfs/proc.c index cedf636bcf3c..be23c3fb9260 100644 --- a/fs/nfs/proc.c +++ b/fs/nfs/proc.c | |||
@@ -114,6 +114,8 @@ nfs_proc_setattr(struct dentry *dentry, struct nfs_fattr *fattr, | |||
114 | dprintk("NFS call setattr\n"); | 114 | dprintk("NFS call setattr\n"); |
115 | fattr->valid = 0; | 115 | fattr->valid = 0; |
116 | status = rpc_call(NFS_CLIENT(inode), NFSPROC_SETATTR, &arg, fattr, 0); | 116 | status = rpc_call(NFS_CLIENT(inode), NFSPROC_SETATTR, &arg, fattr, 0); |
117 | if (status == 0) | ||
118 | nfs_setattr_update_inode(inode, sattr); | ||
117 | dprintk("NFS reply setattr: %d\n", status); | 119 | dprintk("NFS reply setattr: %d\n", status); |
118 | return status; | 120 | return status; |
119 | } | 121 | } |