File libevent-CVE-2014-6272.patch of Package libevent
diff --git a/buffer.c b/buffer.c
index fab7d80..eb41fe4 100644
--- a/buffer.c
+++ b/buffer.c
@@ -157,12 +157,20 @@ evbuffer_chain_new(size_t size)
struct evbuffer_chain *chain;
size_t to_alloc;
+ if (size > SIZE_MAX - EVBUFFER_CHAIN_SIZE)
+ return (NULL);
+
size += EVBUFFER_CHAIN_SIZE;
/* get the next largest memory that can hold the buffer */
- to_alloc = MIN_BUFFER_SIZE;
- while (to_alloc < size)
- to_alloc <<= 1;
+ if (size < SIZE_MAX / 2) {
+ to_alloc = MIN_BUFFER_SIZE;
+ while (to_alloc < size) {
+ to_alloc <<= 1;
+ }
+ } else {
+ to_alloc = size;
+ }
/* we get everything in one chunk */
if ((chain = mm_malloc(to_alloc)) == NULL)
@@ -1002,6 +1010,7 @@ evbuffer_drain(struct evbuffer *buf, size_t len)
buf->first = chain;
if (chain) {
+ EVUTIL_ASSERT(remaining <= chain->off);
chain->misalign += remaining;
chain->off -= remaining;
}
@@ -1068,6 +1077,7 @@ evbuffer_copyout(struct evbuffer *buf, void *data_out, size_t datlen)
if (datlen) {
EVUTIL_ASSERT(chain);
+ EVUTIL_ASSERT(datlen <= chain->off);
memcpy(data, chain->buffer + chain->misalign, datlen);
}
@@ -1543,6 +1553,9 @@ evbuffer_add(struct evbuffer *buf, const void *data_in, size_t datlen)
if (buf->freeze_end) {
goto done;
}
+ if (datlen > EV_SIZE_MAX - buf->total_len) {
+ goto done;
+ }
chain = buf->last;
@@ -1556,7 +1569,10 @@ evbuffer_add(struct evbuffer *buf, const void *data_in, size_t datlen)
}
if ((chain->flags & EVBUFFER_IMMUTABLE) == 0) {
- remain = (size_t)(chain->buffer_len - chain->misalign - chain->off);
+ /* Always true for mutable buffers */
+ EVUTIL_ASSERT(chain->misalign >= 0 &&
+ (ev_uint64_t)chain->misalign <= EV_SIZE_MAX);
+ remain = chain->buffer_len - (size_t)chain->misalign - chain->off;
if (remain >= datlen) {
/* there's enough space to hold all the data in the
* current last chain */
@@ -1627,6 +1643,9 @@ evbuffer_prepend(struct evbuffer *buf, const void *data, size_t datlen)
if (buf->freeze_start) {
goto done;
}
+ if (datlen > EV_SIZE_MAX - buf->total_len) {
+ goto done;
+ }
chain = buf->first;
@@ -1639,6 +1658,10 @@ evbuffer_prepend(struct evbuffer *buf, const void *data, size_t datlen)
/* we cannot touch immutable buffers */
if ((chain->flags & EVBUFFER_IMMUTABLE) == 0) {
+ /* Always true for mutable buffers */
+ EVUTIL_ASSERT(chain->misalign >= 0 &&
+ (ev_uint64_t)chain->misalign <= EV_SIZE_MAX);
+
/* If this chain is empty, we can treat it as
* 'empty at the beginning' rather than 'empty at the end' */
if (chain->off == 0)
@@ -1676,6 +1699,7 @@ evbuffer_prepend(struct evbuffer *buf, const void *data, size_t datlen)
tmp->next = chain;
tmp->off = datlen;
+ EVUTIL_ASSERT(datlen <= tmp->buffer_len);
tmp->misalign = tmp->buffer_len - datlen;
memcpy(tmp->buffer + tmp->misalign, data, datlen);
@@ -1774,7 +1798,8 @@ evbuffer_expand_singlechain(struct evbuffer *buf, size_t datlen)
/* Would expanding this chunk be affordable and worthwhile? */
if (CHAIN_SPACE_LEN(chain) < chain->buffer_len / 8 ||
- chain->off > MAX_TO_COPY_IN_EXPAND) {
+ chain->off > MAX_TO_COPY_IN_EXPAND ||
+ EV_SIZE_MAX - datlen >= chain->off) {
/* It's not worth resizing this chain. Can the next one be
* used? */
if (chain->next && CHAIN_SPACE_LEN(chain->next) >= datlen) {
@@ -1902,6 +1927,8 @@ _evbuffer_expand_fast(struct evbuffer *buf, size_t datlen, int n)
rmv_all = 1;
avail = 0;
} else {
+ /* can't overflow, since only mutable chains have
+ * huge misaligns. */
avail = (size_t) CHAIN_SPACE_LEN(chain);
chain = chain->next;
}
@@ -1912,6 +1939,7 @@ _evbuffer_expand_fast(struct evbuffer *buf, size_t datlen, int n)
EVUTIL_ASSERT(chain->off == 0);
evbuffer_chain_free(chain);
}
+ EVUTIL_ASSERT(datlen >= avail);
tmp = evbuffer_chain_new(datlen - avail);
if (tmp == NULL) {
if (rmv_all) {
@@ -2041,6 +2069,7 @@ get_n_bytes_readable_on_socket(evutil_socket_t fd)
unsigned long lng = EVBUFFER_MAX_READ;
if (ioctlsocket(fd, FIONREAD, &lng) < 0)
return -1;
+ /* Can overflow, but mostly harmlessly. XXXX */
return (int)lng;
#elif defined(FIONREAD)
int n = EVBUFFER_MAX_READ;
@@ -2153,8 +2182,14 @@ evbuffer_read(struct evbuffer *buf, evutil_socket_t fd, int howmuch)
#ifdef USE_IOVEC_IMPL
remaining = n;
for (i=0; i < nvecs; ++i) {
- ev_ssize_t space = (ev_ssize_t) CHAIN_SPACE_LEN(*chainp);
- if (space < remaining) {
+ /* can't overflow, since only mutable chains have
+ * huge misaligns. */
+ size_t space = (size_t) CHAIN_SPACE_LEN(*chainp);
+ /* XXXX This is a kludge that can waste space in perverse
+ * situations. */
+ if (space > EV_SSIZE_MAX)
+ space = EV_SSIZE_MAX;
+ if ((ev_ssize_t)space < remaining) {
(*chainp)->off += space;
remaining -= (int)space;
} else {
@@ -2427,12 +2462,17 @@ evbuffer_ptr_set(struct evbuffer *buf, struct evbuffer_ptr *pos,
case EVBUFFER_PTR_ADD:
/* this avoids iterating over all previous chains if
we just want to advance the position */
+ if (pos->pos < 0 || EV_SIZE_MAX - position < (size_t)pos->pos) {
+ EVBUFFER_UNLOCK(buf);
+ return -1;
+ }
chain = pos->_internal.chain;
pos->pos += position;
position = pos->_internal.pos_in_chain;
break;
}
+ EVUTIL_ASSERT(EV_SIZE_MAX - left >= position);
while (chain && position + left >= chain->off) {
left -= chain->off - position;
chain = chain->next;
@@ -2465,7 +2505,9 @@ evbuffer_ptr_memcmp(const struct evbuffer *buf, const struct evbuffer_ptr *pos,
ASSERT_EVBUFFER_LOCKED(buf);
- if (pos->pos + len > buf->total_len)
+ if (pos->pos < 0 ||
+ EV_SIZE_MAX - len < (size_t)pos->pos ||
+ pos->pos + len > buf->total_len)
return -1;
chain = pos->_internal.chain;
@@ -2651,7 +2693,8 @@ evbuffer_add_vprintf(struct evbuffer *buf, const char *fmt, va_list ap)
va_end(aq);
- if (sz < 0)
+ if (sz < 0 ||
+ (size_t)sz == EV_SIZE_MAX)
goto done;
if ((size_t)sz < space) {
chain->off += sz;
@@ -2746,6 +2789,10 @@ evbuffer_add_file(struct evbuffer *outbuf, int fd,
#endif
int ok = 1;
+ if (offset < 0 ||
+ (ev_uint64_t)offset > EV_SIZE_MAX - length)
+ return (-1);
+
#if defined(USE_SENDFILE)
if (use_sendfile) {
EVBUFFER_LOCK(outbuf);
@@ -2851,7 +2898,8 @@ evbuffer_add_file(struct evbuffer *outbuf, int fd,
* can abort without side effects if the read fails.
*/
while (length) {
- read = evbuffer_readfile(tmp, fd, (ev_ssize_t)length);
+ ev_ssize_t to_read = length > EV_SSIZE_MAX ? EV_SSIZE_MAX : (ev_ssize_t)length;
+ read = evbuffer_readfile(tmp, fd, to_read);
if (read == -1) {
evbuffer_free(tmp);
return (-1);