summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorstbuehler <stbuehler@152afb58-edef-0310-8abb-c4023f1b3aa9>2010-02-01 23:29:15 +0000
committerstbuehler <stbuehler@152afb58-edef-0310-8abb-c4023f1b3aa9>2010-02-01 23:29:15 +0000
commitb83fe93bf42455eebdebfda25a5d288274e4f568 (patch)
tree09603378f2c827af454e16f333608192a0410565
parentb3903f6cf870a49edb4acfcda36b369cada02d2a (diff)
downloadlighttpd-b83fe93bf42455eebdebfda25a5d288274e4f568.tar.gz
Append to previous buffer in con read (fixes #2147, found by liming, CVE-2010-0295)
git-svn-id: svn://svn.lighttpd.net/lighttpd/trunk@2711 152afb58-edef-0310-8abb-c4023f1b3aa9
-rw-r--r--NEWS1
-rw-r--r--src/connections.c10
-rw-r--r--src/network_openssl.c27
-rw-r--r--src/network_win32_send.c26
-rw-r--r--src/network_write.c22
5 files changed, 62 insertions, 24 deletions
diff --git a/NEWS b/NEWS
index f2385b99..ccbde4ea 100644
--- a/NEWS
+++ b/NEWS
@@ -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;