Commit d103e164 authored by Steve French's avatar Steve French

[CIFS] Workaround incomplete byte length returned by some

servers on small SMB responses
Signed-off-by: default avatarSteve French <sfrench@us.ibm.com>
parent 230a0395
...@@ -55,7 +55,7 @@ extern int SendReceiveBlockingLock(const unsigned int /* xid */ , ...@@ -55,7 +55,7 @@ extern int SendReceiveBlockingLock(const unsigned int /* xid */ ,
struct smb_hdr * /* input */ , struct smb_hdr * /* input */ ,
struct smb_hdr * /* out */ , struct smb_hdr * /* out */ ,
int * /* bytes returned */); int * /* bytes returned */);
extern int checkSMB(struct smb_hdr *smb, __u16 mid, int length); extern int checkSMB(struct smb_hdr *smb, __u16 mid, unsigned int length);
extern int is_valid_oplock_break(struct smb_hdr *smb, struct TCP_Server_Info *); extern int is_valid_oplock_break(struct smb_hdr *smb, struct TCP_Server_Info *);
extern int is_size_safe_to_change(struct cifsInodeInfo *); extern int is_size_safe_to_change(struct cifsInodeInfo *);
extern struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *); extern struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *);
......
...@@ -418,26 +418,42 @@ checkSMBhdr(struct smb_hdr *smb, __u16 mid) ...@@ -418,26 +418,42 @@ checkSMBhdr(struct smb_hdr *smb, __u16 mid)
} }
int int
checkSMB(struct smb_hdr *smb, __u16 mid, int length) checkSMB(struct smb_hdr *smb, __u16 mid, unsigned int length)
{ {
__u32 len = smb->smb_buf_length; __u32 len = smb->smb_buf_length;
__u32 clc_len; /* calculated length */ __u32 clc_len; /* calculated length */
cFYI(0, ("checkSMB Length: 0x%x, smb_buf_length: 0x%x", length, len)); cFYI(0, ("checkSMB Length: 0x%x, smb_buf_length: 0x%x", length, len));
if (((unsigned int)length < 2 + sizeof (struct smb_hdr)) ||
(len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4)) { if (length < 2 + sizeof (struct smb_hdr)) {
if ((unsigned int)length < 2 + sizeof (struct smb_hdr)) { if ((length >= sizeof (struct smb_hdr) - 1)
if (((unsigned int)length >=
sizeof (struct smb_hdr) - 1)
&& (smb->Status.CifsError != 0)) { && (smb->Status.CifsError != 0)) {
smb->WordCount = 0; smb->WordCount = 0;
/* some error cases do not return wct and bcc */ /* some error cases do not return wct and bcc */
return 0;
} else if ((length == sizeof(struct smb_hdr) + 1) &&
(smb->WordCount == 0)) {
char * tmp = (char *)smb;
/* Need to work around a bug in two servers here */
/* First, check if the part of bcc they sent was zero */
if (tmp[sizeof(struct smb_hdr)] == 0) {
/* some servers return only half of bcc
* on simple responses (wct, bcc both zero)
* in particular have seen this on
* ulogoffX and FindClose. This leaves
* one byte of bcc potentially unitialized
*/
/* zero rest of bcc */
tmp[sizeof(struct smb_hdr)+1] = 0;
return 0; return 0;
} else {
cERROR(1, ("Length less than smb header size"));
} }
cERROR(1,("rcvd invalid byte count (bcc)"));
} else {
cERROR(1, ("Length less than smb header size"));
} }
if (len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) return 1;
cERROR(1, ("smb length greater than MaxBufSize, mid=%d", }
if (len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) {
cERROR(1, ("smb length greater than MaxBufSize, mid=%d",
smb->Mid)); smb->Mid));
return 1; return 1;
} }
...@@ -446,7 +462,7 @@ checkSMB(struct smb_hdr *smb, __u16 mid, int length) ...@@ -446,7 +462,7 @@ checkSMB(struct smb_hdr *smb, __u16 mid, int length)
return 1; return 1;
clc_len = smbCalcSize_LE(smb); clc_len = smbCalcSize_LE(smb);
if(4 + len != (unsigned int)length) { if(4 + len != length) {
cERROR(1, ("Length read does not match RFC1001 length %d",len)); cERROR(1, ("Length read does not match RFC1001 length %d",len));
return 1; return 1;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment