aboutsummaryrefslogtreecommitdiffstats
path: root/fs/nfs
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
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')
-rw-r--r--fs/nfs/nfs2xdr.c22
-rw-r--r--fs/nfs/nfs3xdr.c23
-rw-r--r--fs/nfs/nfs4xdr.c39
3 files changed, 12 insertions, 72 deletions
diff --git a/fs/nfs/nfs2xdr.c b/fs/nfs/nfs2xdr.c
index db81166182c9..d04f0df7be55 100644
--- a/fs/nfs/nfs2xdr.c
+++ b/fs/nfs/nfs2xdr.c
@@ -106,19 +106,16 @@ static void print_overflow_msg(const char *func, const struct xdr_stream *xdr)
106static int decode_nfsdata(struct xdr_stream *xdr, struct nfs_readres *result) 106static int decode_nfsdata(struct xdr_stream *xdr, struct nfs_readres *result)
107{ 107{
108 u32 recvd, count; 108 u32 recvd, count;
109 size_t hdrlen;
110 __be32 *p; 109 __be32 *p;
111 110
112 p = xdr_inline_decode(xdr, 4); 111 p = xdr_inline_decode(xdr, 4);
113 if (unlikely(p == NULL)) 112 if (unlikely(p == NULL))
114 goto out_overflow; 113 goto out_overflow;
115 count = be32_to_cpup(p); 114 count = be32_to_cpup(p);
116 hdrlen = (u8 *)xdr->p - (u8 *)xdr->iov->iov_base; 115 recvd = xdr_read_pages(xdr, count);
117 recvd = xdr->buf->len - hdrlen;
118 if (unlikely(count > recvd)) 116 if (unlikely(count > recvd))
119 goto out_cheating; 117 goto out_cheating;
120out: 118out:
121 xdr_read_pages(xdr, count);
122 result->eof = 0; /* NFSv2 does not pass EOF flag on the wire. */ 119 result->eof = 0; /* NFSv2 does not pass EOF flag on the wire. */
123 result->count = count; 120 result->count = count;
124 return count; 121 return count;
@@ -440,7 +437,6 @@ static void encode_path(struct xdr_stream *xdr, struct page **pages, u32 length)
440static int decode_path(struct xdr_stream *xdr) 437static int decode_path(struct xdr_stream *xdr)
441{ 438{
442 u32 length, recvd; 439 u32 length, recvd;
443 size_t hdrlen;
444 __be32 *p; 440 __be32 *p;
445 441
446 p = xdr_inline_decode(xdr, 4); 442 p = xdr_inline_decode(xdr, 4);
@@ -449,12 +445,9 @@ static int decode_path(struct xdr_stream *xdr)
449 length = be32_to_cpup(p); 445 length = be32_to_cpup(p);
450 if (unlikely(length >= xdr->buf->page_len || length > NFS_MAXPATHLEN)) 446 if (unlikely(length >= xdr->buf->page_len || length > NFS_MAXPATHLEN))
451 goto out_size; 447 goto out_size;
452 hdrlen = (u8 *)xdr->p - (u8 *)xdr->iov->iov_base; 448 recvd = xdr_read_pages(xdr, length);
453 recvd = xdr->buf->len - hdrlen;
454 if (unlikely(length > recvd)) 449 if (unlikely(length > recvd))
455 goto out_cheating; 450 goto out_cheating;
456
457 xdr_read_pages(xdr, length);
458 xdr_terminate_string(xdr->buf, length); 451 xdr_terminate_string(xdr->buf, length);
459 return 0; 452 return 0;
460out_size: 453out_size:
@@ -972,16 +965,7 @@ out_overflow:
972 */ 965 */
973static int decode_readdirok(struct xdr_stream *xdr) 966static int decode_readdirok(struct xdr_stream *xdr)
974{ 967{
975 u32 recvd, pglen; 968 return xdr_read_pages(xdr, xdr->buf->page_len);
976 size_t hdrlen;
977
978 pglen = xdr->buf->page_len;
979 hdrlen = (u8 *)xdr->p - (u8 *)xdr->iov->iov_base;
980 recvd = xdr->buf->len - hdrlen;
981 if (pglen > recvd)
982 pglen = recvd;
983 xdr_read_pages(xdr, pglen);
984 return pglen;
985} 969}
986 970
987static int nfs2_xdr_dec_readdirres(struct rpc_rqst *req, 971static int nfs2_xdr_dec_readdirres(struct rpc_rqst *req,
diff --git a/fs/nfs/nfs3xdr.c b/fs/nfs/nfs3xdr.c
index 3c61c7f80a4b..d64a00ff5a16 100644
--- a/fs/nfs/nfs3xdr.c
+++ b/fs/nfs/nfs3xdr.c
@@ -246,7 +246,6 @@ static void encode_nfspath3(struct xdr_stream *xdr, struct page **pages,
246static int decode_nfspath3(struct xdr_stream *xdr) 246static int decode_nfspath3(struct xdr_stream *xdr)
247{ 247{
248 u32 recvd, count; 248 u32 recvd, count;
249 size_t hdrlen;
250 __be32 *p; 249 __be32 *p;
251 250
252 p = xdr_inline_decode(xdr, 4); 251 p = xdr_inline_decode(xdr, 4);
@@ -255,12 +254,9 @@ static int decode_nfspath3(struct xdr_stream *xdr)
255 count = be32_to_cpup(p); 254 count = be32_to_cpup(p);
256 if (unlikely(count >= xdr->buf->page_len || count > NFS3_MAXPATHLEN)) 255 if (unlikely(count >= xdr->buf->page_len || count > NFS3_MAXPATHLEN))
257 goto out_nametoolong; 256 goto out_nametoolong;
258 hdrlen = (u8 *)xdr->p - (u8 *)xdr->iov->iov_base; 257 recvd = xdr_read_pages(xdr, count);
259 recvd = xdr->buf->len - hdrlen;
260 if (unlikely(count > recvd)) 258 if (unlikely(count > recvd))
261 goto out_cheating; 259 goto out_cheating;
262
263 xdr_read_pages(xdr, count);
264 xdr_terminate_string(xdr->buf, count); 260 xdr_terminate_string(xdr->buf, count);
265 return 0; 261 return 0;
266 262
@@ -1587,7 +1583,6 @@ static int decode_read3resok(struct xdr_stream *xdr,
1587 struct nfs_readres *result) 1583 struct nfs_readres *result)
1588{ 1584{
1589 u32 eof, count, ocount, recvd; 1585 u32 eof, count, ocount, recvd;
1590 size_t hdrlen;
1591 __be32 *p; 1586 __be32 *p;
1592 1587
1593 p = xdr_inline_decode(xdr, 4 + 4 + 4); 1588 p = xdr_inline_decode(xdr, 4 + 4 + 4);
@@ -1598,13 +1593,10 @@ static int decode_read3resok(struct xdr_stream *xdr,
1598 ocount = be32_to_cpup(p++); 1593 ocount = be32_to_cpup(p++);
1599 if (unlikely(ocount != count)) 1594 if (unlikely(ocount != count))
1600 goto out_mismatch; 1595 goto out_mismatch;
1601 hdrlen = (u8 *)xdr->p - (u8 *)xdr->iov->iov_base; 1596 recvd = xdr_read_pages(xdr, count);
1602 recvd = xdr->buf->len - hdrlen;
1603 if (unlikely(count > recvd)) 1597 if (unlikely(count > recvd))
1604 goto out_cheating; 1598 goto out_cheating;
1605
1606out: 1599out:
1607 xdr_read_pages(xdr, count);
1608 result->eof = eof; 1600 result->eof = eof;
1609 result->count = count; 1601 result->count = count;
1610 return count; 1602 return count;
@@ -2039,16 +2031,7 @@ out_truncated:
2039 */ 2031 */
2040static int decode_dirlist3(struct xdr_stream *xdr) 2032static int decode_dirlist3(struct xdr_stream *xdr)
2041{ 2033{
2042 u32 recvd, pglen; 2034 return xdr_read_pages(xdr, xdr->buf->page_len);
2043 size_t hdrlen;
2044
2045 pglen = xdr->buf->page_len;
2046 hdrlen = (u8 *)xdr->p - (u8 *)xdr->iov->iov_base;
2047 recvd = xdr->buf->len - hdrlen;
2048 if (pglen > recvd)
2049 pglen = recvd;
2050 xdr_read_pages(xdr, pglen);
2051 return pglen;
2052} 2035}
2053 2036
2054static int decode_readdir3resok(struct xdr_stream *xdr, 2037static int decode_readdir3resok(struct xdr_stream *xdr,
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