cifs: consolidate SendReceive response checks
Further consolidate the SendReceive code by moving the checks run over the packet into a separate function that all the SendReceive variants can call. We can also eliminate the check for a receive_len that's too big or too small. cifs_demultiplex_thread already checks that and disconnects the socket if that occurs, while setting the midStatus to MALFORMED. It'll never call this code if that's the case. Finally do a little cleanup. Use "goto out" on errors so that the flow of code in the normal case is more evident. Also switch the logErr variable in map_smb_to_linux_error to a bool. Reviewed-by: Pavel Shilovsky <piastry@etersoft.ru> Signed-off-by: Jeff Layton <jlayton@redhat.com> Signed-off-by: Steve French <sfrench@us.ibm.com>
This commit is contained in:
parent
71a8638480
commit
2c8f981d93
3 changed files with 45 additions and 118 deletions
|
@ -76,6 +76,8 @@ extern int SendReceive(const unsigned int /* xid */ , struct cifsSesInfo *,
|
||||||
int * /* bytes returned */ , const int long_op);
|
int * /* bytes returned */ , const int long_op);
|
||||||
extern int SendReceiveNoRsp(const unsigned int xid, struct cifsSesInfo *ses,
|
extern int SendReceiveNoRsp(const unsigned int xid, struct cifsSesInfo *ses,
|
||||||
struct smb_hdr *in_buf, int flags);
|
struct smb_hdr *in_buf, int flags);
|
||||||
|
extern int cifs_check_receive(struct mid_q_entry *mid,
|
||||||
|
struct TCP_Server_Info *server, bool log_error);
|
||||||
extern int SendReceive2(const unsigned int /* xid */ , struct cifsSesInfo *,
|
extern int SendReceive2(const unsigned int /* xid */ , struct cifsSesInfo *,
|
||||||
struct kvec *, int /* nvec to send */,
|
struct kvec *, int /* nvec to send */,
|
||||||
int * /* type of buf returned */ , const int flags);
|
int * /* type of buf returned */ , const int flags);
|
||||||
|
@ -99,7 +101,7 @@ extern int cifs_convert_address(struct sockaddr *dst, const char *src, int len);
|
||||||
extern int cifs_set_port(struct sockaddr *addr, const unsigned short int port);
|
extern int cifs_set_port(struct sockaddr *addr, const unsigned short int port);
|
||||||
extern int cifs_fill_sockaddr(struct sockaddr *dst, const char *src, int len,
|
extern int cifs_fill_sockaddr(struct sockaddr *dst, const char *src, int len,
|
||||||
const unsigned short int port);
|
const unsigned short int port);
|
||||||
extern int map_smb_to_linux_error(struct smb_hdr *smb, int logErr);
|
extern int map_smb_to_linux_error(struct smb_hdr *smb, bool logErr);
|
||||||
extern void header_assemble(struct smb_hdr *, char /* command */ ,
|
extern void header_assemble(struct smb_hdr *, char /* command */ ,
|
||||||
const struct cifsTconInfo *, int /* length of
|
const struct cifsTconInfo *, int /* length of
|
||||||
fixed section (word count) in two byte units */);
|
fixed section (word count) in two byte units */);
|
||||||
|
|
|
@ -836,7 +836,7 @@ ntstatus_to_dos(__u32 ntstatus, __u8 *eclass, __u16 *ecode)
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
map_smb_to_linux_error(struct smb_hdr *smb, int logErr)
|
map_smb_to_linux_error(struct smb_hdr *smb, bool logErr)
|
||||||
{
|
{
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
int rc = -EIO; /* if transport error smb error may not be set */
|
int rc = -EIO; /* if transport error smb error may not be set */
|
||||||
|
|
|
@ -501,6 +501,25 @@ send_nt_cancel(struct TCP_Server_Info *server, struct smb_hdr *in_buf,
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
cifs_check_receive(struct mid_q_entry *mid, struct TCP_Server_Info *server,
|
||||||
|
bool log_error)
|
||||||
|
{
|
||||||
|
dump_smb(mid->resp_buf,
|
||||||
|
min_t(u32, 92, be32_to_cpu(mid->resp_buf->smb_buf_length)));
|
||||||
|
|
||||||
|
/* convert the length into a more usable form */
|
||||||
|
if (server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) {
|
||||||
|
/* FIXME: add code to kill session */
|
||||||
|
if (cifs_verify_signature(mid->resp_buf, server,
|
||||||
|
mid->sequence_number + 1) != 0)
|
||||||
|
cERROR(1, "Unexpected SMB signature");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* BB special case reconnect tid and uid here? */
|
||||||
|
return map_smb_to_linux_error(mid->resp_buf, log_error);
|
||||||
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
SendReceive2(const unsigned int xid, struct cifsSesInfo *ses,
|
SendReceive2(const unsigned int xid, struct cifsSesInfo *ses,
|
||||||
struct kvec *iov, int n_vec, int *pRespBufType /* ret */,
|
struct kvec *iov, int n_vec, int *pRespBufType /* ret */,
|
||||||
|
@ -508,7 +527,6 @@ SendReceive2(const unsigned int xid, struct cifsSesInfo *ses,
|
||||||
{
|
{
|
||||||
int rc = 0;
|
int rc = 0;
|
||||||
int long_op;
|
int long_op;
|
||||||
unsigned int receive_len;
|
|
||||||
struct mid_q_entry *midQ;
|
struct mid_q_entry *midQ;
|
||||||
struct smb_hdr *in_buf = iov[0].iov_base;
|
struct smb_hdr *in_buf = iov[0].iov_base;
|
||||||
|
|
||||||
|
@ -605,54 +623,24 @@ SendReceive2(const unsigned int xid, struct cifsSesInfo *ses,
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
receive_len = be32_to_cpu(midQ->resp_buf->smb_buf_length);
|
if (!midQ->resp_buf || midQ->midState != MID_RESPONSE_RECEIVED) {
|
||||||
|
|
||||||
if (receive_len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE) {
|
|
||||||
cERROR(1, "Frame too large received. Length: %d Xid: %d",
|
|
||||||
receive_len, xid);
|
|
||||||
rc = -EIO;
|
rc = -EIO;
|
||||||
|
cFYI(1, "Bad MID state?");
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* rcvd frame is ok */
|
iov[0].iov_base = (char *)midQ->resp_buf;
|
||||||
|
iov[0].iov_len = be32_to_cpu(midQ->resp_buf->smb_buf_length) + 4;
|
||||||
|
if (midQ->largeBuf)
|
||||||
|
*pRespBufType = CIFS_LARGE_BUFFER;
|
||||||
|
else
|
||||||
|
*pRespBufType = CIFS_SMALL_BUFFER;
|
||||||
|
|
||||||
if (midQ->resp_buf &&
|
rc = cifs_check_receive(midQ, ses->server, flags & CIFS_LOG_ERROR);
|
||||||
(midQ->midState == MID_RESPONSE_RECEIVED)) {
|
|
||||||
|
|
||||||
iov[0].iov_base = (char *)midQ->resp_buf;
|
|
||||||
if (midQ->largeBuf)
|
|
||||||
*pRespBufType = CIFS_LARGE_BUFFER;
|
|
||||||
else
|
|
||||||
*pRespBufType = CIFS_SMALL_BUFFER;
|
|
||||||
iov[0].iov_len = receive_len + 4;
|
|
||||||
|
|
||||||
dump_smb(midQ->resp_buf, 80);
|
|
||||||
/* convert the length into a more usable form */
|
|
||||||
if ((receive_len > 24) &&
|
|
||||||
(ses->server->secMode & (SECMODE_SIGN_REQUIRED |
|
|
||||||
SECMODE_SIGN_ENABLED))) {
|
|
||||||
rc = cifs_verify_signature(midQ->resp_buf,
|
|
||||||
ses->server,
|
|
||||||
midQ->sequence_number+1);
|
|
||||||
if (rc) {
|
|
||||||
cERROR(1, "Unexpected SMB signature");
|
|
||||||
/* BB FIXME add code to kill session */
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* BB special case reconnect tid and uid here? */
|
|
||||||
rc = map_smb_to_linux_error(midQ->resp_buf,
|
|
||||||
flags & CIFS_LOG_ERROR);
|
|
||||||
|
|
||||||
if ((flags & CIFS_NO_RESP) == 0)
|
|
||||||
midQ->resp_buf = NULL; /* mark it so buf will
|
|
||||||
not be freed by
|
|
||||||
delete_mid */
|
|
||||||
} else {
|
|
||||||
rc = -EIO;
|
|
||||||
cFYI(1, "Bad MID state?");
|
|
||||||
}
|
|
||||||
|
|
||||||
|
/* mark it so buf will not be freed by delete_mid */
|
||||||
|
if ((flags & CIFS_NO_RESP) == 0)
|
||||||
|
midQ->resp_buf = NULL;
|
||||||
out:
|
out:
|
||||||
delete_mid(midQ);
|
delete_mid(midQ);
|
||||||
atomic_dec(&ses->server->inFlight);
|
atomic_dec(&ses->server->inFlight);
|
||||||
|
@ -667,7 +655,6 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses,
|
||||||
int *pbytes_returned, const int long_op)
|
int *pbytes_returned, const int long_op)
|
||||||
{
|
{
|
||||||
int rc = 0;
|
int rc = 0;
|
||||||
unsigned int receive_len;
|
|
||||||
struct mid_q_entry *midQ;
|
struct mid_q_entry *midQ;
|
||||||
|
|
||||||
if (ses == NULL) {
|
if (ses == NULL) {
|
||||||
|
@ -757,47 +744,16 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses,
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
receive_len = be32_to_cpu(midQ->resp_buf->smb_buf_length);
|
if (!midQ->resp_buf || !out_buf ||
|
||||||
|
midQ->midState != MID_RESPONSE_RECEIVED) {
|
||||||
if (receive_len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE) {
|
|
||||||
cERROR(1, "Frame too large received. Length: %d Xid: %d",
|
|
||||||
receive_len, xid);
|
|
||||||
rc = -EIO;
|
rc = -EIO;
|
||||||
|
cERROR(1, "Bad MID state?");
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* rcvd frame is ok */
|
*pbytes_returned = be32_to_cpu(midQ->resp_buf->smb_buf_length);
|
||||||
|
memcpy(out_buf, midQ->resp_buf, *pbytes_returned + 4);
|
||||||
if (midQ->resp_buf && out_buf
|
rc = cifs_check_receive(midQ, ses->server, 0);
|
||||||
&& (midQ->midState == MID_RESPONSE_RECEIVED)) {
|
|
||||||
out_buf->smb_buf_length = cpu_to_be32(receive_len);
|
|
||||||
memcpy((char *)out_buf + 4,
|
|
||||||
(char *)midQ->resp_buf + 4,
|
|
||||||
receive_len);
|
|
||||||
|
|
||||||
dump_smb(out_buf, 92);
|
|
||||||
/* convert the length into a more usable form */
|
|
||||||
if ((receive_len > 24) &&
|
|
||||||
(ses->server->secMode & (SECMODE_SIGN_REQUIRED |
|
|
||||||
SECMODE_SIGN_ENABLED))) {
|
|
||||||
rc = cifs_verify_signature(out_buf,
|
|
||||||
ses->server,
|
|
||||||
midQ->sequence_number+1);
|
|
||||||
if (rc) {
|
|
||||||
cERROR(1, "Unexpected SMB signature");
|
|
||||||
/* BB FIXME add code to kill session */
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
*pbytes_returned = be32_to_cpu(out_buf->smb_buf_length);
|
|
||||||
|
|
||||||
/* BB special case reconnect tid and uid here? */
|
|
||||||
rc = map_smb_to_linux_error(out_buf, 0 /* no log */ );
|
|
||||||
} else {
|
|
||||||
rc = -EIO;
|
|
||||||
cERROR(1, "Bad MID state?");
|
|
||||||
}
|
|
||||||
|
|
||||||
out:
|
out:
|
||||||
delete_mid(midQ);
|
delete_mid(midQ);
|
||||||
atomic_dec(&ses->server->inFlight);
|
atomic_dec(&ses->server->inFlight);
|
||||||
|
@ -838,7 +794,6 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifsTconInfo *tcon,
|
||||||
{
|
{
|
||||||
int rc = 0;
|
int rc = 0;
|
||||||
int rstart = 0;
|
int rstart = 0;
|
||||||
unsigned int receive_len;
|
|
||||||
struct mid_q_entry *midQ;
|
struct mid_q_entry *midQ;
|
||||||
struct cifsSesInfo *ses;
|
struct cifsSesInfo *ses;
|
||||||
|
|
||||||
|
@ -961,46 +916,16 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifsTconInfo *tcon,
|
||||||
if (rc != 0)
|
if (rc != 0)
|
||||||
return rc;
|
return rc;
|
||||||
|
|
||||||
receive_len = be32_to_cpu(midQ->resp_buf->smb_buf_length);
|
|
||||||
if (receive_len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE) {
|
|
||||||
cERROR(1, "Frame too large received. Length: %d Xid: %d",
|
|
||||||
receive_len, xid);
|
|
||||||
rc = -EIO;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* rcvd frame is ok */
|
/* rcvd frame is ok */
|
||||||
|
if (out_buf == NULL || midQ->midState != MID_RESPONSE_RECEIVED) {
|
||||||
if ((out_buf == NULL) || (midQ->midState != MID_RESPONSE_RECEIVED)) {
|
|
||||||
rc = -EIO;
|
rc = -EIO;
|
||||||
cERROR(1, "Bad MID state?");
|
cERROR(1, "Bad MID state?");
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
out_buf->smb_buf_length = cpu_to_be32(receive_len);
|
*pbytes_returned = be32_to_cpu(midQ->resp_buf->smb_buf_length);
|
||||||
memcpy((char *)out_buf + 4,
|
memcpy(out_buf, midQ->resp_buf, *pbytes_returned + 4);
|
||||||
(char *)midQ->resp_buf + 4,
|
rc = cifs_check_receive(midQ, ses->server, 0);
|
||||||
receive_len);
|
|
||||||
|
|
||||||
dump_smb(out_buf, 92);
|
|
||||||
/* convert the length into a more usable form */
|
|
||||||
if ((receive_len > 24) &&
|
|
||||||
(ses->server->secMode & (SECMODE_SIGN_REQUIRED |
|
|
||||||
SECMODE_SIGN_ENABLED))) {
|
|
||||||
rc = cifs_verify_signature(out_buf,
|
|
||||||
ses->server,
|
|
||||||
midQ->sequence_number+1);
|
|
||||||
if (rc) {
|
|
||||||
cERROR(1, "Unexpected SMB signature");
|
|
||||||
/* BB FIXME add code to kill session */
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
*pbytes_returned = be32_to_cpu(out_buf->smb_buf_length);
|
|
||||||
|
|
||||||
/* BB special case reconnect tid and uid here? */
|
|
||||||
rc = map_smb_to_linux_error(out_buf, 0 /* no log */ );
|
|
||||||
|
|
||||||
out:
|
out:
|
||||||
delete_mid(midQ);
|
delete_mid(midQ);
|
||||||
if (rstart && rc == -EACCES)
|
if (rstart && rc == -EACCES)
|
||||||
|
|
Loading…
Reference in a new issue