Fix CVE-2014-6272 in Libevent 1.4

For this fix, we need to make sure that passing too-large inputs to
the evbuffer functions can't make us do bad things with the heap.
This commit is contained in:
Nick Mathewson 2014-01-05 08:30:46 -05:00
parent 53c47c2eb9
commit 7b21c4eabf

View File

@ -144,7 +144,8 @@ evbuffer_add_vprintf(struct evbuffer *buf, const char *fmt, va_list ap)
va_list aq; va_list aq;
/* make sure that at least some space is available */ /* make sure that at least some space is available */
evbuffer_expand(buf, 64); if (evbuffer_expand(buf, 64) < 0)
return (-1);
for (;;) { for (;;) {
size_t used = buf->misalign + buf->off; size_t used = buf->misalign + buf->off;
buffer = (char *)buf->buffer + buf->off; buffer = (char *)buf->buffer + buf->off;
@ -345,31 +346,48 @@ evbuffer_align(struct evbuffer *buf)
buf->misalign = 0; buf->misalign = 0;
} }
#ifndef SIZE_MAX
#define SIZE_MAX ((size_t)-1)
#endif
/* Expands the available space in the event buffer to at least datlen */ /* Expands the available space in the event buffer to at least datlen */
int int
evbuffer_expand(struct evbuffer *buf, size_t datlen) evbuffer_expand(struct evbuffer *buf, size_t datlen)
{ {
size_t need = buf->misalign + buf->off + datlen; size_t used = buf->misalign + buf->off;
size_t need;
assert(buf->totallen >= used);
/* If we can fit all the data, then we don't have to do anything */ /* If we can fit all the data, then we don't have to do anything */
if (buf->totallen >= need) if (buf->totallen - used >= datlen)
return (0); return (0);
/* If we would need to overflow to fit this much data, we can't
* do anything. */
if (datlen > SIZE_MAX - buf->off)
return (-1);
/* /*
* If the misalignment fulfills our data needs, we just force an * If the misalignment fulfills our data needs, we just force an
* alignment to happen. Afterwards, we have enough space. * alignment to happen. Afterwards, we have enough space.
*/ */
if (buf->misalign >= datlen) { if (buf->totallen - buf->off >= datlen) {
evbuffer_align(buf); evbuffer_align(buf);
} else { } else {
void *newbuf; void *newbuf;
size_t length = buf->totallen; size_t length = buf->totallen;
size_t need = buf->off + datlen;
if (length < 256) if (length < 256)
length = 256; length = 256;
while (length < need) if (need < SIZE_MAX / 2) {
length <<= 1; while (length < need) {
length <<= 1;
}
} else {
length = need;
}
if (buf->orig_buffer != buf->buffer) if (buf->orig_buffer != buf->buffer)
evbuffer_align(buf); evbuffer_align(buf);
@ -386,10 +404,10 @@ evbuffer_expand(struct evbuffer *buf, size_t datlen)
int int
evbuffer_add(struct evbuffer *buf, const void *data, size_t datlen) evbuffer_add(struct evbuffer *buf, const void *data, size_t datlen)
{ {
size_t need = buf->misalign + buf->off + datlen; size_t used = buf->misalign + buf->off;
size_t oldoff = buf->off; size_t oldoff = buf->off;
if (buf->totallen < need) { if (buf->totallen - used < datlen) {
if (evbuffer_expand(buf, datlen) == -1) if (evbuffer_expand(buf, datlen) == -1)
return (-1); return (-1);
} }