comparison src/core/ngx_resolver.c @ 6348:7316c57e4fe7

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 81d44cd4044e
children 978e79b95c9f
comparison
equal deleted inserted replaced
6347:81d44cd4044e 6348:7316c57e4fe7
421 ngx_del_timer(ctx->event); 421 ngx_del_timer(ctx->event);
422 } 422 }
423 423
424 /* lock name mutex */ 424 /* lock name mutex */
425 425
426 if (ctx->state == NGX_AGAIN) { 426 if (ctx->state == NGX_AGAIN || ctx->state == NGX_RESOLVE_TIMEDOUT) {
427 427
428 hash = ngx_crc32_short(ctx->name.data, ctx->name.len); 428 hash = ngx_crc32_short(ctx->name.data, ctx->name.len);
429 429
430 rn = ngx_resolver_lookup_name(r, &ctx->name, hash); 430 rn = ngx_resolver_lookup_name(r, &ctx->name, hash);
431 431
579 return NGX_OK; 579 return NGX_OK;
580 } 580 }
581 581
582 if (rn->waiting) { 582 if (rn->waiting) {
583 583
584 if (ctx->event == NULL) {
585 ctx->event = ngx_resolver_calloc(r, sizeof(ngx_event_t));
586 if (ctx->event == NULL) {
587 return NGX_ERROR;
588 }
589
590 ctx->event->handler = ngx_resolver_timeout_handler;
591 ctx->event->data = ctx;
592 ctx->event->log = r->log;
593 ctx->ident = -1;
594
595 ngx_add_timer(ctx->event, ctx->timeout);
596 }
597
584 ctx->next = rn->waiting; 598 ctx->next = rn->waiting;
585 rn->waiting = ctx; 599 rn->waiting = ctx;
586 ctx->state = NGX_AGAIN; 600 ctx->state = NGX_AGAIN;
587 601
588 return NGX_AGAIN; 602 return NGX_AGAIN;
672 if (ctx->event == NULL) { 686 if (ctx->event == NULL) {
673 goto failed; 687 goto failed;
674 } 688 }
675 689
676 ctx->event->handler = ngx_resolver_timeout_handler; 690 ctx->event->handler = ngx_resolver_timeout_handler;
677 ctx->event->data = rn; 691 ctx->event->data = ctx;
678 ctx->event->log = r->log; 692 ctx->event->log = r->log;
679 rn->ident = -1; 693 ctx->ident = -1;
680 694
681 ngx_add_timer(ctx->event, ctx->timeout); 695 ngx_add_timer(ctx->event, ctx->timeout);
682 } 696 }
683 697
684 if (ngx_queue_empty(&r->name_resend_queue)) { 698 if (ngx_queue_empty(&r->name_resend_queue)) {
802 return NGX_OK; 816 return NGX_OK;
803 } 817 }
804 818
805 if (rn->waiting) { 819 if (rn->waiting) {
806 820
821 ctx->event = ngx_resolver_calloc(r, sizeof(ngx_event_t));
822 if (ctx->event == NULL) {
823 return NGX_ERROR;
824 }
825
826 ctx->event->handler = ngx_resolver_timeout_handler;
827 ctx->event->data = ctx;
828 ctx->event->log = r->log;
829 ctx->ident = -1;
830
831 ngx_add_timer(ctx->event, ctx->timeout);
832
807 ctx->next = rn->waiting; 833 ctx->next = rn->waiting;
808 rn->waiting = ctx; 834 rn->waiting = ctx;
809 ctx->state = NGX_AGAIN; 835 ctx->state = NGX_AGAIN;
810 836
811 /* unlock addr mutex */ 837 /* unlock addr mutex */
865 if (ctx->event == NULL) { 891 if (ctx->event == NULL) {
866 goto failed; 892 goto failed;
867 } 893 }
868 894
869 ctx->event->handler = ngx_resolver_timeout_handler; 895 ctx->event->handler = ngx_resolver_timeout_handler;
870 ctx->event->data = rn; 896 ctx->event->data = ctx;
871 ctx->event->log = r->log; 897 ctx->event->log = r->log;
872 rn->ident = -1; 898 ctx->ident = -1;
873 899
874 ngx_add_timer(ctx->event, ctx->timeout); 900 ngx_add_timer(ctx->event, ctx->timeout);
875 901
876 if (ngx_queue_empty(resend_queue)) { 902 if (ngx_queue_empty(resend_queue)) {
877 ngx_add_timer(r->event, (ngx_msec_t) (r->resend_timeout * 1000)); 903 ngx_add_timer(r->event, (ngx_msec_t) (r->resend_timeout * 1000));
957 ngx_del_timer(ctx->event); 983 ngx_del_timer(ctx->event);
958 } 984 }
959 985
960 /* lock addr mutex */ 986 /* lock addr mutex */
961 987
962 if (ctx->state == NGX_AGAIN) { 988 if (ctx->state == NGX_AGAIN || ctx->state == NGX_RESOLVE_TIMEDOUT) {
963 989
964 switch (ctx->addr.sockaddr->sa_family) { 990 switch (ctx->addr.sockaddr->sa_family) {
965 991
966 #if (NGX_HAVE_INET6) 992 #if (NGX_HAVE_INET6)
967 case AF_INET6: 993 case AF_INET6:
2813 2839
2814 2840
2815 static void 2841 static void
2816 ngx_resolver_timeout_handler(ngx_event_t *ev) 2842 ngx_resolver_timeout_handler(ngx_event_t *ev)
2817 { 2843 {
2818 ngx_resolver_ctx_t *ctx, *next; 2844 ngx_resolver_ctx_t *ctx;
2819 ngx_resolver_node_t *rn; 2845
2820 2846 ctx = ev->data;
2821 rn = ev->data; 2847
2822 ctx = rn->waiting; 2848 ctx->state = NGX_RESOLVE_TIMEDOUT;
2823 rn->waiting = NULL; 2849
2824 2850 ctx->handler(ctx);
2825 do {
2826 ctx->state = NGX_RESOLVE_TIMEDOUT;
2827 next = ctx->next;
2828
2829 ctx->handler(ctx);
2830
2831 ctx = next;
2832 } while (ctx);
2833 } 2851 }
2834 2852
2835 2853
2836 static void 2854 static void
2837 ngx_resolver_free_node(ngx_resolver_t *r, ngx_resolver_node_t *rn) 2855 ngx_resolver_free_node(ngx_resolver_t *r, ngx_resolver_node_t *rn)