Sign Up
Log In
Log In
or
Sign Up
Places
All Projects
Status Monitor
Collapse sidebar
DISCONTINUED:openSUSE:11.1:Update
lighttpd
fix-slow-request-dos-in-1.4.x.patch
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
File fix-slow-request-dos-in-1.4.x.patch of Package lighttpd
Subject: [PATCH] Append to previous buffer in con read (fixes #2147, found by liming) * Remove ssl_error_want_reuse_buffer for SSL_read: Although the manual states we have to use the same arguments in the next call after SSL_ERROR_WANT_*, it has been running without this in 1.5 for a long time now. * As POST-data chunks get copied to the next queue, we reuse chunks there as well. --- src/base.h | 1 - src/chunk.c | 2 - src/connections.c | 94 ++++++++++++++++++++++++++++++----------------------- 3 files changed, 53 insertions(+), 44 deletions(-) Index: src/base.h =================================================================== --- src/base.h.orig 2008-01-18 10:07:54.000000000 +0100 +++ src/base.h 2010-02-01 14:59:42.776090957 +0100 @@ -414,7 +414,6 @@ typedef struct { #ifdef USE_OPENSSL SSL *ssl; - buffer *ssl_error_want_reuse_buffer; #endif /* etag handling */ etag_flags_t etag_flags; Index: src/chunk.c =================================================================== --- src/chunk.c.orig 2006-10-04 15:26:23.000000000 +0200 +++ src/chunk.c 2010-02-01 14:58:14.844607476 +0100 @@ -197,8 +197,6 @@ int chunkqueue_append_buffer(chunkqueue int chunkqueue_append_buffer_weak(chunkqueue *cq, buffer *mem) { chunk *c; - if (mem->used == 0) return 0; - c = chunkqueue_get_unused_chunk(cq); c->type = MEM_CHUNK; c->offset = 0; Index: src/connections.c =================================================================== --- src/connections.c.orig 2010-02-01 14:58:12.000000000 +0100 +++ src/connections.c 2010-02-01 15:21:21.277998227 +0100 @@ -192,39 +192,41 @@ static void dump_packet(const unsigned c static int connection_handle_read_ssl(server *srv, connection *con) { #ifdef USE_OPENSSL - int r, ssl_err, len; + int r, ssl_err, len, count = 0, read_offset, toread; buffer *b = NULL; if (!con->conf.is_ssl) return -1; - /* don't resize the buffer if we were in SSL_ERROR_WANT_* */ - ERR_clear_error(); do { - if (!con->ssl_error_want_reuse_buffer) { - b = buffer_init(); - buffer_prepare_copy(b, SSL_pending(con->ssl) + (16 * 1024)); /* the pending bytes + 16kb */ + if (NULL != con->read_queue->last) + b = con->read_queue->last->mem; + + if (NULL == b || b->size - b->used < 1024) { + b = chunkqueue_get_append_buffer(con->read_queue); + len = SSL_pending(con->ssl); + if (len < 4*1024) len = 4*1024; /* always alloc >= 4k buffer */ + buffer_prepare_copy(b, len + 1); /* overwrite everything with 0 */ memset(b->ptr, 0, b->size); - } else { - b = con->ssl_error_want_reuse_buffer; } - len = SSL_read(con->ssl, b->ptr, b->size - 1); - con->ssl_error_want_reuse_buffer = NULL; /* reuse it only once */ + read_offset = (b->used > 0) ? b->used - 1 : 0; + toread = b->size - 1 - read_offset; + + len = SSL_read(con->ssl, b->ptr + read_offset, toread); + if (len > 0) { - b->used = len; + if (b->used > 0) b->used--; + b->used += len; b->ptr[b->used++] = '\0'; - /* we move the buffer to the chunk-queue, no need to free it */ - - chunkqueue_append_buffer_weak(con->read_queue, b); con->bytes_read += len; - b = NULL; + count += len; } - } while (len > 0); + } while (len == toread && count < MAX_READ_LIMIT); if (len < 0) { @@ -232,11 +234,11 @@ static int connection_handle_read_ssl(se case SSL_ERROR_WANT_READ: case SSL_ERROR_WANT_WRITE: con->is_readable = 0; - con->ssl_error_want_reuse_buffer = b; - b = NULL; + /* the manual says we have to call SSL_read with the same arguments next time. + * we ignore this restriction; no one has complained about it in 1.5 yet, so it probably works anyway. + */ - /* we have to steal the buffer from the queue-queue */ return 0; case SSL_ERROR_SYSCALL: /** @@ -285,16 +287,11 @@ static int connection_handle_read_ssl(se connection_set_state(srv, con, CON_STATE_ERROR); - buffer_free(b); - return -1; } else if (len == 0) { con->is_readable = 0; /* the other end close the connection -> KEEP-ALIVE */ - /* pipelining */ - buffer_free(b); - return -2; } @@ -307,27 +304,41 @@ static int connection_handle_read_ssl(se static int connection_handle_read(server *srv, connection *con) { int len; buffer *b; - int toread; + int toread, read_offset; if (con->conf.is_ssl) { return connection_handle_read_ssl(srv, con); } + b = (NULL != con->read_queue->last) ? con->read_queue->last->mem : NULL; + + /* default size for chunks is 4kb; only use bigger chunks if FIONREAD tells + * us more than 4kb is available + * if FIONREAD doesn't signal a big chunk we fill the previous buffer + * if it has >= 1kb free + */ #if defined(__WIN32) - b = chunkqueue_get_append_buffer(con->read_queue); - buffer_prepare_copy(b, 4 * 1024); - len = recv(con->fd, b->ptr, b->size - 1, 0); + if (NULL == b || b->size - b->used < 1024) { + b = chunkqueue_get_append_buffer(con->read_queue); + buffer_prepare_copy(b, 4 * 1024); + } + + read_offset = (b->used == 0) ? 0 : b->used - 1; + len = recv(con->fd, b->ptr + read_offset, b->size - 1 - read_offset, 0); #else - if (ioctl(con->fd, FIONREAD, &toread)) { - log_error_write(srv, __FILE__, __LINE__, "sd", - "unexpected end-of-file:", - con->fd); - return -1; + if (ioctl(con->fd, FIONREAD, &toread) || toread == 0 || toread <= 4*1024) { + if (NULL == b || b->size - b->used < 1024) { + b = chunkqueue_get_append_buffer(con->read_queue); + buffer_prepare_copy(b, 4 * 1024); + } + } else { + if (toread > MAX_READ_LIMIT) toread = MAX_READ_LIMIT; + b = chunkqueue_get_append_buffer(con->read_queue); + buffer_prepare_copy(b, toread + 1); } - b = chunkqueue_get_append_buffer(con->read_queue); - buffer_prepare_copy(b, toread + 1); - len = read(con->fd, b->ptr, b->size - 1); + read_offset = (b->used == 0) ? 0 : b->used - 1; + len = read(con->fd, b->ptr + read_offset, b->size - 1 - read_offset); #endif if (len < 0) { @@ -361,7 +372,8 @@ static int connection_handle_read(server con->is_readable = 0; } - b->used = len; + if (b->used > 0) b->used--; + b->used += len; b->ptr[b->used++] = '\0'; con->bytes_read += len; @@ -849,13 +861,6 @@ int connection_reset(server *srv, connec /* The cond_cache gets reset in response.c */ // config_cond_cache_reset(srv, con); -#ifdef USE_OPENSSL - if (con->ssl_error_want_reuse_buffer) { - buffer_free(con->ssl_error_want_reuse_buffer); - con->ssl_error_want_reuse_buffer = NULL; - } -#endif - con->header_len = 0; con->in_error_handler = 0; @@ -1136,8 +1141,15 @@ int connection_handle_read_state(server } else { buffer *b; - b = chunkqueue_get_append_buffer(dst_cq); - buffer_copy_string_len(b, c->mem->ptr + c->offset, toRead); + if (dst_cq->last && + dst_cq->last->type == MEM_CHUNK) { + b = dst_cq->last->mem; + } else { + b = chunkqueue_get_append_buffer(dst_cq); + /* prepare buffer size for remaining POST data; is < 64kb */ + buffer_prepare_copy(b, con->request.content_length - dst_cq->bytes_in + 1); + } + buffer_append_string_len(b, c->mem->ptr + c->offset, toRead); } c->offset += toRead; Index: src/settings.h =================================================================== --- src/settings.h.orig 2006-10-04 15:26:23.000000000 +0200 +++ src/settings.h 2010-02-01 15:32:12.229211465 +0100 @@ -13,6 +13,7 @@ * 64kB (no real reason, just a guess) */ #define BUFFER_MAX_REUSE_SIZE (4 * 1024) +#define MAX_READ_LIMIT (4*1024*1024) /** * max size of the HTTP request header
Locations
Projects
Search
Status Monitor
Help
OpenBuildService.org
Documentation
API Documentation
Code of Conduct
Contact
Support
@OBShq
Terms
openSUSE Build Service is sponsored by
The Open Build Service is an
openSUSE project
.
Sign Up
Log In
Places
Places
All Projects
Status Monitor