Skip to content

Commit 3681c74

Browse files
Paulo AlcantaraSteve French
Paulo Alcantara
authored and
Steve French
committed
smb: client: handle lack of EA support in smb2_query_path_info()
If the server doesn't support both EAs and reparse point in a file, the SMB2_QUERY_INFO request will fail with either STATUS_NO_EAS_ON_FILE or STATUS_EAS_NOT_SUPPORT in the compound chain, so ignore it as long as reparse point isn't IO_REPARSE_TAG_LX_(CHR|BLK), which would require the EAs to know about major/minor numbers. Reported-by: Pali Rohár <[email protected]> Signed-off-by: Paulo Alcantara (Red Hat) <[email protected]> Signed-off-by: Steve French <[email protected]>
1 parent 056e91c commit 3681c74

File tree

1 file changed

+69
-23
lines changed

1 file changed

+69
-23
lines changed

fs/smb/client/smb2inode.c

Lines changed: 69 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -176,27 +176,27 @@ static int smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon,
176176
struct kvec *out_iov, int *out_buftype, struct dentry *dentry)
177177
{
178178

179-
struct reparse_data_buffer *rbuf;
179+
struct smb2_query_info_rsp *qi_rsp = NULL;
180180
struct smb2_compound_vars *vars = NULL;
181-
struct kvec *rsp_iov, *iov;
182-
struct smb_rqst *rqst;
183-
int rc;
184-
__le16 *utf16_path = NULL;
185181
__u8 oplock = SMB2_OPLOCK_LEVEL_NONE;
186-
struct cifs_fid fid;
182+
struct cifs_open_info_data *idata;
187183
struct cifs_ses *ses = tcon->ses;
184+
struct reparse_data_buffer *rbuf;
188185
struct TCP_Server_Info *server;
189-
int num_rqst = 0, i;
190186
int resp_buftype[MAX_COMPOUND];
191-
struct smb2_query_info_rsp *qi_rsp = NULL;
192-
struct cifs_open_info_data *idata;
187+
int retries = 0, cur_sleep = 1;
188+
__u8 delete_pending[8] = {1,};
189+
struct kvec *rsp_iov, *iov;
193190
struct inode *inode = NULL;
194-
int flags = 0;
195-
__u8 delete_pending[8] = {1, 0, 0, 0, 0, 0, 0, 0};
191+
__le16 *utf16_path = NULL;
192+
struct smb_rqst *rqst;
196193
unsigned int size[2];
197-
void *data[2];
194+
struct cifs_fid fid;
195+
int num_rqst = 0, i;
198196
unsigned int len;
199-
int retries = 0, cur_sleep = 1;
197+
int tmp_rc, rc;
198+
int flags = 0;
199+
void *data[2];
200200

201201
replay_again:
202202
/* reinitialize for possible replay */
@@ -639,7 +639,14 @@ static int smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon,
639639
tcon->need_reconnect = true;
640640
}
641641

642+
tmp_rc = rc;
642643
for (i = 0; i < num_cmds; i++) {
644+
char *buf = rsp_iov[i + i].iov_base;
645+
646+
if (buf && resp_buftype[i + 1] != CIFS_NO_BUFFER)
647+
rc = server->ops->map_error(buf, false);
648+
else
649+
rc = tmp_rc;
643650
switch (cmds[i]) {
644651
case SMB2_OP_QUERY_INFO:
645652
idata = in_iov[i].iov_base;
@@ -805,6 +812,7 @@ static int smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon,
805812
}
806813
}
807814
SMB2_close_free(&rqst[num_rqst]);
815+
rc = tmp_rc;
808816

809817
num_cmds += 2;
810818
if (out_iov && out_buftype) {
@@ -860,22 +868,52 @@ static int parse_create_response(struct cifs_open_info_data *data,
860868
return rc;
861869
}
862870

871+
/* Check only if SMB2_OP_QUERY_WSL_EA command failed in the compound chain */
872+
static bool ea_unsupported(int *cmds, int num_cmds,
873+
struct kvec *out_iov, int *out_buftype)
874+
{
875+
int i;
876+
877+
if (cmds[num_cmds - 1] != SMB2_OP_QUERY_WSL_EA)
878+
return false;
879+
880+
for (i = 1; i < num_cmds - 1; i++) {
881+
struct smb2_hdr *hdr = out_iov[i].iov_base;
882+
883+
if (out_buftype[i] == CIFS_NO_BUFFER || !hdr ||
884+
hdr->Status != STATUS_SUCCESS)
885+
return false;
886+
}
887+
return true;
888+
}
889+
890+
static inline void free_rsp_iov(struct kvec *iovs, int *buftype, int count)
891+
{
892+
int i;
893+
894+
for (i = 0; i < count; i++) {
895+
free_rsp_buf(buftype[i], iovs[i].iov_base);
896+
memset(&iovs[i], 0, sizeof(*iovs));
897+
buftype[i] = CIFS_NO_BUFFER;
898+
}
899+
}
900+
863901
int smb2_query_path_info(const unsigned int xid,
864902
struct cifs_tcon *tcon,
865903
struct cifs_sb_info *cifs_sb,
866904
const char *full_path,
867905
struct cifs_open_info_data *data)
868906
{
907+
struct kvec in_iov[3], out_iov[5] = {};
908+
struct cached_fid *cfid = NULL;
869909
struct cifs_open_parms oparms;
870-
__u32 create_options = 0;
871910
struct cifsFileInfo *cfile;
872-
struct cached_fid *cfid = NULL;
911+
__u32 create_options = 0;
912+
int out_buftype[5] = {};
873913
struct smb2_hdr *hdr;
874-
struct kvec in_iov[3], out_iov[3] = {};
875-
int out_buftype[3] = {};
914+
int num_cmds = 0;
876915
int cmds[3];
877916
bool islink;
878-
int i, num_cmds = 0;
879917
int rc, rc2;
880918

881919
data->adjust_tz = false;
@@ -945,24 +983,33 @@ int smb2_query_path_info(const unsigned int xid,
945983
if (rc || !data->reparse_point)
946984
goto out;
947985

948-
if (!tcon->posix_extensions)
949-
cmds[num_cmds++] = SMB2_OP_QUERY_WSL_EA;
950986
/*
951987
* Skip SMB2_OP_GET_REPARSE if symlink already parsed in create
952988
* response.
953989
*/
954990
if (data->reparse.tag != IO_REPARSE_TAG_SYMLINK)
955991
cmds[num_cmds++] = SMB2_OP_GET_REPARSE;
992+
if (!tcon->posix_extensions)
993+
cmds[num_cmds++] = SMB2_OP_QUERY_WSL_EA;
956994

957995
oparms = CIFS_OPARMS(cifs_sb, tcon, full_path,
958996
FILE_READ_ATTRIBUTES |
959997
FILE_READ_EA | SYNCHRONIZE,
960998
FILE_OPEN, create_options |
961999
OPEN_REPARSE_POINT, ACL_NO_MODE);
9621000
cifs_get_readable_path(tcon, full_path, &cfile);
1001+
free_rsp_iov(out_iov, out_buftype, ARRAY_SIZE(out_iov));
9631002
rc = smb2_compound_op(xid, tcon, cifs_sb, full_path,
9641003
&oparms, in_iov, cmds, num_cmds,
965-
cfile, NULL, NULL, NULL);
1004+
cfile, out_iov, out_buftype, NULL);
1005+
if (rc && ea_unsupported(cmds, num_cmds,
1006+
out_iov, out_buftype)) {
1007+
if (data->reparse.tag != IO_REPARSE_TAG_LX_BLK &&
1008+
data->reparse.tag != IO_REPARSE_TAG_LX_CHR)
1009+
rc = 0;
1010+
else
1011+
rc = -EOPNOTSUPP;
1012+
}
9661013
break;
9671014
case -EREMOTE:
9681015
break;
@@ -980,8 +1027,7 @@ int smb2_query_path_info(const unsigned int xid,
9801027
}
9811028

9821029
out:
983-
for (i = 0; i < ARRAY_SIZE(out_buftype); i++)
984-
free_rsp_buf(out_buftype[i], out_iov[i].iov_base);
1030+
free_rsp_iov(out_iov, out_buftype, ARRAY_SIZE(out_iov));
9851031
return rc;
9861032
}
9871033

0 commit comments

Comments
 (0)