diff options
author | Jeff Layton <jlayton@redhat.com> | 2012-02-23 09:37:45 -0500 |
---|---|---|
committer | Steve French <smfrench@gmail.com> | 2012-02-26 23:16:26 -0600 |
commit | 5bccda0ebc7c0331b81ac47d39e4b920b198b2cd (patch) | |
tree | 542363c187479df4124bed5441a7fc66bafc4065 | |
parent | 6de2ce423157d06f73d570ef7044f08c2f8697da (diff) | |
download | linux-5bccda0ebc7c0331b81ac47d39e4b920b198b2cd.tar.gz linux-5bccda0ebc7c0331b81ac47d39e4b920b198b2cd.tar.bz2 linux-5bccda0ebc7c0331b81ac47d39e4b920b198b2cd.zip |
cifs: fix dentry refcount leak when opening a FIFO on lookup
The cifs code will attempt to open files on lookup under certain
circumstances. What happens though if we find that the file we opened
was actually a FIFO or other special file?
Currently, the open filehandle just ends up being leaked leading to
a dentry refcount mismatch and oops on umount. Fix this by having the
code close the filehandle on the server if it turns out not to be a
regular file. While we're at it, change this spaghetti if statement
into a switch too.
Cc: stable@vger.kernel.org
Reported-by: CAI Qian <caiqian@redhat.com>
Tested-by: CAI Qian <caiqian@redhat.com>
Reviewed-by: Shirish Pargaonkar <shirishpargaonkar@gmail.com>
Signed-off-by: Jeff Layton <jlayton@redhat.com>
Signed-off-by: Steve French <smfrench@gmail.com>
-rw-r--r-- | fs/cifs/dir.c | 20 |
1 files changed, 18 insertions, 2 deletions
diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c index 63a196b97d50..bc7e24420ac0 100644 --- a/fs/cifs/dir.c +++ b/fs/cifs/dir.c @@ -584,10 +584,26 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry, * If either that or op not supported returned, follow * the normal lookup. */ - if ((rc == 0) || (rc == -ENOENT)) + switch (rc) { + case 0: + /* + * The server may allow us to open things like + * FIFOs, but the client isn't set up to deal + * with that. If it's not a regular file, just + * close it and proceed as if it were a normal + * lookup. + */ + if (newInode && !S_ISREG(newInode->i_mode)) { + CIFSSMBClose(xid, pTcon, fileHandle); + break; + } + case -ENOENT: posix_open = true; - else if ((rc == -EINVAL) || (rc != -EOPNOTSUPP)) + case -EOPNOTSUPP: + break; + default: pTcon->broken_posix_open = true; + } } if (!posix_open) rc = cifs_get_inode_info_unix(&newInode, full_path, |