Skip to content

Commit b909d77

Browse files
committed
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
2 parents 58fdd84 + 895ad6f commit b909d77

File tree

5 files changed

+71
-37
lines changed

5 files changed

+71
-37
lines changed

fs/smb/client/cifsfs.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -173,7 +173,7 @@ module_param(enable_oplocks, bool, 0644);
173173
MODULE_PARM_DESC(enable_oplocks, "Enable or disable oplocks. Default: y/Y/1");
174174

175175
module_param(enable_gcm_256, bool, 0644);
176-
MODULE_PARM_DESC(enable_gcm_256, "Enable requesting strongest (256 bit) GCM encryption. Default: y/Y/0");
176+
MODULE_PARM_DESC(enable_gcm_256, "Enable requesting strongest (256 bit) GCM encryption. Default: y/Y/1");
177177

178178
module_param(require_gcm_256, bool, 0644);
179179
MODULE_PARM_DESC(require_gcm_256, "Require strongest (256 bit) GCM encryption. Default: n/N/0");

fs/smb/client/cifsproto.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -616,6 +616,8 @@ extern int E_md4hash(const unsigned char *passwd, unsigned char *p16,
616616
extern struct TCP_Server_Info *
617617
cifs_find_tcp_session(struct smb3_fs_context *ctx);
618618

619+
struct cifs_tcon *cifs_setup_ipc(struct cifs_ses *ses, bool seal);
620+
619621
void __cifs_put_smb_ses(struct cifs_ses *ses);
620622

621623
extern struct cifs_ses *

fs/smb/client/connect.c

Lines changed: 19 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -310,6 +310,8 @@ cifs_abort_connection(struct TCP_Server_Info *server)
310310
server->ssocket->flags);
311311
sock_release(server->ssocket);
312312
server->ssocket = NULL;
313+
} else if (cifs_rdma_enabled(server)) {
314+
smbd_destroy(server);
313315
}
314316
server->sequence_number = 0;
315317
server->session_estab = false;
@@ -338,12 +340,6 @@ cifs_abort_connection(struct TCP_Server_Info *server)
338340
mid_execute_callback(mid);
339341
release_mid(mid);
340342
}
341-
342-
if (cifs_rdma_enabled(server)) {
343-
cifs_server_lock(server);
344-
smbd_destroy(server);
345-
cifs_server_unlock(server);
346-
}
347343
}
348344

349345
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,
20152011
/**
20162012
* cifs_setup_ipc - helper to setup the IPC tcon for the session
20172013
* @ses: smb session to issue the request on
2018-
* @ctx: the superblock configuration context to use for building the
2019-
* new tree connection for the IPC (interprocess communication RPC)
2014+
* @seal: if encryption is requested
20202015
*
20212016
* A new IPC connection is made and stored in the session
20222017
* tcon_ipc. The IPC tcon has the same lifetime as the session.
20232018
*/
2024-
static int
2025-
cifs_setup_ipc(struct cifs_ses *ses, struct smb3_fs_context *ctx)
2019+
struct cifs_tcon *cifs_setup_ipc(struct cifs_ses *ses, bool seal)
20262020
{
20272021
int rc = 0, xid;
20282022
struct cifs_tcon *tcon;
20292023
char unc[SERVER_NAME_LENGTH + sizeof("//x/IPC$")] = {0};
2030-
bool seal = false;
20312024
struct TCP_Server_Info *server = ses->server;
20322025

20332026
/*
20342027
* If the mount request that resulted in the creation of the
20352028
* session requires encryption, force IPC to be encrypted too.
20362029
*/
2037-
if (ctx->seal) {
2038-
if (server->capabilities & SMB2_GLOBAL_CAP_ENCRYPTION)
2039-
seal = true;
2040-
else {
2041-
cifs_server_dbg(VFS,
2042-
"IPC: server doesn't support encryption\n");
2043-
return -EOPNOTSUPP;
2044-
}
2030+
if (seal && !(server->capabilities & SMB2_GLOBAL_CAP_ENCRYPTION)) {
2031+
cifs_server_dbg(VFS, "IPC: server doesn't support encryption\n");
2032+
return ERR_PTR(-EOPNOTSUPP);
20452033
}
20462034

20472035
/* no need to setup directory caching on IPC share, so pass in false */
20482036
tcon = tcon_info_alloc(false, netfs_trace_tcon_ref_new_ipc);
20492037
if (tcon == NULL)
2050-
return -ENOMEM;
2038+
return ERR_PTR(-ENOMEM);
20512039

20522040
spin_lock(&server->srv_lock);
20532041
scnprintf(unc, sizeof(unc), "\\\\%s\\IPC$", server->hostname);
@@ -2057,23 +2045,21 @@ cifs_setup_ipc(struct cifs_ses *ses, struct smb3_fs_context *ctx)
20572045
tcon->ses = ses;
20582046
tcon->ipc = true;
20592047
tcon->seal = seal;
2060-
rc = server->ops->tree_connect(xid, ses, unc, tcon, ctx->local_nls);
2048+
rc = server->ops->tree_connect(xid, ses, unc, tcon, ses->local_nls);
20612049
free_xid(xid);
20622050

20632051
if (rc) {
2064-
cifs_server_dbg(VFS, "failed to connect to IPC (rc=%d)\n", rc);
2052+
cifs_server_dbg(VFS | ONCE, "failed to connect to IPC (rc=%d)\n", rc);
20652053
tconInfoFree(tcon, netfs_trace_tcon_ref_free_ipc_fail);
2066-
goto out;
2054+
return ERR_PTR(rc);
20672055
}
20682056

20692057
cifs_dbg(FYI, "IPC tcon rc=%d ipc tid=0x%x\n", rc, tcon->tid);
20702058

20712059
spin_lock(&tcon->tc_lock);
20722060
tcon->status = TID_GOOD;
20732061
spin_unlock(&tcon->tc_lock);
2074-
ses->tcon_ipc = tcon;
2075-
out:
2076-
return rc;
2062+
return tcon;
20772063
}
20782064

20792065
static struct cifs_ses *
@@ -2347,6 +2333,7 @@ cifs_get_smb_ses(struct TCP_Server_Info *server, struct smb3_fs_context *ctx)
23472333
{
23482334
struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)&server->dstaddr;
23492335
struct sockaddr_in *addr = (struct sockaddr_in *)&server->dstaddr;
2336+
struct cifs_tcon *ipc;
23502337
struct cifs_ses *ses;
23512338
unsigned int xid;
23522339
int retries = 0;
@@ -2525,7 +2512,12 @@ cifs_get_smb_ses(struct TCP_Server_Info *server, struct smb3_fs_context *ctx)
25252512
list_add(&ses->smb_ses_list, &server->smb_ses_list);
25262513
spin_unlock(&cifs_tcp_ses_lock);
25272514

2528-
cifs_setup_ipc(ses, ctx);
2515+
ipc = cifs_setup_ipc(ses, ctx->seal);
2516+
spin_lock(&cifs_tcp_ses_lock);
2517+
spin_lock(&ses->ses_lock);
2518+
ses->tcon_ipc = !IS_ERR(ipc) ? ipc : NULL;
2519+
spin_unlock(&ses->ses_lock);
2520+
spin_unlock(&cifs_tcp_ses_lock);
25292521

25302522
free_xid(xid);
25312523

fs/smb/client/dfs_cache.c

Lines changed: 47 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1120,24 +1120,63 @@ static bool target_share_equal(struct cifs_tcon *tcon, const char *s1)
11201120
return match;
11211121
}
11221122

1123-
static bool is_ses_good(struct cifs_ses *ses)
1123+
static bool is_ses_good(struct cifs_tcon *tcon, struct cifs_ses *ses)
11241124
{
11251125
struct TCP_Server_Info *server = ses->server;
1126-
struct cifs_tcon *tcon = ses->tcon_ipc;
1126+
struct cifs_tcon *ipc = NULL;
11271127
bool ret;
11281128

1129+
spin_lock(&cifs_tcp_ses_lock);
11291130
spin_lock(&ses->ses_lock);
11301131
spin_lock(&ses->chan_lock);
1132+
11311133
ret = !cifs_chan_needs_reconnect(ses, server) &&
1132-
ses->ses_status == SES_GOOD &&
1133-
!tcon->need_reconnect;
1134+
ses->ses_status == SES_GOOD;
1135+
11341136
spin_unlock(&ses->chan_lock);
1137+
1138+
if (!ret)
1139+
goto out;
1140+
1141+
if (likely(ses->tcon_ipc)) {
1142+
if (ses->tcon_ipc->need_reconnect) {
1143+
ret = false;
1144+
goto out;
1145+
}
1146+
} else {
1147+
spin_unlock(&ses->ses_lock);
1148+
spin_unlock(&cifs_tcp_ses_lock);
1149+
1150+
ipc = cifs_setup_ipc(ses, tcon->seal);
1151+
1152+
spin_lock(&cifs_tcp_ses_lock);
1153+
spin_lock(&ses->ses_lock);
1154+
if (!IS_ERR(ipc)) {
1155+
if (!ses->tcon_ipc) {
1156+
ses->tcon_ipc = ipc;
1157+
ipc = NULL;
1158+
}
1159+
} else {
1160+
ret = false;
1161+
ipc = NULL;
1162+
}
1163+
}
1164+
1165+
out:
11351166
spin_unlock(&ses->ses_lock);
1167+
spin_unlock(&cifs_tcp_ses_lock);
1168+
if (ipc && server->ops->tree_disconnect) {
1169+
unsigned int xid = get_xid();
1170+
1171+
(void)server->ops->tree_disconnect(xid, ipc);
1172+
_free_xid(xid);
1173+
}
1174+
tconInfoFree(ipc, netfs_trace_tcon_ref_free_ipc);
11361175
return ret;
11371176
}
11381177

11391178
/* Refresh dfs referral of @ses */
1140-
static void refresh_ses_referral(struct cifs_ses *ses)
1179+
static void refresh_ses_referral(struct cifs_tcon *tcon, struct cifs_ses *ses)
11411180
{
11421181
struct cache_entry *ce;
11431182
unsigned int xid;
@@ -1153,7 +1192,7 @@ static void refresh_ses_referral(struct cifs_ses *ses)
11531192
}
11541193

11551194
ses = CIFS_DFS_ROOT_SES(ses);
1156-
if (!is_ses_good(ses)) {
1195+
if (!is_ses_good(tcon, ses)) {
11571196
cifs_dbg(FYI, "%s: skip cache refresh due to disconnected ipc\n",
11581197
__func__);
11591198
goto out;
@@ -1241,7 +1280,7 @@ static void refresh_tcon_referral(struct cifs_tcon *tcon, bool force_refresh)
12411280
up_read(&htable_rw_lock);
12421281

12431282
ses = CIFS_DFS_ROOT_SES(ses);
1244-
if (!is_ses_good(ses)) {
1283+
if (!is_ses_good(tcon, ses)) {
12451284
cifs_dbg(FYI, "%s: skip cache refresh due to disconnected ipc\n",
12461285
__func__);
12471286
goto out;
@@ -1309,7 +1348,7 @@ void dfs_cache_refresh(struct work_struct *work)
13091348
tcon = container_of(work, struct cifs_tcon, dfs_cache_work.work);
13101349

13111350
list_for_each_entry(ses, &tcon->dfs_ses_list, dlist)
1312-
refresh_ses_referral(ses);
1351+
refresh_ses_referral(tcon, ses);
13131352
refresh_tcon_referral(tcon, false);
13141353

13151354
queue_delayed_work(dfscache_wq, &tcon->dfs_cache_work,

fs/smb/client/smb2ops.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2799,11 +2799,12 @@ smb2_query_info_compound(const unsigned int xid, struct cifs_tcon *tcon,
27992799
struct cifs_fid fid;
28002800
int rc;
28012801
__le16 *utf16_path;
2802-
struct cached_fid *cfid = NULL;
2802+
struct cached_fid *cfid;
28032803
int retries = 0, cur_sleep = 1;
28042804

28052805
replay_again:
28062806
/* reinitialize for possible replay */
2807+
cfid = NULL;
28072808
flags = CIFS_CP_CREATE_CLOSE_OP;
28082809
oplock = SMB2_OPLOCK_LEVEL_NONE;
28092810
server = cifs_pick_channel(ses);

0 commit comments

Comments
 (0)