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