diff options
Diffstat (limited to 'fs/cifs/misc.c')
-rw-r--r-- | fs/cifs/misc.c | 189 |
1 files changed, 66 insertions, 123 deletions
diff --git a/fs/cifs/misc.c b/fs/cifs/misc.c index 43f10281bc19..2a930a752a78 100644 --- a/fs/cifs/misc.c +++ b/fs/cifs/misc.c | |||
@@ -236,10 +236,7 @@ __u16 GetNextMid(struct TCP_Server_Info *server) | |||
236 | { | 236 | { |
237 | __u16 mid = 0; | 237 | __u16 mid = 0; |
238 | __u16 last_mid; | 238 | __u16 last_mid; |
239 | int collision; | 239 | bool collision; |
240 | |||
241 | if (server == NULL) | ||
242 | return mid; | ||
243 | 240 | ||
244 | spin_lock(&GlobalMid_Lock); | 241 | spin_lock(&GlobalMid_Lock); |
245 | last_mid = server->CurrentMid; /* we do not want to loop forever */ | 242 | last_mid = server->CurrentMid; /* we do not want to loop forever */ |
@@ -252,24 +249,38 @@ __u16 GetNextMid(struct TCP_Server_Info *server) | |||
252 | (and it would also have to have been a request that | 249 | (and it would also have to have been a request that |
253 | did not time out) */ | 250 | did not time out) */ |
254 | while (server->CurrentMid != last_mid) { | 251 | while (server->CurrentMid != last_mid) { |
255 | struct list_head *tmp; | ||
256 | struct mid_q_entry *mid_entry; | 252 | struct mid_q_entry *mid_entry; |
253 | unsigned int num_mids; | ||
257 | 254 | ||
258 | collision = 0; | 255 | collision = false; |
259 | if (server->CurrentMid == 0) | 256 | if (server->CurrentMid == 0) |
260 | server->CurrentMid++; | 257 | server->CurrentMid++; |
261 | 258 | ||
262 | list_for_each(tmp, &server->pending_mid_q) { | 259 | num_mids = 0; |
263 | mid_entry = list_entry(tmp, struct mid_q_entry, qhead); | 260 | list_for_each_entry(mid_entry, &server->pending_mid_q, qhead) { |
264 | 261 | ++num_mids; | |
265 | if ((mid_entry->mid == server->CurrentMid) && | 262 | if (mid_entry->mid == server->CurrentMid && |
266 | (mid_entry->midState == MID_REQUEST_SUBMITTED)) { | 263 | mid_entry->midState == MID_REQUEST_SUBMITTED) { |
267 | /* This mid is in use, try a different one */ | 264 | /* This mid is in use, try a different one */ |
268 | collision = 1; | 265 | collision = true; |
269 | break; | 266 | break; |
270 | } | 267 | } |
271 | } | 268 | } |
272 | if (collision == 0) { | 269 | |
270 | /* | ||
271 | * if we have more than 32k mids in the list, then something | ||
272 | * is very wrong. Possibly a local user is trying to DoS the | ||
273 | * box by issuing long-running calls and SIGKILL'ing them. If | ||
274 | * we get to 2^16 mids then we're in big trouble as this | ||
275 | * function could loop forever. | ||
276 | * | ||
277 | * Go ahead and assign out the mid in this situation, but force | ||
278 | * an eventual reconnect to clean out the pending_mid_q. | ||
279 | */ | ||
280 | if (num_mids > 32768) | ||
281 | server->tcpStatus = CifsNeedReconnect; | ||
282 | |||
283 | if (!collision) { | ||
273 | mid = server->CurrentMid; | 284 | mid = server->CurrentMid; |
274 | break; | 285 | break; |
275 | } | 286 | } |
@@ -381,29 +392,31 @@ header_assemble(struct smb_hdr *buffer, char smb_command /* command */ , | |||
381 | } | 392 | } |
382 | 393 | ||
383 | static int | 394 | static int |
384 | checkSMBhdr(struct smb_hdr *smb, __u16 mid) | 395 | check_smb_hdr(struct smb_hdr *smb, __u16 mid) |
385 | { | 396 | { |
386 | /* Make sure that this really is an SMB, that it is a response, | 397 | /* does it have the right SMB "signature" ? */ |
387 | and that the message ids match */ | 398 | if (*(__le32 *) smb->Protocol != cpu_to_le32(0x424d53ff)) { |
388 | if ((*(__le32 *) smb->Protocol == cpu_to_le32(0x424d53ff)) && | 399 | cERROR(1, "Bad protocol string signature header 0x%x", |
389 | (mid == smb->Mid)) { | 400 | *(unsigned int *)smb->Protocol); |
390 | if (smb->Flags & SMBFLG_RESPONSE) | 401 | return 1; |
391 | return 0; | ||
392 | else { | ||
393 | /* only one valid case where server sends us request */ | ||
394 | if (smb->Command == SMB_COM_LOCKING_ANDX) | ||
395 | return 0; | ||
396 | else | ||
397 | cERROR(1, "Received Request not response"); | ||
398 | } | ||
399 | } else { /* bad signature or mid */ | ||
400 | if (*(__le32 *) smb->Protocol != cpu_to_le32(0x424d53ff)) | ||
401 | cERROR(1, "Bad protocol string signature header %x", | ||
402 | *(unsigned int *) smb->Protocol); | ||
403 | if (mid != smb->Mid) | ||
404 | cERROR(1, "Mids do not match"); | ||
405 | } | 402 | } |
406 | cERROR(1, "bad smb detected. The Mid=%d", smb->Mid); | 403 | |
404 | /* Make sure that message ids match */ | ||
405 | if (mid != smb->Mid) { | ||
406 | cERROR(1, "Mids do not match. received=%u expected=%u", | ||
407 | smb->Mid, mid); | ||
408 | return 1; | ||
409 | } | ||
410 | |||
411 | /* if it's a response then accept */ | ||
412 | if (smb->Flags & SMBFLG_RESPONSE) | ||
413 | return 0; | ||
414 | |||
415 | /* only one valid case where server sends us request */ | ||
416 | if (smb->Command == SMB_COM_LOCKING_ANDX) | ||
417 | return 0; | ||
418 | |||
419 | cERROR(1, "Server sent request, not response. mid=%u", smb->Mid); | ||
407 | return 1; | 420 | return 1; |
408 | } | 421 | } |
409 | 422 | ||
@@ -448,7 +461,7 @@ checkSMB(struct smb_hdr *smb, __u16 mid, unsigned int length) | |||
448 | return 1; | 461 | return 1; |
449 | } | 462 | } |
450 | 463 | ||
451 | if (checkSMBhdr(smb, mid)) | 464 | if (check_smb_hdr(smb, mid)) |
452 | return 1; | 465 | return 1; |
453 | clc_len = smbCalcSize_LE(smb); | 466 | clc_len = smbCalcSize_LE(smb); |
454 | 467 | ||
@@ -465,25 +478,26 @@ checkSMB(struct smb_hdr *smb, __u16 mid, unsigned int length) | |||
465 | if (((4 + len) & 0xFFFF) == (clc_len & 0xFFFF)) | 478 | if (((4 + len) & 0xFFFF) == (clc_len & 0xFFFF)) |
466 | return 0; /* bcc wrapped */ | 479 | return 0; /* bcc wrapped */ |
467 | } | 480 | } |
468 | cFYI(1, "Calculated size %d vs length %d mismatch for mid %d", | 481 | cFYI(1, "Calculated size %u vs length %u mismatch for mid=%u", |
469 | clc_len, 4 + len, smb->Mid); | 482 | clc_len, 4 + len, smb->Mid); |
470 | /* Windows XP can return a few bytes too much, presumably | 483 | |
471 | an illegal pad, at the end of byte range lock responses | 484 | if (4 + len < clc_len) { |
472 | so we allow for that three byte pad, as long as actual | 485 | cERROR(1, "RFC1001 size %u smaller than SMB for mid=%u", |
473 | received length is as long or longer than calculated length */ | ||
474 | /* We have now had to extend this more, since there is a | ||
475 | case in which it needs to be bigger still to handle a | ||
476 | malformed response to transact2 findfirst from WinXP when | ||
477 | access denied is returned and thus bcc and wct are zero | ||
478 | but server says length is 0x21 bytes too long as if the server | ||
479 | forget to reset the smb rfc1001 length when it reset the | ||
480 | wct and bcc to minimum size and drop the t2 parms and data */ | ||
481 | if ((4+len > clc_len) && (len <= clc_len + 512)) | ||
482 | return 0; | ||
483 | else { | ||
484 | cERROR(1, "RFC1001 size %d bigger than SMB for Mid=%d", | ||
485 | len, smb->Mid); | 486 | len, smb->Mid); |
486 | return 1; | 487 | return 1; |
488 | } else if (len > clc_len + 512) { | ||
489 | /* | ||
490 | * Some servers (Windows XP in particular) send more | ||
491 | * data than the lengths in the SMB packet would | ||
492 | * indicate on certain calls (byte range locks and | ||
493 | * trans2 find first calls in particular). While the | ||
494 | * client can handle such a frame by ignoring the | ||
495 | * trailing data, we choose limit the amount of extra | ||
496 | * data to 512 bytes. | ||
497 | */ | ||
498 | cERROR(1, "RFC1001 size %u more than 512 bytes larger " | ||
499 | "than SMB for mid=%u", len, smb->Mid); | ||
500 | return 1; | ||
487 | } | 501 | } |
488 | } | 502 | } |
489 | return 0; | 503 | return 0; |
@@ -571,7 +585,7 @@ is_valid_oplock_break(struct smb_hdr *buf, struct TCP_Server_Info *srv) | |||
571 | pCifsInode = CIFS_I(netfile->dentry->d_inode); | 585 | pCifsInode = CIFS_I(netfile->dentry->d_inode); |
572 | 586 | ||
573 | cifs_set_oplock_level(pCifsInode, | 587 | cifs_set_oplock_level(pCifsInode, |
574 | pSMB->OplockLevel); | 588 | pSMB->OplockLevel ? OPLOCK_READ : 0); |
575 | /* | 589 | /* |
576 | * cifs_oplock_break_put() can't be called | 590 | * cifs_oplock_break_put() can't be called |
577 | * from here. Get reference after queueing | 591 | * from here. Get reference after queueing |
@@ -637,77 +651,6 @@ dump_smb(struct smb_hdr *smb_buf, int smb_buf_length) | |||
637 | return; | 651 | return; |
638 | } | 652 | } |
639 | 653 | ||
640 | /* Convert 16 bit Unicode pathname to wire format from string in current code | ||
641 | page. Conversion may involve remapping up the seven characters that are | ||
642 | only legal in POSIX-like OS (if they are present in the string). Path | ||
643 | names are little endian 16 bit Unicode on the wire */ | ||
644 | int | ||
645 | cifsConvertToUCS(__le16 *target, const char *source, int maxlen, | ||
646 | const struct nls_table *cp, int mapChars) | ||
647 | { | ||
648 | int i, j, charlen; | ||
649 | int len_remaining = maxlen; | ||
650 | char src_char; | ||
651 | __u16 temp; | ||
652 | |||
653 | if (!mapChars) | ||
654 | return cifs_strtoUCS(target, source, PATH_MAX, cp); | ||
655 | |||
656 | for (i = 0, j = 0; i < maxlen; j++) { | ||
657 | src_char = source[i]; | ||
658 | switch (src_char) { | ||
659 | case 0: | ||
660 | target[j] = 0; | ||
661 | goto ctoUCS_out; | ||
662 | case ':': | ||
663 | target[j] = cpu_to_le16(UNI_COLON); | ||
664 | break; | ||
665 | case '*': | ||
666 | target[j] = cpu_to_le16(UNI_ASTERIK); | ||
667 | break; | ||
668 | case '?': | ||
669 | target[j] = cpu_to_le16(UNI_QUESTION); | ||
670 | break; | ||
671 | case '<': | ||
672 | target[j] = cpu_to_le16(UNI_LESSTHAN); | ||
673 | break; | ||
674 | case '>': | ||
675 | target[j] = cpu_to_le16(UNI_GRTRTHAN); | ||
676 | break; | ||
677 | case '|': | ||
678 | target[j] = cpu_to_le16(UNI_PIPE); | ||
679 | break; | ||
680 | /* BB We can not handle remapping slash until | ||
681 | all the calls to build_path_from_dentry | ||
682 | are modified, as they use slash as separator BB */ | ||
683 | /* case '\\': | ||
684 | target[j] = cpu_to_le16(UNI_SLASH); | ||
685 | break;*/ | ||
686 | default: | ||
687 | charlen = cp->char2uni(source+i, | ||
688 | len_remaining, &temp); | ||
689 | /* if no match, use question mark, which | ||
690 | at least in some cases servers as wild card */ | ||
691 | if (charlen < 1) { | ||
692 | target[j] = cpu_to_le16(0x003f); | ||
693 | charlen = 1; | ||
694 | } else | ||
695 | target[j] = cpu_to_le16(temp); | ||
696 | len_remaining -= charlen; | ||
697 | /* character may take more than one byte in the | ||
698 | the source string, but will take exactly two | ||
699 | bytes in the target string */ | ||
700 | i += charlen; | ||
701 | continue; | ||
702 | } | ||
703 | i++; /* move to next char in source string */ | ||
704 | len_remaining--; | ||
705 | } | ||
706 | |||
707 | ctoUCS_out: | ||
708 | return i; | ||
709 | } | ||
710 | |||
711 | void | 654 | void |
712 | cifs_autodisable_serverino(struct cifs_sb_info *cifs_sb) | 655 | cifs_autodisable_serverino(struct cifs_sb_info *cifs_sb) |
713 | { | 656 | { |