diff options
Diffstat (limited to 'fs/cifs/misc.c')
| -rw-r--r-- | fs/cifs/misc.c | 50 |
1 files changed, 28 insertions, 22 deletions
diff --git a/fs/cifs/misc.c b/fs/cifs/misc.c index 812c6bb0fe38..fafd056426e4 100644 --- a/fs/cifs/misc.c +++ b/fs/cifs/misc.c | |||
| @@ -72,10 +72,9 @@ sesInfoAlloc(void) | |||
| 72 | struct cifsSesInfo *ret_buf; | 72 | struct cifsSesInfo *ret_buf; |
| 73 | 73 | ||
| 74 | ret_buf = | 74 | ret_buf = |
| 75 | (struct cifsSesInfo *) kmalloc(sizeof (struct cifsSesInfo), | 75 | (struct cifsSesInfo *) kzalloc(sizeof (struct cifsSesInfo), |
| 76 | GFP_KERNEL); | 76 | GFP_KERNEL); |
| 77 | if (ret_buf) { | 77 | if (ret_buf) { |
| 78 | memset(ret_buf, 0, sizeof (struct cifsSesInfo)); | ||
| 79 | write_lock(&GlobalSMBSeslock); | 78 | write_lock(&GlobalSMBSeslock); |
| 80 | atomic_inc(&sesInfoAllocCount); | 79 | atomic_inc(&sesInfoAllocCount); |
| 81 | ret_buf->status = CifsNew; | 80 | ret_buf->status = CifsNew; |
| @@ -110,10 +109,9 @@ tconInfoAlloc(void) | |||
| 110 | { | 109 | { |
| 111 | struct cifsTconInfo *ret_buf; | 110 | struct cifsTconInfo *ret_buf; |
| 112 | ret_buf = | 111 | ret_buf = |
| 113 | (struct cifsTconInfo *) kmalloc(sizeof (struct cifsTconInfo), | 112 | (struct cifsTconInfo *) kzalloc(sizeof (struct cifsTconInfo), |
| 114 | GFP_KERNEL); | 113 | GFP_KERNEL); |
| 115 | if (ret_buf) { | 114 | if (ret_buf) { |
| 116 | memset(ret_buf, 0, sizeof (struct cifsTconInfo)); | ||
| 117 | write_lock(&GlobalSMBSeslock); | 115 | write_lock(&GlobalSMBSeslock); |
| 118 | atomic_inc(&tconInfoAllocCount); | 116 | atomic_inc(&tconInfoAllocCount); |
| 119 | list_add(&ret_buf->cifsConnectionList, | 117 | list_add(&ret_buf->cifsConnectionList, |
| @@ -423,9 +421,7 @@ checkSMB(struct smb_hdr *smb, __u16 mid, int length) | |||
| 423 | { | 421 | { |
| 424 | __u32 len = smb->smb_buf_length; | 422 | __u32 len = smb->smb_buf_length; |
| 425 | __u32 clc_len; /* calculated length */ | 423 | __u32 clc_len; /* calculated length */ |
| 426 | cFYI(0, | 424 | cFYI(0, ("checkSMB Length: 0x%x, smb_buf_length: 0x%x", length, len)); |
| 427 | ("Entering checkSMB with Length: %x, smb_buf_length: %x", | ||
| 428 | length, len)); | ||
| 429 | if (((unsigned int)length < 2 + sizeof (struct smb_hdr)) || | 425 | if (((unsigned int)length < 2 + sizeof (struct smb_hdr)) || |
| 430 | (len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4)) { | 426 | (len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4)) { |
| 431 | if ((unsigned int)length < 2 + sizeof (struct smb_hdr)) { | 427 | if ((unsigned int)length < 2 + sizeof (struct smb_hdr)) { |
| @@ -433,29 +429,36 @@ checkSMB(struct smb_hdr *smb, __u16 mid, int length) | |||
| 433 | sizeof (struct smb_hdr) - 1) | 429 | sizeof (struct smb_hdr) - 1) |
| 434 | && (smb->Status.CifsError != 0)) { | 430 | && (smb->Status.CifsError != 0)) { |
| 435 | smb->WordCount = 0; | 431 | smb->WordCount = 0; |
| 436 | return 0; /* some error cases do not return wct and bcc */ | 432 | /* some error cases do not return wct and bcc */ |
| 433 | return 0; | ||
| 437 | } else { | 434 | } else { |
| 438 | cERROR(1, ("Length less than smb header size")); | 435 | cERROR(1, ("Length less than smb header size")); |
| 439 | } | 436 | } |
| 440 | |||
| 441 | } | 437 | } |
| 442 | if (len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) | 438 | if (len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) |
| 443 | cERROR(1, | 439 | cERROR(1, ("smb length greater than MaxBufSize, mid=%d", |
| 444 | ("smb_buf_length greater than MaxBufSize")); | 440 | smb->Mid)); |
| 445 | cERROR(1, | ||
| 446 | ("bad smb detected. Illegal length. mid=%d", | ||
| 447 | smb->Mid)); | ||
| 448 | return 1; | 441 | return 1; |
| 449 | } | 442 | } |
| 450 | 443 | ||
| 451 | if (checkSMBhdr(smb, mid)) | 444 | if (checkSMBhdr(smb, mid)) |
| 452 | return 1; | 445 | return 1; |
| 453 | clc_len = smbCalcSize_LE(smb); | 446 | clc_len = smbCalcSize_LE(smb); |
| 454 | if ((4 + len != clc_len) | 447 | |
| 455 | || (4 + len != (unsigned int)length)) { | 448 | if(4 + len != (unsigned int)length) { |
| 456 | cERROR(1, ("Calculated size 0x%x vs actual length 0x%x", | 449 | cERROR(1, ("Length read does not match RFC1001 length %d",len)); |
| 457 | clc_len, 4 + len)); | 450 | return 1; |
| 458 | cERROR(1, ("bad smb size detected for Mid=%d", smb->Mid)); | 451 | } |
| 452 | |||
| 453 | if (4 + len != clc_len) { | ||
| 454 | /* check if bcc wrapped around for large read responses */ | ||
| 455 | if((len > 64 * 1024) && (len > clc_len)) { | ||
| 456 | /* check if lengths match mod 64K */ | ||
| 457 | if(((4 + len) & 0xFFFF) == (clc_len & 0xFFFF)) | ||
| 458 | return 0; /* bcc wrapped */ | ||
| 459 | } | ||
| 460 | cFYI(1, ("Calculated size %d vs length %d mismatch for mid %d", | ||
| 461 | clc_len, 4 + len, smb->Mid)); | ||
| 459 | /* Windows XP can return a few bytes too much, presumably | 462 | /* Windows XP can return a few bytes too much, presumably |
| 460 | an illegal pad, at the end of byte range lock responses | 463 | an illegal pad, at the end of byte range lock responses |
| 461 | so we allow for that three byte pad, as long as actual | 464 | so we allow for that three byte pad, as long as actual |
| @@ -469,13 +472,16 @@ checkSMB(struct smb_hdr *smb, __u16 mid, int length) | |||
| 469 | wct and bcc to minimum size and drop the t2 parms and data */ | 472 | wct and bcc to minimum size and drop the t2 parms and data */ |
| 470 | if((4+len > clc_len) && (len <= clc_len + 512)) | 473 | if((4+len > clc_len) && (len <= clc_len + 512)) |
| 471 | return 0; | 474 | return 0; |
| 472 | else | 475 | else { |
| 476 | cERROR(1, ("RFC1001 size %d bigger than SMB for Mid=%d", | ||
| 477 | len, smb->Mid)); | ||
| 473 | return 1; | 478 | return 1; |
| 479 | } | ||
| 474 | } | 480 | } |
| 475 | return 0; | 481 | return 0; |
| 476 | } | 482 | } |
| 477 | int | 483 | int |
| 478 | is_valid_oplock_break(struct smb_hdr *buf) | 484 | is_valid_oplock_break(struct smb_hdr *buf, struct TCP_Server_Info *srv) |
| 479 | { | 485 | { |
| 480 | struct smb_com_lock_req * pSMB = (struct smb_com_lock_req *)buf; | 486 | struct smb_com_lock_req * pSMB = (struct smb_com_lock_req *)buf; |
| 481 | struct list_head *tmp; | 487 | struct list_head *tmp; |
| @@ -535,7 +541,7 @@ is_valid_oplock_break(struct smb_hdr *buf) | |||
| 535 | read_lock(&GlobalSMBSeslock); | 541 | read_lock(&GlobalSMBSeslock); |
| 536 | list_for_each(tmp, &GlobalTreeConnectionList) { | 542 | list_for_each(tmp, &GlobalTreeConnectionList) { |
| 537 | tcon = list_entry(tmp, struct cifsTconInfo, cifsConnectionList); | 543 | tcon = list_entry(tmp, struct cifsTconInfo, cifsConnectionList); |
| 538 | if (tcon->tid == buf->Tid) { | 544 | if ((tcon->tid == buf->Tid) && (srv == tcon->ses->server)) { |
| 539 | cifs_stats_inc(&tcon->num_oplock_brks); | 545 | cifs_stats_inc(&tcon->num_oplock_brks); |
| 540 | list_for_each(tmp1,&tcon->openFileList){ | 546 | list_for_each(tmp1,&tcon->openFileList){ |
| 541 | netfile = list_entry(tmp1,struct cifsFileInfo, | 547 | netfile = list_entry(tmp1,struct cifsFileInfo, |
