From 7b21c4eabf1f3946d3f63cce1319c490caab8ecf Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Sun, 5 Jan 2014 08:30:46 -0500 Subject: [PATCH] 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. --- buffer.c | 34 ++++++++++++++++++++++++++-------- 1 file changed, 26 insertions(+), 8 deletions(-) diff --git a/buffer.c b/buffer.c index 09d2160d..64324bbd 100644 --- a/buffer.c +++ b/buffer.c @@ -144,7 +144,8 @@ evbuffer_add_vprintf(struct evbuffer *buf, const char *fmt, va_list ap) va_list aq; /* make sure that at least some space is available */ - evbuffer_expand(buf, 64); + if (evbuffer_expand(buf, 64) < 0) + return (-1); for (;;) { size_t used = buf->misalign + buf->off; buffer = (char *)buf->buffer + buf->off; @@ -345,31 +346,48 @@ evbuffer_align(struct evbuffer *buf) 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 */ int 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 (buf->totallen >= need) + if (buf->totallen - used >= datlen) 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 * alignment to happen. Afterwards, we have enough space. */ - if (buf->misalign >= datlen) { + if (buf->totallen - buf->off >= datlen) { evbuffer_align(buf); } else { void *newbuf; size_t length = buf->totallen; + size_t need = buf->off + datlen; if (length < 256) length = 256; - while (length < need) - length <<= 1; + if (need < SIZE_MAX / 2) { + while (length < need) { + length <<= 1; + } + } else { + length = need; + } if (buf->orig_buffer != buf->buffer) evbuffer_align(buf); @@ -386,10 +404,10 @@ evbuffer_expand(struct evbuffer *buf, size_t datlen) int 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; - if (buf->totallen < need) { + if (buf->totallen - used < datlen) { if (evbuffer_expand(buf, datlen) == -1) return (-1); }