aboutsummaryrefslogtreecommitdiffstats
path: root/fs/nfs
diff options
context:
space:
mode:
Diffstat (limited to 'fs/nfs')
-rw-r--r--fs/nfs/nfs4proc.c16
-rw-r--r--fs/nfs/nfs4xdr.c18
2 files changed, 21 insertions, 13 deletions
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
index 60d5f4c26dda..f5f125fdae1b 100644
--- a/fs/nfs/nfs4proc.c
+++ b/fs/nfs/nfs4proc.c
@@ -3684,19 +3684,23 @@ static ssize_t __nfs4_get_acl_uncached(struct inode *inode, void *buf, size_t bu
3684 if (npages == 0) 3684 if (npages == 0)
3685 npages = 1; 3685 npages = 1;
3686 3686
3687 /* Add an extra page to handle the bitmap returned */
3688 npages++;
3689
3687 for (i = 0; i < npages; i++) { 3690 for (i = 0; i < npages; i++) {
3688 pages[i] = alloc_page(GFP_KERNEL); 3691 pages[i] = alloc_page(GFP_KERNEL);
3689 if (!pages[i]) 3692 if (!pages[i])
3690 goto out_free; 3693 goto out_free;
3691 } 3694 }
3692 if (npages > 1) { 3695
3693 /* for decoding across pages */ 3696 /* for decoding across pages */
3694 res.acl_scratch = alloc_page(GFP_KERNEL); 3697 res.acl_scratch = alloc_page(GFP_KERNEL);
3695 if (!res.acl_scratch) 3698 if (!res.acl_scratch)
3696 goto out_free; 3699 goto out_free;
3697 } 3700
3698 args.acl_len = npages * PAGE_SIZE; 3701 args.acl_len = npages * PAGE_SIZE;
3699 args.acl_pgbase = 0; 3702 args.acl_pgbase = 0;
3703
3700 /* Let decode_getfacl know not to fail if the ACL data is larger than 3704 /* Let decode_getfacl know not to fail if the ACL data is larger than
3701 * the page we send as a guess */ 3705 * the page we send as a guess */
3702 if (buf == NULL) 3706 if (buf == NULL)
diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c
index 77fc5f959c4e..9312dd78d349 100644
--- a/fs/nfs/nfs4xdr.c
+++ b/fs/nfs/nfs4xdr.c
@@ -4902,11 +4902,19 @@ static int decode_getacl(struct xdr_stream *xdr, struct rpc_rqst *req,
4902 bitmap[3] = {0}; 4902 bitmap[3] = {0};
4903 struct kvec *iov = req->rq_rcv_buf.head; 4903 struct kvec *iov = req->rq_rcv_buf.head;
4904 int status; 4904 int status;
4905 size_t page_len = xdr->buf->page_len;
4905 4906
4906 res->acl_len = 0; 4907 res->acl_len = 0;
4907 if ((status = decode_op_hdr(xdr, OP_GETATTR)) != 0) 4908 if ((status = decode_op_hdr(xdr, OP_GETATTR)) != 0)
4908 goto out; 4909 goto out;
4910
4909 bm_p = xdr->p; 4911 bm_p = xdr->p;
4912 res->acl_data_offset = be32_to_cpup(bm_p) + 2;
4913 res->acl_data_offset <<= 2;
4914 /* Check if the acl data starts beyond the allocated buffer */
4915 if (res->acl_data_offset > page_len)
4916 return -ERANGE;
4917
4910 if ((status = decode_attr_bitmap(xdr, bitmap)) != 0) 4918 if ((status = decode_attr_bitmap(xdr, bitmap)) != 0)
4911 goto out; 4919 goto out;
4912 if ((status = decode_attr_length(xdr, &attrlen, &savep)) != 0) 4920 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,
4916 return -EIO; 4924 return -EIO;
4917 if (likely(bitmap[0] & FATTR4_WORD0_ACL)) { 4925 if (likely(bitmap[0] & FATTR4_WORD0_ACL)) {
4918 size_t hdrlen; 4926 size_t hdrlen;
4919 u32 recvd;
4920 4927
4921 /* The bitmap (xdr len + bitmaps) and the attr xdr len words 4928 /* The bitmap (xdr len + bitmaps) and the attr xdr len words
4922 * are stored with the acl data to handle the problem of 4929 * are stored with the acl data to handle the problem of
4923 * variable length bitmaps.*/ 4930 * variable length bitmaps.*/
4924 xdr->p = bm_p; 4931 xdr->p = bm_p;
4925 res->acl_data_offset = be32_to_cpup(bm_p) + 2;
4926 res->acl_data_offset <<= 2;
4927 4932
4928 /* We ignore &savep and don't do consistency checks on 4933 /* We ignore &savep and don't do consistency checks on
4929 * the attr length. Let userspace figure it out.... */ 4934 * the attr length. Let userspace figure it out.... */
4930 hdrlen = (u8 *)xdr->p - (u8 *)iov->iov_base; 4935 hdrlen = (u8 *)xdr->p - (u8 *)iov->iov_base;
4931 attrlen += res->acl_data_offset; 4936 attrlen += res->acl_data_offset;
4932 recvd = req->rq_rcv_buf.len - hdrlen; 4937 if (attrlen > page_len) {
4933 if (attrlen > recvd) {
4934 if (res->acl_flags & NFS4_ACL_LEN_REQUEST) { 4938 if (res->acl_flags & NFS4_ACL_LEN_REQUEST) {
4935 /* getxattr interface called with a NULL buf */ 4939 /* getxattr interface called with a NULL buf */
4936 res->acl_len = attrlen; 4940 res->acl_len = attrlen;
4937 goto out; 4941 goto out;
4938 } 4942 }
4939 dprintk("NFS: acl reply: attrlen %u > recvd %u\n", 4943 dprintk("NFS: acl reply: attrlen %zu > page_len %u\n",
4940 attrlen, recvd); 4944 attrlen, page_len);
4941 return -EINVAL; 4945 return -EINVAL;
4942 } 4946 }
4943 xdr_read_pages(xdr, attrlen); 4947 xdr_read_pages(xdr, attrlen);