Fix various CVEs from 1.8.1
This commit is contained in:
parent
310718c028
commit
2f9b55b87b
181
nginx-1.6.3-Resolver-change-ngx_resolver_create-arguments.patch
Normal file
181
nginx-1.6.3-Resolver-change-ngx_resolver_create-arguments.patch
Normal 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;
|
||||
}
|
80
nginx-1.6.3-Resolver-fix-CNAME-processing.patch
Normal file
80
nginx-1.6.3-Resolver-fix-CNAME-processing.patch
Normal 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;
|
||||
}
|
134
nginx-1.6.3-Resolver-fix-crashes-in-timeout-handler.patch
Normal file
134
nginx-1.6.3-Resolver-fix-crashes-in-timeout-handler.patch
Normal 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
|
||||
|
22
nginx-1.6.3-Resolver-fix-possible-segmentation-fault.patch
Normal file
22
nginx-1.6.3-Resolver-fix-possible-segmentation-fault.patch
Normal 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);
|
252
nginx-1.6.3-Resolver-fix-use-after-free-with-CNAME.patch
Normal file
252
nginx-1.6.3-Resolver-fix-use-after-free-with-CNAME.patch
Normal 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;
|
||||
};
|
||||
|
||||
|
68
nginx-1.6.3-Resolver-limit-CNAME-recursion.patch
Normal file
68
nginx-1.6.3-Resolver-limit-CNAME-recursion.patch
Normal 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;
|
23
nginx.spec
23
nginx.spec
@ -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)
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user