Commit 7f28af9c authored by Paulo Alcantara's avatar Paulo Alcantara Committed by Steve French

cifs: fix potential use-after-free bugs

Ensure that share and prefix variables are set to NULL after kfree()
when looping through DFS targets in __tree_connect_dfs_target().

Also, get rid of @ref in __tree_connect_dfs_target() and just pass a
boolean to indicate whether we're handling link targets or not.

Fixes: c88f7dcd ("cifs: support nested dfs links over reconnect")
Signed-off-by: default avatarPaulo Alcantara (SUSE) <pc@cjr.nz>
Signed-off-by: default avatarSteve French <stfrench@microsoft.com>
parent 869da64d
...@@ -4141,14 +4141,13 @@ static int target_share_matches_server(struct TCP_Server_Info *server, const cha ...@@ -4141,14 +4141,13 @@ static int target_share_matches_server(struct TCP_Server_Info *server, const cha
} }
static int __tree_connect_dfs_target(const unsigned int xid, struct cifs_tcon *tcon, static int __tree_connect_dfs_target(const unsigned int xid, struct cifs_tcon *tcon,
struct cifs_sb_info *cifs_sb, char *tree, struct cifs_sb_info *cifs_sb, char *tree, bool islink,
struct dfs_cache_tgt_list *tl, struct dfs_info3_param *ref) struct dfs_cache_tgt_list *tl)
{ {
int rc; int rc;
struct TCP_Server_Info *server = tcon->ses->server; struct TCP_Server_Info *server = tcon->ses->server;
const struct smb_version_operations *ops = server->ops; const struct smb_version_operations *ops = server->ops;
struct cifs_tcon *ipc = tcon->ses->tcon_ipc; struct cifs_tcon *ipc = tcon->ses->tcon_ipc;
bool islink;
char *share = NULL, *prefix = NULL; char *share = NULL, *prefix = NULL;
const char *tcp_host; const char *tcp_host;
size_t tcp_host_len; size_t tcp_host_len;
...@@ -4157,9 +4156,6 @@ static int __tree_connect_dfs_target(const unsigned int xid, struct cifs_tcon *t ...@@ -4157,9 +4156,6 @@ static int __tree_connect_dfs_target(const unsigned int xid, struct cifs_tcon *t
extract_unc_hostname(server->hostname, &tcp_host, &tcp_host_len); extract_unc_hostname(server->hostname, &tcp_host, &tcp_host_len);
islink = ref->server_type == DFS_TYPE_LINK;
free_dfs_info_param(ref);
tit = dfs_cache_get_tgt_iterator(tl); tit = dfs_cache_get_tgt_iterator(tl);
if (!tit) { if (!tit) {
rc = -ENOENT; rc = -ENOENT;
...@@ -4173,6 +4169,7 @@ static int __tree_connect_dfs_target(const unsigned int xid, struct cifs_tcon *t ...@@ -4173,6 +4169,7 @@ static int __tree_connect_dfs_target(const unsigned int xid, struct cifs_tcon *t
kfree(share); kfree(share);
kfree(prefix); kfree(prefix);
share = prefix = NULL;
/* Check if share matches with tcp ses */ /* Check if share matches with tcp ses */
rc = dfs_cache_get_tgt_share(server->current_fullpath + 1, tit, &share, &prefix); rc = dfs_cache_get_tgt_share(server->current_fullpath + 1, tit, &share, &prefix);
...@@ -4209,15 +4206,14 @@ static int __tree_connect_dfs_target(const unsigned int xid, struct cifs_tcon *t ...@@ -4209,15 +4206,14 @@ static int __tree_connect_dfs_target(const unsigned int xid, struct cifs_tcon *t
* newly resolved target. * newly resolved target.
*/ */
if (dfs_cache_find(xid, tcon->ses, cifs_sb->local_nls, cifs_remap(cifs_sb), target, if (dfs_cache_find(xid, tcon->ses, cifs_sb->local_nls, cifs_remap(cifs_sb), target,
ref, &ntl)) { NULL, &ntl)) {
rc = ops->tree_connect(xid, tcon->ses, tree, tcon, cifs_sb->local_nls); rc = ops->tree_connect(xid, tcon->ses, tree, tcon, cifs_sb->local_nls);
if (rc) if (rc)
continue; continue;
rc = dfs_cache_noreq_update_tgthint(server->current_fullpath + 1, tit); rc = dfs_cache_noreq_update_tgthint(server->current_fullpath + 1, tit);
if (!rc) if (!rc)
rc = cifs_update_super_prepath(cifs_sb, prefix); rc = cifs_update_super_prepath(cifs_sb, prefix);
break; } else {
}
/* Target is another dfs share */ /* Target is another dfs share */
rc = update_server_fullpath(server, cifs_sb, target); rc = update_server_fullpath(server, cifs_sb, target);
dfs_cache_free_tgts(tl); dfs_cache_free_tgts(tl);
...@@ -4225,9 +4221,8 @@ static int __tree_connect_dfs_target(const unsigned int xid, struct cifs_tcon *t ...@@ -4225,9 +4221,8 @@ static int __tree_connect_dfs_target(const unsigned int xid, struct cifs_tcon *t
if (!rc) { if (!rc) {
rc = -EREMOTE; rc = -EREMOTE;
list_replace_init(&ntl.tl_list, &tl->tl_list); list_replace_init(&ntl.tl_list, &tl->tl_list);
} else { } else
dfs_cache_free_tgts(&ntl); dfs_cache_free_tgts(&ntl);
free_dfs_info_param(ref);
} }
break; break;
} }
...@@ -4240,15 +4235,15 @@ static int __tree_connect_dfs_target(const unsigned int xid, struct cifs_tcon *t ...@@ -4240,15 +4235,15 @@ static int __tree_connect_dfs_target(const unsigned int xid, struct cifs_tcon *t
} }
static int tree_connect_dfs_target(const unsigned int xid, struct cifs_tcon *tcon, static int tree_connect_dfs_target(const unsigned int xid, struct cifs_tcon *tcon,
struct cifs_sb_info *cifs_sb, char *tree, struct cifs_sb_info *cifs_sb, char *tree, bool islink,
struct dfs_cache_tgt_list *tl, struct dfs_info3_param *ref) struct dfs_cache_tgt_list *tl)
{ {
int rc; int rc;
int num_links = 0; int num_links = 0;
struct TCP_Server_Info *server = tcon->ses->server; struct TCP_Server_Info *server = tcon->ses->server;
do { do {
rc = __tree_connect_dfs_target(xid, tcon, cifs_sb, tree, tl, ref); rc = __tree_connect_dfs_target(xid, tcon, cifs_sb, tree, islink, tl);
if (!rc || rc != -EREMOTE) if (!rc || rc != -EREMOTE)
break; break;
} while (rc = -ELOOP, ++num_links < MAX_NESTED_LINKS); } while (rc = -ELOOP, ++num_links < MAX_NESTED_LINKS);
...@@ -4302,7 +4297,9 @@ int cifs_tree_connect(const unsigned int xid, struct cifs_tcon *tcon, const stru ...@@ -4302,7 +4297,9 @@ int cifs_tree_connect(const unsigned int xid, struct cifs_tcon *tcon, const stru
goto out; goto out;
} }
rc = tree_connect_dfs_target(xid, tcon, cifs_sb, tree, &tl, &ref); rc = tree_connect_dfs_target(xid, tcon, cifs_sb, tree, ref.server_type == DFS_TYPE_LINK,
&tl);
free_dfs_info_param(&ref);
out: out:
kfree(tree); kfree(tree);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment