mirror of
https://github.com/torvalds/linux.git
synced 2025-12-07 20:06:24 +00:00
Merge tag '6.18-rc3-smb-client-fixes' of git://git.samba.org/sfrench/cifs-2.6
Pull smb client fixes from Steve French: - fix potential UAF in statfs - DFS fix for expired referrals - fix minor modinfo typo - small improvement to reconnect for smbdirect * tag '6.18-rc3-smb-client-fixes' of git://git.samba.org/sfrench/cifs-2.6: smb: client: call smbd_destroy() in the same splace as kernel_sock_shutdown()/sock_release() smb: client: handle lack of IPC in dfs_cache_refresh() smb: client: fix potential cfid UAF in smb2_query_info_compound cifs: fix typo in enable_gcm_256 module parameter
This commit is contained in:
@@ -173,7 +173,7 @@ module_param(enable_oplocks, bool, 0644);
|
||||
MODULE_PARM_DESC(enable_oplocks, "Enable or disable oplocks. Default: y/Y/1");
|
||||
|
||||
module_param(enable_gcm_256, bool, 0644);
|
||||
MODULE_PARM_DESC(enable_gcm_256, "Enable requesting strongest (256 bit) GCM encryption. Default: y/Y/0");
|
||||
MODULE_PARM_DESC(enable_gcm_256, "Enable requesting strongest (256 bit) GCM encryption. Default: y/Y/1");
|
||||
|
||||
module_param(require_gcm_256, bool, 0644);
|
||||
MODULE_PARM_DESC(require_gcm_256, "Require strongest (256 bit) GCM encryption. Default: n/N/0");
|
||||
|
||||
@@ -616,6 +616,8 @@ extern int E_md4hash(const unsigned char *passwd, unsigned char *p16,
|
||||
extern struct TCP_Server_Info *
|
||||
cifs_find_tcp_session(struct smb3_fs_context *ctx);
|
||||
|
||||
struct cifs_tcon *cifs_setup_ipc(struct cifs_ses *ses, bool seal);
|
||||
|
||||
void __cifs_put_smb_ses(struct cifs_ses *ses);
|
||||
|
||||
extern struct cifs_ses *
|
||||
|
||||
@@ -310,6 +310,8 @@ cifs_abort_connection(struct TCP_Server_Info *server)
|
||||
server->ssocket->flags);
|
||||
sock_release(server->ssocket);
|
||||
server->ssocket = NULL;
|
||||
} else if (cifs_rdma_enabled(server)) {
|
||||
smbd_destroy(server);
|
||||
}
|
||||
server->sequence_number = 0;
|
||||
server->session_estab = false;
|
||||
@@ -338,12 +340,6 @@ cifs_abort_connection(struct TCP_Server_Info *server)
|
||||
mid_execute_callback(mid);
|
||||
release_mid(mid);
|
||||
}
|
||||
|
||||
if (cifs_rdma_enabled(server)) {
|
||||
cifs_server_lock(server);
|
||||
smbd_destroy(server);
|
||||
cifs_server_unlock(server);
|
||||
}
|
||||
}
|
||||
|
||||
static bool cifs_tcp_ses_needs_reconnect(struct TCP_Server_Info *server, int num_targets)
|
||||
@@ -2015,39 +2011,31 @@ static int match_session(struct cifs_ses *ses,
|
||||
/**
|
||||
* cifs_setup_ipc - helper to setup the IPC tcon for the session
|
||||
* @ses: smb session to issue the request on
|
||||
* @ctx: the superblock configuration context to use for building the
|
||||
* new tree connection for the IPC (interprocess communication RPC)
|
||||
* @seal: if encryption is requested
|
||||
*
|
||||
* A new IPC connection is made and stored in the session
|
||||
* tcon_ipc. The IPC tcon has the same lifetime as the session.
|
||||
*/
|
||||
static int
|
||||
cifs_setup_ipc(struct cifs_ses *ses, struct smb3_fs_context *ctx)
|
||||
struct cifs_tcon *cifs_setup_ipc(struct cifs_ses *ses, bool seal)
|
||||
{
|
||||
int rc = 0, xid;
|
||||
struct cifs_tcon *tcon;
|
||||
char unc[SERVER_NAME_LENGTH + sizeof("//x/IPC$")] = {0};
|
||||
bool seal = false;
|
||||
struct TCP_Server_Info *server = ses->server;
|
||||
|
||||
/*
|
||||
* If the mount request that resulted in the creation of the
|
||||
* session requires encryption, force IPC to be encrypted too.
|
||||
*/
|
||||
if (ctx->seal) {
|
||||
if (server->capabilities & SMB2_GLOBAL_CAP_ENCRYPTION)
|
||||
seal = true;
|
||||
else {
|
||||
cifs_server_dbg(VFS,
|
||||
"IPC: server doesn't support encryption\n");
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
if (seal && !(server->capabilities & SMB2_GLOBAL_CAP_ENCRYPTION)) {
|
||||
cifs_server_dbg(VFS, "IPC: server doesn't support encryption\n");
|
||||
return ERR_PTR(-EOPNOTSUPP);
|
||||
}
|
||||
|
||||
/* no need to setup directory caching on IPC share, so pass in false */
|
||||
tcon = tcon_info_alloc(false, netfs_trace_tcon_ref_new_ipc);
|
||||
if (tcon == NULL)
|
||||
return -ENOMEM;
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
spin_lock(&server->srv_lock);
|
||||
scnprintf(unc, sizeof(unc), "\\\\%s\\IPC$", server->hostname);
|
||||
@@ -2057,13 +2045,13 @@ cifs_setup_ipc(struct cifs_ses *ses, struct smb3_fs_context *ctx)
|
||||
tcon->ses = ses;
|
||||
tcon->ipc = true;
|
||||
tcon->seal = seal;
|
||||
rc = server->ops->tree_connect(xid, ses, unc, tcon, ctx->local_nls);
|
||||
rc = server->ops->tree_connect(xid, ses, unc, tcon, ses->local_nls);
|
||||
free_xid(xid);
|
||||
|
||||
if (rc) {
|
||||
cifs_server_dbg(VFS, "failed to connect to IPC (rc=%d)\n", rc);
|
||||
cifs_server_dbg(VFS | ONCE, "failed to connect to IPC (rc=%d)\n", rc);
|
||||
tconInfoFree(tcon, netfs_trace_tcon_ref_free_ipc_fail);
|
||||
goto out;
|
||||
return ERR_PTR(rc);
|
||||
}
|
||||
|
||||
cifs_dbg(FYI, "IPC tcon rc=%d ipc tid=0x%x\n", rc, tcon->tid);
|
||||
@@ -2071,9 +2059,7 @@ cifs_setup_ipc(struct cifs_ses *ses, struct smb3_fs_context *ctx)
|
||||
spin_lock(&tcon->tc_lock);
|
||||
tcon->status = TID_GOOD;
|
||||
spin_unlock(&tcon->tc_lock);
|
||||
ses->tcon_ipc = tcon;
|
||||
out:
|
||||
return rc;
|
||||
return tcon;
|
||||
}
|
||||
|
||||
static struct cifs_ses *
|
||||
@@ -2347,6 +2333,7 @@ cifs_get_smb_ses(struct TCP_Server_Info *server, struct smb3_fs_context *ctx)
|
||||
{
|
||||
struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)&server->dstaddr;
|
||||
struct sockaddr_in *addr = (struct sockaddr_in *)&server->dstaddr;
|
||||
struct cifs_tcon *ipc;
|
||||
struct cifs_ses *ses;
|
||||
unsigned int xid;
|
||||
int retries = 0;
|
||||
@@ -2525,7 +2512,12 @@ retry_new_session:
|
||||
list_add(&ses->smb_ses_list, &server->smb_ses_list);
|
||||
spin_unlock(&cifs_tcp_ses_lock);
|
||||
|
||||
cifs_setup_ipc(ses, ctx);
|
||||
ipc = cifs_setup_ipc(ses, ctx->seal);
|
||||
spin_lock(&cifs_tcp_ses_lock);
|
||||
spin_lock(&ses->ses_lock);
|
||||
ses->tcon_ipc = !IS_ERR(ipc) ? ipc : NULL;
|
||||
spin_unlock(&ses->ses_lock);
|
||||
spin_unlock(&cifs_tcp_ses_lock);
|
||||
|
||||
free_xid(xid);
|
||||
|
||||
|
||||
@@ -1120,24 +1120,63 @@ static bool target_share_equal(struct cifs_tcon *tcon, const char *s1)
|
||||
return match;
|
||||
}
|
||||
|
||||
static bool is_ses_good(struct cifs_ses *ses)
|
||||
static bool is_ses_good(struct cifs_tcon *tcon, struct cifs_ses *ses)
|
||||
{
|
||||
struct TCP_Server_Info *server = ses->server;
|
||||
struct cifs_tcon *tcon = ses->tcon_ipc;
|
||||
struct cifs_tcon *ipc = NULL;
|
||||
bool ret;
|
||||
|
||||
spin_lock(&cifs_tcp_ses_lock);
|
||||
spin_lock(&ses->ses_lock);
|
||||
spin_lock(&ses->chan_lock);
|
||||
|
||||
ret = !cifs_chan_needs_reconnect(ses, server) &&
|
||||
ses->ses_status == SES_GOOD &&
|
||||
!tcon->need_reconnect;
|
||||
ses->ses_status == SES_GOOD;
|
||||
|
||||
spin_unlock(&ses->chan_lock);
|
||||
|
||||
if (!ret)
|
||||
goto out;
|
||||
|
||||
if (likely(ses->tcon_ipc)) {
|
||||
if (ses->tcon_ipc->need_reconnect) {
|
||||
ret = false;
|
||||
goto out;
|
||||
}
|
||||
} else {
|
||||
spin_unlock(&ses->ses_lock);
|
||||
spin_unlock(&cifs_tcp_ses_lock);
|
||||
|
||||
ipc = cifs_setup_ipc(ses, tcon->seal);
|
||||
|
||||
spin_lock(&cifs_tcp_ses_lock);
|
||||
spin_lock(&ses->ses_lock);
|
||||
if (!IS_ERR(ipc)) {
|
||||
if (!ses->tcon_ipc) {
|
||||
ses->tcon_ipc = ipc;
|
||||
ipc = NULL;
|
||||
}
|
||||
} else {
|
||||
ret = false;
|
||||
ipc = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
out:
|
||||
spin_unlock(&ses->ses_lock);
|
||||
spin_unlock(&cifs_tcp_ses_lock);
|
||||
if (ipc && server->ops->tree_disconnect) {
|
||||
unsigned int xid = get_xid();
|
||||
|
||||
(void)server->ops->tree_disconnect(xid, ipc);
|
||||
_free_xid(xid);
|
||||
}
|
||||
tconInfoFree(ipc, netfs_trace_tcon_ref_free_ipc);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Refresh dfs referral of @ses */
|
||||
static void refresh_ses_referral(struct cifs_ses *ses)
|
||||
static void refresh_ses_referral(struct cifs_tcon *tcon, struct cifs_ses *ses)
|
||||
{
|
||||
struct cache_entry *ce;
|
||||
unsigned int xid;
|
||||
@@ -1153,7 +1192,7 @@ static void refresh_ses_referral(struct cifs_ses *ses)
|
||||
}
|
||||
|
||||
ses = CIFS_DFS_ROOT_SES(ses);
|
||||
if (!is_ses_good(ses)) {
|
||||
if (!is_ses_good(tcon, ses)) {
|
||||
cifs_dbg(FYI, "%s: skip cache refresh due to disconnected ipc\n",
|
||||
__func__);
|
||||
goto out;
|
||||
@@ -1241,7 +1280,7 @@ static void refresh_tcon_referral(struct cifs_tcon *tcon, bool force_refresh)
|
||||
up_read(&htable_rw_lock);
|
||||
|
||||
ses = CIFS_DFS_ROOT_SES(ses);
|
||||
if (!is_ses_good(ses)) {
|
||||
if (!is_ses_good(tcon, ses)) {
|
||||
cifs_dbg(FYI, "%s: skip cache refresh due to disconnected ipc\n",
|
||||
__func__);
|
||||
goto out;
|
||||
@@ -1309,7 +1348,7 @@ void dfs_cache_refresh(struct work_struct *work)
|
||||
tcon = container_of(work, struct cifs_tcon, dfs_cache_work.work);
|
||||
|
||||
list_for_each_entry(ses, &tcon->dfs_ses_list, dlist)
|
||||
refresh_ses_referral(ses);
|
||||
refresh_ses_referral(tcon, ses);
|
||||
refresh_tcon_referral(tcon, false);
|
||||
|
||||
queue_delayed_work(dfscache_wq, &tcon->dfs_cache_work,
|
||||
|
||||
@@ -2799,11 +2799,12 @@ smb2_query_info_compound(const unsigned int xid, struct cifs_tcon *tcon,
|
||||
struct cifs_fid fid;
|
||||
int rc;
|
||||
__le16 *utf16_path;
|
||||
struct cached_fid *cfid = NULL;
|
||||
struct cached_fid *cfid;
|
||||
int retries = 0, cur_sleep = 1;
|
||||
|
||||
replay_again:
|
||||
/* reinitialize for possible replay */
|
||||
cfid = NULL;
|
||||
flags = CIFS_CP_CREATE_CLOSE_OP;
|
||||
oplock = SMB2_OPLOCK_LEVEL_NONE;
|
||||
server = cifs_pick_channel(ses);
|
||||
|
||||
Reference in New Issue
Block a user