Fix various CVEs from 1.8.1

This commit is contained in:
Jamie Nguyen 2016-01-26 18:06:38 +00:00
parent 310718c028
commit 2f9b55b87b
7 changed files with 759 additions and 1 deletions

View File

@ -0,0 +1,181 @@
exporting patch:
# HG changeset patch
# User Roman Arutyunyan <arut@nginx.com>
# Date 1453816008 -10800
# Tue Jan 26 16:46:48 2016 +0300
# Branch stable-1.8
# Node ID 5557bf31e25da68d5cda19dbc91d86f47430df1f
# Parent 838946300825379ccdd3acfb131cf66d6ae3cb85
Resolver: changed the ngx_resolver_create_*_query() arguments.
No functional changes.
This is needed by the following change.
diff -r 838946300825 -r 5557bf31e25d src/core/ngx_resolver.c
--- a/src/core/ngx_resolver.c Tue Jan 26 16:46:38 2016 +0300
+++ b/src/core/ngx_resolver.c Tue Jan 26 16:46:48 2016 +0300
@@ -64,10 +64,10 @@
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);
@@ -651,7 +651,7 @@
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;
@@ -878,7 +878,7 @@
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;
}
@@ -2511,27 +2511,23 @@
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;
@@ -2550,8 +2546,8 @@
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);
@@ -2581,11 +2577,11 @@
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++;
@@ -2621,8 +2617,8 @@
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);
@@ -2639,11 +2635,12 @@
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;
@@ -2652,7 +2649,7 @@
struct sockaddr_in6 *sin6;
#endif
- switch (ctx->addr.sockaddr->sa_family) {
+ switch (addr->sockaddr->sa_family) {
#if (NGX_HAVE_INET6)
case AF_INET6:
@@ -2669,7 +2666,7 @@
+ sizeof(ngx_resolver_qs_t);
}
- p = ngx_resolver_alloc(ctx->resolver, len);
+ p = ngx_resolver_alloc(r, len);
if (p == NULL) {
return NGX_ERROR;
}
@@ -2693,11 +2690,11 @@
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",
@@ -2712,11 +2709,11 @@
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,80 @@
exporting patch:
# HG changeset patch
# User Ruslan Ermilov <ru@nginx.com>
# Date 1453815998 -10800
# Tue Jan 26 16:46:38 2016 +0300
# Branch stable-1.8
# Node ID 838946300825379ccdd3acfb131cf66d6ae3cb85
# Parent f63dd04c158062d73fcb6aff59124910fa1fae75
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.
diff -r f63dd04c1580 -r 838946300825 src/core/ngx_resolver.c
--- a/src/core/ngx_resolver.c Tue Jan 26 16:46:31 2016 +0300
+++ b/src/core/ngx_resolver.c Tue Jan 26 16:46:38 2016 +0300
@@ -473,7 +473,7 @@
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);
@@ -484,6 +484,9 @@
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");
@@ -511,7 +514,7 @@
}
}
- ctx->next = rn->waiting;
+ last->next = rn->waiting;
rn->waiting = NULL;
/* unlock name mutex */
@@ -557,7 +560,7 @@
return ngx_resolve_name_locked(r, ctx);
}
- ctx->next = rn->waiting;
+ last->next = rn->waiting;
rn->waiting = NULL;
/* unlock name mutex */
@@ -590,7 +593,7 @@
ngx_add_timer(ctx->event, ctx->timeout);
}
- ctx->next = rn->waiting;
+ last->next = rn->waiting;
rn->waiting = ctx;
ctx->state = NGX_AGAIN;
@@ -661,8 +664,14 @@
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,134 @@
exporting patch:
# HG changeset patch
# User Ruslan Ermilov <ru@nginx.com>
# Date 1453815991 -10800
# Tue Jan 26 16:46:31 2016 +0300
# Branch stable-1.8
# Node ID f63dd04c158062d73fcb6aff59124910fa1fae75
# Parent c36482d0a79fe0f2e1467f80ec2fbcd0a2d682c6
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.
diff --git a/src/core/ngx_resolver.c b/src/core/ngx_resolver.c
index fe0ce50..7aa88a6 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);
}
--
2.5.0

View File

@ -0,0 +1,22 @@
exporting patch:
# HG changeset patch
# User Roman Arutyunyan <arut@nginx.com>
# Date 1453815978 -10800
# Tue Jan 26 16:46:18 2016 +0300
# Branch stable-1.8
# Node ID c36482d0a79fe0f2e1467f80ec2fbcd0a2d682c6
# Parent e9a4531a2a5dabb9bee93cb8b41f24b8aeeba504
Resolver: fixed possible segmentation fault on DNS format error.
diff -r e9a4531a2a5d -r c36482d0a79f src/core/ngx_resolver.c
--- a/src/core/ngx_resolver.c Mon Jan 25 21:58:21 2016 +0300
+++ b/src/core/ngx_resolver.c Tue Jan 26 16:46:18 2016 +0300
@@ -1292,7 +1292,7 @@
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,252 @@
exporting patch:
# HG changeset patch
# User Roman Arutyunyan <arut@nginx.com>
# Date 1453816019 -10800
# Tue Jan 26 16:46:59 2016 +0300
# Branch stable-1.8
# Node ID dac6eda40475f08b7372159d78dad1e13cd5bc7f
# Parent 5557bf31e25da68d5cda19dbc91d86f47430df1f
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.
diff -r 5557bf31e25d -r dac6eda40475 src/core/ngx_resolver.c
--- a/src/core/ngx_resolver.c Tue Jan 26 16:46:48 2016 +0300
+++ b/src/core/ngx_resolver.c Tue Jan 26 16:46:59 2016 +0300
@@ -59,7 +59,7 @@
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,
@@ -375,7 +375,7 @@
/* 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;
@@ -402,7 +402,6 @@
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;
@@ -424,9 +423,7 @@
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;
@@ -467,20 +464,22 @@
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);
-
- hash = ngx_crc32_short(ctx->name.data, ctx->name.len);
-
- rn = ngx_resolver_lookup_name(r, &ctx->name, hash);
+ ngx_strlow(name->data, name->data, name->len);
+
+ hash = ngx_crc32_short(name->data, name->len);
+
+ rn = ngx_resolver_lookup_name(r, name, hash);
if (rn) {
@@ -554,10 +553,10 @@
if (ctx->recursion++ < NGX_RESOLVER_MAX_RECURSION) {
- ctx->name.len = rn->cnlen;
- ctx->name.data = rn->u.cname;
-
- return ngx_resolve_name_locked(r, ctx);
+ cname.len = rn->cnlen;
+ cname.data = rn->u.cname;
+
+ return ngx_resolve_name_locked(r, ctx, &cname);
}
last->next = rn->waiting;
@@ -597,6 +596,11 @@
rn->waiting = ctx;
ctx->state = NGX_AGAIN;
+ do {
+ ctx->node = rn;
+ ctx = ctx->next;
+ } while (ctx);
+
return NGX_AGAIN;
}
@@ -635,14 +639,14 @@
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;
@@ -651,7 +655,7 @@
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;
@@ -715,6 +719,11 @@
ctx->state = NGX_AGAIN;
+ do {
+ ctx->node = rn;
+ ctx = ctx->next;
+ } while (ctx);
+
return NGX_AGAIN;
failed:
@@ -837,6 +846,7 @@
ctx->next = rn->waiting;
rn->waiting = ctx;
ctx->state = NGX_AGAIN;
+ ctx->node = rn;
/* unlock addr mutex */
@@ -922,6 +932,7 @@
/* unlock addr mutex */
ctx->state = NGX_AGAIN;
+ ctx->node = rn;
return NGX_OK;
@@ -952,17 +963,11 @@
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;
@@ -991,21 +996,7 @@
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;
@@ -1994,9 +1985,12 @@
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 -r 5557bf31e25d -r dac6eda40475 src/core/ngx_resolver.h
--- a/src/core/ngx_resolver.h Tue Jan 26 16:46:48 2016 +0300
+++ b/src/core/ngx_resolver.h Tue Jan 26 16:46:59 2016 +0300
@@ -161,6 +161,8 @@
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,68 @@
exporting patch:
# HG changeset patch
# User Ruslan Ermilov <ru@nginx.com>
# Date 1453816034 -10800
# Tue Jan 26 16:47:14 2016 +0300
# Branch stable-1.8
# Node ID 93d70d87914c350948ab701cc99569680320e198
# Parent dac6eda40475f08b7372159d78dad1e13cd5bc7f
Resolver: limited CNAME recursion.
Previously, the recursion was only limited for cached responses.
diff -r dac6eda40475 -r 93d70d87914c src/core/ngx_resolver.c
--- a/src/core/ngx_resolver.c Tue Jan 26 16:46:59 2016 +0300
+++ b/src/core/ngx_resolver.c Tue Jan 26 16:47:14 2016 +0300
@@ -1981,24 +1981,40 @@
ngx_queue_insert_head(&r->name_expire_queue, &rn->queue);
- ctx = rn->waiting;
- rn->waiting = NULL;
-
- if (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);
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;
+ }
+
+ (void) ngx_resolve_name_locked(r, ctx, &name);
+ }
+
/* unlock name mutex */
return;

View File

@ -21,7 +21,7 @@
Name: nginx
Epoch: 1
Version: 1.6.3
Release: 7%{?dist}
Release: 8%{?dist}
Summary: A high performance web server and reverse proxy server
Group: System Environment/Daemons
@ -47,6 +47,16 @@ Source104: 50x.html
# -D_FORTIFY_SOURCE=2 causing warnings to turn into errors.
Patch0: nginx-auto-cc-gcc.patch
# Patches taken from 1.8.1 release. Only the second patch in this series
# failed to apply and had to be modified.
Patch10: nginx-1.6.3-Resolver-fix-possible-segmentation-fault.patch
Patch11: nginx-1.6.3-Resolver-fix-crashes-in-timeout-handler.patch
Patch12: nginx-1.6.3-Resolver-fix-CNAME-processing.patch
Patch13: nginx-1.6.3-Resolver-change-ngx_resolver_create-arguments.patch
Patch14: nginx-1.6.3-Resolver-fix-use-after-free-with-CNAME.patch
Patch15: nginx-1.6.3-Resolver-limit-CNAME-recursion.patch
BuildRequires: GeoIP-devel
BuildRequires: gd-devel
%if 0%{?with_gperftools}
@ -93,6 +103,12 @@ directories.
%prep
%setup -q
%patch0 -p0
%patch10 -p1
%patch11 -p1
%patch12 -p1
%patch13 -p1
%patch14 -p1
%patch15 -p1
%build
@ -256,6 +272,11 @@ fi
%changelog
* Tue Jan 26 2016 Jamie Nguyen <jamielinux@fedoraproject.org> - 1:1.6.3-8
- CVE-2016-0747: Insufficient limits of CNAME resolution in resolver
- CVE-2016-0746: Use-after-free during CNAME response processing in resolver
- CVE-2016-0742: Invalid pointer dereference in resolver
* Sun Oct 04 2015 Jamie Nguyen <jamielinux@fedoraproject.org> - 1:1.6.3-7
- remove PID file before starting nginx (#1268621)