diff options
-rw-r--r-- | NEWS | 1 | ||||
-rw-r--r-- | src/connections.c | 10 | ||||
-rw-r--r-- | src/network_openssl.c | 27 | ||||
-rw-r--r-- | src/network_win32_send.c | 26 | ||||
-rw-r--r-- | src/network_write.c | 22 |
5 files changed, 62 insertions, 24 deletions
@@ -159,6 +159,7 @@ NEWS * mod_accesslog: support %e (fixes #2113, thx presbrey) * Require at least glib 2.10.0 for g_atomic_int_set (fixes #2127) * Fix select() backend under high load (off-by-one, noticed by Manuel Scharf in a forum thread) + * Append to previous buffer in con read (fixes #2147, found by liming, CVE-2010-0295) - 1.5.0-r19.. - * -F option added for spawn-fcgi diff --git a/src/connections.c b/src/connections.c index 3f1db107..1069adab 100644 --- a/src/connections.c +++ b/src/connections.c @@ -802,8 +802,14 @@ static handler_t connection_handle_read_request_content(server *srv, connection } else { buffer *b; - b = chunkqueue_get_append_buffer(out); - buffer_copy_string_len(b, c->mem->ptr + c->offset, toRead); + b = (out->last) ? out->last->mem : NULL; + + if (NULL == b) { + b = chunkqueue_get_append_buffer(out); + buffer_prepare_copy(b, con->request.content_length - out->bytes_in + 1); + } + + buffer_append_string_len(b, c->mem->ptr + c->offset, toRead); } c->offset += toRead; diff --git a/src/network_openssl.c b/src/network_openssl.c index 0586d146..7ffc8c47 100644 --- a/src/network_openssl.c +++ b/src/network_openssl.c @@ -37,16 +37,29 @@ NETWORK_BACKEND_READ(openssl) { off_t max_read = 256 * 1024; off_t start_bytes_in = cq->bytes_in; network_status_t res; + int toread, read_offset; UNUSED(srv); UNUSED(con); + /* use a chunk-size of 4k, append to last buffer if it has >= 1kb free */ +#define TOREAD 4096 + do { int oerrno; - b = chunkqueue_get_append_buffer(cq); - buffer_prepare_copy(b, 8192 + 12); /* ssl-chunk-size is 8kb */ + + b = (cq->last) ? cq->last->mem : NULL; + + if (NULL == b || b->size - b->used < 1024) { + b = chunkqueue_get_append_buffer(cq); + buffer_prepare_copy(b, TOREAD+1); + } + + read_offset = (b->used == 0) ? 0 : b->used - 1; + toread = b->size - 1 - read_offset; + ERR_clear_error(); - len = SSL_read(sock->ssl, b->ptr, b->size - 1); + len = SSL_read(sock->ssl, b->ptr + read_offset, toread); /** * man SSL_read: @@ -63,6 +76,7 @@ NETWORK_BACKEND_READ(openssl) { switch ((r = SSL_get_error(sock->ssl, len))) { case SSL_ERROR_WANT_READ: + case SSL_ERROR_WANT_WRITE: return read_something ? NETWORK_STATUS_SUCCESS : NETWORK_STATUS_WAIT_FOR_EVENT; case SSL_ERROR_SYSCALL: /** @@ -123,6 +137,7 @@ NETWORK_BACKEND_READ(openssl) { return res; } } else { + if (b->used > 0) b->used--; b->used += len; b->ptr[b->used++] = '\0'; @@ -130,10 +145,10 @@ NETWORK_BACKEND_READ(openssl) { cq->bytes_in += len; } - if (cq->bytes_in - start_bytes_in > max_read) return NETWORK_STATUS_SUCCESS; - } while (1); + if (cq->bytes_in - start_bytes_in > max_read) break; + } while (len == toread); - return NETWORK_STATUS_FATAL_ERROR; + return NETWORK_STATUS_SUCCESS; } diff --git a/src/network_win32_send.c b/src/network_win32_send.c index b6d59303..0ee3f4aa 100644 --- a/src/network_win32_send.c +++ b/src/network_win32_send.c @@ -30,7 +30,7 @@ */ NETWORK_BACKEND_READ(win32recv) { - int toread; + int toread, read_offset; buffer *b; off_t r, start_bytes_in; off_t max_read = 256 * 1024; @@ -45,15 +45,21 @@ NETWORK_BACKEND_READ(win32recv) start_bytes_in = cq->bytes_in; - /* use a chunk-size of 16k */ + /* use a chunk-size of 4k, append to last buffer if it has >= 1kb free */ +#define TOREAD 4096 + do { - toread = 16384; + b = (cq->last) ? cq->last->mem : NULL; - b = chunkqueue_get_append_buffer(cq); + if (NULL == b || b->size - b->used < 1024) { + b = chunkqueue_get_append_buffer(cq); + buffer_prepare_copy(b, TOREAD+1); + } - buffer_prepare_copy(b, toread); + read_offset = (b->used == 0) ? 0 : b->used - 1; + toread = b->size - 1 - read_offset; - if (-1 == (r = recv(sock->fd, b->ptr, toread, 0))) { + if (-1 == (r = recv(sock->fd, b->ptr + read_offset, toread, 0))) { switch (light_sock_errno()) { case EAGAIN: case EWOULDBLOCK: @@ -76,17 +82,19 @@ NETWORK_BACKEND_READ(win32recv) read_something = 1; - b->used = r; + if (b->used > 0) b->used--; + b->used += r; b->ptr[b->used++] = '\0'; + cq->bytes_in += r; if (cq->bytes_in - start_bytes_in > max_read) break; - } while (r == toread); + } while (r == toread); return NETWORK_STATUS_SUCCESS; } -NETWORK_BACKEND_WRITE(win32send) +NETWORK_BACKEND_WRITE(win32send) { chunk *c; size_t chunks_written = 0; diff --git a/src/network_write.c b/src/network_write.c index 58de7209..5de91927 100644 --- a/src/network_write.c +++ b/src/network_write.c @@ -35,7 +35,7 @@ * as vectors */ NETWORK_BACKEND_READ(read) { - int toread; + int toread, read_offset; buffer *b; off_t r, start_bytes_in; off_t max_read = 256 * 1024; @@ -50,15 +50,21 @@ NETWORK_BACKEND_READ(read) { start_bytes_in = cq->bytes_in; - /* use a chunk-size of 16k */ + /* use a chunk-size of 4k, append to last buffer if it has >= 1kb free */ +#define TOREAD 4096 + do { - toread = 16384; + b = (cq->last) ? cq->last->mem : NULL; - b = chunkqueue_get_append_buffer(cq); + if (NULL == b || b->size - b->used < 1024) { + b = chunkqueue_get_append_buffer(cq); + buffer_prepare_copy(b, TOREAD+1); + } - buffer_prepare_copy(b, toread); + read_offset = (b->used == 0) ? 0 : b->used - 1; + toread = b->size - 1 - read_offset; - if (-1 == (r = read(sock->fd, b->ptr, toread))) { + if (-1 == (r = read(sock->fd, b->ptr + read_offset, toread))) { switch (errno) { case EAGAIN: /* remove the last chunk from the chunkqueue */ @@ -80,8 +86,10 @@ NETWORK_BACKEND_READ(read) { read_something = 1; - b->used = r; + if (b->used > 0) b->used--; + b->used += r; b->ptr[b->used++] = '\0'; + cq->bytes_in += r; if (cq->bytes_in - start_bytes_in > max_read) break; |