diff options
Diffstat (limited to 'fs/nfs/nfs4xdr.c')
| -rw-r--r-- | fs/nfs/nfs4xdr.c | 53 | 
1 files changed, 35 insertions, 18 deletions
diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c index c74fdb114b4..c54aae364be 100644 --- a/fs/nfs/nfs4xdr.c +++ b/fs/nfs/nfs4xdr.c @@ -74,7 +74,7 @@ static int nfs4_stat_to_errno(int);  /* lock,open owner id:   * we currently use size 2 (u64) out of (NFS4_OPAQUE_LIMIT  >> 2)   */ -#define open_owner_id_maxsz	(1 + 1 + 4) +#define open_owner_id_maxsz	(1 + 2 + 1 + 1 + 2)  #define lock_owner_id_maxsz	(1 + 1 + 4)  #define decode_lockowner_maxsz	(1 + XDR_QUADLEN(IDMAP_NAMESZ))  #define compound_encode_hdr_maxsz	(3 + (NFS4_MAXTAGLEN >> 2)) @@ -1340,12 +1340,13 @@ static inline void encode_openhdr(struct xdr_stream *xdr, const struct nfs_opena   */  	encode_nfs4_seqid(xdr, arg->seqid);  	encode_share_access(xdr, arg->fmode); -	p = reserve_space(xdr, 32); +	p = reserve_space(xdr, 36);  	p = xdr_encode_hyper(p, arg->clientid); -	*p++ = cpu_to_be32(20); +	*p++ = cpu_to_be32(24);  	p = xdr_encode_opaque_fixed(p, "open id:", 8);  	*p++ = cpu_to_be32(arg->server->s_dev); -	xdr_encode_hyper(p, arg->id); +	*p++ = cpu_to_be32(arg->id.uniquifier); +	xdr_encode_hyper(p, arg->id.create_time);  }  static inline void encode_createmode(struct xdr_stream *xdr, const struct nfs_openargs *arg) @@ -4257,8 +4258,6 @@ static int decode_getfattr_attrs(struct xdr_stream *xdr, uint32_t *bitmap,  	status = decode_attr_error(xdr, bitmap, &err);  	if (status < 0)  		goto xdr_error; -	if (err == -NFS4ERR_WRONGSEC) -		nfs_fixup_secinfo_attributes(fattr, fh);  	status = decode_attr_filehandle(xdr, bitmap, fh);  	if (status < 0) @@ -4901,11 +4900,19 @@ static int decode_getacl(struct xdr_stream *xdr, struct rpc_rqst *req,  		 bitmap[3] = {0};  	struct kvec *iov = req->rq_rcv_buf.head;  	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; +  	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;  	if ((status = decode_attr_length(xdr, &attrlen, &savep)) != 0) @@ -4915,28 +4922,24 @@ static int decode_getacl(struct xdr_stream *xdr, struct rpc_rqst *req,  		return -EIO;  	if (likely(bitmap[0] & FATTR4_WORD0_ACL)) {  		size_t hdrlen; -		u32 recvd;  		/* 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 = be32_to_cpup(bm_p) + 2; -		res->acl_data_offset <<= 2;  		/* We ignore &savep and don't do consistency checks on  		 * the attr length.  Let userspace figure it out.... */  		hdrlen = (u8 *)xdr->p - (u8 *)iov->iov_base;  		attrlen += res->acl_data_offset; -		recvd = req->rq_rcv_buf.len - hdrlen; -		if (attrlen > recvd) { +		if (attrlen > page_len) {  			if (res->acl_flags & NFS4_ACL_LEN_REQUEST) {  				/* getxattr interface called with a NULL buf */  				res->acl_len = attrlen;  				goto out;  			} -			dprintk("NFS: acl reply: attrlen %u > recvd %u\n", -					attrlen, recvd); +			dprintk("NFS: acl reply: attrlen %u > page_len %zu\n", +					attrlen, page_len);  			return -EINVAL;  		}  		xdr_read_pages(xdr, attrlen); @@ -5089,16 +5092,13 @@ out_err:  	return -EINVAL;  } -static int decode_secinfo(struct xdr_stream *xdr, struct nfs4_secinfo_res *res) +static int decode_secinfo_common(struct xdr_stream *xdr, struct nfs4_secinfo_res *res)  {  	struct nfs4_secinfo_flavor *sec_flavor;  	int status;  	__be32 *p;  	int i, num_flavors; -	status = decode_op_hdr(xdr, OP_SECINFO); -	if (status) -		goto out;  	p = xdr_inline_decode(xdr, 4);  	if (unlikely(!p))  		goto out_overflow; @@ -5124,6 +5124,7 @@ static int decode_secinfo(struct xdr_stream *xdr, struct nfs4_secinfo_res *res)  		res->flavors->num_flavors++;  	} +	status = 0;  out:  	return status;  out_overflow: @@ -5131,7 +5132,23 @@ out_overflow:  	return -EIO;  } +static int decode_secinfo(struct xdr_stream *xdr, struct nfs4_secinfo_res *res) +{ +	int status = decode_op_hdr(xdr, OP_SECINFO); +	if (status) +		return status; +	return decode_secinfo_common(xdr, res); +} +  #if defined(CONFIG_NFS_V4_1) +static int decode_secinfo_no_name(struct xdr_stream *xdr, struct nfs4_secinfo_res *res) +{ +	int status = decode_op_hdr(xdr, OP_SECINFO_NO_NAME); +	if (status) +		return status; +	return decode_secinfo_common(xdr, res); +} +  static int decode_exchange_id(struct xdr_stream *xdr,  			      struct nfs41_exchange_id_res *res)  { @@ -6816,7 +6833,7 @@ static int nfs4_xdr_dec_secinfo_no_name(struct rpc_rqst *rqstp,  	status = decode_putrootfh(xdr);  	if (status)  		goto out; -	status = decode_secinfo(xdr, res); +	status = decode_secinfo_no_name(xdr, res);  out:  	return status;  }  |