Re: [PATCH 1/3] NFSv4: Fix pointer arithmetic in decode_getacl

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Thu, 2012-08-16 at 14:29 +0100, Sachin Prabhu wrote:
> On Tue, 2012-08-14 at 18:47 -0400, Trond Myklebust wrote:
> > Resetting the cursor xdr->p to a previous value is not a safe
> > practice: if the xdr_stream has crossed out of the initial iovec,
> > then a bunch of other fields would need to be reset too.
> > 
> > Fix this issue by using xdr_enter_page() so that the buffer gets
> > page aligned at the bitmap _before_ we decode it.
> > 
> > Also fix the confusion of the ACL length with the page buffer length
> > by not adding the base offset to the ACL length...
> > 
> > Signed-off-by: Trond Myklebust <Trond.Myklebust@xxxxxxxxxx>
> > Cc: stable@xxxxxxxxxxxxxxx
> > ---
> >  fs/nfs/nfs4proc.c |  2 +-
> >  fs/nfs/nfs4xdr.c  | 21 +++++++--------------
> >  2 files changed, 8 insertions(+), 15 deletions(-)
> > 
> > diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
> > index c77d296..286ab70 100644
> > --- a/fs/nfs/nfs4proc.c
> > +++ b/fs/nfs/nfs4proc.c
> > @@ -3819,7 +3819,7 @@ static ssize_t __nfs4_get_acl_uncached(struct inode *inode, void *buf, size_t bu
> >  	if (ret)
> >  		goto out_free;
> >  
> > -	acl_len = res.acl_len - res.acl_data_offset;
> > +	acl_len = res.acl_len;
> >  	if (acl_len > args.acl_len)
> >  		nfs4_write_cached_acl(inode, NULL, 0, acl_len);
> >  	else
> > diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c
> > index ca13483..54d3f5a 100644
> > --- a/fs/nfs/nfs4xdr.c
> > +++ b/fs/nfs/nfs4xdr.c
> > @@ -5049,18 +5049,14 @@ static int decode_getacl(struct xdr_stream *xdr, struct rpc_rqst *req,
> >  	uint32_t attrlen,
> >  		 bitmap[3] = {0};
> >  	int status;
> > -	size_t page_len = xdr->buf->page_len;
> >  
> >  	res->acl_len = 0;
> >  	if ((status = decode_op_hdr(xdr, OP_GETATTR)) != 0)
> >  		goto out;
> >  
> > +	xdr_enter_page(xdr, xdr->buf->page_len);
> > +
> >  	bm_p = xdr->p;
> > -	res->acl_data_offset = be32_to_cpup(bm_p) + 2;
> > -	res->acl_data_offset <<= 2;
> > -	/* Check if the acl data starts beyond the allocated buffer */
> > -	if (res->acl_data_offset > page_len)
> > -		return -ERANGE;
> >  
> >  	if ((status = decode_attr_bitmap(xdr, bitmap)) != 0)
> >  		goto out;
> > @@ -5074,23 +5070,20 @@ static int decode_getacl(struct xdr_stream *xdr, struct rpc_rqst *req,
> >  		/* The bitmap (xdr len + bitmaps) and the attr xdr len words
> >  		 * are stored with the acl data to handle the problem of
> >  		 * variable length bitmaps.*/
> > -		xdr->p = bm_p;
> > +		res->acl_data_offset = (xdr->p - bm_p) << 2;
> 
> The problem here is with an unbounded bitmap. In the case where the
> server decides to send a large bitmap and the value of bitmap array + 2
> (for the acl length attribute) is greater than the buffer allocated, we
> will move to the tail section of the xdr and the pointer arithmetic here
> will be wrong. 

> Maybe we are better off setting res->acl_data_offset as in the earlier
> block. We will not need the variable bm_p in that case.


If we overflow the page while reading the bitmap, then we are screwed
anyway, since xdr_inline_decode() will fail. Changing the way that the
data offset is calculated won't fix that.

-- 
Trond Myklebust
Linux NFS client maintainer

NetApp
Trond.Myklebust@xxxxxxxxxx
www.netapp.com

��.n��������+%������w��{.n�����{��w���jg��������ݢj����G�������j:+v���w�m������w�������h�����٥



[Index of Archives]     [Linux Filesystem Development]     [Linux USB Development]     [Linux Media Development]     [Video for Linux]     [Linux NILFS]     [Linux Audio Users]     [Yosemite Info]     [Linux SCSI]

  Powered by Linux