aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorTrond Myklebust <Trond.Myklebust@netapp.com>2006-10-09 22:08:22 -0400
committerTrond Myklebust <Trond.Myklebust@netapp.com>2006-12-06 10:46:33 -0500
commitbee57c99c322d64407b80c8171958b4384902da4 (patch)
tree68c35bd43760e691288e03638491536e9f645ff3 /net
parent4e3e43ad14c574281034a27420abf1993694ac11 (diff)
SUNRPC: Ensure xdr_buf_read_netobj() checks for memory overruns
Also clean up the code... Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
Diffstat (limited to 'net')
-rw-r--r--net/sunrpc/xdr.c59
1 files changed, 26 insertions, 33 deletions
diff --git a/net/sunrpc/xdr.c b/net/sunrpc/xdr.c
index ebdff6beba31..5a6485946f3c 100644
--- a/net/sunrpc/xdr.c
+++ b/net/sunrpc/xdr.c
@@ -773,44 +773,37 @@ xdr_encode_word(struct xdr_buf *buf, unsigned int base, u32 obj)
773 * entirely in the head or the tail, set object to point to it; otherwise 773 * entirely in the head or the tail, set object to point to it; otherwise
774 * try to find space for it at the end of the tail, copy it there, and 774 * try to find space for it at the end of the tail, copy it there, and
775 * set obj to point to it. */ 775 * set obj to point to it. */
776int 776int xdr_buf_read_netobj(struct xdr_buf *buf, struct xdr_netobj *obj, unsigned int offset)
777xdr_buf_read_netobj(struct xdr_buf *buf, struct xdr_netobj *obj, unsigned int offset)
778{ 777{
779 unsigned int tail_offset = buf->head[0].iov_len + buf->page_len; 778 struct xdr_buf subbuf;
780 unsigned int obj_end_offset;
781 779
782 if (xdr_decode_word(buf, offset, &obj->len)) 780 if (xdr_decode_word(buf, offset, &obj->len))
783 goto out; 781 return -EFAULT;
784 obj_end_offset = offset + 4 + obj->len; 782 if (xdr_buf_subsegment(buf, &subbuf, offset + 4, obj->len))
785 783 return -EFAULT;
786 if (obj_end_offset <= buf->head[0].iov_len) {
787 /* The obj is contained entirely in the head: */
788 obj->data = buf->head[0].iov_base + offset + 4;
789 } else if (offset + 4 >= tail_offset) {
790 if (obj_end_offset - tail_offset
791 > buf->tail[0].iov_len)
792 goto out;
793 /* The obj is contained entirely in the tail: */
794 obj->data = buf->tail[0].iov_base
795 + offset - tail_offset + 4;
796 } else {
797 /* use end of tail as storage for obj:
798 * (We don't copy to the beginning because then we'd have
799 * to worry about doing a potentially overlapping copy.
800 * This assumes the object is at most half the length of the
801 * tail.) */
802 if (obj->len > buf->tail[0].iov_len)
803 goto out;
804 obj->data = buf->tail[0].iov_base + buf->tail[0].iov_len -
805 obj->len;
806 if (read_bytes_from_xdr_buf(buf, offset + 4,
807 obj->data, obj->len))
808 goto out;
809 784
810 } 785 /* Is the obj contained entirely in the head? */
786 obj->data = subbuf.head[0].iov_base;
787 if (subbuf.head[0].iov_len == obj->len)
788 return 0;
789 /* ..or is the obj contained entirely in the tail? */
790 obj->data = subbuf.tail[0].iov_base;
791 if (subbuf.tail[0].iov_len == obj->len)
792 return 0;
793
794 /* use end of tail as storage for obj:
795 * (We don't copy to the beginning because then we'd have
796 * to worry about doing a potentially overlapping copy.
797 * This assumes the object is at most half the length of the
798 * tail.) */
799 if (obj->len > buf->buflen - buf->len)
800 return -ENOMEM;
801 if (buf->tail[0].iov_len != 0)
802 obj->data = buf->tail[0].iov_base + buf->tail[0].iov_len;
803 else
804 obj->data = buf->head[0].iov_base + buf->head[0].iov_len;
805 __read_bytes_from_xdr_buf(&subbuf, obj->data, obj->len);
811 return 0; 806 return 0;
812out:
813 return -1;
814} 807}
815 808
816/* Returns 0 on success, or else a negative error code. */ 809/* Returns 0 on success, or else a negative error code. */