Compare commits

...
Sign in to create a new pull request.

4 commits

Author SHA1 Message Date
Christos Trochalakis
b2867579bb Release 1.6.2-5+deb8u2~bpo70+1 2016-06-07 11:26:43 +03:00
Christos Trochalakis
6322b86a76 Release 1.6.2-5+deb8u2 2016-05-31 23:10:05 +03:00
Christos Trochalakis
1079d2a277 Release 1.6.2-5+deb8u1 2016-01-27 12:41:09 +02:00
Christos Trochalakis
04dd449771 Fix multiple resolver CVEs (Closes #812806)
Backported all relevant commits from the 1.8.1 series.
2016-01-27 12:22:40 +02:00
9 changed files with 785 additions and 0 deletions

25
debian/changelog vendored
View file

@ -1,3 +1,28 @@
nginx (1.6.2-5+deb8u2~bpo70+1) wheezy-backports; urgency=high
[ Christos Trochalakis ]
* Rebuild for wheezy-backports.
-- Christos Trochalakis <yatiohi@ideopolis.gr> Tue, 07 Jun 2016 11:18:23 +0300
nginx (1.6.2-5+deb8u2) jessie-security; urgency=high
[ Christos Trochalakis ]
* Fixes CVE-2016-4450
NULL pointer dereference while writing client request body.
(Closes: #825960)
-- Christos Trochalakis <yatiohi@ideopolis.gr> Tue, 31 May 2016 22:55:34 +0300
nginx (1.6.2-5+deb8u1) jessie-security; urgency=high
[ Christos Trochalakis ]
* Fixes multiple resolver CVEs,
CVE-2016-0742, CVE-2016-0746, CVE-2016-0747
Closes: #812806
-- Christos Trochalakis <yatiohi@ideopolis.gr> Wed, 27 Jan 2016 12:22:00 +0200
nginx (1.6.2-5) unstable; urgency=medium
[ Christos Trochalakis ]

View file

@ -0,0 +1,21 @@
From: Roman Arutyunyan <arut@nginx.com>
Date: Tue, 26 Jan 2016 16:46:18 +0300
Subject: Resolver: fixed possible segmentation fault on DNS format error.
---
src/core/ngx_resolver.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/core/ngx_resolver.c b/src/core/ngx_resolver.c
index 5a944fc..726de9b 100644
--- a/src/core/ngx_resolver.c
+++ b/src/core/ngx_resolver.c
@@ -1287,7 +1287,7 @@ ngx_resolver_process_response(ngx_resolver_t *r, u_char *buf, size_t n)
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);

View file

@ -0,0 +1,128 @@
From: Ruslan Ermilov <ru@nginx.com>
Date: Tue, 26 Jan 2016 16:46:31 +0300
Subject: 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.
---
src/core/ngx_resolver.c | 50 +++++++++++++++++++++++++++++++++----------------
1 file changed, 34 insertions(+), 16 deletions(-)
diff --git a/src/core/ngx_resolver.c b/src/core/ngx_resolver.c
index 726de9b..8ebef6f 100644
--- a/src/core/ngx_resolver.c
+++ b/src/core/ngx_resolver.c
@@ -417,7 +417,7 @@ ngx_resolve_name_done(ngx_resolver_ctx_t *ctx)
/* lock name mutex */
- if (ctx->state == NGX_AGAIN) {
+ if (ctx->state == NGX_AGAIN || ctx->state == NGX_RESOLVE_TIMEDOUT) {
hash = ngx_crc32_short(ctx->name.data, ctx->name.len);
@@ -571,6 +571,20 @@ ngx_resolve_name_locked(ngx_resolver_t *r, ngx_resolver_ctx_t *ctx)
if (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);
+ }
+
ctx->next = rn->waiting;
rn->waiting = ctx;
ctx->state = NGX_AGAIN;
@@ -664,7 +678,7 @@ ngx_resolve_name_locked(ngx_resolver_t *r, 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;
ctx->ident = -1;
@@ -794,6 +808,18 @@ 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;
@@ -857,7 +883,7 @@ 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;
ctx->ident = -1;
@@ -949,7 +975,7 @@ ngx_resolve_addr_done(ngx_resolver_ctx_t *ctx)
/* lock addr mutex */
- if (ctx->state == NGX_AGAIN) {
+ if (ctx->state == NGX_AGAIN || ctx->state == NGX_RESOLVE_TIMEDOUT) {
switch (ctx->addr.sockaddr->sa_family) {
@@ -2791,21 +2817,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);
}

View file

@ -0,0 +1,78 @@
From: Ruslan Ermilov <ru@nginx.com>
Date: Tue, 26 Jan 2016 16:46:38 +0300
Subject: Resolver: fixed CNAME processing for several requests.
When several requests were waiting for a response, then after getting
a CNAME response only the last request was properly processed, while
others were left waiting.
---
src/core/ngx_resolver.c | 21 +++++++++++++++------
1 file changed, 15 insertions(+), 6 deletions(-)
diff --git a/src/core/ngx_resolver.c b/src/core/ngx_resolver.c
index 8ebef6f..3c01584 100644
--- a/src/core/ngx_resolver.c
+++ b/src/core/ngx_resolver.c
@@ -468,7 +468,7 @@ ngx_resolve_name_locked(ngx_resolver_t *r, ngx_resolver_ctx_t *ctx)
ngx_int_t rc;
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);
@@ -479,6 +479,9 @@ ngx_resolve_name_locked(ngx_resolver_t *r, ngx_resolver_ctx_t *ctx)
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");
@@ -506,7 +509,7 @@ ngx_resolve_name_locked(ngx_resolver_t *r, ngx_resolver_ctx_t *ctx)
}
}
- ctx->next = rn->waiting;
+ last->next = rn->waiting;
rn->waiting = NULL;
/* unlock name mutex */
@@ -552,7 +555,7 @@ ngx_resolve_name_locked(ngx_resolver_t *r, ngx_resolver_ctx_t *ctx)
return ngx_resolve_name_locked(r, ctx);
}
- ctx->next = rn->waiting;
+ last->next = rn->waiting;
rn->waiting = NULL;
/* unlock name mutex */
@@ -585,7 +588,7 @@ ngx_resolve_name_locked(ngx_resolver_t *r, ngx_resolver_ctx_t *ctx)
ngx_add_timer(ctx->event, ctx->timeout);
}
- ctx->next = rn->waiting;
+ last->next = rn->waiting;
rn->waiting = ctx;
ctx->state = NGX_AGAIN;
@@ -656,8 +659,14 @@ ngx_resolve_name_locked(ngx_resolver_t *r, ngx_resolver_ctx_t *ctx)
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;
}

View file

@ -0,0 +1,179 @@
From: Roman Arutyunyan <arut@nginx.com>
Date: Tue, 26 Jan 2016 16:46:48 +0300
Subject: Resolver: changed the ngx_resolver_create_*_query() arguments.
No functional changes.
This is needed by the following change.
---
src/core/ngx_resolver.c | 57 +++++++++++++++++++++++--------------------------
1 file changed, 27 insertions(+), 30 deletions(-)
diff --git a/src/core/ngx_resolver.c b/src/core/ngx_resolver.c
index 3c01584..1899564 100644
--- a/src/core/ngx_resolver.c
+++ b/src/core/ngx_resolver.c
@@ -59,10 +59,10 @@ 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);
@@ -646,7 +646,7 @@ ngx_resolve_name_locked(ngx_resolver_t *r, ngx_resolver_ctx_t *ctx)
ngx_rbtree_insert(&r->name_rbtree, &rn->node);
}
- rc = ngx_resolver_create_name_query(rn, ctx);
+ rc = ngx_resolver_create_name_query(r, rn, &ctx->name);
if (rc == NGX_ERROR) {
goto failed;
@@ -873,7 +873,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;
}
@@ -2506,27 +2506,23 @@ ngx_resolver_rbtree_insert_addr6_value(ngx_rbtree_node_t *temp,
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;
@@ -2545,8 +2541,8 @@ ngx_resolver_create_name_query(ngx_resolver_node_t *rn, ngx_resolver_ctx_t *ctx)
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);
@@ -2576,11 +2572,11 @@ ngx_resolver_create_name_query(ngx_resolver_node_t *rn, ngx_resolver_ctx_t *ctx)
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++;
@@ -2616,8 +2612,8 @@ ngx_resolver_create_name_query(ngx_resolver_node_t *rn, ngx_resolver_ctx_t *ctx)
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);
@@ -2634,11 +2630,12 @@ 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)
+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;
@@ -2647,7 +2644,7 @@ ngx_resolver_create_addr_query(ngx_resolver_node_t *rn, ngx_resolver_ctx_t *ctx)
struct sockaddr_in6 *sin6;
#endif
- switch (ctx->addr.sockaddr->sa_family) {
+ switch (addr->sockaddr->sa_family) {
#if (NGX_HAVE_INET6)
case AF_INET6:
@@ -2664,7 +2661,7 @@ ngx_resolver_create_addr_query(ngx_resolver_node_t *rn, ngx_resolver_ctx_t *ctx)
+ sizeof(ngx_resolver_qs_t);
}
- p = ngx_resolver_alloc(ctx->resolver, len);
+ p = ngx_resolver_alloc(r, len);
if (p == NULL) {
return NGX_ERROR;
}
@@ -2688,11 +2685,11 @@ ngx_resolver_create_addr_query(ngx_resolver_node_t *rn, ngx_resolver_ctx_t *ctx)
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",
@@ -2707,11 +2704,11 @@ ngx_resolver_create_addr_query(ngx_resolver_node_t *rn, ngx_resolver_ctx_t *ctx)
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;
}

View file

@ -0,0 +1,248 @@
From: Roman Arutyunyan <arut@nginx.com>
Date: Tue, 26 Jan 2016 16:46:59 +0300
Subject: Resolver: fixed use-after-free memory accesses with CNAME.
When several requests were waiting for a response, then after getting
a CNAME response only the last request's context had the name updated.
Contexts of other requests had the wrong name. This name was used by
ngx_resolve_name_done() to find the node to remove the request context
from. When the name was wrong, the request could not be properly
cancelled, its context was freed but stayed linked to the node's waiting
list. This happened e.g. when the first request was aborted or timed
out before the resolving completed. When it completed, this triggered
a use-after-free memory access by calling ctx->handler of already freed
request context. The bug manifests itself by
"could not cancel <name> resolving" alerts in error_log.
When a request was responded with a CNAME, the request context kept
the pointer to the original node's rn->u.cname. If the original node
expired before the resolving timed out or completed with an error,
this would trigger a use-after-free memory access via ctx->name in
ctx->handler().
The fix is to keep ctx->name unmodified. The name from context
is no longer used by ngx_resolve_name_done(). Instead, we now keep
the pointer to resolver node to which this request is linked.
Keeping the original name intact also improves logging.
---
src/core/ngx_resolver.c | 72 +++++++++++++++++++++++--------------------------
src/core/ngx_resolver.h | 2 ++
2 files changed, 35 insertions(+), 39 deletions(-)
diff --git a/src/core/ngx_resolver.c b/src/core/ngx_resolver.c
index 1899564..2bd754c 100644
--- a/src/core/ngx_resolver.c
+++ b/src/core/ngx_resolver.c
@@ -54,7 +54,7 @@ ngx_int_t ngx_udp_connect(ngx_udp_connection_t *uc);
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,
@@ -370,7 +370,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;
@@ -397,7 +397,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;
@@ -419,9 +418,7 @@ ngx_resolve_name_done(ngx_resolver_ctx_t *ctx)
if (ctx->state == NGX_AGAIN || ctx->state == NGX_RESOLVE_TIMEDOUT) {
- hash = ngx_crc32_short(ctx->name.data, ctx->name.len);
-
- rn = ngx_resolver_lookup_name(r, &ctx->name, hash);
+ rn = ctx->node;
if (rn) {
p = &rn->waiting;
@@ -462,20 +459,22 @@ 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, *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) {
@@ -549,10 +548,10 @@ ngx_resolve_name_locked(ngx_resolver_t *r, ngx_resolver_ctx_t *ctx)
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);
}
last->next = rn->waiting;
@@ -592,6 +591,11 @@ ngx_resolve_name_locked(ngx_resolver_t *r, ngx_resolver_ctx_t *ctx)
rn->waiting = ctx;
ctx->state = NGX_AGAIN;
+ do {
+ ctx->node = rn;
+ ctx = ctx->next;
+ } while (ctx);
+
return NGX_AGAIN;
}
@@ -630,14 +634,14 @@ ngx_resolve_name_locked(ngx_resolver_t *r, ngx_resolver_ctx_t *ctx)
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;
@@ -646,7 +650,7 @@ ngx_resolve_name_locked(ngx_resolver_t *r, ngx_resolver_ctx_t *ctx)
ngx_rbtree_insert(&r->name_rbtree, &rn->node);
}
- rc = ngx_resolver_create_name_query(r, rn, &ctx->name);
+ rc = ngx_resolver_create_name_query(r, rn, name);
if (rc == NGX_ERROR) {
goto failed;
@@ -710,6 +714,11 @@ ngx_resolve_name_locked(ngx_resolver_t *r, ngx_resolver_ctx_t *ctx)
ctx->state = NGX_AGAIN;
+ do {
+ ctx->node = rn;
+ ctx = ctx->next;
+ } while (ctx);
+
return NGX_AGAIN;
failed:
@@ -832,6 +841,7 @@ ngx_resolve_addr(ngx_resolver_ctx_t *ctx)
ctx->next = rn->waiting;
rn->waiting = ctx;
ctx->state = NGX_AGAIN;
+ ctx->node = rn;
/* unlock addr mutex */
@@ -917,6 +927,7 @@ ngx_resolve_addr(ngx_resolver_ctx_t *ctx)
/* unlock addr mutex */
ctx->state = NGX_AGAIN;
+ ctx->node = rn;
return NGX_OK;
@@ -947,17 +958,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;
@@ -986,21 +991,7 @@ ngx_resolve_addr_done(ngx_resolver_ctx_t *ctx)
if (ctx->state == NGX_AGAIN || ctx->state == NGX_RESOLVE_TIMEDOUT) {
- 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
-
- 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;
@@ -1989,9 +1980,12 @@ ngx_resolver_process_a(ngx_resolver_t *r, u_char *buf, size_t last,
rn->waiting = NULL;
if (ctx) {
- ctx->name = name;
- (void) ngx_resolve_name_locked(r, ctx);
+ for (next = ctx; next; next = next->next) {
+ next->node = NULL;
+ }
+
+ (void) ngx_resolve_name_locked(r, ctx, &name);
}
ngx_resolver_free(r, rn->query);
diff --git a/src/core/ngx_resolver.h b/src/core/ngx_resolver.h
index 264c8c4..0186e22 100644
--- a/src/core/ngx_resolver.h
+++ b/src/core/ngx_resolver.h
@@ -161,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;
};

View file

@ -0,0 +1,60 @@
From: Ruslan Ermilov <ru@nginx.com>
Date: Tue, 26 Jan 2016 16:47:14 +0300
Subject: Resolver: limited CNAME recursion.
Previously, the recursion was only limited for cached responses.
---
src/core/ngx_resolver.c | 28 ++++++++++++++++++++++------
1 file changed, 22 insertions(+), 6 deletions(-)
diff --git a/src/core/ngx_resolver.c b/src/core/ngx_resolver.c
index 2bd754c..25d643d 100644
--- a/src/core/ngx_resolver.c
+++ b/src/core/ngx_resolver.c
@@ -1976,11 +1976,33 @@ ngx_resolver_process_a(ngx_resolver_t *r, u_char *buf, size_t last,
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) {
+ if (ctx->recursion++ >= NGX_RESOLVER_MAX_RECURSION) {
+
+ /* 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;
}
@@ -1988,12 +2010,6 @@ ngx_resolver_process_a(ngx_resolver_t *r, u_char *buf, size_t last,
(void) ngx_resolve_name_locked(r, ctx, &name);
}
- ngx_resolver_free(r, rn->query);
- rn->query = NULL;
-#if (NGX_HAVE_INET6)
- rn->query6 = NULL;
-#endif
-
/* unlock name mutex */
return;

View file

@ -0,0 +1,39 @@
From: Maxim Dounin <mdounin@mdounin.ru>
Date: Tue, 31 May 2016 05:13:30 +0300
Subject: Core: skip special buffers on writing (ticket #981).
A special last buffer with cl->buf->pos set to NULL can be present in
a chain when writing request body if chunked encoding was used. This
resulted in a NULL pointer dereference if it happened to be the only
buffer left after a do...while loop iteration in ngx_write_chain_to_file().
The problem originally appeared in nginx 1.3.9 with chunked encoding
support. Additionally, rev. 3832b608dc8d (nginx 1.9.13) changed the
minimum number of buffers to trigger this from IOV_MAX (typically 1024)
to NGX_IOVS_PREALLOCATE (typically 64).
Fix is to skip such buffers in ngx_chain_to_iovec(), much like it is
done in other places.
Backported by 1.11.1 for debian.
---
src/os/unix/ngx_files.c | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/src/os/unix/ngx_files.c b/src/os/unix/ngx_files.c
index c3ae47f..1970184 100644
--- a/src/os/unix/ngx_files.c
+++ b/src/os/unix/ngx_files.c
@@ -183,6 +183,12 @@ ngx_write_chain_to_file(ngx_file_t *file, ngx_chain_t *cl, off_t offset,
/* create the iovec and coalesce the neighbouring bufs */
while (cl && vec.nelts < IOV_MAX) {
+
+ if (ngx_buf_special(cl->buf)) {
+ cl = cl->next;
+ continue;
+ }
+
if (prev == cl->buf->pos) {
iov->iov_len += cl->buf->last - cl->buf->pos;

View file

@ -1 +1,8 @@
perl-use-dpkg-buildflags.patch
0003-Resolver-fixed-possible-segmentation-fault-on-DNS-fo.patch
0004-Resolver-fixed-crashes-in-timeout-handler.patch
0005-Resolver-fixed-CNAME-processing-for-several-requests.patch
0006-Resolver-changed-the-ngx_resolver_create_-_query-arg.patch
0007-Resolver-fixed-use-after-free-memory-accesses-with-C.patch
0008-Resolver-limited-CNAME-recursion.patch
0009-Core-skip-special-buffers-on-writing-ticket-981.patch