SUNRPC: Ensure xdr_buf_read_netobj() checks for memory overruns

Also clean up the code...

Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
This commit is contained in:
Trond Myklebust 2006-10-09 22:08:22 -04:00
parent 4e3e43ad14
commit bee57c99c3
1 changed files with 25 additions and 32 deletions

View File

@ -773,44 +773,37 @@ xdr_encode_word(struct xdr_buf *buf, unsigned int base, u32 obj)
* entirely in the head or the tail, set object to point to it; otherwise
* try to find space for it at the end of the tail, copy it there, and
* set obj to point to it. */
int
xdr_buf_read_netobj(struct xdr_buf *buf, struct xdr_netobj *obj, unsigned int offset)
int xdr_buf_read_netobj(struct xdr_buf *buf, struct xdr_netobj *obj, unsigned int offset)
{
unsigned int tail_offset = buf->head[0].iov_len + buf->page_len;
unsigned int obj_end_offset;
struct xdr_buf subbuf;
if (xdr_decode_word(buf, offset, &obj->len))
goto out;
obj_end_offset = offset + 4 + obj->len;
return -EFAULT;
if (xdr_buf_subsegment(buf, &subbuf, offset + 4, obj->len))
return -EFAULT;
if (obj_end_offset <= buf->head[0].iov_len) {
/* The obj is contained entirely in the head: */
obj->data = buf->head[0].iov_base + offset + 4;
} else if (offset + 4 >= tail_offset) {
if (obj_end_offset - tail_offset
> buf->tail[0].iov_len)
goto out;
/* The obj is contained entirely in the tail: */
obj->data = buf->tail[0].iov_base
+ offset - tail_offset + 4;
} else {
/* use end of tail as storage for obj:
* (We don't copy to the beginning because then we'd have
* to worry about doing a potentially overlapping copy.
* This assumes the object is at most half the length of the
* tail.) */
if (obj->len > buf->tail[0].iov_len)
goto out;
obj->data = buf->tail[0].iov_base + buf->tail[0].iov_len -
obj->len;
if (read_bytes_from_xdr_buf(buf, offset + 4,
obj->data, obj->len))
goto out;
/* Is the obj contained entirely in the head? */
obj->data = subbuf.head[0].iov_base;
if (subbuf.head[0].iov_len == obj->len)
return 0;
/* ..or is the obj contained entirely in the tail? */
obj->data = subbuf.tail[0].iov_base;
if (subbuf.tail[0].iov_len == obj->len)
return 0;
}
/* use end of tail as storage for obj:
* (We don't copy to the beginning because then we'd have
* to worry about doing a potentially overlapping copy.
* This assumes the object is at most half the length of the
* tail.) */
if (obj->len > buf->buflen - buf->len)
return -ENOMEM;
if (buf->tail[0].iov_len != 0)
obj->data = buf->tail[0].iov_base + buf->tail[0].iov_len;
else
obj->data = buf->head[0].iov_base + buf->head[0].iov_len;
__read_bytes_from_xdr_buf(&subbuf, obj->data, obj->len);
return 0;
out:
return -1;
}
/* Returns 0 on success, or else a negative error code. */