aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorTrond Myklebust <Trond.Myklebust@netapp.com>2009-07-21 19:22:38 -0400
committerTrond Myklebust <Trond.Myklebust@netapp.com>2009-07-21 19:22:38 -0400
commitd953126a28f97ec965d23c69fd5795854c048f30 (patch)
treed3f239909dac00e1bc7882a783b8b63b20345d4d /fs
parentfccba8045537f7e840d0e7565e1989d465e488a3 (diff)
NFSv4: Fix a problem whereby a buggy server can oops the kernel
We just had a case in which a buggy server occasionally returns the wrong attributes during an OPEN call. While the client does catch this sort of condition in nfs4_open_done(), and causes the nfs4_atomic_open() to return -EISDIR, the logic in nfs_atomic_lookup() is broken, since it causes a fallback to an ordinary lookup instead of just returning the error. When the buggy server then returns a regular file for the fallback lookup, the VFS allows the open, and bad things start to happen, since the open file doesn't have any associated NFSv4 state. The fix is firstly to return the EISDIR/ENOTDIR errors immediately, and secondly to ensure that we are always careful when dereferencing the nfs_open_context state pointer. Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
Diffstat (limited to 'fs')
-rw-r--r--fs/nfs/dir.c2
-rw-r--r--fs/nfs/nfs4proc.c16
2 files changed, 13 insertions, 5 deletions
diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c
index 38d42c29fb92..32062c33c859 100644
--- a/fs/nfs/dir.c
+++ b/fs/nfs/dir.c
@@ -1025,12 +1025,12 @@ static struct dentry *nfs_atomic_lookup(struct inode *dir, struct dentry *dentry
1025 res = NULL; 1025 res = NULL;
1026 goto out; 1026 goto out;
1027 /* This turned out not to be a regular file */ 1027 /* This turned out not to be a regular file */
1028 case -EISDIR:
1029 case -ENOTDIR: 1028 case -ENOTDIR:
1030 goto no_open; 1029 goto no_open;
1031 case -ELOOP: 1030 case -ELOOP:
1032 if (!(nd->intent.open.flags & O_NOFOLLOW)) 1031 if (!(nd->intent.open.flags & O_NOFOLLOW))
1033 goto no_open; 1032 goto no_open;
1033 /* case -EISDIR: */
1034 /* case -EINVAL: */ 1034 /* case -EINVAL: */
1035 default: 1035 default:
1036 goto out; 1036 goto out;
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
index df24f67bca69..6917311f201c 100644
--- a/fs/nfs/nfs4proc.c
+++ b/fs/nfs/nfs4proc.c
@@ -4093,15 +4093,23 @@ nfs4_proc_lock(struct file *filp, int cmd, struct file_lock *request)
4093 if (request->fl_start < 0 || request->fl_end < 0) 4093 if (request->fl_start < 0 || request->fl_end < 0)
4094 return -EINVAL; 4094 return -EINVAL;
4095 4095
4096 if (IS_GETLK(cmd)) 4096 if (IS_GETLK(cmd)) {
4097 return nfs4_proc_getlk(state, F_GETLK, request); 4097 if (state != NULL)
4098 return nfs4_proc_getlk(state, F_GETLK, request);
4099 return 0;
4100 }
4098 4101
4099 if (!(IS_SETLK(cmd) || IS_SETLKW(cmd))) 4102 if (!(IS_SETLK(cmd) || IS_SETLKW(cmd)))
4100 return -EINVAL; 4103 return -EINVAL;
4101 4104
4102 if (request->fl_type == F_UNLCK) 4105 if (request->fl_type == F_UNLCK) {
4103 return nfs4_proc_unlck(state, cmd, request); 4106 if (state != NULL)
4107 return nfs4_proc_unlck(state, cmd, request);
4108 return 0;
4109 }
4104 4110
4111 if (state == NULL)
4112 return -ENOLCK;
4105 do { 4113 do {
4106 status = nfs4_proc_setlk(state, cmd, request); 4114 status = nfs4_proc_setlk(state, cmd, request);
4107 if ((status != -EAGAIN) || IS_SETLK(cmd)) 4115 if ((status != -EAGAIN) || IS_SETLK(cmd))