Skip to content

Commit

Permalink
Merge tag '5.1-rc3-smb3-fixes' of git://git.samba.org/sfrench/cifs-2.6
Browse files Browse the repository at this point in the history
Pull smb3 fixes from Steve French:
 "Four smb3 fixes for stable:

   - fix an open path where we had an unitialized structure

   - fix for snapshot (previous version) enumeration

   - allow reconnect timeout on handles to be configurable to better
     handle network or server crash

   - correctly handle lack of file_all_info structure"

* tag '5.1-rc3-smb3-fixes' of git://git.samba.org/sfrench/cifs-2.6:
  cifs: a smb2_validate_and_copy_iov failure does not mean the handle is invalid.
  SMB3: Allow persistent handle timeout to be configurable on mount
  smb3: Fix enumerating snapshots to Azure
  cifs: fix kref underflow in close_shroot()
  • Loading branch information
Linus Torvalds committed Apr 4, 2019
2 parents 8ed8662 + 4811e30 commit 145f47c
Show file tree
Hide file tree
Showing 7 changed files with 121 additions and 47 deletions.
2 changes: 2 additions & 0 deletions fs/cifs/cifsfs.c
Original file line number Diff line number Diff line change
Expand Up @@ -559,6 +559,8 @@ cifs_show_options(struct seq_file *s, struct dentry *root)
tcon->ses->server->echo_interval / HZ);
if (tcon->snapshot_time)
seq_printf(s, ",snapshot=%llu", tcon->snapshot_time);
if (tcon->handle_timeout)
seq_printf(s, ",handletimeout=%u", tcon->handle_timeout);
/* convert actimeo and display it in seconds */
seq_printf(s, ",actimeo=%lu", cifs_sb->actimeo / HZ);

Expand Down
8 changes: 8 additions & 0 deletions fs/cifs/cifsglob.h
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,12 @@
*/
#define CIFS_MAX_ACTIMEO (1 << 30)

/*
* Max persistent and resilient handle timeout (milliseconds).
* Windows durable max was 960000 (16 minutes)
*/
#define SMB3_MAX_HANDLE_TIMEOUT 960000

/*
* MAX_REQ is the maximum number of requests that WE will send
* on one socket concurrently.
Expand Down Expand Up @@ -586,6 +592,7 @@ struct smb_vol {
struct nls_table *local_nls;
unsigned int echo_interval; /* echo interval in secs */
__u64 snapshot_time; /* needed for timewarp tokens */
__u32 handle_timeout; /* persistent and durable handle timeout in ms */
unsigned int max_credits; /* smb3 max_credits 10 < credits < 60000 */
};

Expand Down Expand Up @@ -1058,6 +1065,7 @@ struct cifs_tcon {
__u32 vol_serial_number;
__le64 vol_create_time;
__u64 snapshot_time; /* for timewarp tokens - timestamp of snapshot */
__u32 handle_timeout; /* persistent and durable handle timeout in ms */
__u32 ss_flags; /* sector size flags */
__u32 perf_sector_size; /* best sector size for perf */
__u32 max_chunks;
Expand Down
30 changes: 29 additions & 1 deletion fs/cifs/connect.c
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ enum {
Opt_cruid, Opt_gid, Opt_file_mode,
Opt_dirmode, Opt_port,
Opt_blocksize, Opt_rsize, Opt_wsize, Opt_actimeo,
Opt_echo_interval, Opt_max_credits,
Opt_echo_interval, Opt_max_credits, Opt_handletimeout,
Opt_snapshot,

/* Mount options which take string value */
Expand Down Expand Up @@ -208,6 +208,7 @@ static const match_table_t cifs_mount_option_tokens = {
{ Opt_rsize, "rsize=%s" },
{ Opt_wsize, "wsize=%s" },
{ Opt_actimeo, "actimeo=%s" },
{ Opt_handletimeout, "handletimeout=%s" },
{ Opt_echo_interval, "echo_interval=%s" },
{ Opt_max_credits, "max_credits=%s" },
{ Opt_snapshot, "snapshot=%s" },
Expand Down Expand Up @@ -1619,6 +1620,9 @@ cifs_parse_mount_options(const char *mountdata, const char *devname,

vol->actimeo = CIFS_DEF_ACTIMEO;

/* Most clients set timeout to 0, allows server to use its default */
vol->handle_timeout = 0; /* See MS-SMB2 spec section 2.2.14.2.12 */

/* offer SMB2.1 and later (SMB3 etc). Secure and widely accepted */
vol->ops = &smb30_operations;
vol->vals = &smbdefault_values;
Expand Down Expand Up @@ -2017,6 +2021,18 @@ cifs_parse_mount_options(const char *mountdata, const char *devname,
goto cifs_parse_mount_err;
}
break;
case Opt_handletimeout:
if (get_option_ul(args, &option)) {
cifs_dbg(VFS, "%s: Invalid handletimeout value\n",
__func__);
goto cifs_parse_mount_err;
}
vol->handle_timeout = option;
if (vol->handle_timeout > SMB3_MAX_HANDLE_TIMEOUT) {
cifs_dbg(VFS, "Invalid handle cache timeout, longer than 16 minutes\n");
goto cifs_parse_mount_err;
}
break;
case Opt_echo_interval:
if (get_option_ul(args, &option)) {
cifs_dbg(VFS, "%s: Invalid echo interval value\n",
Expand Down Expand Up @@ -3183,6 +3199,8 @@ static int match_tcon(struct cifs_tcon *tcon, struct smb_vol *volume_info)
return 0;
if (tcon->snapshot_time != volume_info->snapshot_time)
return 0;
if (tcon->handle_timeout != volume_info->handle_timeout)
return 0;
return 1;
}

Expand Down Expand Up @@ -3297,6 +3315,16 @@ cifs_get_tcon(struct cifs_ses *ses, struct smb_vol *volume_info)
tcon->snapshot_time = volume_info->snapshot_time;
}

if (volume_info->handle_timeout) {
if (ses->server->vals->protocol_id == 0) {
cifs_dbg(VFS,
"Use SMB2.1 or later for handle timeout option\n");
rc = -EOPNOTSUPP;
goto out_fail;
} else
tcon->handle_timeout = volume_info->handle_timeout;
}

tcon->ses = ses;
if (volume_info->password) {
tcon->password = kstrdup(volume_info->password, GFP_KERNEL);
Expand Down
6 changes: 4 additions & 2 deletions fs/cifs/smb2file.c
Original file line number Diff line number Diff line change
Expand Up @@ -68,13 +68,15 @@ smb2_open_file(const unsigned int xid, struct cifs_open_parms *oparms,


if (oparms->tcon->use_resilient) {
nr_ioctl_req.Timeout = 0; /* use server default (120 seconds) */
/* default timeout is 0, servers pick default (120 seconds) */
nr_ioctl_req.Timeout =
cpu_to_le32(oparms->tcon->handle_timeout);
nr_ioctl_req.Reserved = 0;
rc = SMB2_ioctl(xid, oparms->tcon, fid->persistent_fid,
fid->volatile_fid, FSCTL_LMR_REQUEST_RESILIENCY,
true /* is_fsctl */,
(char *)&nr_ioctl_req, sizeof(nr_ioctl_req),
NULL, NULL /* no return info */);
CIFSMaxBufSize, NULL, NULL /* no return info */);
if (rc == -EOPNOTSUPP) {
cifs_dbg(VFS,
"resiliency not supported by server, disabling\n");
Expand Down
68 changes: 42 additions & 26 deletions fs/cifs/smb2ops.c
Original file line number Diff line number Diff line change
Expand Up @@ -581,7 +581,7 @@ SMB3_request_interfaces(const unsigned int xid, struct cifs_tcon *tcon)
rc = SMB2_ioctl(xid, tcon, NO_FILE_ID, NO_FILE_ID,
FSCTL_QUERY_NETWORK_INTERFACE_INFO, true /* is_fsctl */,
NULL /* no data input */, 0 /* no data input */,
(char **)&out_buf, &ret_data_len);
CIFSMaxBufSize, (char **)&out_buf, &ret_data_len);
if (rc == -EOPNOTSUPP) {
cifs_dbg(FYI,
"server does not support query network interfaces\n");
Expand Down Expand Up @@ -717,32 +717,28 @@ int open_shroot(unsigned int xid, struct cifs_tcon *tcon, struct cifs_fid *pfid)
oparms.fid->mid = le64_to_cpu(o_rsp->sync_hdr.MessageId);
#endif /* CIFS_DEBUG2 */

if (o_rsp->OplockLevel == SMB2_OPLOCK_LEVEL_LEASE)
oplock = smb2_parse_lease_state(server, o_rsp,
&oparms.fid->epoch,
oparms.fid->lease_key);
else
goto oshr_exit;


memcpy(tcon->crfid.fid, pfid, sizeof(struct cifs_fid));
tcon->crfid.tcon = tcon;
tcon->crfid.is_valid = true;
kref_init(&tcon->crfid.refcount);
kref_get(&tcon->crfid.refcount);

if (o_rsp->OplockLevel == SMB2_OPLOCK_LEVEL_LEASE) {
kref_get(&tcon->crfid.refcount);
oplock = smb2_parse_lease_state(server, o_rsp,
&oparms.fid->epoch,
oparms.fid->lease_key);
} else
goto oshr_exit;

qi_rsp = (struct smb2_query_info_rsp *)rsp_iov[1].iov_base;
if (le32_to_cpu(qi_rsp->OutputBufferLength) < sizeof(struct smb2_file_all_info))
goto oshr_exit;
rc = smb2_validate_and_copy_iov(
if (!smb2_validate_and_copy_iov(
le16_to_cpu(qi_rsp->OutputBufferOffset),
sizeof(struct smb2_file_all_info),
&rsp_iov[1], sizeof(struct smb2_file_all_info),
(char *)&tcon->crfid.file_all_info);
if (rc)
goto oshr_exit;
tcon->crfid.file_all_info_is_valid = 1;
(char *)&tcon->crfid.file_all_info))
tcon->crfid.file_all_info_is_valid = 1;

oshr_exit:
mutex_unlock(&tcon->crfid.fid_mutex);
Expand Down Expand Up @@ -1299,7 +1295,7 @@ SMB2_request_res_key(const unsigned int xid, struct cifs_tcon *tcon,

rc = SMB2_ioctl(xid, tcon, persistent_fid, volatile_fid,
FSCTL_SRV_REQUEST_RESUME_KEY, true /* is_fsctl */,
NULL, 0 /* no input */,
NULL, 0 /* no input */, CIFSMaxBufSize,
(char **)&res_key, &ret_data_len);

if (rc) {
Expand Down Expand Up @@ -1404,7 +1400,7 @@ smb2_ioctl_query_info(const unsigned int xid,
rc = SMB2_ioctl_init(tcon, &rqst[1],
COMPOUND_FID, COMPOUND_FID,
qi.info_type, true, NULL,
0);
0, CIFSMaxBufSize);
}
} else if (qi.flags == PASSTHRU_QUERY_INFO) {
memset(&qi_iov, 0, sizeof(qi_iov));
Expand Down Expand Up @@ -1532,8 +1528,8 @@ smb2_copychunk_range(const unsigned int xid,
rc = SMB2_ioctl(xid, tcon, trgtfile->fid.persistent_fid,
trgtfile->fid.volatile_fid, FSCTL_SRV_COPYCHUNK_WRITE,
true /* is_fsctl */, (char *)pcchunk,
sizeof(struct copychunk_ioctl), (char **)&retbuf,
&ret_data_len);
sizeof(struct copychunk_ioctl), CIFSMaxBufSize,
(char **)&retbuf, &ret_data_len);
if (rc == 0) {
if (ret_data_len !=
sizeof(struct copychunk_ioctl_rsp)) {
Expand Down Expand Up @@ -1693,7 +1689,7 @@ static bool smb2_set_sparse(const unsigned int xid, struct cifs_tcon *tcon,
rc = SMB2_ioctl(xid, tcon, cfile->fid.persistent_fid,
cfile->fid.volatile_fid, FSCTL_SET_SPARSE,
true /* is_fctl */,
&setsparse, 1, NULL, NULL);
&setsparse, 1, CIFSMaxBufSize, NULL, NULL);
if (rc) {
tcon->broken_sparse_sup = true;
cifs_dbg(FYI, "set sparse rc = %d\n", rc);
Expand Down Expand Up @@ -1766,7 +1762,7 @@ smb2_duplicate_extents(const unsigned int xid,
true /* is_fsctl */,
(char *)&dup_ext_buf,
sizeof(struct duplicate_extents_to_file),
NULL,
CIFSMaxBufSize, NULL,
&ret_data_len);

if (ret_data_len > 0)
Expand Down Expand Up @@ -1801,14 +1797,16 @@ smb3_set_integrity(const unsigned int xid, struct cifs_tcon *tcon,
true /* is_fsctl */,
(char *)&integr_info,
sizeof(struct fsctl_set_integrity_information_req),
NULL,
CIFSMaxBufSize, NULL,
&ret_data_len);

}

/* GMT Token is @GMT-YYYY.MM.DD-HH.MM.SS Unicode which is 48 bytes + null */
#define GMT_TOKEN_SIZE 50

#define MIN_SNAPSHOT_ARRAY_SIZE 16 /* See MS-SMB2 section 3.3.5.15.1 */

/*
* Input buffer contains (empty) struct smb_snapshot array with size filled in
* For output see struct SRV_SNAPSHOT_ARRAY in MS-SMB2 section 2.2.32.2
Expand All @@ -1820,13 +1818,29 @@ smb3_enum_snapshots(const unsigned int xid, struct cifs_tcon *tcon,
char *retbuf = NULL;
unsigned int ret_data_len = 0;
int rc;
u32 max_response_size;
struct smb_snapshot_array snapshot_in;

if (get_user(ret_data_len, (unsigned int __user *)ioc_buf))
return -EFAULT;

/*
* Note that for snapshot queries that servers like Azure expect that
* the first query be minimal size (and just used to get the number/size
* of previous versions) so response size must be specified as EXACTLY
* sizeof(struct snapshot_array) which is 16 when rounded up to multiple
* of eight bytes.
*/
if (ret_data_len == 0)
max_response_size = MIN_SNAPSHOT_ARRAY_SIZE;
else
max_response_size = CIFSMaxBufSize;

rc = SMB2_ioctl(xid, tcon, cfile->fid.persistent_fid,
cfile->fid.volatile_fid,
FSCTL_SRV_ENUMERATE_SNAPSHOTS,
true /* is_fsctl */,
NULL, 0 /* no input data */,
NULL, 0 /* no input data */, max_response_size,
(char **)&retbuf,
&ret_data_len);
cifs_dbg(FYI, "enum snaphots ioctl returned %d and ret buflen is %d\n",
Expand Down Expand Up @@ -2304,7 +2318,7 @@ smb2_get_dfs_refer(const unsigned int xid, struct cifs_ses *ses,
rc = SMB2_ioctl(xid, tcon, NO_FILE_ID, NO_FILE_ID,
FSCTL_DFS_GET_REFERRALS,
true /* is_fsctl */,
(char *)dfs_req, dfs_req_size,
(char *)dfs_req, dfs_req_size, CIFSMaxBufSize,
(char **)&dfs_rsp, &dfs_rsp_size);
} while (rc == -EAGAIN);

Expand Down Expand Up @@ -2658,7 +2672,8 @@ static long smb3_zero_range(struct file *file, struct cifs_tcon *tcon,
rc = SMB2_ioctl_init(tcon, &rqst[num++], cfile->fid.persistent_fid,
cfile->fid.volatile_fid, FSCTL_SET_ZERO_DATA,
true /* is_fctl */, (char *)&fsctl_buf,
sizeof(struct file_zero_data_information));
sizeof(struct file_zero_data_information),
CIFSMaxBufSize);
if (rc)
goto zero_range_exit;

Expand Down Expand Up @@ -2735,7 +2750,8 @@ static long smb3_punch_hole(struct file *file, struct cifs_tcon *tcon,
rc = SMB2_ioctl(xid, tcon, cfile->fid.persistent_fid,
cfile->fid.volatile_fid, FSCTL_SET_ZERO_DATA,
true /* is_fctl */, (char *)&fsctl_buf,
sizeof(struct file_zero_data_information), NULL, NULL);
sizeof(struct file_zero_data_information),
CIFSMaxBufSize, NULL, NULL);
free_xid(xid);
return rc;
}
Expand Down
Loading

0 comments on commit 145f47c

Please sign in to comment.