Skip to content

Commit 4bb6682

Browse files
Steve Frenchjfvogel
authored andcommitted
smb311: failure to open files of length 1040 when mounting with SMB3.1.1 POSIX extensions
[ Upstream commit 9df2380 ] 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> Signed-off-by: Sasha Levin <sashal@kernel.org> (cherry picked from commit f2e8f906f9ed5529283f8c139859efc7bff4f2ef) Signed-off-by: Jack Vogel <jack.vogel@oracle.com>
1 parent 07c8427 commit 4bb6682

File tree

4 files changed

+29
-7
lines changed

4 files changed

+29
-7
lines changed

fs/smb/client/cifsglob.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -210,6 +210,7 @@ struct cifs_cred {
210210
struct cifs_open_info_data {
211211
bool adjust_tz;
212212
bool reparse_point;
213+
bool contains_posix_file_info;
213214
struct {
214215
/* ioctl response buffer */
215216
struct {

fs/smb/client/reparse.h

Lines changed: 22 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -97,14 +97,30 @@ static inline bool reparse_inode_match(struct inode *inode,
9797

9898
static inline bool cifs_open_data_reparse(struct cifs_open_info_data *data)
9999
{
100-
struct smb2_file_all_info *fi = &data->fi;
101-
u32 attrs = le32_to_cpu(fi->Attributes);
100+
u32 attrs;
102101
bool ret;
103102

104-
ret = data->reparse_point || (attrs & ATTR_REPARSE);
105-
if (ret)
106-
attrs |= ATTR_REPARSE;
107-
fi->Attributes = cpu_to_le32(attrs);
103+
if (data->contains_posix_file_info) {
104+
struct smb311_posix_qinfo *fi = &data->posix_fi;
105+
106+
attrs = le32_to_cpu(fi->DosAttributes);
107+
if (data->reparse_point) {
108+
attrs |= ATTR_REPARSE;
109+
fi->DosAttributes = cpu_to_le32(attrs);
110+
}
111+
112+
} else {
113+
struct smb2_file_all_info *fi = &data->fi;
114+
115+
attrs = le32_to_cpu(fi->Attributes);
116+
if (data->reparse_point) {
117+
attrs |= ATTR_REPARSE;
118+
fi->Attributes = cpu_to_le32(attrs);
119+
}
120+
}
121+
122+
ret = attrs & ATTR_REPARSE;
123+
108124
return ret;
109125
}
110126

fs/smb/client/smb2inode.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -648,6 +648,7 @@ static int smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon,
648648
switch (cmds[i]) {
649649
case SMB2_OP_QUERY_INFO:
650650
idata = in_iov[i].iov_base;
651+
idata->contains_posix_file_info = false;
651652
if (rc == 0 && cfile && cfile->symlink_target) {
652653
idata->symlink_target = kstrdup(cfile->symlink_target, GFP_KERNEL);
653654
if (!idata->symlink_target)
@@ -671,6 +672,7 @@ static int smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon,
671672
break;
672673
case SMB2_OP_POSIX_QUERY_INFO:
673674
idata = in_iov[i].iov_base;
675+
idata->contains_posix_file_info = true;
674676
if (rc == 0 && cfile && cfile->symlink_target) {
675677
idata->symlink_target = kstrdup(cfile->symlink_target, GFP_KERNEL);
676678
if (!idata->symlink_target)
@@ -768,6 +770,7 @@ static int smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon,
768770
idata = in_iov[i].iov_base;
769771
idata->reparse.io.iov = *iov;
770772
idata->reparse.io.buftype = resp_buftype[i + 1];
773+
idata->contains_posix_file_info = false; /* BB VERIFY */
771774
rbuf = reparse_buf_ptr(iov);
772775
if (IS_ERR(rbuf)) {
773776
rc = PTR_ERR(rbuf);
@@ -789,6 +792,7 @@ static int smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon,
789792
case SMB2_OP_QUERY_WSL_EA:
790793
if (!rc) {
791794
idata = in_iov[i].iov_base;
795+
idata->contains_posix_file_info = false;
792796
qi_rsp = rsp_iov[i + 1].iov_base;
793797
data[0] = (u8 *)qi_rsp + le16_to_cpu(qi_rsp->OutputBufferOffset);
794798
size[0] = le32_to_cpu(qi_rsp->OutputBufferLength);

fs/smb/client/smb2ops.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1001,6 +1001,7 @@ static int smb2_query_file_info(const unsigned int xid, struct cifs_tcon *tcon,
10011001
if (!data->symlink_target)
10021002
return -ENOMEM;
10031003
}
1004+
data->contains_posix_file_info = false;
10041005
return SMB2_query_info(xid, tcon, fid->persistent_fid, fid->volatile_fid, &data->fi);
10051006
}
10061007

@@ -5177,7 +5178,7 @@ int __cifs_sfu_make_node(unsigned int xid, struct inode *inode,
51775178
FILE_CREATE, CREATE_NOT_DIR |
51785179
CREATE_OPTION_SPECIAL, ACL_NO_MODE);
51795180
oparms.fid = &fid;
5180-
5181+
idata.contains_posix_file_info = false;
51815182
rc = server->ops->open(xid, &oparms, &oplock, &idata);
51825183
if (rc)
51835184
goto out;

0 commit comments

Comments
 (0)