summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJeff Layton <jlayton@redhat.com>2012-02-23 09:37:45 -0500
committerWilly Tarreau <w@1wt.eu>2012-03-17 11:14:49 +0100
commit3af36e8a6301cbf03d4cc9a3881a1e03137dba03 (patch)
treeb0437e80315429738a3ff5c43da7afa736655d4a
parentf30c620b9f629115de4f3f171c7df46efb4e4b04 (diff)
downloadlinux-stable-3af36e8a6301cbf03d4cc9a3881a1e03137dba03.tar.gz
linux-stable-3af36e8a6301cbf03d4cc9a3881a1e03137dba03.tar.bz2
linux-stable-3af36e8a6301cbf03d4cc9a3881a1e03137dba03.zip
cifs: fix dentry refcount leak when opening a FIFO on lookup
commit 5bccda0ebc7c0331b81ac47d39e4b920b198b2cd upstream. 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> Signed-off-by: Willy Tarreau <w@1wt.eu>
-rw-r--r--fs/cifs/dir.c20
1 files changed, 18 insertions, 2 deletions
diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c
index c3d6182d0ebe..7c863b598639 100644
--- a/fs/cifs/dir.c
+++ b/fs/cifs/dir.c
@@ -691,10 +691,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,