diff options
author | Sachin Prabhu <sprabhu@redhat.com> | 2016-07-07 21:28:27 +0100 |
---|---|---|
committer | Willy Tarreau <w@1wt.eu> | 2016-08-27 11:40:37 +0200 |
commit | 60a8744f15d8bdcab6dc4f21728d8e9cb5e8880f (patch) | |
tree | 317a16ec6ef876c220dd989bd49405f9547503bd | |
parent | 9e10c1166f492b7979a6cf1b71e2ffa19c18e21c (diff) |
cifs: Check for existing directory when opening file with O_CREAT
commit 8d9535b6efd86e6c07da59f97e68f44efb7fe080 upstream.
When opening a file with O_CREAT flag, check to see if the file opened
is an existing directory.
This prevents the directory from being opened which subsequently causes
a crash when the close function for directories cifs_closedir() is called
which frees up the file->private_data memory while the file is still
listed on the open file list for the tcon.
Signed-off-by: Sachin Prabhu <sprabhu@redhat.com>
Signed-off-by: Steve French <smfrench@gmail.com>
CC: Stable <stable@vger.kernel.org>
Reported-by: Xiaoli Feng <xifeng@redhat.com>
Signed-off-by: Willy Tarreau <w@1wt.eu>
-rw-r--r-- | fs/cifs/dir.c | 24 |
1 files changed, 21 insertions, 3 deletions
diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c index 0c2425b21974..a998c929286f 100644 --- a/fs/cifs/dir.c +++ b/fs/cifs/dir.c @@ -227,6 +227,13 @@ cifs_do_create(struct inode *inode, struct dentry *direntry, unsigned int xid, goto cifs_create_get_file_info; } + if (S_ISDIR(newinode->i_mode)) { + CIFSSMBClose(xid, tcon, fid->netfid); + iput(newinode); + rc = -EISDIR; + goto out; + } + if (!S_ISREG(newinode->i_mode)) { /* * The server may allow us to open things like @@ -391,10 +398,14 @@ cifs_create_set_dentry: if (rc != 0) { cifs_dbg(FYI, "Create worked, get_inode_info failed rc = %d\n", rc); - if (server->ops->close) - server->ops->close(xid, tcon, fid); - goto out; + goto out_err; } + + if (S_ISDIR(newinode->i_mode)) { + rc = -EISDIR; + goto out_err; + } + d_drop(direntry); d_add(direntry, newinode); @@ -402,6 +413,13 @@ out: kfree(buf); kfree(full_path); return rc; + +out_err: + if (server->ops->close) + server->ops->close(xid, tcon, fid); + if (newinode) + iput(newinode); + goto out; } int |