From 8c6b0f77af6f92f95d8aaf406d3bfd0167dc9db6 Mon Sep 17 00:00:00 2001 From: "Yichun Zhang (agentzh)" Date: Thu, 28 Jan 2016 09:28:18 -0800 Subject: [PATCH] bugfix: applied nginx-1.9.7-resolver_security_fixes.patch by default. --- .../nginx-1.9.7-resolver_security_fixes.patch | 565 ++++++++++++++++++ util/mirror-tarballs | 6 + util/ver | 2 +- 3 files changed, 572 insertions(+), 1 deletion(-) create mode 100644 patches/nginx-1.9.7-resolver_security_fixes.patch diff --git a/patches/nginx-1.9.7-resolver_security_fixes.patch b/patches/nginx-1.9.7-resolver_security_fixes.patch new file mode 100644 index 0000000..cdef0c3 --- /dev/null +++ b/patches/nginx-1.9.7-resolver_security_fixes.patch @@ -0,0 +1,565 @@ +diff -upr nginx-1.9.7-old/src/core/ngx_resolver.c nginx-1.9.7/src/core/ngx_resolver.c +--- nginx-1.9.7-old/src/core/ngx_resolver.c 2016-01-26 11:54:55.915406799 -0800 ++++ nginx-1.9.7/src/core/ngx_resolver.c 2016-01-26 11:55:27.067782268 -0800 +@@ -59,15 +59,15 @@ ngx_int_t ngx_udp_connect(ngx_udp_connec + static void ngx_resolver_cleanup(void *data); + static void ngx_resolver_cleanup_tree(ngx_resolver_t *r, ngx_rbtree_t *tree); + static ngx_int_t ngx_resolve_name_locked(ngx_resolver_t *r, +- ngx_resolver_ctx_t *ctx); ++ ngx_resolver_ctx_t *ctx, ngx_str_t *name); + static void ngx_resolver_expire(ngx_resolver_t *r, ngx_rbtree_t *tree, + ngx_queue_t *queue); + static ngx_int_t ngx_resolver_send_query(ngx_resolver_t *r, + ngx_resolver_node_t *rn); +-static ngx_int_t ngx_resolver_create_name_query(ngx_resolver_node_t *rn, +- ngx_resolver_ctx_t *ctx); +-static ngx_int_t ngx_resolver_create_addr_query(ngx_resolver_node_t *rn, +- ngx_resolver_ctx_t *ctx); ++static ngx_int_t ngx_resolver_create_name_query(ngx_resolver_t *r, ++ ngx_resolver_node_t *rn, ngx_str_t *name); ++static ngx_int_t ngx_resolver_create_addr_query(ngx_resolver_t *r, ++ ngx_resolver_node_t *rn, ngx_addr_t *addr); + static void ngx_resolver_resend_handler(ngx_event_t *ev); + static time_t ngx_resolver_resend(ngx_resolver_t *r, ngx_rbtree_t *tree, + ngx_queue_t *queue); +@@ -376,7 +376,7 @@ ngx_resolve_name(ngx_resolver_ctx_t *ctx + + /* lock name mutex */ + +- rc = ngx_resolve_name_locked(r, ctx); ++ rc = ngx_resolve_name_locked(r, ctx, &ctx->name); + + if (rc == NGX_OK) { + return NGX_OK; +@@ -403,7 +403,6 @@ ngx_resolve_name(ngx_resolver_ctx_t *ctx + void + ngx_resolve_name_done(ngx_resolver_ctx_t *ctx) + { +- uint32_t hash; + ngx_resolver_t *r; + ngx_resolver_ctx_t *w, **p; + ngx_resolver_node_t *rn; +@@ -423,11 +422,9 @@ ngx_resolve_name_done(ngx_resolver_ctx_t + + /* lock name mutex */ + +- if (ctx->state == NGX_AGAIN) { +- +- hash = ngx_crc32_short(ctx->name.data, ctx->name.len); ++ if (ctx->state == NGX_AGAIN || ctx->state == NGX_RESOLVE_TIMEDOUT) { + +- rn = ngx_resolver_lookup_name(r, &ctx->name, hash); ++ rn = ctx->node; + + if (rn) { + p = &rn->waiting; +@@ -472,23 +469,28 @@ done: + + + static ngx_int_t +-ngx_resolve_name_locked(ngx_resolver_t *r, ngx_resolver_ctx_t *ctx) ++ngx_resolve_name_locked(ngx_resolver_t *r, ngx_resolver_ctx_t *ctx, ++ ngx_str_t *name) + { + uint32_t hash; + ngx_int_t rc; ++ ngx_str_t cname; + ngx_uint_t naddrs; + ngx_addr_t *addrs; +- ngx_resolver_ctx_t *next; ++ ngx_resolver_ctx_t *next, *last; + ngx_resolver_node_t *rn; + +- ngx_strlow(ctx->name.data, ctx->name.data, ctx->name.len); ++ ngx_strlow(name->data, name->data, name->len); + +- hash = ngx_crc32_short(ctx->name.data, ctx->name.len); ++ hash = ngx_crc32_short(name->data, name->len); + +- rn = ngx_resolver_lookup_name(r, &ctx->name, hash); ++ rn = ngx_resolver_lookup_name(r, name, hash); + + if (rn) { + ++ /* ctx can be a list after NGX_RESOLVE_CNAME */ ++ for (last = ctx; last->next; last = last->next); ++ + if (rn->valid >= ngx_time()) { + + ngx_log_debug0(NGX_LOG_DEBUG_CORE, r->log, 0, "resolve cached"); +@@ -516,7 +518,7 @@ ngx_resolve_name_locked(ngx_resolver_t * + } + } + +- ctx->next = rn->waiting; ++ last->next = rn->waiting; + rn->waiting = NULL; + + /* unlock name mutex */ +@@ -556,13 +558,13 @@ ngx_resolve_name_locked(ngx_resolver_t * + + if (ctx->recursion++ < NGX_RESOLVER_MAX_RECURSION) { + +- ctx->name.len = rn->cnlen; +- ctx->name.data = rn->u.cname; ++ cname.len = rn->cnlen; ++ cname.data = rn->u.cname; + +- return ngx_resolve_name_locked(r, ctx); ++ return ngx_resolve_name_locked(r, ctx, &cname); + } + +- ctx->next = rn->waiting; ++ last->next = rn->waiting; + rn->waiting = NULL; + + /* unlock name mutex */ +@@ -581,10 +583,29 @@ ngx_resolve_name_locked(ngx_resolver_t * + + if (rn->waiting) { + +- ctx->next = rn->waiting; ++ if (ctx->event == NULL) { ++ ctx->event = ngx_resolver_calloc(r, sizeof(ngx_event_t)); ++ if (ctx->event == NULL) { ++ return NGX_ERROR; ++ } ++ ++ ctx->event->handler = ngx_resolver_timeout_handler; ++ ctx->event->data = ctx; ++ ctx->event->log = r->log; ++ ctx->ident = -1; ++ ++ ngx_add_timer(ctx->event, ctx->timeout); ++ } ++ ++ last->next = rn->waiting; + rn->waiting = ctx; + ctx->state = NGX_AGAIN; + ++ do { ++ ctx->node = rn; ++ ctx = ctx->next; ++ } while (ctx); ++ + return NGX_AGAIN; + } + +@@ -623,14 +644,14 @@ ngx_resolve_name_locked(ngx_resolver_t * + return NGX_ERROR; + } + +- rn->name = ngx_resolver_dup(r, ctx->name.data, ctx->name.len); ++ rn->name = ngx_resolver_dup(r, name->data, name->len); + if (rn->name == NULL) { + ngx_resolver_free(r, rn); + return NGX_ERROR; + } + + rn->node.key = hash; +- rn->nlen = (u_short) ctx->name.len; ++ rn->nlen = (u_short) name->len; + rn->query = NULL; + #if (NGX_HAVE_INET6) + rn->query6 = NULL; +@@ -639,7 +660,7 @@ ngx_resolve_name_locked(ngx_resolver_t * + ngx_rbtree_insert(&r->name_rbtree, &rn->node); + } + +- rc = ngx_resolver_create_name_query(rn, ctx); ++ rc = ngx_resolver_create_name_query(r, rn, name); + + if (rc == NGX_ERROR) { + goto failed; +@@ -652,8 +673,14 @@ ngx_resolve_name_locked(ngx_resolver_t * + ngx_resolver_free(r, rn->name); + ngx_resolver_free(r, rn); + +- ctx->state = NGX_RESOLVE_NXDOMAIN; +- ctx->handler(ctx); ++ do { ++ ctx->state = NGX_RESOLVE_NXDOMAIN; ++ next = ctx->next; ++ ++ ctx->handler(ctx); ++ ++ ctx = next; ++ } while (ctx); + + return NGX_OK; + } +@@ -674,9 +701,9 @@ ngx_resolve_name_locked(ngx_resolver_t * + } + + ctx->event->handler = ngx_resolver_timeout_handler; +- ctx->event->data = rn; ++ ctx->event->data = ctx; + ctx->event->log = r->log; +- rn->ident = -1; ++ ctx->ident = -1; + + ngx_add_timer(ctx->event, ctx->timeout); + } +@@ -697,6 +724,11 @@ ngx_resolve_name_locked(ngx_resolver_t * + + ctx->state = NGX_AGAIN; + ++ do { ++ ctx->node = rn; ++ ctx = ctx->next; ++ } while (ctx); ++ + return NGX_AGAIN; + + failed: +@@ -804,9 +836,22 @@ ngx_resolve_addr(ngx_resolver_ctx_t *ctx + + if (rn->waiting) { + ++ ctx->event = ngx_resolver_calloc(r, sizeof(ngx_event_t)); ++ if (ctx->event == NULL) { ++ return NGX_ERROR; ++ } ++ ++ ctx->event->handler = ngx_resolver_timeout_handler; ++ ctx->event->data = ctx; ++ ctx->event->log = r->log; ++ ctx->ident = -1; ++ ++ ngx_add_timer(ctx->event, ctx->timeout); ++ + ctx->next = rn->waiting; + rn->waiting = ctx; + ctx->state = NGX_AGAIN; ++ ctx->node = rn; + + /* unlock addr mutex */ + +@@ -848,7 +893,7 @@ ngx_resolve_addr(ngx_resolver_ctx_t *ctx + ngx_rbtree_insert(tree, &rn->node); + } + +- if (ngx_resolver_create_addr_query(rn, ctx) != NGX_OK) { ++ if (ngx_resolver_create_addr_query(r, rn, &ctx->addr) != NGX_OK) { + goto failed; + } + +@@ -867,9 +912,9 @@ ngx_resolve_addr(ngx_resolver_ctx_t *ctx + } + + ctx->event->handler = ngx_resolver_timeout_handler; +- ctx->event->data = rn; ++ ctx->event->data = ctx; + ctx->event->log = r->log; +- rn->ident = -1; ++ ctx->ident = -1; + + ngx_add_timer(ctx->event, ctx->timeout); + +@@ -892,6 +937,7 @@ ngx_resolve_addr(ngx_resolver_ctx_t *ctx + /* unlock addr mutex */ + + ctx->state = NGX_AGAIN; ++ ctx->node = rn; + + return NGX_OK; + +@@ -922,17 +968,11 @@ failed: + void + ngx_resolve_addr_done(ngx_resolver_ctx_t *ctx) + { +- in_addr_t addr; + ngx_queue_t *expire_queue; + ngx_rbtree_t *tree; + ngx_resolver_t *r; + ngx_resolver_ctx_t *w, **p; +- struct sockaddr_in *sin; + ngx_resolver_node_t *rn; +-#if (NGX_HAVE_INET6) +- uint32_t hash; +- struct sockaddr_in6 *sin6; +-#endif + + r = ctx->resolver; + +@@ -959,23 +999,9 @@ ngx_resolve_addr_done(ngx_resolver_ctx_t + + /* lock addr mutex */ + +- if (ctx->state == NGX_AGAIN) { +- +- switch (ctx->addr.sockaddr->sa_family) { +- +-#if (NGX_HAVE_INET6) +- case AF_INET6: +- sin6 = (struct sockaddr_in6 *) ctx->addr.sockaddr; +- hash = ngx_crc32_short(sin6->sin6_addr.s6_addr, 16); +- rn = ngx_resolver_lookup_addr6(r, &sin6->sin6_addr, hash); +- break; +-#endif ++ if (ctx->state == NGX_AGAIN || ctx->state == NGX_RESOLVE_TIMEDOUT) { + +- default: /* AF_INET */ +- sin = (struct sockaddr_in *) ctx->addr.sockaddr; +- addr = ntohl(sin->sin_addr.s_addr); +- rn = ngx_resolver_lookup_addr(r, addr); +- } ++ rn = ctx->node; + + if (rn) { + p = &rn->waiting; +@@ -1312,7 +1338,7 @@ ngx_resolver_process_response(ngx_resolv + times = 0; + + for (q = ngx_queue_head(&r->name_resend_queue); +- q != ngx_queue_sentinel(&r->name_resend_queue) || times++ < 100; ++ q != ngx_queue_sentinel(&r->name_resend_queue) && times++ < 100; + q = ngx_queue_next(q)) + { + rn = ngx_queue_data(q, ngx_resolver_node_t, queue); +@@ -1975,20 +2001,39 @@ ngx_resolver_process_a(ngx_resolver_t *r + + ngx_queue_insert_head(&r->name_expire_queue, &rn->queue); + ++ ngx_resolver_free(r, rn->query); ++ rn->query = NULL; ++#if (NGX_HAVE_INET6) ++ rn->query6 = NULL; ++#endif ++ + ctx = rn->waiting; + rn->waiting = NULL; + + if (ctx) { +- ctx->name = name; + +- (void) ngx_resolve_name_locked(r, ctx); +- } ++ if (ctx->recursion++ >= NGX_RESOLVER_MAX_RECURSION) { + +- ngx_resolver_free(r, rn->query); +- rn->query = NULL; +-#if (NGX_HAVE_INET6) +- rn->query6 = NULL; +-#endif ++ /* unlock name mutex */ ++ ++ do { ++ ctx->state = NGX_RESOLVE_NXDOMAIN; ++ next = ctx->next; ++ ++ ctx->handler(ctx); ++ ++ ctx = next; ++ } while (ctx); ++ ++ return; ++ } ++ ++ for (next = ctx; next; next = next->next) { ++ next->node = NULL; ++ } ++ ++ (void) ngx_resolve_name_locked(r, ctx, &name); ++ } + + /* unlock name mutex */ + +@@ -2496,27 +2541,23 @@ ngx_resolver_rbtree_insert_addr6_value(n + + + static ngx_int_t +-ngx_resolver_create_name_query(ngx_resolver_node_t *rn, ngx_resolver_ctx_t *ctx) ++ngx_resolver_create_name_query(ngx_resolver_t *r, ngx_resolver_node_t *rn, ++ ngx_str_t *name) + { + u_char *p, *s; + size_t len, nlen; + ngx_uint_t ident; +-#if (NGX_HAVE_INET6) +- ngx_resolver_t *r; +-#endif + ngx_resolver_qs_t *qs; + ngx_resolver_hdr_t *query; + +- nlen = ctx->name.len ? (1 + ctx->name.len + 1) : 1; ++ nlen = name->len ? (1 + name->len + 1) : 1; + + len = sizeof(ngx_resolver_hdr_t) + nlen + sizeof(ngx_resolver_qs_t); + + #if (NGX_HAVE_INET6) +- r = ctx->resolver; +- +- p = ngx_resolver_alloc(ctx->resolver, r->ipv6 ? len * 2 : len); ++ p = ngx_resolver_alloc(r, r->ipv6 ? len * 2 : len); + #else +- p = ngx_resolver_alloc(ctx->resolver, len); ++ p = ngx_resolver_alloc(r, len); + #endif + if (p == NULL) { + return NGX_ERROR; +@@ -2535,8 +2576,8 @@ ngx_resolver_create_name_query(ngx_resol + + ident = ngx_random(); + +- ngx_log_debug2(NGX_LOG_DEBUG_CORE, ctx->resolver->log, 0, +- "resolve: \"%V\" A %i", &ctx->name, ident & 0xffff); ++ ngx_log_debug2(NGX_LOG_DEBUG_CORE, r->log, 0, ++ "resolve: \"%V\" A %i", name, ident & 0xffff); + + query->ident_hi = (u_char) ((ident >> 8) & 0xff); + query->ident_lo = (u_char) (ident & 0xff); +@@ -2566,11 +2607,11 @@ ngx_resolver_create_name_query(ngx_resol + p--; + *p-- = '\0'; + +- if (ctx->name.len == 0) { ++ if (name->len == 0) { + return NGX_DECLINED; + } + +- for (s = ctx->name.data + ctx->name.len - 1; s >= ctx->name.data; s--) { ++ for (s = name->data + name->len - 1; s >= name->data; s--) { + if (*s != '.') { + *p = *s; + len++; +@@ -2606,8 +2647,8 @@ ngx_resolver_create_name_query(ngx_resol + + ident = ngx_random(); + +- ngx_log_debug2(NGX_LOG_DEBUG_CORE, ctx->resolver->log, 0, +- "resolve: \"%V\" AAAA %i", &ctx->name, ident & 0xffff); ++ ngx_log_debug2(NGX_LOG_DEBUG_CORE, r->log, 0, ++ "resolve: \"%V\" AAAA %i", name, ident & 0xffff); + + query->ident_hi = (u_char) ((ident >> 8) & 0xff); + query->ident_lo = (u_char) (ident & 0xff); +@@ -2624,11 +2665,12 @@ ngx_resolver_create_name_query(ngx_resol + + + static ngx_int_t +-ngx_resolver_create_addr_query(ngx_resolver_node_t *rn, ngx_resolver_ctx_t *ctx) ++ngx_resolver_create_addr_query(ngx_resolver_t *r, ngx_resolver_node_t *rn, ++ ngx_addr_t *addr) + { + u_char *p, *d; + size_t len; +- in_addr_t addr; ++ in_addr_t inaddr; + ngx_int_t n; + ngx_uint_t ident; + ngx_resolver_hdr_t *query; +@@ -2637,7 +2679,7 @@ ngx_resolver_create_addr_query(ngx_resol + struct sockaddr_in6 *sin6; + #endif + +- switch (ctx->addr.sockaddr->sa_family) { ++ switch (addr->sockaddr->sa_family) { + + #if (NGX_HAVE_INET6) + case AF_INET6: +@@ -2654,7 +2696,7 @@ ngx_resolver_create_addr_query(ngx_resol + + sizeof(ngx_resolver_qs_t); + } + +- p = ngx_resolver_alloc(ctx->resolver, len); ++ p = ngx_resolver_alloc(r, len); + if (p == NULL) { + return NGX_ERROR; + } +@@ -2678,11 +2720,11 @@ ngx_resolver_create_addr_query(ngx_resol + + p += sizeof(ngx_resolver_hdr_t); + +- switch (ctx->addr.sockaddr->sa_family) { ++ switch (addr->sockaddr->sa_family) { + + #if (NGX_HAVE_INET6) + case AF_INET6: +- sin6 = (struct sockaddr_in6 *) ctx->addr.sockaddr; ++ sin6 = (struct sockaddr_in6 *) addr->sockaddr; + + for (n = 15; n >= 0; n--) { + p = ngx_sprintf(p, "\1%xd\1%xd", +@@ -2697,11 +2739,11 @@ ngx_resolver_create_addr_query(ngx_resol + + default: /* AF_INET */ + +- sin = (struct sockaddr_in *) ctx->addr.sockaddr; +- addr = ntohl(sin->sin_addr.s_addr); ++ sin = (struct sockaddr_in *) addr->sockaddr; ++ inaddr = ntohl(sin->sin_addr.s_addr); + + for (n = 0; n < 32; n += 8) { +- d = ngx_sprintf(&p[1], "%ud", (addr >> n) & 0xff); ++ d = ngx_sprintf(&p[1], "%ud", (inaddr >> n) & 0xff); + *p = (u_char) (d - &p[1]); + p = d; + } +@@ -2815,21 +2857,13 @@ done: + static void + ngx_resolver_timeout_handler(ngx_event_t *ev) + { +- ngx_resolver_ctx_t *ctx, *next; +- ngx_resolver_node_t *rn; ++ ngx_resolver_ctx_t *ctx; + +- rn = ev->data; +- ctx = rn->waiting; +- rn->waiting = NULL; ++ ctx = ev->data; + +- do { +- ctx->state = NGX_RESOLVE_TIMEDOUT; +- next = ctx->next; +- +- ctx->handler(ctx); ++ ctx->state = NGX_RESOLVE_TIMEDOUT; + +- ctx = next; +- } while (ctx); ++ ctx->handler(ctx); + } + + +diff -upr nginx-1.9.7-old/src/core/ngx_resolver.h nginx-1.9.7/src/core/ngx_resolver.h +--- nginx-1.9.7-old/src/core/ngx_resolver.h 2016-01-26 11:54:55.914404751 -0800 ++++ nginx-1.9.7/src/core/ngx_resolver.h 2016-01-26 11:55:27.068784001 -0800 +@@ -51,15 +51,11 @@ typedef void (*ngx_resolver_handler_pt)( + + + typedef struct { +- /* PTR: resolved name, A: name to resolve */ +- u_char *name; +- ++ ngx_rbtree_node_t node; + ngx_queue_t queue; + +- /* event ident must be after 3 pointers as in ngx_connection_t */ +- ngx_int_t ident; +- +- ngx_rbtree_node_t node; ++ /* PTR: resolved name, A: name to resolve */ ++ u_char *name; + + #if (NGX_HAVE_INET6) + /* PTR: IPv6 address to resolve (IPv4 address is in rbtree node key) */ +@@ -147,6 +143,9 @@ struct ngx_resolver_ctx_s { + ngx_resolver_t *resolver; + ngx_udp_connection_t *udp_connection; + ++ /* event ident must be after 3 pointers as in ngx_connection_t */ ++ ngx_int_t ident; ++ + ngx_int_t state; + ngx_str_t name; + +@@ -162,6 +161,8 @@ struct ngx_resolver_ctx_s { + ngx_uint_t quick; /* unsigned quick:1; */ + ngx_uint_t recursion; + ngx_event_t *event; ++ ++ ngx_resolver_node_t *node; + }; + + diff --git a/util/mirror-tarballs b/util/mirror-tarballs index 0889703..ef9eea9 100755 --- a/util/mirror-tarballs +++ b/util/mirror-tarballs @@ -293,6 +293,12 @@ if [ "$answer" = "N" ]; then echo fi +if [ "$main_ver" = "1.9.7" ]; then + echo "$info_txt applying the resolver_security_fixes patch for nginx" + patch -p1 < $root/patches/nginx-$main_ver-resolver_security_fixes.patch || exit 1 + echo +fi + rm -f *.patch || exit 1 echo "$info_txt applying the always_enable_cc_feature_tests patch to nginx" diff --git a/util/ver b/util/ver index 9359af9..ee48471 100755 --- a/util/ver +++ b/util/ver @@ -1,7 +1,7 @@ #!/bin/bash main_ver=1.9.7 -minor_ver=2 +minor_ver=3rc1 version=$main_ver.$minor_ver echo $version