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,
.desired_access = FILE_READ_DATA | FILE_READ_ATTRIBUTES,
.disposition = FILE_OPEN,
.fid = pfid,
.replay = !!(retries),
};
rc = SMB2_open_init(tcon, server,
......
......@@ -1378,6 +1378,7 @@ struct cifs_open_parms {
struct cifs_fid *fid;
umode_t mode;
bool reconnect:1;
bool replay:1; /* indicates that this open is for a replay */
};
struct cifs_fid {
......
......@@ -3444,8 +3444,18 @@ int cifs_mount_get_tcon(struct cifs_mount_ctx *mnt_ctx)
* the user on mount
*/
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) ||
(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,
case Opt_wsize:
ctx->wsize = result.uint_32;
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;
case Opt_acregmax:
ctx->acregmax = HZ * result.uint_32;
......
......@@ -168,6 +168,21 @@ static char *automount_fullpath(struct dentry *dentry, void *page)
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
*/
......@@ -205,6 +220,7 @@ static struct vfsmount *cifs_do_automount(struct path *path)
tmp.leaf_fullpath = NULL;
tmp.UNC = tmp.prepath = NULL;
tmp.dfs_root_ses = NULL;
fs_context_set_ids(&tmp);
rc = smb3_fs_context_dup(ctx, &tmp);
if (rc) {
......
......@@ -619,7 +619,7 @@ parse_server_interfaces(struct network_interface_info_ioctl_rsp *buf,
goto out;
}
while (bytes_left >= sizeof(*p)) {
while (bytes_left >= (ssize_t)sizeof(*p)) {
memset(&tmp_iface, 0, sizeof(tmp_iface));
tmp_iface.speed = le64_to_cpu(p->LinkSpeed);
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,
.disposition = FILE_OPEN,
.create_options = cifs_create_options(cifs_sb, 0),
.fid = &fid,
.replay = !!(retries),
};
rc = SMB2_open_init(tcon, server,
......@@ -1569,6 +1570,7 @@ smb2_ioctl_query_info(const unsigned int xid,
.disposition = FILE_OPEN,
.create_options = cifs_create_options(cifs_sb, create_options),
.fid = &fid,
.replay = !!(retries),
};
if (qi.flags & PASSTHRU_FSCTL) {
......@@ -2295,6 +2297,7 @@ smb2_query_dir_first(const unsigned int xid, struct cifs_tcon *tcon,
.disposition = FILE_OPEN,
.create_options = cifs_create_options(cifs_sb, 0),
.fid = fid,
.replay = !!(retries),
};
rc = SMB2_open_init(tcon, server,
......@@ -2681,6 +2684,7 @@ smb2_query_info_compound(const unsigned int xid, struct cifs_tcon *tcon,
.disposition = FILE_OPEN,
.create_options = cifs_create_options(cifs_sb, 0),
.fid = &fid,
.replay = !!(retries),
};
rc = SMB2_open_init(tcon, server,
......@@ -5213,7 +5217,7 @@ static int smb2_create_reparse_symlink(const unsigned int xid,
struct inode *new;
struct kvec iov;
__le16 *path;
char *sym;
char *sym, sep = CIFS_DIR_SEP(cifs_sb);
u16 len, plen;
int rc = 0;
......@@ -5227,7 +5231,8 @@ static int smb2_create_reparse_symlink(const unsigned int xid,
.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) {
rc = -ENOMEM;
goto out;
......@@ -5250,7 +5255,10 @@ static int smb2_create_reparse_symlink(const unsigned int xid,
buf->PrintNameLength = cpu_to_le16(plen);
memcpy(buf->PathBuffer, path, plen);
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_len = len;
new = smb2_get_reparse_inode(&data, inode->i_sb, xid,
......
......@@ -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.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" */
buf->Name[0] = 'D';
......@@ -3142,6 +3147,7 @@ SMB2_open(const unsigned int xid, struct cifs_open_parms *oparms, __le16 *path,
/* reinitialize for possible replay */
flags = 0;
server = cifs_pick_channel(ses);
oparms->replay = !!(retries);
cifs_dbg(FYI, "create/open\n");
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