diff options
author | 2023-04-26 13:43:53 -0300 | |
---|---|---|
committer | 2023-05-03 23:29:39 -0500 | |
commit | 3dc9c433c9dde15477d02b609ccb4328e2adb6dc (patch) | |
tree | d097b78d406ba5b6324c3e732ce8aebfc6aa4440 /fs/cifs/dfs.c | |
parent | cifs: fix potential race when tree connecting ipc (diff) | |
download | linux-3dc9c433c9dde15477d02b609ccb4328e2adb6dc.tar.gz linux-3dc9c433c9dde15477d02b609ccb4328e2adb6dc.tar.bz2 linux-3dc9c433c9dde15477d02b609ccb4328e2adb6dc.zip |
cifs: protect access of TCP_Server_Info::{origin,leaf}_fullpath
Protect access of TCP_Server_Info::{origin,leaf}_fullpath when
matching DFS connections, and get rid of
TCP_Server_Info::current_fullpath while we're at it.
Cc: stable@vger.kernel.org # v6.2+
Signed-off-by: Paulo Alcantara (SUSE) <pc@manguebit.com>
Signed-off-by: Steve French <stfrench@microsoft.com>
Diffstat (limited to 'fs/cifs/dfs.c')
-rw-r--r-- | fs/cifs/dfs.c | 14 |
1 files changed, 8 insertions, 6 deletions
diff --git a/fs/cifs/dfs.c b/fs/cifs/dfs.c index 37f7da4f5c8b..c4ec5c67087b 100644 --- a/fs/cifs/dfs.c +++ b/fs/cifs/dfs.c @@ -248,11 +248,12 @@ static int __dfs_mount_share(struct cifs_mount_ctx *mnt_ctx) tcon = mnt_ctx->tcon; mutex_lock(&server->refpath_lock); + spin_lock(&server->srv_lock); if (!server->origin_fullpath) { server->origin_fullpath = origin_fullpath; - server->current_fullpath = server->leaf_fullpath; origin_fullpath = NULL; } + spin_unlock(&server->srv_lock); mutex_unlock(&server->refpath_lock); if (list_empty(&tcon->dfs_ses_list)) { @@ -342,10 +343,11 @@ static int update_server_fullpath(struct TCP_Server_Info *server, struct cifs_sb rc = PTR_ERR(npath); } else { mutex_lock(&server->refpath_lock); + spin_lock(&server->srv_lock); kfree(server->leaf_fullpath); server->leaf_fullpath = npath; + spin_unlock(&server->srv_lock); mutex_unlock(&server->refpath_lock); - server->current_fullpath = server->leaf_fullpath; } return rc; } @@ -450,7 +452,7 @@ static int __tree_connect_dfs_target(const unsigned int xid, struct cifs_tcon *t share = prefix = NULL; /* 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->leaf_fullpath + 1, tit, &share, &prefix); if (rc) { cifs_dbg(VFS, "%s: failed to parse target share: %d\n", __func__, rc); break; @@ -464,7 +466,7 @@ static int __tree_connect_dfs_target(const unsigned int xid, struct cifs_tcon *t continue; } - dfs_cache_noreq_update_tgthint(server->current_fullpath + 1, tit); + dfs_cache_noreq_update_tgthint(server->leaf_fullpath + 1, tit); tree_connect_ipc(xid, tree, cifs_sb, tcon); scnprintf(tree, MAX_TREE_SIZE, "\\%s", share); @@ -582,8 +584,8 @@ int cifs_tree_connect(const unsigned int xid, struct cifs_tcon *tcon, const stru cifs_sb = CIFS_SB(sb); /* If it is not dfs or there was no cached dfs referral, then reconnect to same share */ - if (!server->current_fullpath || - dfs_cache_noreq_find(server->current_fullpath + 1, &ref, &tl)) { + if (!server->leaf_fullpath || + dfs_cache_noreq_find(server->leaf_fullpath + 1, &ref, &tl)) { rc = ops->tree_connect(xid, tcon->ses, tcon->tree_name, tcon, cifs_sb->local_nls); goto out; } |