Mercurial > hg > nginx
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 |