comparison src/core/ngx_resolver.c @ 6356:f63dd04c1580 stable-1.8

Resolver: fixed crashes in timeout handler. If one or more requests were waiting for a response, then after getting a CNAME response, the timeout event on the first request remained active, pointing to the wrong node with an empty rn->waiting list, and that could cause either null pointer dereference or use-after-free memory access if this timeout expired. If several requests were waiting for a response, and the first request terminated (e.g., due to client closing a connection), other requests were left without a timeout and could potentially wait indefinitely. This is fixed by introducing per-request independent timeouts. This change also reverts 954867a2f0a6 and 5004210e8c78.
author Ruslan Ermilov <ru@nginx.com>
date Tue, 26 Jan 2016 16:46:31 +0300
parents c36482d0a79f
children 838946300825
comparison
equal deleted inserted replaced
6355:c36482d0a79f 6356:f63dd04c1580
420 ngx_del_timer(ctx->event); 420 ngx_del_timer(ctx->event);
421 } 421 }
422 422
423 /* lock name mutex */ 423 /* lock name mutex */
424 424
425 if (ctx->state == NGX_AGAIN) { 425 if (ctx->state == NGX_AGAIN || ctx->state == NGX_RESOLVE_TIMEDOUT) {
426 426
427 hash = ngx_crc32_short(ctx->name.data, ctx->name.len); 427 hash = ngx_crc32_short(ctx->name.data, ctx->name.len);
428 428
429 rn = ngx_resolver_lookup_name(r, &ctx->name, hash); 429 rn = ngx_resolver_lookup_name(r, &ctx->name, hash);
430 430
574 return NGX_OK; 574 return NGX_OK;
575 } 575 }
576 576
577 if (rn->waiting) { 577 if (rn->waiting) {
578 578
579 if (ctx->event == NULL) {
580 ctx->event = ngx_resolver_calloc(r, sizeof(ngx_event_t));
581 if (ctx->event == NULL) {
582 return NGX_ERROR;
583 }
584
585 ctx->event->handler = ngx_resolver_timeout_handler;
586 ctx->event->data = ctx;
587 ctx->event->log = r->log;
588 ctx->ident = -1;
589
590 ngx_add_timer(ctx->event, ctx->timeout);
591 }
592
579 ctx->next = rn->waiting; 593 ctx->next = rn->waiting;
580 rn->waiting = ctx; 594 rn->waiting = ctx;
581 ctx->state = NGX_AGAIN; 595 ctx->state = NGX_AGAIN;
582 596
583 return NGX_AGAIN; 597 return NGX_AGAIN;
667 if (ctx->event == NULL) { 681 if (ctx->event == NULL) {
668 goto failed; 682 goto failed;
669 } 683 }
670 684
671 ctx->event->handler = ngx_resolver_timeout_handler; 685 ctx->event->handler = ngx_resolver_timeout_handler;
672 ctx->event->data = rn; 686 ctx->event->data = ctx;
673 ctx->event->log = r->log; 687 ctx->event->log = r->log;
674 rn->ident = -1; 688 ctx->ident = -1;
675 689
676 ngx_add_timer(ctx->event, ctx->timeout); 690 ngx_add_timer(ctx->event, ctx->timeout);
677 } 691 }
678 692
679 if (ngx_queue_empty(&r->name_resend_queue)) { 693 if (ngx_queue_empty(&r->name_resend_queue)) {
797 return NGX_OK; 811 return NGX_OK;
798 } 812 }
799 813
800 if (rn->waiting) { 814 if (rn->waiting) {
801 815
816 ctx->event = ngx_resolver_calloc(r, sizeof(ngx_event_t));
817 if (ctx->event == NULL) {
818 return NGX_ERROR;
819 }
820
821 ctx->event->handler = ngx_resolver_timeout_handler;
822 ctx->event->data = ctx;
823 ctx->event->log = r->log;
824 ctx->ident = -1;
825
826 ngx_add_timer(ctx->event, ctx->timeout);
827
802 ctx->next = rn->waiting; 828 ctx->next = rn->waiting;
803 rn->waiting = ctx; 829 rn->waiting = ctx;
804 ctx->state = NGX_AGAIN; 830 ctx->state = NGX_AGAIN;
805 831
806 /* unlock addr mutex */ 832 /* unlock addr mutex */
860 if (ctx->event == NULL) { 886 if (ctx->event == NULL) {
861 goto failed; 887 goto failed;
862 } 888 }
863 889
864 ctx->event->handler = ngx_resolver_timeout_handler; 890 ctx->event->handler = ngx_resolver_timeout_handler;
865 ctx->event->data = rn; 891 ctx->event->data = ctx;
866 ctx->event->log = r->log; 892 ctx->event->log = r->log;
867 rn->ident = -1; 893 ctx->ident = -1;
868 894
869 ngx_add_timer(ctx->event, ctx->timeout); 895 ngx_add_timer(ctx->event, ctx->timeout);
870 896
871 if (ngx_queue_empty(resend_queue)) { 897 if (ngx_queue_empty(resend_queue)) {
872 ngx_add_timer(r->event, (ngx_msec_t) (r->resend_timeout * 1000)); 898 ngx_add_timer(r->event, (ngx_msec_t) (r->resend_timeout * 1000));
952 ngx_del_timer(ctx->event); 978 ngx_del_timer(ctx->event);
953 } 979 }
954 980
955 /* lock addr mutex */ 981 /* lock addr mutex */
956 982
957 if (ctx->state == NGX_AGAIN) { 983 if (ctx->state == NGX_AGAIN || ctx->state == NGX_RESOLVE_TIMEDOUT) {
958 984
959 switch (ctx->addr.sockaddr->sa_family) { 985 switch (ctx->addr.sockaddr->sa_family) {
960 986
961 #if (NGX_HAVE_INET6) 987 #if (NGX_HAVE_INET6)
962 case AF_INET6: 988 case AF_INET6:
2793 2819
2794 2820
2795 static void 2821 static void
2796 ngx_resolver_timeout_handler(ngx_event_t *ev) 2822 ngx_resolver_timeout_handler(ngx_event_t *ev)
2797 { 2823 {
2798 ngx_resolver_ctx_t *ctx, *next; 2824 ngx_resolver_ctx_t *ctx;
2799 ngx_resolver_node_t *rn; 2825
2800 2826 ctx = ev->data;
2801 rn = ev->data; 2827
2802 ctx = rn->waiting; 2828 ctx->state = NGX_RESOLVE_TIMEDOUT;
2803 rn->waiting = NULL; 2829
2804 2830 ctx->handler(ctx);
2805 do {
2806 ctx->state = NGX_RESOLVE_TIMEDOUT;
2807 next = ctx->next;
2808
2809 ctx->handler(ctx);
2810
2811 ctx = next;
2812 } while (ctx);
2813 } 2831 }
2814 2832
2815 2833
2816 static void 2834 static void
2817 ngx_resolver_free_node(ngx_resolver_t *r, ngx_resolver_node_t *rn) 2835 ngx_resolver_free_node(ngx_resolver_t *r, ngx_resolver_node_t *rn)