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);
|
||||
extern int SendReceiveNoRsp(const unsigned int xid, struct cifsSesInfo *ses,
|
||||
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 *,
|
||||
struct kvec *, int /* nvec to send */,
|
||||
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_fill_sockaddr(struct sockaddr *dst, const char *src, int len,
|
||||
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 */ ,
|
||||
const struct cifsTconInfo *, int /* length of
|
||||
fixed section (word count) in two byte units */);
|
||||
|
|
|
@ -836,7 +836,7 @@ ntstatus_to_dos(__u32 ntstatus, __u8 *eclass, __u16 *ecode)
|
|||
}
|
||||
|
||||
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;
|
||||
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;
|
||||
}
|
||||
|
||||
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
|
||||
SendReceive2(const unsigned int xid, struct cifsSesInfo *ses,
|
||||
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 long_op;
|
||||
unsigned int receive_len;
|
||||
struct mid_q_entry *midQ;
|
||||
struct smb_hdr *in_buf = iov[0].iov_base;
|
||||
|
||||
|
@ -605,54 +623,24 @@ SendReceive2(const unsigned int xid, struct cifsSesInfo *ses,
|
|||
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);
|
||||
if (!midQ->resp_buf || midQ->midState != MID_RESPONSE_RECEIVED) {
|
||||
rc = -EIO;
|
||||
cFYI(1, "Bad MID state?");
|
||||
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 &&
|
||||
(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?");
|
||||
}
|
||||
rc = cifs_check_receive(midQ, ses->server, flags & CIFS_LOG_ERROR);
|
||||
|
||||
/* mark it so buf will not be freed by delete_mid */
|
||||
if ((flags & CIFS_NO_RESP) == 0)
|
||||
midQ->resp_buf = NULL;
|
||||
out:
|
||||
delete_mid(midQ);
|
||||
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 rc = 0;
|
||||
unsigned int receive_len;
|
||||
struct mid_q_entry *midQ;
|
||||
|
||||
if (ses == NULL) {
|
||||
|
@ -757,47 +744,16 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses,
|
|||
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);
|
||||
if (!midQ->resp_buf || !out_buf ||
|
||||
midQ->midState != MID_RESPONSE_RECEIVED) {
|
||||
rc = -EIO;
|
||||
cERROR(1, "Bad MID state?");
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* rcvd frame is ok */
|
||||
|
||||
if (midQ->resp_buf && out_buf
|
||||
&& (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?");
|
||||
}
|
||||
|
||||
*pbytes_returned = be32_to_cpu(midQ->resp_buf->smb_buf_length);
|
||||
memcpy(out_buf, midQ->resp_buf, *pbytes_returned + 4);
|
||||
rc = cifs_check_receive(midQ, ses->server, 0);
|
||||
out:
|
||||
delete_mid(midQ);
|
||||
atomic_dec(&ses->server->inFlight);
|
||||
|
@ -838,7 +794,6 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifsTconInfo *tcon,
|
|||
{
|
||||
int rc = 0;
|
||||
int rstart = 0;
|
||||
unsigned int receive_len;
|
||||
struct mid_q_entry *midQ;
|
||||
struct cifsSesInfo *ses;
|
||||
|
||||
|
@ -961,46 +916,16 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifsTconInfo *tcon,
|
|||
if (rc != 0)
|
||||
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 */
|
||||
|
||||
if ((out_buf == NULL) || (midQ->midState != MID_RESPONSE_RECEIVED)) {
|
||||
if (out_buf == NULL || midQ->midState != MID_RESPONSE_RECEIVED) {
|
||||
rc = -EIO;
|
||||
cERROR(1, "Bad MID state?");
|
||||
goto out;
|
||||
}
|
||||
|
||||
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 */ );
|
||||
|
||||
*pbytes_returned = be32_to_cpu(midQ->resp_buf->smb_buf_length);
|
||||
memcpy(out_buf, midQ->resp_buf, *pbytes_returned + 4);
|
||||
rc = cifs_check_receive(midQ, ses->server, 0);
|
||||
out:
|
||||
delete_mid(midQ);
|
||||
if (rstart && rc == -EACCES)
|
||||
|
|
Loading…
Reference in a new issue