diff options
author | Jeff Layton <jlayton@redhat.com> | 2011-05-19 16:22:52 -0400 |
---|---|---|
committer | Steve French <sfrench@us.ibm.com> | 2011-05-22 22:58:24 -0400 |
commit | 2c8f981d93f830c167c811f046b5107cc24b6e1b (patch) | |
tree | 8150cda7231acf1afc073b2eaaed0947d1937e16 | |
parent | 71a8638480eb8fb6cfabe2ee9ca3fbc6e3453a14 (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>
-rw-r--r-- | fs/cifs/cifsproto.h | 4 | ||||
-rw-r--r-- | fs/cifs/netmisc.c | 2 | ||||
-rw-r--r-- | fs/cifs/transport.c | 157 |
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); |
77 | extern int SendReceiveNoRsp(const unsigned int xid, struct cifsSesInfo *ses, | 77 | extern 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); |
79 | extern int cifs_check_receive(struct mid_q_entry *mid, | ||
80 | struct TCP_Server_Info *server, bool log_error); | ||
79 | extern int SendReceive2(const unsigned int /* xid */ , struct cifsSesInfo *, | 81 | extern 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); | |||
99 | extern int cifs_set_port(struct sockaddr *addr, const unsigned short int port); | 101 | extern int cifs_set_port(struct sockaddr *addr, const unsigned short int port); |
100 | extern int cifs_fill_sockaddr(struct sockaddr *dst, const char *src, int len, | 102 | extern int cifs_fill_sockaddr(struct sockaddr *dst, const char *src, int len, |
101 | const unsigned short int port); | 103 | const unsigned short int port); |
102 | extern int map_smb_to_linux_error(struct smb_hdr *smb, int logErr); | 104 | extern int map_smb_to_linux_error(struct smb_hdr *smb, bool logErr); |
103 | extern void header_assemble(struct smb_hdr *, char /* command */ , | 105 | extern 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 | ||
838 | int | 838 | int |
839 | map_smb_to_linux_error(struct smb_hdr *smb, int logErr) | 839 | map_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 | ||
504 | int | 504 | int |
505 | cifs_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 | |||
523 | int | ||
505 | SendReceive2(const unsigned int xid, struct cifsSesInfo *ses, | 524 | SendReceive2(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; | ||
656 | out: | 644 | out: |
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); | ||
801 | out: | 757 | out: |
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 | |||
1004 | out: | 929 | out: |
1005 | delete_mid(midQ); | 930 | delete_mid(midQ); |
1006 | if (rstart && rc == -EACCES) | 931 | if (rstart && rc == -EACCES) |