|
@@ -236,10 +236,7 @@ __u16 GetNextMid(struct TCP_Server_Info *server)
|
|
|
{
|
|
|
__u16 mid = 0;
|
|
|
__u16 last_mid;
|
|
|
- int collision;
|
|
|
-
|
|
|
- if (server == NULL)
|
|
|
- return mid;
|
|
|
+ bool collision;
|
|
|
|
|
|
spin_lock(&GlobalMid_Lock);
|
|
|
last_mid = server->CurrentMid; /* we do not want to loop forever */
|
|
@@ -252,24 +249,38 @@ __u16 GetNextMid(struct TCP_Server_Info *server)
|
|
|
(and it would also have to have been a request that
|
|
|
did not time out) */
|
|
|
while (server->CurrentMid != last_mid) {
|
|
|
- struct list_head *tmp;
|
|
|
struct mid_q_entry *mid_entry;
|
|
|
+ unsigned int num_mids;
|
|
|
|
|
|
- collision = 0;
|
|
|
+ collision = false;
|
|
|
if (server->CurrentMid == 0)
|
|
|
server->CurrentMid++;
|
|
|
|
|
|
- list_for_each(tmp, &server->pending_mid_q) {
|
|
|
- mid_entry = list_entry(tmp, struct mid_q_entry, qhead);
|
|
|
-
|
|
|
- if ((mid_entry->mid == server->CurrentMid) &&
|
|
|
- (mid_entry->midState == MID_REQUEST_SUBMITTED)) {
|
|
|
+ num_mids = 0;
|
|
|
+ list_for_each_entry(mid_entry, &server->pending_mid_q, qhead) {
|
|
|
+ ++num_mids;
|
|
|
+ if (mid_entry->mid == server->CurrentMid &&
|
|
|
+ mid_entry->midState == MID_REQUEST_SUBMITTED) {
|
|
|
/* This mid is in use, try a different one */
|
|
|
- collision = 1;
|
|
|
+ collision = true;
|
|
|
break;
|
|
|
}
|
|
|
}
|
|
|
- if (collision == 0) {
|
|
|
+
|
|
|
+ /*
|
|
|
+ * if we have more than 32k mids in the list, then something
|
|
|
+ * is very wrong. Possibly a local user is trying to DoS the
|
|
|
+ * box by issuing long-running calls and SIGKILL'ing them. If
|
|
|
+ * we get to 2^16 mids then we're in big trouble as this
|
|
|
+ * function could loop forever.
|
|
|
+ *
|
|
|
+ * Go ahead and assign out the mid in this situation, but force
|
|
|
+ * an eventual reconnect to clean out the pending_mid_q.
|
|
|
+ */
|
|
|
+ if (num_mids > 32768)
|
|
|
+ server->tcpStatus = CifsNeedReconnect;
|
|
|
+
|
|
|
+ if (!collision) {
|
|
|
mid = server->CurrentMid;
|
|
|
break;
|
|
|
}
|
|
@@ -381,29 +392,31 @@ header_assemble(struct smb_hdr *buffer, char smb_command /* command */ ,
|
|
|
}
|
|
|
|
|
|
static int
|
|
|
-checkSMBhdr(struct smb_hdr *smb, __u16 mid)
|
|
|
+check_smb_hdr(struct smb_hdr *smb, __u16 mid)
|
|
|
{
|
|
|
- /* Make sure that this really is an SMB, that it is a response,
|
|
|
- and that the message ids match */
|
|
|
- if ((*(__le32 *) smb->Protocol == cpu_to_le32(0x424d53ff)) &&
|
|
|
- (mid == smb->Mid)) {
|
|
|
- if (smb->Flags & SMBFLG_RESPONSE)
|
|
|
- return 0;
|
|
|
- else {
|
|
|
- /* only one valid case where server sends us request */
|
|
|
- if (smb->Command == SMB_COM_LOCKING_ANDX)
|
|
|
- return 0;
|
|
|
- else
|
|
|
- cERROR(1, "Received Request not response");
|
|
|
- }
|
|
|
- } else { /* bad signature or mid */
|
|
|
- if (*(__le32 *) smb->Protocol != cpu_to_le32(0x424d53ff))
|
|
|
- cERROR(1, "Bad protocol string signature header %x",
|
|
|
- *(unsigned int *) smb->Protocol);
|
|
|
- if (mid != smb->Mid)
|
|
|
- cERROR(1, "Mids do not match");
|
|
|
+ /* does it have the right SMB "signature" ? */
|
|
|
+ if (*(__le32 *) smb->Protocol != cpu_to_le32(0x424d53ff)) {
|
|
|
+ cERROR(1, "Bad protocol string signature header 0x%x",
|
|
|
+ *(unsigned int *)smb->Protocol);
|
|
|
+ return 1;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* Make sure that message ids match */
|
|
|
+ if (mid != smb->Mid) {
|
|
|
+ cERROR(1, "Mids do not match. received=%u expected=%u",
|
|
|
+ smb->Mid, mid);
|
|
|
+ return 1;
|
|
|
}
|
|
|
- cERROR(1, "bad smb detected. The Mid=%d", smb->Mid);
|
|
|
+
|
|
|
+ /* if it's a response then accept */
|
|
|
+ if (smb->Flags & SMBFLG_RESPONSE)
|
|
|
+ return 0;
|
|
|
+
|
|
|
+ /* only one valid case where server sends us request */
|
|
|
+ if (smb->Command == SMB_COM_LOCKING_ANDX)
|
|
|
+ return 0;
|
|
|
+
|
|
|
+ cERROR(1, "Server sent request, not response. mid=%u", smb->Mid);
|
|
|
return 1;
|
|
|
}
|
|
|
|
|
@@ -448,7 +461,7 @@ checkSMB(struct smb_hdr *smb, __u16 mid, unsigned int length)
|
|
|
return 1;
|
|
|
}
|
|
|
|
|
|
- if (checkSMBhdr(smb, mid))
|
|
|
+ if (check_smb_hdr(smb, mid))
|
|
|
return 1;
|
|
|
clc_len = smbCalcSize_LE(smb);
|
|
|
|
|
@@ -465,25 +478,26 @@ checkSMB(struct smb_hdr *smb, __u16 mid, unsigned int length)
|
|
|
if (((4 + len) & 0xFFFF) == (clc_len & 0xFFFF))
|
|
|
return 0; /* bcc wrapped */
|
|
|
}
|
|
|
- cFYI(1, "Calculated size %d vs length %d mismatch for mid %d",
|
|
|
+ cFYI(1, "Calculated size %u vs length %u mismatch for mid=%u",
|
|
|
clc_len, 4 + len, smb->Mid);
|
|
|
- /* Windows XP can return a few bytes too much, presumably
|
|
|
- an illegal pad, at the end of byte range lock responses
|
|
|
- so we allow for that three byte pad, as long as actual
|
|
|
- received length is as long or longer than calculated length */
|
|
|
- /* We have now had to extend this more, since there is a
|
|
|
- case in which it needs to be bigger still to handle a
|
|
|
- malformed response to transact2 findfirst from WinXP when
|
|
|
- access denied is returned and thus bcc and wct are zero
|
|
|
- but server says length is 0x21 bytes too long as if the server
|
|
|
- forget to reset the smb rfc1001 length when it reset the
|
|
|
- wct and bcc to minimum size and drop the t2 parms and data */
|
|
|
- if ((4+len > clc_len) && (len <= clc_len + 512))
|
|
|
- return 0;
|
|
|
- else {
|
|
|
- cERROR(1, "RFC1001 size %d bigger than SMB for Mid=%d",
|
|
|
+
|
|
|
+ if (4 + len < clc_len) {
|
|
|
+ cERROR(1, "RFC1001 size %u smaller than SMB for mid=%u",
|
|
|
len, smb->Mid);
|
|
|
return 1;
|
|
|
+ } else if (len > clc_len + 512) {
|
|
|
+ /*
|
|
|
+ * Some servers (Windows XP in particular) send more
|
|
|
+ * data than the lengths in the SMB packet would
|
|
|
+ * indicate on certain calls (byte range locks and
|
|
|
+ * trans2 find first calls in particular). While the
|
|
|
+ * client can handle such a frame by ignoring the
|
|
|
+ * trailing data, we choose limit the amount of extra
|
|
|
+ * data to 512 bytes.
|
|
|
+ */
|
|
|
+ cERROR(1, "RFC1001 size %u more than 512 bytes larger "
|
|
|
+ "than SMB for mid=%u", len, smb->Mid);
|
|
|
+ return 1;
|
|
|
}
|
|
|
}
|
|
|
return 0;
|