changeset 5226:a30ea5c6451d

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.
author Ruslan Ermilov <ru@nginx.com>
date Thu, 23 May 2013 16:26:10 +0400
parents 15a7deeaa19a
children ea41bba49e8a
files src/http/modules/ngx_http_memcached_module.c
diffstat 1 files changed, 17 insertions(+), 9 deletions(-) [+]
line wrap: on
line diff
--- 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;
 }