Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit d103e164 authored by Steve French's avatar Steve French
Browse files

[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
Loading
Loading
Loading
Loading
+1 −1
Original line number Original line Diff line number Diff line
@@ -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 *);
+29 −13
Original line number Original line Diff line number Diff line
@@ -418,25 +418,41 @@ 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;
			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;
			}
			cERROR(1,("rcvd invalid byte count (bcc)"));
		} else {
		} else {
			cERROR(1, ("Length less than smb header size"));
			cERROR(1, ("Length less than smb header size"));
		}
		}
		return 1;
	}
	}
		if (len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4)
	if (len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) {
		cERROR(1, ("smb length greater than MaxBufSize, mid=%d",
		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)
		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;
	}
	}