|
@@ -4902,11 +4902,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)
|
|
@@ -4916,28 +4924,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 %zu > page_len %u\n",
|
|
|
+ attrlen, page_len);
|
|
|
return -EINVAL;
|
|
|
}
|
|
|
xdr_read_pages(xdr, attrlen);
|