smb311: failure to open files of length 1040 when mounting with SMB3.1.1 POSIX extensions
If a file size has bits 0x410 = ATTR_DIRECTORY | ATTR_REPARSE set then during queryinfo (stat) the file is regarded as a directory and subsequent opens can fail. A simple test example is trying to open any file 1040 bytes long when mounting with "posix" (SMB3.1.1 POSIX/Linux Extensions). The cause of this bug is that Attributes field in smb2_file_all_info struct occupies the same place that EndOfFile field in smb311_posix_qinfo, and sometimes the latter struct is incorrectly processed as if it was the first one. Reported-by: Oleh Nykyforchyn <oleh.nyk@gmail.com> Tested-by: Oleh Nykyforchyn <oleh.nyk@gmail.com> Acked-by: Paulo Alcantara (Red Hat) <pc@manguebit.com> Cc: stable@vger.kernel.org Signed-off-by: Steve French <stfrench@microsoft.com>
This commit is contained in:
parent
7330195e60
commit
9df23801c8
4 changed files with 29 additions and 7 deletions
|
@ -253,6 +253,7 @@ struct cifs_cred {
|
|||
struct cifs_open_info_data {
|
||||
bool adjust_tz;
|
||||
bool reparse_point;
|
||||
bool contains_posix_file_info;
|
||||
struct {
|
||||
/* ioctl response buffer */
|
||||
struct {
|
||||
|
|
|
@ -99,14 +99,30 @@ static inline bool reparse_inode_match(struct inode *inode,
|
|||
|
||||
static inline bool cifs_open_data_reparse(struct cifs_open_info_data *data)
|
||||
{
|
||||
struct smb2_file_all_info *fi = &data->fi;
|
||||
u32 attrs = le32_to_cpu(fi->Attributes);
|
||||
u32 attrs;
|
||||
bool ret;
|
||||
|
||||
ret = data->reparse_point || (attrs & ATTR_REPARSE);
|
||||
if (ret)
|
||||
attrs |= ATTR_REPARSE;
|
||||
fi->Attributes = cpu_to_le32(attrs);
|
||||
if (data->contains_posix_file_info) {
|
||||
struct smb311_posix_qinfo *fi = &data->posix_fi;
|
||||
|
||||
attrs = le32_to_cpu(fi->DosAttributes);
|
||||
if (data->reparse_point) {
|
||||
attrs |= ATTR_REPARSE;
|
||||
fi->DosAttributes = cpu_to_le32(attrs);
|
||||
}
|
||||
|
||||
} else {
|
||||
struct smb2_file_all_info *fi = &data->fi;
|
||||
|
||||
attrs = le32_to_cpu(fi->Attributes);
|
||||
if (data->reparse_point) {
|
||||
attrs |= ATTR_REPARSE;
|
||||
fi->Attributes = cpu_to_le32(attrs);
|
||||
}
|
||||
}
|
||||
|
||||
ret = attrs & ATTR_REPARSE;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
|
@ -650,6 +650,7 @@ finished:
|
|||
switch (cmds[i]) {
|
||||
case SMB2_OP_QUERY_INFO:
|
||||
idata = in_iov[i].iov_base;
|
||||
idata->contains_posix_file_info = false;
|
||||
if (rc == 0 && cfile && cfile->symlink_target) {
|
||||
idata->symlink_target = kstrdup(cfile->symlink_target, GFP_KERNEL);
|
||||
if (!idata->symlink_target)
|
||||
|
@ -673,6 +674,7 @@ finished:
|
|||
break;
|
||||
case SMB2_OP_POSIX_QUERY_INFO:
|
||||
idata = in_iov[i].iov_base;
|
||||
idata->contains_posix_file_info = true;
|
||||
if (rc == 0 && cfile && cfile->symlink_target) {
|
||||
idata->symlink_target = kstrdup(cfile->symlink_target, GFP_KERNEL);
|
||||
if (!idata->symlink_target)
|
||||
|
@ -770,6 +772,7 @@ finished:
|
|||
idata = in_iov[i].iov_base;
|
||||
idata->reparse.io.iov = *iov;
|
||||
idata->reparse.io.buftype = resp_buftype[i + 1];
|
||||
idata->contains_posix_file_info = false; /* BB VERIFY */
|
||||
rbuf = reparse_buf_ptr(iov);
|
||||
if (IS_ERR(rbuf)) {
|
||||
rc = PTR_ERR(rbuf);
|
||||
|
@ -791,6 +794,7 @@ finished:
|
|||
case SMB2_OP_QUERY_WSL_EA:
|
||||
if (!rc) {
|
||||
idata = in_iov[i].iov_base;
|
||||
idata->contains_posix_file_info = false;
|
||||
qi_rsp = rsp_iov[i + 1].iov_base;
|
||||
data[0] = (u8 *)qi_rsp + le16_to_cpu(qi_rsp->OutputBufferOffset);
|
||||
size[0] = le32_to_cpu(qi_rsp->OutputBufferLength);
|
||||
|
|
|
@ -1001,6 +1001,7 @@ static int smb2_query_file_info(const unsigned int xid, struct cifs_tcon *tcon,
|
|||
if (!data->symlink_target)
|
||||
return -ENOMEM;
|
||||
}
|
||||
data->contains_posix_file_info = false;
|
||||
return SMB2_query_info(xid, tcon, fid->persistent_fid, fid->volatile_fid, &data->fi);
|
||||
}
|
||||
|
||||
|
@ -5146,7 +5147,7 @@ int __cifs_sfu_make_node(unsigned int xid, struct inode *inode,
|
|||
FILE_CREATE, CREATE_NOT_DIR |
|
||||
CREATE_OPTION_SPECIAL, ACL_NO_MODE);
|
||||
oparms.fid = &fid;
|
||||
|
||||
idata.contains_posix_file_info = false;
|
||||
rc = server->ops->open(xid, &oparms, &oplock, &idata);
|
||||
if (rc)
|
||||
goto out;
|
||||
|
|
Loading…
Add table
Reference in a new issue