Skip to content

Commit 05df919

Browse files
committed
Merge tag 'v6.16-rc4-smb3-client-fixes' of git://git.samba.org/sfrench/cifs-2.6
Pull smb client fixes from Steve French: - Two reconnect fixes including one for a reboot/reconnect race - Fix for incorrect file type that can be returned by SMB3.1.1 POSIX extensions - tcon initialization fix - Fix for resolving Windows symlinks with absolute paths * tag 'v6.16-rc4-smb3-client-fixes' of git://git.samba.org/sfrench/cifs-2.6: smb: client: fix native SMB symlink traversal smb: client: fix race condition in negotiate timeout by using more precise timing cifs: all initializations for tcon should happen in tcon_info_alloc smb: client: fix warning when reconnecting channel smb: client: fix readdir returning wrong type with POSIX extensions
2 parents fd860cd + 3363da8 commit 05df919

File tree

8 files changed

+39
-36
lines changed

8 files changed

+39
-36
lines changed

fs/smb/client/cifsglob.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -777,6 +777,7 @@ struct TCP_Server_Info {
777777
__le32 session_key_id; /* retrieved from negotiate response and send in session setup request */
778778
struct session_key session_key;
779779
unsigned long lstrp; /* when we got last response from this server */
780+
unsigned long neg_start; /* when negotiate started (jiffies) */
780781
struct cifs_secmech secmech; /* crypto sec mech functs, descriptors */
781782
#define CIFS_NEGFLAVOR_UNENCAP 1 /* wct == 17, but no ext_sec */
782783
#define CIFS_NEGFLAVOR_EXTENDED 2 /* wct == 17, ext_sec bit set */
@@ -1303,6 +1304,7 @@ struct cifs_tcon {
13031304
bool use_persistent:1; /* use persistent instead of durable handles */
13041305
bool no_lease:1; /* Do not request leases on files or directories */
13051306
bool use_witness:1; /* use witness protocol */
1307+
bool dummy:1; /* dummy tcon used for reconnecting channels */
13061308
__le32 capabilities;
13071309
__u32 share_flags;
13081310
__u32 maximal_access;

fs/smb/client/cifsproto.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,7 @@ extern int SendReceiveBlockingLock(const unsigned int xid,
136136
struct smb_hdr *out_buf,
137137
int *bytes_returned);
138138

139+
void smb2_query_server_interfaces(struct work_struct *work);
139140
void
140141
cifs_signal_cifsd_for_reconnect(struct TCP_Server_Info *server,
141142
bool all_channels);

fs/smb/client/connect.c

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ static int reconn_set_ipaddr_from_hostname(struct TCP_Server_Info *server)
9797
return rc;
9898
}
9999

100-
static void smb2_query_server_interfaces(struct work_struct *work)
100+
void smb2_query_server_interfaces(struct work_struct *work)
101101
{
102102
int rc;
103103
int xid;
@@ -679,12 +679,12 @@ server_unresponsive(struct TCP_Server_Info *server)
679679
/*
680680
* If we're in the process of mounting a share or reconnecting a session
681681
* and the server abruptly shut down (e.g. socket wasn't closed, packet
682-
* had been ACK'ed but no SMB response), don't wait longer than 20s to
683-
* negotiate protocol.
682+
* had been ACK'ed but no SMB response), don't wait longer than 20s from
683+
* when negotiate actually started.
684684
*/
685685
spin_lock(&server->srv_lock);
686686
if (server->tcpStatus == CifsInNegotiate &&
687-
time_after(jiffies, server->lstrp + 20 * HZ)) {
687+
time_after(jiffies, server->neg_start + 20 * HZ)) {
688688
spin_unlock(&server->srv_lock);
689689
cifs_reconnect(server, false);
690690
return true;
@@ -2880,20 +2880,14 @@ cifs_get_tcon(struct cifs_ses *ses, struct smb3_fs_context *ctx)
28802880
tcon->max_cached_dirs = ctx->max_cached_dirs;
28812881
tcon->nodelete = ctx->nodelete;
28822882
tcon->local_lease = ctx->local_lease;
2883-
INIT_LIST_HEAD(&tcon->pending_opens);
28842883
tcon->status = TID_GOOD;
28852884

2886-
INIT_DELAYED_WORK(&tcon->query_interfaces,
2887-
smb2_query_server_interfaces);
28882885
if (ses->server->dialect >= SMB30_PROT_ID &&
28892886
(ses->server->capabilities & SMB2_GLOBAL_CAP_MULTI_CHANNEL)) {
28902887
/* schedule query interfaces poll */
28912888
queue_delayed_work(cifsiod_wq, &tcon->query_interfaces,
28922889
(SMB_INTERFACE_POLL_INTERVAL * HZ));
28932890
}
2894-
#ifdef CONFIG_CIFS_DFS_UPCALL
2895-
INIT_DELAYED_WORK(&tcon->dfs_cache_work, dfs_cache_refresh);
2896-
#endif
28972891
spin_lock(&cifs_tcp_ses_lock);
28982892
list_add(&tcon->tcon_list, &ses->tcon_list);
28992893
spin_unlock(&cifs_tcp_ses_lock);
@@ -4215,6 +4209,7 @@ cifs_negotiate_protocol(const unsigned int xid, struct cifs_ses *ses,
42154209

42164210
server->lstrp = jiffies;
42174211
server->tcpStatus = CifsInNegotiate;
4212+
server->neg_start = jiffies;
42184213
spin_unlock(&server->srv_lock);
42194214

42204215
rc = server->ops->negotiate(xid, ses, server);

fs/smb/client/fs_context.c

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1824,10 +1824,14 @@ static int smb3_fs_context_parse_param(struct fs_context *fc,
18241824
cifs_errorf(fc, "symlinkroot mount options must be absolute path\n");
18251825
goto cifs_parse_mount_err;
18261826
}
1827-
kfree(ctx->symlinkroot);
1828-
ctx->symlinkroot = kstrdup(param->string, GFP_KERNEL);
1829-
if (!ctx->symlinkroot)
1827+
if (strnlen(param->string, PATH_MAX) == PATH_MAX) {
1828+
cifs_errorf(fc, "symlinkroot path too long (max path length: %u)\n",
1829+
PATH_MAX - 1);
18301830
goto cifs_parse_mount_err;
1831+
}
1832+
kfree(ctx->symlinkroot);
1833+
ctx->symlinkroot = param->string;
1834+
param->string = NULL;
18311835
break;
18321836
}
18331837
/* case Opt_ignore: - is ignored as expected ... */
@@ -1837,13 +1841,6 @@ static int smb3_fs_context_parse_param(struct fs_context *fc,
18371841
goto cifs_parse_mount_err;
18381842
}
18391843

1840-
/*
1841-
* By default resolve all native absolute symlinks relative to "/mnt/".
1842-
* Same default has drvfs driver running in WSL for resolving SMB shares.
1843-
*/
1844-
if (!ctx->symlinkroot)
1845-
ctx->symlinkroot = kstrdup("/mnt/", GFP_KERNEL);
1846-
18471844
return 0;
18481845

18491846
cifs_parse_mount_err:

fs/smb/client/misc.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,12 @@ tcon_info_alloc(bool dir_leases_enabled, enum smb3_tcon_ref_trace trace)
151151
#ifdef CONFIG_CIFS_DFS_UPCALL
152152
INIT_LIST_HEAD(&ret_buf->dfs_ses_list);
153153
#endif
154+
INIT_LIST_HEAD(&ret_buf->pending_opens);
155+
INIT_DELAYED_WORK(&ret_buf->query_interfaces,
156+
smb2_query_server_interfaces);
157+
#ifdef CONFIG_CIFS_DFS_UPCALL
158+
INIT_DELAYED_WORK(&ret_buf->dfs_cache_work, dfs_cache_refresh);
159+
#endif
154160

155161
return ret_buf;
156162
}

fs/smb/client/readdir.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -264,7 +264,7 @@ cifs_posix_to_fattr(struct cifs_fattr *fattr, struct smb2_posix_info *info,
264264
/* The Mode field in the response can now include the file type as well */
265265
fattr->cf_mode = wire_mode_to_posix(le32_to_cpu(info->Mode),
266266
fattr->cf_cifsattrs & ATTR_DIRECTORY);
267-
fattr->cf_dtype = S_DT(le32_to_cpu(info->Mode));
267+
fattr->cf_dtype = S_DT(fattr->cf_mode);
268268

269269
switch (fattr->cf_mode & S_IFMT) {
270270
case S_IFLNK:

fs/smb/client/reparse.c

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ static int create_native_symlink(const unsigned int xid, struct inode *inode,
5757
struct reparse_symlink_data_buffer *buf = NULL;
5858
struct cifs_open_info_data data = {};
5959
struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
60+
const char *symroot = cifs_sb->ctx->symlinkroot;
6061
struct inode *new;
6162
struct kvec iov;
6263
__le16 *path = NULL;
@@ -82,7 +83,8 @@ static int create_native_symlink(const unsigned int xid, struct inode *inode,
8283
.symlink_target = symlink_target,
8384
};
8485

85-
if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS) && symname[0] == '/') {
86+
if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS) &&
87+
symroot && symname[0] == '/') {
8688
/*
8789
* This is a request to create an absolute symlink on the server
8890
* which does not support POSIX paths, and expects symlink in
@@ -92,7 +94,7 @@ static int create_native_symlink(const unsigned int xid, struct inode *inode,
9294
* ensure compatibility of this symlink stored in absolute form
9395
* on the SMB server.
9496
*/
95-
if (!strstarts(symname, cifs_sb->ctx->symlinkroot)) {
97+
if (!strstarts(symname, symroot)) {
9698
/*
9799
* If the absolute Linux symlink target path is not
98100
* inside "symlinkroot" location then there is no way
@@ -101,12 +103,12 @@ static int create_native_symlink(const unsigned int xid, struct inode *inode,
101103
cifs_dbg(VFS,
102104
"absolute symlink '%s' cannot be converted to NT format "
103105
"because it is outside of symlinkroot='%s'\n",
104-
symname, cifs_sb->ctx->symlinkroot);
106+
symname, symroot);
105107
rc = -EINVAL;
106108
goto out;
107109
}
108-
len = strlen(cifs_sb->ctx->symlinkroot);
109-
if (cifs_sb->ctx->symlinkroot[len-1] != '/')
110+
len = strlen(symroot);
111+
if (symroot[len - 1] != '/')
110112
len++;
111113
if (symname[len] >= 'a' && symname[len] <= 'z' &&
112114
(symname[len+1] == '/' || symname[len+1] == '\0')) {
@@ -782,6 +784,7 @@ int smb2_parse_native_symlink(char **target, const char *buf, unsigned int len,
782784
const char *full_path,
783785
struct cifs_sb_info *cifs_sb)
784786
{
787+
const char *symroot = cifs_sb->ctx->symlinkroot;
785788
char sep = CIFS_DIR_SEP(cifs_sb);
786789
char *linux_target = NULL;
787790
char *smb_target = NULL;
@@ -815,7 +818,8 @@ int smb2_parse_native_symlink(char **target, const char *buf, unsigned int len,
815818
goto out;
816819
}
817820

818-
if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS) && !relative) {
821+
if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS) &&
822+
symroot && !relative) {
819823
/*
820824
* This is an absolute symlink from the server which does not
821825
* support POSIX paths, so the symlink is in NT-style path.
@@ -907,15 +911,15 @@ int smb2_parse_native_symlink(char **target, const char *buf, unsigned int len,
907911
}
908912

909913
abs_path_len = strlen(abs_path)+1;
910-
symlinkroot_len = strlen(cifs_sb->ctx->symlinkroot);
911-
if (cifs_sb->ctx->symlinkroot[symlinkroot_len-1] == '/')
914+
symlinkroot_len = strlen(symroot);
915+
if (symroot[symlinkroot_len - 1] == '/')
912916
symlinkroot_len--;
913917
linux_target = kmalloc(symlinkroot_len + 1 + abs_path_len, GFP_KERNEL);
914918
if (!linux_target) {
915919
rc = -ENOMEM;
916920
goto out;
917921
}
918-
memcpy(linux_target, cifs_sb->ctx->symlinkroot, symlinkroot_len);
922+
memcpy(linux_target, symroot, symlinkroot_len);
919923
linux_target[symlinkroot_len] = '/';
920924
memcpy(linux_target + symlinkroot_len + 1, abs_path, abs_path_len);
921925
} else if (smb_target[0] == sep && relative) {

fs/smb/client/smb2pdu.c

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -424,9 +424,9 @@ smb2_reconnect(__le16 smb2_command, struct cifs_tcon *tcon,
424424
free_xid(xid);
425425
ses->flags &= ~CIFS_SES_FLAGS_PENDING_QUERY_INTERFACES;
426426

427-
/* regardless of rc value, setup polling */
428-
queue_delayed_work(cifsiod_wq, &tcon->query_interfaces,
429-
(SMB_INTERFACE_POLL_INTERVAL * HZ));
427+
if (!tcon->ipc && !tcon->dummy)
428+
queue_delayed_work(cifsiod_wq, &tcon->query_interfaces,
429+
(SMB_INTERFACE_POLL_INTERVAL * HZ));
430430

431431
mutex_unlock(&ses->session_mutex);
432432

@@ -4229,10 +4229,8 @@ void smb2_reconnect_server(struct work_struct *work)
42294229
}
42304230
goto done;
42314231
}
4232-
42334232
tcon->status = TID_GOOD;
4234-
tcon->retry = false;
4235-
tcon->need_reconnect = false;
4233+
tcon->dummy = true;
42364234

42374235
/* now reconnect sessions for necessary channels */
42384236
list_for_each_entry_safe(ses, ses2, &tmp_ses_list, rlist) {

0 commit comments

Comments
 (0)