# HG changeset patch # User Ruslan Ermilov # Date 1369311970 -14400 # Node ID a30ea5c6451dcae3ce1e6d9eabe718c0222e5d9f # Parent 15a7deeaa19a1f388a357682343bd8b4e90ad90d Memcached: stricten header validation. An invalid memcached reply that started with '\n' could cause segmentation fault. An invalid memcached reply "VALUE / 0 2\r?ok\r\nEND\r\n" was considered as a valid response. In addition, if memcached reports that the key was not found, set u->headers_in.content_length_n to 0. This ensures that ngx_http_memcached_filter() will not be called while previous code relied on always intercepting 404. Initialization of ctx->rest was moved to where it belongs. diff --git a/src/http/modules/ngx_http_memcached_module.c b/src/http/modules/ngx_http_memcached_module.c --- a/src/http/modules/ngx_http_memcached_module.c +++ b/src/http/modules/ngx_http_memcached_module.c @@ -197,7 +197,6 @@ ngx_http_memcached_handler(ngx_http_requ return NGX_HTTP_INTERNAL_SERVER_ERROR; } - ctx->rest = NGX_HTTP_MEMCACHED_END; ctx->request = r; ngx_http_set_ctx(r, ctx, ngx_http_memcached_module); @@ -309,10 +308,15 @@ ngx_http_memcached_process_header(ngx_ht found: - *p = '\0'; + line.data = u->buffer.pos; + line.len = p - u->buffer.pos; - line.len = p - u->buffer.pos - 1; - line.data = u->buffer.pos; + if (line.len == 0 || *(p - 1) != CR) { + goto no_valid; + } + + *p = '\0'; + line.len--; ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "memcached: \"%V\"", &line); @@ -387,10 +391,9 @@ found: length: start = p; + p = line.data + line.len; - while (*p && *p++ != CR) { /* void */ } - - u->headers_in.content_length_n = ngx_atoof(start, p - start - 1); + u->headers_in.content_length_n = ngx_atoof(start, p - start); if (u->headers_in.content_length_n == -1) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "memcached sent invalid length in response \"%V\" " @@ -401,7 +404,7 @@ found: u->headers_in.status_n = 200; u->state->status = 200; - u->buffer.pos = p + 1; + u->buffer.pos = p + sizeof(CRLF) - 1; return NGX_OK; } @@ -410,8 +413,10 @@ found: ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, "key: \"%V\" was not found by memcached", &ctx->key); + u->headers_in.content_length_n = 0; u->headers_in.status_n = 404; u->state->status = 404; + u->buffer.pos = p + sizeof("END" CRLF) - 1; u->keepalive = 1; return NGX_OK; @@ -435,7 +440,10 @@ ngx_http_memcached_filter_init(void *dat u = ctx->request->upstream; - u->length += NGX_HTTP_MEMCACHED_END; + if (u->headers_in.status_n != 404) { + u->length += NGX_HTTP_MEMCACHED_END; + ctx->rest = NGX_HTTP_MEMCACHED_END; + } return NGX_OK; }