aboutsummaryrefslogtreecommitdiffstats
path: root/fs/cifs
diff options
context:
space:
mode:
authorJeff Layton <jlayton@redhat.com>2011-05-19 16:22:52 -0400
committerSteve French <sfrench@us.ibm.com>2011-05-22 22:58:24 -0400
commit2c8f981d93f830c167c811f046b5107cc24b6e1b (patch)
tree8150cda7231acf1afc073b2eaaed0947d1937e16 /fs/cifs
parent71a8638480eb8fb6cfabe2ee9ca3fbc6e3453a14 (diff)
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>
Diffstat (limited to 'fs/cifs')
-rw-r--r--fs/cifs/cifsproto.h4
-rw-r--r--fs/cifs/netmisc.c2
-rw-r--r--fs/cifs/transport.c157
3 files changed, 45 insertions, 118 deletions
diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h
index 6e69e06a30b3..7aa131112884 100644
--- a/fs/cifs/cifsproto.h
+++ b/fs/cifs/cifsproto.h
@@ -76,6 +76,8 @@ extern int SendReceive(const unsigned int /* xid */ , struct cifsSesInfo *,
76 int * /* bytes returned */ , const int long_op); 76 int * /* bytes returned */ , const int long_op);
77extern int SendReceiveNoRsp(const unsigned int xid, struct cifsSesInfo *ses, 77extern int SendReceiveNoRsp(const unsigned int xid, struct cifsSesInfo *ses,
78 struct smb_hdr *in_buf, int flags); 78 struct smb_hdr *in_buf, int flags);
79extern int cifs_check_receive(struct mid_q_entry *mid,
80 struct TCP_Server_Info *server, bool log_error);
79extern int SendReceive2(const unsigned int /* xid */ , struct cifsSesInfo *, 81extern int SendReceive2(const unsigned int /* xid */ , struct cifsSesInfo *,
80 struct kvec *, int /* nvec to send */, 82 struct kvec *, int /* nvec to send */,
81 int * /* type of buf returned */ , const int flags); 83 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);
99extern int cifs_set_port(struct sockaddr *addr, const unsigned short int port); 101extern int cifs_set_port(struct sockaddr *addr, const unsigned short int port);
100extern int cifs_fill_sockaddr(struct sockaddr *dst, const char *src, int len, 102extern int cifs_fill_sockaddr(struct sockaddr *dst, const char *src, int len,
101 const unsigned short int port); 103 const unsigned short int port);
102extern int map_smb_to_linux_error(struct smb_hdr *smb, int logErr); 104extern int map_smb_to_linux_error(struct smb_hdr *smb, bool logErr);
103extern void header_assemble(struct smb_hdr *, char /* command */ , 105extern void header_assemble(struct smb_hdr *, char /* command */ ,
104 const struct cifsTconInfo *, int /* length of 106 const struct cifsTconInfo *, int /* length of
105 fixed section (word count) in two byte units */); 107 fixed section (word count) in two byte units */);
diff --git a/fs/cifs/netmisc.c b/fs/cifs/netmisc.c
index 79b71c2c7c9d..73e47e84b61a 100644
--- a/fs/cifs/netmisc.c
+++ b/fs/cifs/netmisc.c
@@ -836,7 +836,7 @@ ntstatus_to_dos(__u32 ntstatus, __u8 *eclass, __u16 *ecode)
836} 836}
837 837
838int 838int
839map_smb_to_linux_error(struct smb_hdr *smb, int logErr) 839map_smb_to_linux_error(struct smb_hdr *smb, bool logErr)
840{ 840{
841 unsigned int i; 841 unsigned int i;
842 int rc = -EIO; /* if transport error smb error may not be set */ 842 int rc = -EIO; /* if transport error smb error may not be set */
diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c
index f2513fb8c391..43633a79942a 100644
--- a/fs/cifs/transport.c
+++ b/fs/cifs/transport.c
@@ -502,13 +502,31 @@ send_nt_cancel(struct TCP_Server_Info *server, struct smb_hdr *in_buf,
502} 502}
503 503
504int 504int
505cifs_check_receive(struct mid_q_entry *mid, struct TCP_Server_Info *server,
506 bool log_error)
507{
508 dump_smb(mid->resp_buf,
509 min_t(u32, 92, be32_to_cpu(mid->resp_buf->smb_buf_length)));
510
511 /* convert the length into a more usable form */
512 if (server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) {
513 /* FIXME: add code to kill session */
514 if (cifs_verify_signature(mid->resp_buf, server,
515 mid->sequence_number + 1) != 0)
516 cERROR(1, "Unexpected SMB signature");
517 }
518
519 /* BB special case reconnect tid and uid here? */
520 return map_smb_to_linux_error(mid->resp_buf, log_error);
521}
522
523int
505SendReceive2(const unsigned int xid, struct cifsSesInfo *ses, 524SendReceive2(const unsigned int xid, struct cifsSesInfo *ses,
506 struct kvec *iov, int n_vec, int *pRespBufType /* ret */, 525 struct kvec *iov, int n_vec, int *pRespBufType /* ret */,
507 const int flags) 526 const int flags)
508{ 527{
509 int rc = 0; 528 int rc = 0;
510 int long_op; 529 int long_op;
511 unsigned int receive_len;
512 struct mid_q_entry *midQ; 530 struct mid_q_entry *midQ;
513 struct smb_hdr *in_buf = iov[0].iov_base; 531 struct smb_hdr *in_buf = iov[0].iov_base;
514 532
@@ -605,54 +623,24 @@ SendReceive2(const unsigned int xid, struct cifsSesInfo *ses,
605 return rc; 623 return rc;
606 } 624 }
607 625
608 receive_len = be32_to_cpu(midQ->resp_buf->smb_buf_length); 626 if (!midQ->resp_buf || midQ->midState != MID_RESPONSE_RECEIVED) {
609
610 if (receive_len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE) {
611 cERROR(1, "Frame too large received. Length: %d Xid: %d",
612 receive_len, xid);
613 rc = -EIO; 627 rc = -EIO;
628 cFYI(1, "Bad MID state?");
614 goto out; 629 goto out;
615 } 630 }
616 631
617 /* rcvd frame is ok */ 632 iov[0].iov_base = (char *)midQ->resp_buf;
618 633 iov[0].iov_len = be32_to_cpu(midQ->resp_buf->smb_buf_length) + 4;
619 if (midQ->resp_buf && 634 if (midQ->largeBuf)
620 (midQ->midState == MID_RESPONSE_RECEIVED)) { 635 *pRespBufType = CIFS_LARGE_BUFFER;
621 636 else
622 iov[0].iov_base = (char *)midQ->resp_buf; 637 *pRespBufType = CIFS_SMALL_BUFFER;
623 if (midQ->largeBuf)
624 *pRespBufType = CIFS_LARGE_BUFFER;
625 else
626 *pRespBufType = CIFS_SMALL_BUFFER;
627 iov[0].iov_len = receive_len + 4;
628
629 dump_smb(midQ->resp_buf, 80);
630 /* convert the length into a more usable form */
631 if ((receive_len > 24) &&
632 (ses->server->secMode & (SECMODE_SIGN_REQUIRED |
633 SECMODE_SIGN_ENABLED))) {
634 rc = cifs_verify_signature(midQ->resp_buf,
635 ses->server,
636 midQ->sequence_number+1);
637 if (rc) {
638 cERROR(1, "Unexpected SMB signature");
639 /* BB FIXME add code to kill session */
640 }
641 }
642
643 /* BB special case reconnect tid and uid here? */
644 rc = map_smb_to_linux_error(midQ->resp_buf,
645 flags & CIFS_LOG_ERROR);
646 638
647 if ((flags & CIFS_NO_RESP) == 0) 639 rc = cifs_check_receive(midQ, ses->server, flags & CIFS_LOG_ERROR);
648 midQ->resp_buf = NULL; /* mark it so buf will
649 not be freed by
650 delete_mid */
651 } else {
652 rc = -EIO;
653 cFYI(1, "Bad MID state?");
654 }
655 640
641 /* mark it so buf will not be freed by delete_mid */
642 if ((flags & CIFS_NO_RESP) == 0)
643 midQ->resp_buf = NULL;
656out: 644out:
657 delete_mid(midQ); 645 delete_mid(midQ);
658 atomic_dec(&ses->server->inFlight); 646 atomic_dec(&ses->server->inFlight);
@@ -667,7 +655,6 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses,
667 int *pbytes_returned, const int long_op) 655 int *pbytes_returned, const int long_op)
668{ 656{
669 int rc = 0; 657 int rc = 0;
670 unsigned int receive_len;
671 struct mid_q_entry *midQ; 658 struct mid_q_entry *midQ;
672 659
673 if (ses == NULL) { 660 if (ses == NULL) {
@@ -757,47 +744,16 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses,
757 return rc; 744 return rc;
758 } 745 }
759 746
760 receive_len = be32_to_cpu(midQ->resp_buf->smb_buf_length); 747 if (!midQ->resp_buf || !out_buf ||
761 748 midQ->midState != MID_RESPONSE_RECEIVED) {
762 if (receive_len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE) {
763 cERROR(1, "Frame too large received. Length: %d Xid: %d",
764 receive_len, xid);
765 rc = -EIO;
766 goto out;
767 }
768
769 /* rcvd frame is ok */
770
771 if (midQ->resp_buf && out_buf
772 && (midQ->midState == MID_RESPONSE_RECEIVED)) {
773 out_buf->smb_buf_length = cpu_to_be32(receive_len);
774 memcpy((char *)out_buf + 4,
775 (char *)midQ->resp_buf + 4,
776 receive_len);
777
778 dump_smb(out_buf, 92);
779 /* convert the length into a more usable form */
780 if ((receive_len > 24) &&
781 (ses->server->secMode & (SECMODE_SIGN_REQUIRED |
782 SECMODE_SIGN_ENABLED))) {
783 rc = cifs_verify_signature(out_buf,
784 ses->server,
785 midQ->sequence_number+1);
786 if (rc) {
787 cERROR(1, "Unexpected SMB signature");
788 /* BB FIXME add code to kill session */
789 }
790 }
791
792 *pbytes_returned = be32_to_cpu(out_buf->smb_buf_length);
793
794 /* BB special case reconnect tid and uid here? */
795 rc = map_smb_to_linux_error(out_buf, 0 /* no log */ );
796 } else {
797 rc = -EIO; 749 rc = -EIO;
798 cERROR(1, "Bad MID state?"); 750 cERROR(1, "Bad MID state?");
751 goto out;
799 } 752 }
800 753
754 *pbytes_returned = be32_to_cpu(midQ->resp_buf->smb_buf_length);
755 memcpy(out_buf, midQ->resp_buf, *pbytes_returned + 4);
756 rc = cifs_check_receive(midQ, ses->server, 0);
801out: 757out:
802 delete_mid(midQ); 758 delete_mid(midQ);
803 atomic_dec(&ses->server->inFlight); 759 atomic_dec(&ses->server->inFlight);
@@ -838,7 +794,6 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifsTconInfo *tcon,
838{ 794{
839 int rc = 0; 795 int rc = 0;
840 int rstart = 0; 796 int rstart = 0;
841 unsigned int receive_len;
842 struct mid_q_entry *midQ; 797 struct mid_q_entry *midQ;
843 struct cifsSesInfo *ses; 798 struct cifsSesInfo *ses;
844 799
@@ -961,46 +916,16 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifsTconInfo *tcon,
961 if (rc != 0) 916 if (rc != 0)
962 return rc; 917 return rc;
963 918
964 receive_len = be32_to_cpu(midQ->resp_buf->smb_buf_length);
965 if (receive_len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE) {
966 cERROR(1, "Frame too large received. Length: %d Xid: %d",
967 receive_len, xid);
968 rc = -EIO;
969 goto out;
970 }
971
972 /* rcvd frame is ok */ 919 /* rcvd frame is ok */
973 920 if (out_buf == NULL || midQ->midState != MID_RESPONSE_RECEIVED) {
974 if ((out_buf == NULL) || (midQ->midState != MID_RESPONSE_RECEIVED)) {
975 rc = -EIO; 921 rc = -EIO;
976 cERROR(1, "Bad MID state?"); 922 cERROR(1, "Bad MID state?");
977 goto out; 923 goto out;
978 } 924 }
979 925
980 out_buf->smb_buf_length = cpu_to_be32(receive_len); 926 *pbytes_returned = be32_to_cpu(midQ->resp_buf->smb_buf_length);
981 memcpy((char *)out_buf + 4, 927 memcpy(out_buf, midQ->resp_buf, *pbytes_returned + 4);
982 (char *)midQ->resp_buf + 4, 928 rc = cifs_check_receive(midQ, ses->server, 0);
983 receive_len);
984
985 dump_smb(out_buf, 92);
986 /* convert the length into a more usable form */
987 if ((receive_len > 24) &&
988 (ses->server->secMode & (SECMODE_SIGN_REQUIRED |
989 SECMODE_SIGN_ENABLED))) {
990 rc = cifs_verify_signature(out_buf,
991 ses->server,
992 midQ->sequence_number+1);
993 if (rc) {
994 cERROR(1, "Unexpected SMB signature");
995 /* BB FIXME add code to kill session */
996 }
997 }
998
999 *pbytes_returned = be32_to_cpu(out_buf->smb_buf_length);
1000
1001 /* BB special case reconnect tid and uid here? */
1002 rc = map_smb_to_linux_error(out_buf, 0 /* no log */ );
1003
1004out: 929out:
1005 delete_mid(midQ); 930 delete_mid(midQ);
1006 if (rstart && rc == -EACCES) 931 if (rstart && rc == -EACCES)