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