aboutsummaryrefslogtreecommitdiffstats
path: root/fs/nfs/nfs4xdr.c
diff options
context:
space:
mode:
authorTrond Myklebust <Trond.Myklebust@netapp.com>2012-06-20 22:35:05 -0400
committerTrond Myklebust <Trond.Myklebust@netapp.com>2012-06-28 17:20:43 -0400
commit64bd577ea0021f5903505de061b3b7d8a785ee94 (patch)
tree7081480d903325bb82d2384b69cff4579f289de1 /fs/nfs/nfs4xdr.c
parentc337d3655ce85e12c7c476cb81406521926cacd2 (diff)
NFS: Let xdr_read_pages() check for buffer overflows
xdr_read_pages will already do all of the buffer overflow checks that are currently being open-coded in the various callers. This patch simplifies the existing code by replacing the open coded checks. Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
Diffstat (limited to 'fs/nfs/nfs4xdr.c')
-rw-r--r--fs/nfs/nfs4xdr.c39
1 files changed, 6 insertions, 33 deletions
diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c
index 18fae29b0301..2754f7268c1f 100644
--- a/fs/nfs/nfs4xdr.c
+++ b/fs/nfs/nfs4xdr.c
@@ -4920,9 +4920,8 @@ static int decode_putrootfh(struct xdr_stream *xdr)
4920 4920
4921static int decode_read(struct xdr_stream *xdr, struct rpc_rqst *req, struct nfs_readres *res) 4921static int decode_read(struct xdr_stream *xdr, struct rpc_rqst *req, struct nfs_readres *res)
4922{ 4922{
4923 struct kvec *iov = req->rq_rcv_buf.head;
4924 __be32 *p; 4923 __be32 *p;
4925 uint32_t count, eof, recvd, hdrlen; 4924 uint32_t count, eof, recvd;
4926 int status; 4925 int status;
4927 4926
4928 status = decode_op_hdr(xdr, OP_READ); 4927 status = decode_op_hdr(xdr, OP_READ);
@@ -4933,15 +4932,13 @@ static int decode_read(struct xdr_stream *xdr, struct rpc_rqst *req, struct nfs_
4933 goto out_overflow; 4932 goto out_overflow;
4934 eof = be32_to_cpup(p++); 4933 eof = be32_to_cpup(p++);
4935 count = be32_to_cpup(p); 4934 count = be32_to_cpup(p);
4936 hdrlen = (u8 *) xdr->p - (u8 *) iov->iov_base; 4935 recvd = xdr_read_pages(xdr, count);
4937 recvd = req->rq_rcv_buf.len - hdrlen;
4938 if (count > recvd) { 4936 if (count > recvd) {
4939 dprintk("NFS: server cheating in read reply: " 4937 dprintk("NFS: server cheating in read reply: "
4940 "count %u > recvd %u\n", count, recvd); 4938 "count %u > recvd %u\n", count, recvd);
4941 count = recvd; 4939 count = recvd;
4942 eof = 0; 4940 eof = 0;
4943 } 4941 }
4944 xdr_read_pages(xdr, count);
4945 res->eof = eof; 4942 res->eof = eof;
4946 res->count = count; 4943 res->count = count;
4947 return 0; 4944 return 0;
@@ -4952,10 +4949,6 @@ out_overflow:
4952 4949
4953static int decode_readdir(struct xdr_stream *xdr, struct rpc_rqst *req, struct nfs4_readdir_res *readdir) 4950static int decode_readdir(struct xdr_stream *xdr, struct rpc_rqst *req, struct nfs4_readdir_res *readdir)
4954{ 4951{
4955 struct xdr_buf *rcvbuf = &req->rq_rcv_buf;
4956 struct kvec *iov = rcvbuf->head;
4957 size_t hdrlen;
4958 u32 recvd, pglen = rcvbuf->page_len;
4959 int status; 4952 int status;
4960 __be32 verf[2]; 4953 __be32 verf[2];
4961 4954
@@ -4967,22 +4960,12 @@ static int decode_readdir(struct xdr_stream *xdr, struct rpc_rqst *req, struct n
4967 memcpy(verf, readdir->verifier.data, sizeof(verf)); 4960 memcpy(verf, readdir->verifier.data, sizeof(verf));
4968 dprintk("%s: verifier = %08x:%08x\n", 4961 dprintk("%s: verifier = %08x:%08x\n",
4969 __func__, verf[0], verf[1]); 4962 __func__, verf[0], verf[1]);
4970 4963 return xdr_read_pages(xdr, xdr->buf->page_len);
4971 hdrlen = (char *) xdr->p - (char *) iov->iov_base;
4972 recvd = rcvbuf->len - hdrlen;
4973 if (pglen > recvd)
4974 pglen = recvd;
4975 xdr_read_pages(xdr, pglen);
4976
4977
4978 return pglen;
4979} 4964}
4980 4965
4981static int decode_readlink(struct xdr_stream *xdr, struct rpc_rqst *req) 4966static int decode_readlink(struct xdr_stream *xdr, struct rpc_rqst *req)
4982{ 4967{
4983 struct xdr_buf *rcvbuf = &req->rq_rcv_buf; 4968 struct xdr_buf *rcvbuf = &req->rq_rcv_buf;
4984 struct kvec *iov = rcvbuf->head;
4985 size_t hdrlen;
4986 u32 len, recvd; 4969 u32 len, recvd;
4987 __be32 *p; 4970 __be32 *p;
4988 int status; 4971 int status;
@@ -5000,14 +4983,12 @@ static int decode_readlink(struct xdr_stream *xdr, struct rpc_rqst *req)
5000 dprintk("nfs: server returned giant symlink!\n"); 4983 dprintk("nfs: server returned giant symlink!\n");
5001 return -ENAMETOOLONG; 4984 return -ENAMETOOLONG;
5002 } 4985 }
5003 hdrlen = (char *) xdr->p - (char *) iov->iov_base; 4986 recvd = xdr_read_pages(xdr, len);
5004 recvd = req->rq_rcv_buf.len - hdrlen;
5005 if (recvd < len) { 4987 if (recvd < len) {
5006 dprintk("NFS: server cheating in readlink reply: " 4988 dprintk("NFS: server cheating in readlink reply: "
5007 "count %u > recvd %u\n", len, recvd); 4989 "count %u > recvd %u\n", len, recvd);
5008 return -EIO; 4990 return -EIO;
5009 } 4991 }
5010 xdr_read_pages(xdr, len);
5011 /* 4992 /*
5012 * The XDR encode routine has set things up so that 4993 * The XDR encode routine has set things up so that
5013 * the link text will be copied directly into the 4994 * the link text will be copied directly into the
@@ -5066,7 +5047,6 @@ static int decode_getacl(struct xdr_stream *xdr, struct rpc_rqst *req,
5066 __be32 *savep, *bm_p; 5047 __be32 *savep, *bm_p;
5067 uint32_t attrlen, 5048 uint32_t attrlen,
5068 bitmap[3] = {0}; 5049 bitmap[3] = {0};
5069 struct kvec *iov = req->rq_rcv_buf.head;
5070 int status; 5050 int status;
5071 size_t page_len = xdr->buf->page_len; 5051 size_t page_len = xdr->buf->page_len;
5072 5052
@@ -5089,7 +5069,6 @@ static int decode_getacl(struct xdr_stream *xdr, struct rpc_rqst *req,
5089 if (unlikely(bitmap[0] & (FATTR4_WORD0_ACL - 1U))) 5069 if (unlikely(bitmap[0] & (FATTR4_WORD0_ACL - 1U)))
5090 return -EIO; 5070 return -EIO;
5091 if (likely(bitmap[0] & FATTR4_WORD0_ACL)) { 5071 if (likely(bitmap[0] & FATTR4_WORD0_ACL)) {
5092 size_t hdrlen;
5093 5072
5094 /* The bitmap (xdr len + bitmaps) and the attr xdr len words 5073 /* The bitmap (xdr len + bitmaps) and the attr xdr len words
5095 * are stored with the acl data to handle the problem of 5074 * are stored with the acl data to handle the problem of
@@ -5098,7 +5077,6 @@ static int decode_getacl(struct xdr_stream *xdr, struct rpc_rqst *req,
5098 5077
5099 /* We ignore &savep and don't do consistency checks on 5078 /* We ignore &savep and don't do consistency checks on
5100 * the attr length. Let userspace figure it out.... */ 5079 * the attr length. Let userspace figure it out.... */
5101 hdrlen = (u8 *)xdr->p - (u8 *)iov->iov_base;
5102 attrlen += res->acl_data_offset; 5080 attrlen += res->acl_data_offset;
5103 if (attrlen > page_len) { 5081 if (attrlen > page_len) {
5104 if (res->acl_flags & NFS4_ACL_LEN_REQUEST) { 5082 if (res->acl_flags & NFS4_ACL_LEN_REQUEST) {
@@ -5707,9 +5685,7 @@ static int decode_layoutget(struct xdr_stream *xdr, struct rpc_rqst *req,
5707 __be32 *p; 5685 __be32 *p;
5708 int status; 5686 int status;
5709 u32 layout_count; 5687 u32 layout_count;
5710 struct xdr_buf *rcvbuf = &req->rq_rcv_buf; 5688 u32 recvd;
5711 struct kvec *iov = rcvbuf->head;
5712 u32 hdrlen, recvd;
5713 5689
5714 status = decode_op_hdr(xdr, OP_LAYOUTGET); 5690 status = decode_op_hdr(xdr, OP_LAYOUTGET);
5715 if (status) 5691 if (status)
@@ -5746,8 +5722,7 @@ static int decode_layoutget(struct xdr_stream *xdr, struct rpc_rqst *req,
5746 res->type, 5722 res->type,
5747 res->layoutp->len); 5723 res->layoutp->len);
5748 5724
5749 hdrlen = (u8 *) xdr->p - (u8 *) iov->iov_base; 5725 recvd = xdr_read_pages(xdr, res->layoutp->len);
5750 recvd = req->rq_rcv_buf.len - hdrlen;
5751 if (res->layoutp->len > recvd) { 5726 if (res->layoutp->len > recvd) {
5752 dprintk("NFS: server cheating in layoutget reply: " 5727 dprintk("NFS: server cheating in layoutget reply: "
5753 "layout len %u > recvd %u\n", 5728 "layout len %u > recvd %u\n",
@@ -5755,8 +5730,6 @@ static int decode_layoutget(struct xdr_stream *xdr, struct rpc_rqst *req,
5755 return -EINVAL; 5730 return -EINVAL;
5756 } 5731 }
5757 5732
5758 xdr_read_pages(xdr, res->layoutp->len);
5759
5760 if (layout_count > 1) { 5733 if (layout_count > 1) {
5761 /* We only handle a length one array at the moment. Any 5734 /* We only handle a length one array at the moment. Any
5762 * further entries are just ignored. Note that this means 5735 * further entries are just ignored. Note that this means