Skip to content

Commit 9df2380

Browse files
author
Steve French
committed
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 <[email protected]> Tested-by: Oleh Nykyforchyn <[email protected]> Acked-by: Paulo Alcantara (Red Hat) <[email protected]> Cc: [email protected] Signed-off-by: Steve French <[email protected]>
1 parent 7330195 commit 9df2380

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
@@ -253,6 +253,7 @@ struct cifs_cred {
253253
struct cifs_open_info_data {
254254
bool adjust_tz;
255255
bool reparse_point;
256+
bool contains_posix_file_info;
256257
struct {
257258
/* ioctl response buffer */
258259
struct {

fs/smb/client/reparse.h

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

100100
static inline bool cifs_open_data_reparse(struct cifs_open_info_data *data)
101101
{
102-
struct smb2_file_all_info *fi = &data->fi;
103-
u32 attrs = le32_to_cpu(fi->Attributes);
102+
u32 attrs;
104103
bool ret;
105104

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

fs/smb/client/smb2inode.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -650,6 +650,7 @@ static int smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon,
650650
switch (cmds[i]) {
651651
case SMB2_OP_QUERY_INFO:
652652
idata = in_iov[i].iov_base;
653+
idata->contains_posix_file_info = false;
653654
if (rc == 0 && cfile && cfile->symlink_target) {
654655
idata->symlink_target = kstrdup(cfile->symlink_target, GFP_KERNEL);
655656
if (!idata->symlink_target)
@@ -673,6 +674,7 @@ static int smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon,
673674
break;
674675
case SMB2_OP_POSIX_QUERY_INFO:
675676
idata = in_iov[i].iov_base;
677+
idata->contains_posix_file_info = true;
676678
if (rc == 0 && cfile && cfile->symlink_target) {
677679
idata->symlink_target = kstrdup(cfile->symlink_target, GFP_KERNEL);
678680
if (!idata->symlink_target)
@@ -770,6 +772,7 @@ static int smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon,
770772
idata = in_iov[i].iov_base;
771773
idata->reparse.io.iov = *iov;
772774
idata->reparse.io.buftype = resp_buftype[i + 1];
775+
idata->contains_posix_file_info = false; /* BB VERIFY */
773776
rbuf = reparse_buf_ptr(iov);
774777
if (IS_ERR(rbuf)) {
775778
rc = PTR_ERR(rbuf);
@@ -791,6 +794,7 @@ static int smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon,
791794
case SMB2_OP_QUERY_WSL_EA:
792795
if (!rc) {
793796
idata = in_iov[i].iov_base;
797+
idata->contains_posix_file_info = false;
794798
qi_rsp = rsp_iov[i + 1].iov_base;
795799
data[0] = (u8 *)qi_rsp + le16_to_cpu(qi_rsp->OutputBufferOffset);
796800
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

@@ -5146,7 +5147,7 @@ int __cifs_sfu_make_node(unsigned int xid, struct inode *inode,
51465147
FILE_CREATE, CREATE_NOT_DIR |
51475148
CREATE_OPTION_SPECIAL, ACL_NO_MODE);
51485149
oparms.fid = &fid;
5149-
5150+
idata.contains_posix_file_info = false;
51505151
rc = server->ops->open(xid, &oparms, &oplock, &idata);
51515152
if (rc)
51525153
goto out;

0 commit comments

Comments
 (0)