comparison src/http/modules/ngx_http_memcached_module.c @ 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 fd84344f1df7
children f538a67c9f77
comparison
equal deleted inserted replaced
5225:15a7deeaa19a 5226:a30ea5c6451d
195 ctx = ngx_palloc(r->pool, sizeof(ngx_http_memcached_ctx_t)); 195 ctx = ngx_palloc(r->pool, sizeof(ngx_http_memcached_ctx_t));
196 if (ctx == NULL) { 196 if (ctx == NULL) {
197 return NGX_HTTP_INTERNAL_SERVER_ERROR; 197 return NGX_HTTP_INTERNAL_SERVER_ERROR;
198 } 198 }
199 199
200 ctx->rest = NGX_HTTP_MEMCACHED_END;
201 ctx->request = r; 200 ctx->request = r;
202 201
203 ngx_http_set_ctx(r, ctx, ngx_http_memcached_module); 202 ngx_http_set_ctx(r, ctx, ngx_http_memcached_module);
204 203
205 u->input_filter_init = ngx_http_memcached_filter_init; 204 u->input_filter_init = ngx_http_memcached_filter_init;
307 306
308 return NGX_AGAIN; 307 return NGX_AGAIN;
309 308
310 found: 309 found:
311 310
311 line.data = u->buffer.pos;
312 line.len = p - u->buffer.pos;
313
314 if (line.len == 0 || *(p - 1) != CR) {
315 goto no_valid;
316 }
317
312 *p = '\0'; 318 *p = '\0';
313 319 line.len--;
314 line.len = p - u->buffer.pos - 1;
315 line.data = u->buffer.pos;
316 320
317 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, 321 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
318 "memcached: \"%V\"", &line); 322 "memcached: \"%V\"", &line);
319 323
320 p = u->buffer.pos; 324 p = u->buffer.pos;
385 } 389 }
386 390
387 length: 391 length:
388 392
389 start = p; 393 start = p;
390 394 p = line.data + line.len;
391 while (*p && *p++ != CR) { /* void */ } 395
392 396 u->headers_in.content_length_n = ngx_atoof(start, p - start);
393 u->headers_in.content_length_n = ngx_atoof(start, p - start - 1);
394 if (u->headers_in.content_length_n == -1) { 397 if (u->headers_in.content_length_n == -1) {
395 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, 398 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
396 "memcached sent invalid length in response \"%V\" " 399 "memcached sent invalid length in response \"%V\" "
397 "for key \"%V\"", 400 "for key \"%V\"",
398 &line, &ctx->key); 401 &line, &ctx->key);
399 return NGX_HTTP_UPSTREAM_INVALID_HEADER; 402 return NGX_HTTP_UPSTREAM_INVALID_HEADER;
400 } 403 }
401 404
402 u->headers_in.status_n = 200; 405 u->headers_in.status_n = 200;
403 u->state->status = 200; 406 u->state->status = 200;
404 u->buffer.pos = p + 1; 407 u->buffer.pos = p + sizeof(CRLF) - 1;
405 408
406 return NGX_OK; 409 return NGX_OK;
407 } 410 }
408 411
409 if (ngx_strcmp(p, "END\x0d") == 0) { 412 if (ngx_strcmp(p, "END\x0d") == 0) {
410 ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, 413 ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
411 "key: \"%V\" was not found by memcached", &ctx->key); 414 "key: \"%V\" was not found by memcached", &ctx->key);
412 415
416 u->headers_in.content_length_n = 0;
413 u->headers_in.status_n = 404; 417 u->headers_in.status_n = 404;
414 u->state->status = 404; 418 u->state->status = 404;
419 u->buffer.pos = p + sizeof("END" CRLF) - 1;
415 u->keepalive = 1; 420 u->keepalive = 1;
416 421
417 return NGX_OK; 422 return NGX_OK;
418 } 423 }
419 424
433 438
434 ngx_http_upstream_t *u; 439 ngx_http_upstream_t *u;
435 440
436 u = ctx->request->upstream; 441 u = ctx->request->upstream;
437 442
438 u->length += NGX_HTTP_MEMCACHED_END; 443 if (u->headers_in.status_n != 404) {
444 u->length += NGX_HTTP_MEMCACHED_END;
445 ctx->rest = NGX_HTTP_MEMCACHED_END;
446 }
439 447
440 return NGX_OK; 448 return NGX_OK;
441 } 449 }
442 450
443 451