···55 struct smb_hdr * /* input */ ,56 struct smb_hdr * /* out */ ,57 int * /* bytes returned */);58-extern int checkSMB(struct smb_hdr *smb, __u16 mid, int length);59extern int is_valid_oplock_break(struct smb_hdr *smb, struct TCP_Server_Info *);60extern int is_size_safe_to_change(struct cifsInodeInfo *);61extern struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *);
···55 struct smb_hdr * /* input */ ,56 struct smb_hdr * /* out */ ,57 int * /* bytes returned */);58+extern int checkSMB(struct smb_hdr *smb, __u16 mid, unsigned int length);59extern int is_valid_oplock_break(struct smb_hdr *smb, struct TCP_Server_Info *);60extern int is_size_safe_to_change(struct cifsInodeInfo *);61extern struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *);
+29-13
fs/cifs/misc.c
···418}419420int421-checkSMB(struct smb_hdr *smb, __u16 mid, int length)422{423 __u32 len = smb->smb_buf_length;424 __u32 clc_len; /* calculated length */425 cFYI(0, ("checkSMB Length: 0x%x, smb_buf_length: 0x%x", length, len));426- if (((unsigned int)length < 2 + sizeof (struct smb_hdr)) ||427- (len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4)) {428- if ((unsigned int)length < 2 + sizeof (struct smb_hdr)) {429- if (((unsigned int)length >= 430- sizeof (struct smb_hdr) - 1)431 && (smb->Status.CifsError != 0)) {432- smb->WordCount = 0;433- /* some error cases do not return wct and bcc */000000000000000434 return 0;435- } else {436- cERROR(1, ("Length less than smb header size"));437 }000438 }439- if (len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4)440- cERROR(1, ("smb length greater than MaxBufSize, mid=%d",00441 smb->Mid));442 return 1;443 }···462 return 1;463 clc_len = smbCalcSize_LE(smb);464465- if(4 + len != (unsigned int)length) {466 cERROR(1, ("Length read does not match RFC1001 length %d",len));467 return 1;468 }
···418}419420int421+checkSMB(struct smb_hdr *smb, __u16 mid, unsigned int length)422{423 __u32 len = smb->smb_buf_length;424 __u32 clc_len; /* calculated length */425 cFYI(0, ("checkSMB Length: 0x%x, smb_buf_length: 0x%x", length, len));426+427+ if (length < 2 + sizeof (struct smb_hdr)) {428+ if ((length >= sizeof (struct smb_hdr) - 1)00429 && (smb->Status.CifsError != 0)) {430+ smb->WordCount = 0;431+ /* some error cases do not return wct and bcc */432+ return 0;433+ } else if ((length == sizeof(struct smb_hdr) + 1) && 434+ (smb->WordCount == 0)) {435+ char * tmp = (char *)smb;436+ /* Need to work around a bug in two servers here */437+ /* First, check if the part of bcc they sent was zero */438+ if (tmp[sizeof(struct smb_hdr)] == 0) {439+ /* some servers return only half of bcc440+ * on simple responses (wct, bcc both zero)441+ * in particular have seen this on442+ * ulogoffX and FindClose. This leaves443+ * one byte of bcc potentially unitialized444+ */445+ /* zero rest of bcc */446+ tmp[sizeof(struct smb_hdr)+1] = 0;447 return 0;00448 }449+ cERROR(1,("rcvd invalid byte count (bcc)"));450+ } else {451+ cERROR(1, ("Length less than smb header size"));452 }453+ return 1;454+ }455+ if (len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) {456+ cERROR(1, ("smb length greater than MaxBufSize, mid=%d",457 smb->Mid));458 return 1;459 }···446 return 1;447 clc_len = smbCalcSize_LE(smb);448449+ if(4 + len != length) {450 cERROR(1, ("Length read does not match RFC1001 length %d",len));451 return 1;452 }