Skip to content

Commit 77aefd1

Browse files
pcacjrgregkh
authored andcommitted
smb: client: handle lack of EA support in smb2_query_path_info()
commit 3681c74 upstream. 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]> Signed-off-by: Greg Kroah-Hartman <[email protected]>
1 parent d9da7a6 commit 77aefd1

File tree

1 file changed

+69
-23
lines changed

1 file changed

+69
-23
lines changed

fs/smb/client/smb2inode.c

+69-23
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 */
@@ -637,7 +637,14 @@ static int smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon,
637637
tcon->need_reconnect = true;
638638
}
639639

640+
tmp_rc = rc;
640641
for (i = 0; i < num_cmds; i++) {
642+
char *buf = rsp_iov[i + i].iov_base;
643+
644+
if (buf && resp_buftype[i + 1] != CIFS_NO_BUFFER)
645+
rc = server->ops->map_error(buf, false);
646+
else
647+
rc = tmp_rc;
641648
switch (cmds[i]) {
642649
case SMB2_OP_QUERY_INFO:
643650
idata = in_iov[i].iov_base;
@@ -803,6 +810,7 @@ static int smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon,
803810
}
804811
}
805812
SMB2_close_free(&rqst[num_rqst]);
813+
rc = tmp_rc;
806814

807815
num_cmds += 2;
808816
if (out_iov && out_buftype) {
@@ -858,22 +866,52 @@ static int parse_create_response(struct cifs_open_info_data *data,
858866
return rc;
859867
}
860868

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

879917
data->adjust_tz = false;
@@ -943,24 +981,33 @@ int smb2_query_path_info(const unsigned int xid,
943981
if (rc || !data->reparse_point)
944982
goto out;
945983

946-
if (!tcon->posix_extensions)
947-
cmds[num_cmds++] = SMB2_OP_QUERY_WSL_EA;
948984
/*
949985
* Skip SMB2_OP_GET_REPARSE if symlink already parsed in create
950986
* response.
951987
*/
952988
if (data->reparse.tag != IO_REPARSE_TAG_SYMLINK)
953989
cmds[num_cmds++] = SMB2_OP_GET_REPARSE;
990+
if (!tcon->posix_extensions)
991+
cmds[num_cmds++] = SMB2_OP_QUERY_WSL_EA;
954992

955993
oparms = CIFS_OPARMS(cifs_sb, tcon, full_path,
956994
FILE_READ_ATTRIBUTES |
957995
FILE_READ_EA | SYNCHRONIZE,
958996
FILE_OPEN, create_options |
959997
OPEN_REPARSE_POINT, ACL_NO_MODE);
960998
cifs_get_readable_path(tcon, full_path, &cfile);
999+
free_rsp_iov(out_iov, out_buftype, ARRAY_SIZE(out_iov));
9611000
rc = smb2_compound_op(xid, tcon, cifs_sb, full_path,
9621001
&oparms, in_iov, cmds, num_cmds,
963-
cfile, NULL, NULL, NULL);
1002+
cfile, out_iov, out_buftype, NULL);
1003+
if (rc && ea_unsupported(cmds, num_cmds,
1004+
out_iov, out_buftype)) {
1005+
if (data->reparse.tag != IO_REPARSE_TAG_LX_BLK &&
1006+
data->reparse.tag != IO_REPARSE_TAG_LX_CHR)
1007+
rc = 0;
1008+
else
1009+
rc = -EOPNOTSUPP;
1010+
}
9641011
break;
9651012
case -EREMOTE:
9661013
break;
@@ -978,8 +1025,7 @@ int smb2_query_path_info(const unsigned int xid,
9781025
}
9791026

9801027
out:
981-
for (i = 0; i < ARRAY_SIZE(out_buftype); i++)
982-
free_rsp_buf(out_buftype[i], out_iov[i].iov_base);
1028+
free_rsp_iov(out_iov, out_buftype, ARRAY_SIZE(out_iov));
9831029
return rc;
9841030
}
9851031

0 commit comments

Comments
 (0)