diff options
Diffstat (limited to 'fs/nfs/nfs4xdr.c')
-rw-r--r-- | fs/nfs/nfs4xdr.c | 30 |
1 files changed, 20 insertions, 10 deletions
diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c index 207d399c8dee..40da65e8fa2a 100644 --- a/fs/nfs/nfs4xdr.c +++ b/fs/nfs/nfs4xdr.c | |||
@@ -2656,6 +2656,10 @@ static void nfs4_xdr_enc_layoutget(struct rpc_rqst *req, | |||
2656 | encode_sequence(xdr, &args->seq_args, &hdr); | 2656 | encode_sequence(xdr, &args->seq_args, &hdr); |
2657 | encode_putfh(xdr, NFS_FH(args->inode), &hdr); | 2657 | encode_putfh(xdr, NFS_FH(args->inode), &hdr); |
2658 | encode_layoutget(xdr, args, &hdr); | 2658 | encode_layoutget(xdr, args, &hdr); |
2659 | |||
2660 | xdr_inline_pages(&req->rq_rcv_buf, hdr.replen << 2, | ||
2661 | args->layout.pages, 0, args->layout.pglen); | ||
2662 | |||
2659 | encode_nops(&hdr); | 2663 | encode_nops(&hdr); |
2660 | } | 2664 | } |
2661 | 2665 | ||
@@ -5022,6 +5026,9 @@ static int decode_layoutget(struct xdr_stream *xdr, struct rpc_rqst *req, | |||
5022 | __be32 *p; | 5026 | __be32 *p; |
5023 | int status; | 5027 | int status; |
5024 | u32 layout_count; | 5028 | u32 layout_count; |
5029 | struct xdr_buf *rcvbuf = &req->rq_rcv_buf; | ||
5030 | struct kvec *iov = rcvbuf->head; | ||
5031 | u32 hdrlen, recvd; | ||
5025 | 5032 | ||
5026 | status = decode_op_hdr(xdr, OP_LAYOUTGET); | 5033 | status = decode_op_hdr(xdr, OP_LAYOUTGET); |
5027 | if (status) | 5034 | if (status) |
@@ -5038,17 +5045,14 @@ static int decode_layoutget(struct xdr_stream *xdr, struct rpc_rqst *req, | |||
5038 | return -EINVAL; | 5045 | return -EINVAL; |
5039 | } | 5046 | } |
5040 | 5047 | ||
5041 | p = xdr_inline_decode(xdr, 24); | 5048 | p = xdr_inline_decode(xdr, 28); |
5042 | if (unlikely(!p)) | 5049 | if (unlikely(!p)) |
5043 | goto out_overflow; | 5050 | goto out_overflow; |
5044 | p = xdr_decode_hyper(p, &res->range.offset); | 5051 | p = xdr_decode_hyper(p, &res->range.offset); |
5045 | p = xdr_decode_hyper(p, &res->range.length); | 5052 | p = xdr_decode_hyper(p, &res->range.length); |
5046 | res->range.iomode = be32_to_cpup(p++); | 5053 | res->range.iomode = be32_to_cpup(p++); |
5047 | res->type = be32_to_cpup(p++); | 5054 | res->type = be32_to_cpup(p++); |
5048 | 5055 | res->layoutp->len = be32_to_cpup(p); | |
5049 | status = decode_opaque_inline(xdr, &res->layout.len, (char **)&p); | ||
5050 | if (unlikely(status)) | ||
5051 | return status; | ||
5052 | 5056 | ||
5053 | dprintk("%s roff:%lu rlen:%lu riomode:%d, lo_type:0x%x, lo.len:%d\n", | 5057 | dprintk("%s roff:%lu rlen:%lu riomode:%d, lo_type:0x%x, lo.len:%d\n", |
5054 | __func__, | 5058 | __func__, |
@@ -5056,12 +5060,18 @@ static int decode_layoutget(struct xdr_stream *xdr, struct rpc_rqst *req, | |||
5056 | (unsigned long)res->range.length, | 5060 | (unsigned long)res->range.length, |
5057 | res->range.iomode, | 5061 | res->range.iomode, |
5058 | res->type, | 5062 | res->type, |
5059 | res->layout.len); | 5063 | res->layoutp->len); |
5064 | |||
5065 | hdrlen = (u8 *) xdr->p - (u8 *) iov->iov_base; | ||
5066 | recvd = req->rq_rcv_buf.len - hdrlen; | ||
5067 | if (res->layoutp->len > recvd) { | ||
5068 | dprintk("NFS: server cheating in layoutget reply: " | ||
5069 | "layout len %u > recvd %u\n", | ||
5070 | res->layoutp->len, recvd); | ||
5071 | return -EINVAL; | ||
5072 | } | ||
5060 | 5073 | ||
5061 | /* nfs4_proc_layoutget allocated a single page */ | 5074 | xdr_read_pages(xdr, res->layoutp->len); |
5062 | if (res->layout.len > PAGE_SIZE) | ||
5063 | return -ENOMEM; | ||
5064 | memcpy(res->layout.buf, p, res->layout.len); | ||
5065 | 5075 | ||
5066 | if (layout_count > 1) { | 5076 | if (layout_count > 1) { |
5067 | /* We only handle a length one array at the moment. Any | 5077 | /* We only handle a length one array at the moment. Any |