Commit 55f626f2 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag '6.8-rc4-smb3-client-fixes' of git://git.samba.org/sfrench/cifs-2.6

Pull smb client fixes from Steve French:
 "Five smb3 client fixes, most also for stable:

   - Two multichannel fixes (one to fix potential handle leak on retry)

   - Work around possible serious data corruption (due to change in
     folios in 6.3, for cases when non standard maximum write size
     negotiated)

   - Symlink creation fix

   - Multiuser automount fix"

* tag '6.8-rc4-smb3-client-fixes' of git://git.samba.org/sfrench/cifs-2.6:
  smb: Fix regression in writes when non-standard maximum write size negotiated
  smb: client: handle path separator of created SMB symlinks
  smb: client: set correct id, uid and cruid for multiuser automounts
  cifs: update the same create_guid on replay
  cifs: fix underflow in parse_server_interfaces()
parents c1ca10ce 4860abb9
...@@ -242,6 +242,7 @@ int open_cached_dir(unsigned int xid, struct cifs_tcon *tcon, ...@@ -242,6 +242,7 @@ int open_cached_dir(unsigned int xid, struct cifs_tcon *tcon,
.desired_access = FILE_READ_DATA | FILE_READ_ATTRIBUTES, .desired_access = FILE_READ_DATA | FILE_READ_ATTRIBUTES,
.disposition = FILE_OPEN, .disposition = FILE_OPEN,
.fid = pfid, .fid = pfid,
.replay = !!(retries),
}; };
rc = SMB2_open_init(tcon, server, rc = SMB2_open_init(tcon, server,
......
...@@ -1378,6 +1378,7 @@ struct cifs_open_parms { ...@@ -1378,6 +1378,7 @@ struct cifs_open_parms {
struct cifs_fid *fid; struct cifs_fid *fid;
umode_t mode; umode_t mode;
bool reconnect:1; bool reconnect:1;
bool replay:1; /* indicates that this open is for a replay */
}; };
struct cifs_fid { struct cifs_fid {
......
...@@ -3444,8 +3444,18 @@ int cifs_mount_get_tcon(struct cifs_mount_ctx *mnt_ctx) ...@@ -3444,8 +3444,18 @@ int cifs_mount_get_tcon(struct cifs_mount_ctx *mnt_ctx)
* the user on mount * the user on mount
*/ */
if ((cifs_sb->ctx->wsize == 0) || if ((cifs_sb->ctx->wsize == 0) ||
(cifs_sb->ctx->wsize > server->ops->negotiate_wsize(tcon, ctx))) (cifs_sb->ctx->wsize > server->ops->negotiate_wsize(tcon, ctx))) {
cifs_sb->ctx->wsize = server->ops->negotiate_wsize(tcon, ctx); cifs_sb->ctx->wsize =
round_down(server->ops->negotiate_wsize(tcon, ctx), PAGE_SIZE);
/*
* in the very unlikely event that the server sent a max write size under PAGE_SIZE,
* (which would get rounded down to 0) then reset wsize to absolute minimum eg 4096
*/
if (cifs_sb->ctx->wsize == 0) {
cifs_sb->ctx->wsize = PAGE_SIZE;
cifs_dbg(VFS, "wsize too small, reset to minimum ie PAGE_SIZE, usually 4096\n");
}
}
if ((cifs_sb->ctx->rsize == 0) || if ((cifs_sb->ctx->rsize == 0) ||
(cifs_sb->ctx->rsize > server->ops->negotiate_rsize(tcon, ctx))) (cifs_sb->ctx->rsize > server->ops->negotiate_rsize(tcon, ctx)))
cifs_sb->ctx->rsize = server->ops->negotiate_rsize(tcon, ctx); cifs_sb->ctx->rsize = server->ops->negotiate_rsize(tcon, ctx);
......
...@@ -1111,6 +1111,17 @@ static int smb3_fs_context_parse_param(struct fs_context *fc, ...@@ -1111,6 +1111,17 @@ static int smb3_fs_context_parse_param(struct fs_context *fc,
case Opt_wsize: case Opt_wsize:
ctx->wsize = result.uint_32; ctx->wsize = result.uint_32;
ctx->got_wsize = true; ctx->got_wsize = true;
if (ctx->wsize % PAGE_SIZE != 0) {
ctx->wsize = round_down(ctx->wsize, PAGE_SIZE);
if (ctx->wsize == 0) {
ctx->wsize = PAGE_SIZE;
cifs_dbg(VFS, "wsize too small, reset to minimum %ld\n", PAGE_SIZE);
} else {
cifs_dbg(VFS,
"wsize rounded down to %d to multiple of PAGE_SIZE %ld\n",
ctx->wsize, PAGE_SIZE);
}
}
break; break;
case Opt_acregmax: case Opt_acregmax:
ctx->acregmax = HZ * result.uint_32; ctx->acregmax = HZ * result.uint_32;
......
...@@ -168,6 +168,21 @@ static char *automount_fullpath(struct dentry *dentry, void *page) ...@@ -168,6 +168,21 @@ static char *automount_fullpath(struct dentry *dentry, void *page)
return s; return s;
} }
static void fs_context_set_ids(struct smb3_fs_context *ctx)
{
kuid_t uid = current_fsuid();
kgid_t gid = current_fsgid();
if (ctx->multiuser) {
if (!ctx->uid_specified)
ctx->linux_uid = uid;
if (!ctx->gid_specified)
ctx->linux_gid = gid;
}
if (!ctx->cruid_specified)
ctx->cred_uid = uid;
}
/* /*
* Create a vfsmount that we can automount * Create a vfsmount that we can automount
*/ */
...@@ -205,6 +220,7 @@ static struct vfsmount *cifs_do_automount(struct path *path) ...@@ -205,6 +220,7 @@ static struct vfsmount *cifs_do_automount(struct path *path)
tmp.leaf_fullpath = NULL; tmp.leaf_fullpath = NULL;
tmp.UNC = tmp.prepath = NULL; tmp.UNC = tmp.prepath = NULL;
tmp.dfs_root_ses = NULL; tmp.dfs_root_ses = NULL;
fs_context_set_ids(&tmp);
rc = smb3_fs_context_dup(ctx, &tmp); rc = smb3_fs_context_dup(ctx, &tmp);
if (rc) { if (rc) {
......
...@@ -619,7 +619,7 @@ parse_server_interfaces(struct network_interface_info_ioctl_rsp *buf, ...@@ -619,7 +619,7 @@ parse_server_interfaces(struct network_interface_info_ioctl_rsp *buf,
goto out; goto out;
} }
while (bytes_left >= sizeof(*p)) { while (bytes_left >= (ssize_t)sizeof(*p)) {
memset(&tmp_iface, 0, sizeof(tmp_iface)); memset(&tmp_iface, 0, sizeof(tmp_iface));
tmp_iface.speed = le64_to_cpu(p->LinkSpeed); tmp_iface.speed = le64_to_cpu(p->LinkSpeed);
tmp_iface.rdma_capable = le32_to_cpu(p->Capability & RDMA_CAPABLE) ? 1 : 0; tmp_iface.rdma_capable = le32_to_cpu(p->Capability & RDMA_CAPABLE) ? 1 : 0;
...@@ -1204,6 +1204,7 @@ smb2_set_ea(const unsigned int xid, struct cifs_tcon *tcon, ...@@ -1204,6 +1204,7 @@ smb2_set_ea(const unsigned int xid, struct cifs_tcon *tcon,
.disposition = FILE_OPEN, .disposition = FILE_OPEN,
.create_options = cifs_create_options(cifs_sb, 0), .create_options = cifs_create_options(cifs_sb, 0),
.fid = &fid, .fid = &fid,
.replay = !!(retries),
}; };
rc = SMB2_open_init(tcon, server, rc = SMB2_open_init(tcon, server,
...@@ -1569,6 +1570,7 @@ smb2_ioctl_query_info(const unsigned int xid, ...@@ -1569,6 +1570,7 @@ smb2_ioctl_query_info(const unsigned int xid,
.disposition = FILE_OPEN, .disposition = FILE_OPEN,
.create_options = cifs_create_options(cifs_sb, create_options), .create_options = cifs_create_options(cifs_sb, create_options),
.fid = &fid, .fid = &fid,
.replay = !!(retries),
}; };
if (qi.flags & PASSTHRU_FSCTL) { if (qi.flags & PASSTHRU_FSCTL) {
...@@ -2295,6 +2297,7 @@ smb2_query_dir_first(const unsigned int xid, struct cifs_tcon *tcon, ...@@ -2295,6 +2297,7 @@ smb2_query_dir_first(const unsigned int xid, struct cifs_tcon *tcon,
.disposition = FILE_OPEN, .disposition = FILE_OPEN,
.create_options = cifs_create_options(cifs_sb, 0), .create_options = cifs_create_options(cifs_sb, 0),
.fid = fid, .fid = fid,
.replay = !!(retries),
}; };
rc = SMB2_open_init(tcon, server, rc = SMB2_open_init(tcon, server,
...@@ -2681,6 +2684,7 @@ smb2_query_info_compound(const unsigned int xid, struct cifs_tcon *tcon, ...@@ -2681,6 +2684,7 @@ smb2_query_info_compound(const unsigned int xid, struct cifs_tcon *tcon,
.disposition = FILE_OPEN, .disposition = FILE_OPEN,
.create_options = cifs_create_options(cifs_sb, 0), .create_options = cifs_create_options(cifs_sb, 0),
.fid = &fid, .fid = &fid,
.replay = !!(retries),
}; };
rc = SMB2_open_init(tcon, server, rc = SMB2_open_init(tcon, server,
...@@ -5213,7 +5217,7 @@ static int smb2_create_reparse_symlink(const unsigned int xid, ...@@ -5213,7 +5217,7 @@ static int smb2_create_reparse_symlink(const unsigned int xid,
struct inode *new; struct inode *new;
struct kvec iov; struct kvec iov;
__le16 *path; __le16 *path;
char *sym; char *sym, sep = CIFS_DIR_SEP(cifs_sb);
u16 len, plen; u16 len, plen;
int rc = 0; int rc = 0;
...@@ -5227,7 +5231,8 @@ static int smb2_create_reparse_symlink(const unsigned int xid, ...@@ -5227,7 +5231,8 @@ static int smb2_create_reparse_symlink(const unsigned int xid,
.symlink_target = sym, .symlink_target = sym,
}; };
path = cifs_convert_path_to_utf16(symname, cifs_sb); convert_delimiter(sym, sep);
path = cifs_convert_path_to_utf16(sym, cifs_sb);
if (!path) { if (!path) {
rc = -ENOMEM; rc = -ENOMEM;
goto out; goto out;
...@@ -5250,7 +5255,10 @@ static int smb2_create_reparse_symlink(const unsigned int xid, ...@@ -5250,7 +5255,10 @@ static int smb2_create_reparse_symlink(const unsigned int xid,
buf->PrintNameLength = cpu_to_le16(plen); buf->PrintNameLength = cpu_to_le16(plen);
memcpy(buf->PathBuffer, path, plen); memcpy(buf->PathBuffer, path, plen);
buf->Flags = cpu_to_le32(*symname != '/' ? SYMLINK_FLAG_RELATIVE : 0); buf->Flags = cpu_to_le32(*symname != '/' ? SYMLINK_FLAG_RELATIVE : 0);
if (*sym != sep)
buf->Flags = cpu_to_le32(SYMLINK_FLAG_RELATIVE);
convert_delimiter(sym, '/');
iov.iov_base = buf; iov.iov_base = buf;
iov.iov_len = len; iov.iov_len = len;
new = smb2_get_reparse_inode(&data, inode->i_sb, xid, new = smb2_get_reparse_inode(&data, inode->i_sb, xid,
......
...@@ -2404,8 +2404,13 @@ create_durable_v2_buf(struct cifs_open_parms *oparms) ...@@ -2404,8 +2404,13 @@ create_durable_v2_buf(struct cifs_open_parms *oparms)
*/ */
buf->dcontext.Timeout = cpu_to_le32(oparms->tcon->handle_timeout); buf->dcontext.Timeout = cpu_to_le32(oparms->tcon->handle_timeout);
buf->dcontext.Flags = cpu_to_le32(SMB2_DHANDLE_FLAG_PERSISTENT); buf->dcontext.Flags = cpu_to_le32(SMB2_DHANDLE_FLAG_PERSISTENT);
generate_random_uuid(buf->dcontext.CreateGuid);
memcpy(pfid->create_guid, buf->dcontext.CreateGuid, 16); /* for replay, we should not overwrite the existing create guid */
if (!oparms->replay) {
generate_random_uuid(buf->dcontext.CreateGuid);
memcpy(pfid->create_guid, buf->dcontext.CreateGuid, 16);
} else
memcpy(buf->dcontext.CreateGuid, pfid->create_guid, 16);
/* SMB2_CREATE_DURABLE_HANDLE_REQUEST is "DH2Q" */ /* SMB2_CREATE_DURABLE_HANDLE_REQUEST is "DH2Q" */
buf->Name[0] = 'D'; buf->Name[0] = 'D';
...@@ -3142,6 +3147,7 @@ SMB2_open(const unsigned int xid, struct cifs_open_parms *oparms, __le16 *path, ...@@ -3142,6 +3147,7 @@ SMB2_open(const unsigned int xid, struct cifs_open_parms *oparms, __le16 *path,
/* reinitialize for possible replay */ /* reinitialize for possible replay */
flags = 0; flags = 0;
server = cifs_pick_channel(ses); server = cifs_pick_channel(ses);
oparms->replay = !!(retries);
cifs_dbg(FYI, "create/open\n"); cifs_dbg(FYI, "create/open\n");
if (!ses || !server) if (!ses || !server)
......
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