diff options
author | Trond Myklebust <Trond.Myklebust@netapp.com> | 2006-10-09 22:08:22 -0400 |
---|---|---|
committer | Trond Myklebust <Trond.Myklebust@netapp.com> | 2006-12-06 10:46:33 -0500 |
commit | bee57c99c322d64407b80c8171958b4384902da4 (patch) | |
tree | 68c35bd43760e691288e03638491536e9f645ff3 /net | |
parent | 4e3e43ad14c574281034a27420abf1993694ac11 (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.c | 59 |
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. */ |
776 | int | 776 | int xdr_buf_read_netobj(struct xdr_buf *buf, struct xdr_netobj *obj, unsigned int offset) |
777 | xdr_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; |
812 | out: | ||
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. */ |