Re: [PATCH] cifs: Fix a kernel BUG with remote OS/2 server

Jeff Layton <[email protected]>
Newsgroups gmane.linux.file-systems.cifs
Message-ID <[email protected]>
On Tue, 30 Mar 2010 14:17:43 +0530
Suresh Jayaraman <[email protected]> wrote:

> While chasing a bug report involving a OS/2 server, I noticed the server sets
> pSMBr->CountHigh to a incorrect value even in case of normal writes. This
> leads to 'nbytes' being computed wrongly and triggers a kernel BUG at
> mm/filemap.c.
> 
> void iov_iter_advance(struct iov_iter *i, size_t bytes)
> {
>         BUG_ON(i->count < bytes);    <--- BUG here
> 
> Why the server is setting 'CountHigh' is not clear but only does so after
> writing 64k bytes. Though this looks like the server bug, the client side
> crash may not be acceptable.
> 
> Looking up the CIFS spec, the purpose of 'CountHigh' field in WriteAndX
> response is not clear. But since 'nbytes' can be greater than 64k only
> in case of large writes (default writes can be upto 56k), I assume 'CountHigh'
> is used only for larger writes. The below patch workarounds the case when
> servers set 'CountHigh' incorrectly for normal writes.
> 
> Signed-off-by: Suresh Jayaraman <[email protected]>
> ---
>  fs/cifs/cifssmb.c |   20 ++++++++++++++++----
>  1 files changed, 16 insertions(+), 4 deletions(-)
> 
> diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c
> index 7cc7f83..ceced62 100644
> --- a/fs/cifs/cifssmb.c
> +++ b/fs/cifs/cifssmb.c
> @@ -1514,8 +1514,14 @@ CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon,
>  		cFYI(1, ("Send error in write = %d", rc));
>  		*nbytes = 0;
>  	} else {
> -		*nbytes = le16_to_cpu(pSMBr->CountHigh);
> -		*nbytes = (*nbytes) << 16;
> +		/*
> +		 * Some legacy servers (read OS/2) might incorrectly set
> +		 * CountHigh for normal writes resulting in wrong 'nbytes' value
> +		 */
> +		if (tcon->ses->capabilities & CAP_LARGE_WRITE_X) {
> +			*nbytes = le16_to_cpu(pSMBr->CountHigh);
> +			*nbytes = (*nbytes) << 16;
> +		}
>  		*nbytes += le16_to_cpu(pSMBr->Count);
>  	}
>  
> @@ -1602,8 +1608,14 @@ CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon,
>  		rc = -EIO;
>  	} else {
>  		WRITE_RSP *pSMBr = (WRITE_RSP *)iov[0].iov_base;
> -		*nbytes = le16_to_cpu(pSMBr->CountHigh);
> -		*nbytes = (*nbytes) << 16;
> +		/*
> +		 * Some legacy servers (read OS/2) might incorrectly set
> +		 * CountHigh for normal writes resulting in wrong 'nbytes' value
> +		 */
> +		if (tcon->ses->capabilities & CAP_LARGE_WRITE_X) {
> +			*nbytes = le16_to_cpu(pSMBr->CountHigh);
> +			*nbytes = (*nbytes) << 16;
> +		}
>  		*nbytes += le16_to_cpu(pSMBr->Count);
>  	}
>  

MS-SMB says that CAP_LARGE_WRITE_X allows you to write up to 65536
bytes. But, writing that many bytes doesn't require more than the 16
bit count field. The MS-SMB/CIFS specs say that the CountHigh field is
"Reserved" and make no mention of it.

I have a vague recollection of someone (Jeremy?) mentioning using a
portion of the reserved field to handle large writes, but I don't
recall how they indicated its presence. I'm not sure that
CAP_LARGE_WRITE_X is the right bit to key off of here. Might there be
servers that set that bit, but still put junk the the "reserved"
section?

Either way, I think we need some clarification on when it's safe to
trust the CountHigh field.

-- 
Jeff Layton <[email protected]>
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.