Commit bf99f6be authored by Paulo Alcantara's avatar Paulo Alcantara Committed by Steve French

smb: client: fix missed ses refcounting

Use new cifs_smb_ses_inc_refcount() helper to get an active reference
of @ses and @ses->dfs_root_ses (if set).  This will prevent
@ses->dfs_root_ses of being put in the next call to cifs_put_smb_ses()
and thus potentially causing an use-after-free bug.

Fixes: 8e355415 ("cifs: fix sharing of DFS connections")
Signed-off-by: default avatarPaulo Alcantara (SUSE) <pc@manguebit.com>
Signed-off-by: default avatarSteve French <stfrench@microsoft.com>
parent f1f047bd
...@@ -66,6 +66,12 @@ static int get_session(struct cifs_mount_ctx *mnt_ctx, const char *full_path) ...@@ -66,6 +66,12 @@ static int get_session(struct cifs_mount_ctx *mnt_ctx, const char *full_path)
return rc; return rc;
} }
/*
* Track individual DFS referral servers used by new DFS mount.
*
* On success, their lifetime will be shared by final tcon (dfs_ses_list).
* Otherwise, they will be put by dfs_put_root_smb_sessions() in cifs_mount().
*/
static int add_root_smb_session(struct cifs_mount_ctx *mnt_ctx) static int add_root_smb_session(struct cifs_mount_ctx *mnt_ctx)
{ {
struct smb3_fs_context *ctx = mnt_ctx->fs_ctx; struct smb3_fs_context *ctx = mnt_ctx->fs_ctx;
...@@ -80,11 +86,12 @@ static int add_root_smb_session(struct cifs_mount_ctx *mnt_ctx) ...@@ -80,11 +86,12 @@ static int add_root_smb_session(struct cifs_mount_ctx *mnt_ctx)
INIT_LIST_HEAD(&root_ses->list); INIT_LIST_HEAD(&root_ses->list);
spin_lock(&cifs_tcp_ses_lock); spin_lock(&cifs_tcp_ses_lock);
ses->ses_count++; cifs_smb_ses_inc_refcount(ses);
spin_unlock(&cifs_tcp_ses_lock); spin_unlock(&cifs_tcp_ses_lock);
root_ses->ses = ses; root_ses->ses = ses;
list_add_tail(&root_ses->list, &mnt_ctx->dfs_ses_list); list_add_tail(&root_ses->list, &mnt_ctx->dfs_ses_list);
} }
/* Select new DFS referral server so that new referrals go through it */
ctx->dfs_root_ses = ses; ctx->dfs_root_ses = ses;
return 0; return 0;
} }
...@@ -242,7 +249,6 @@ static int __dfs_mount_share(struct cifs_mount_ctx *mnt_ctx) ...@@ -242,7 +249,6 @@ static int __dfs_mount_share(struct cifs_mount_ctx *mnt_ctx)
int dfs_mount_share(struct cifs_mount_ctx *mnt_ctx, bool *isdfs) int dfs_mount_share(struct cifs_mount_ctx *mnt_ctx, bool *isdfs)
{ {
struct smb3_fs_context *ctx = mnt_ctx->fs_ctx; struct smb3_fs_context *ctx = mnt_ctx->fs_ctx;
struct cifs_ses *ses;
bool nodfs = ctx->nodfs; bool nodfs = ctx->nodfs;
int rc; int rc;
...@@ -276,20 +282,8 @@ int dfs_mount_share(struct cifs_mount_ctx *mnt_ctx, bool *isdfs) ...@@ -276,20 +282,8 @@ int dfs_mount_share(struct cifs_mount_ctx *mnt_ctx, bool *isdfs)
} }
*isdfs = true; *isdfs = true;
/* add_root_smb_session(mnt_ctx);
* Prevent DFS root session of being put in the first call to return __dfs_mount_share(mnt_ctx);
* cifs_mount_put_conns(). If another DFS root server was not found
* while chasing the referrals (@ctx->dfs_root_ses == @ses), then we
* can safely put extra refcount of @ses.
*/
ses = mnt_ctx->ses;
mnt_ctx->ses = NULL;
mnt_ctx->server = NULL;
rc = __dfs_mount_share(mnt_ctx);
if (ses == ctx->dfs_root_ses)
cifs_put_smb_ses(ses);
return rc;
} }
/* Update dfs referral path of superblock */ /* Update dfs referral path of superblock */
......
...@@ -160,7 +160,7 @@ smb2_find_smb_ses_unlocked(struct TCP_Server_Info *server, __u64 ses_id) ...@@ -160,7 +160,7 @@ smb2_find_smb_ses_unlocked(struct TCP_Server_Info *server, __u64 ses_id)
spin_unlock(&ses->ses_lock); spin_unlock(&ses->ses_lock);
continue; continue;
} }
++ses->ses_count; cifs_smb_ses_inc_refcount(ses);
spin_unlock(&ses->ses_lock); spin_unlock(&ses->ses_lock);
return ses; return ses;
} }
......
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