Merge branch 'nginx' (nginx-1.13.3).

Change-Id: Id47104dc65ce8e6479304589c892961011edb753
Signed-off-by: Piotr Sikora <piotrsikora@google.com>
diff --git a/.hgtags b/.hgtags
index 849abee..62a304a 100644
--- a/.hgtags
+++ b/.hgtags
@@ -415,3 +415,4 @@
 3671096a45bce570a2afa20b9faf42c7fb0f7e66 release-1.13.0
 539f7893ecb96bee60965528c8958d7eb2f1ce6b release-1.13.1
 5be2b25bdc65775a85f18f68a4be4f58c7384415 release-1.13.2
+8457ce87640f9bfe6221c4ac4466ced20e03bebe release-1.13.3
diff --git a/BUILD b/BUILD
index 0a3141c..7330d05 100644
--- a/BUILD
+++ b/BUILD
@@ -1468,5 +1468,5 @@
     preinst = "@nginx_pkgoss//:debian_preinst",
     prerm = "@nginx_pkgoss//:debian_prerm",
     section = "httpd",
-    version = "1.13.2",
+    version = "1.13.3",
 )
diff --git a/build.bzl b/build.bzl
index b5a8c99..09469c1 100644
--- a/build.bzl
+++ b/build.bzl
@@ -663,7 +663,7 @@
         name = "nginx_pkgoss",
         build_file_content = _PKGOSS_BUILD_FILE.format(nginx = nginx) +
                              _PKGOSS_BUILD_FILE_TAIL,
-        commit = "0be78ae1bf9b0fbb97b94e2569581bb77ff4cb60",  # nginx-1.13.2
+        commit = "0f32bf04f8e7599eca0083d0670b53baeab5b98c",  # nginx-1.13.3
         remote = "https://nginx.googlesource.com/nginx-pkgoss",
     )
 
diff --git a/docs/xml/nginx/changes.xml b/docs/xml/nginx/changes.xml
index 535704c..e2da1e4 100644
--- a/docs/xml/nginx/changes.xml
+++ b/docs/xml/nginx/changes.xml
@@ -5,6 +5,26 @@
 <change_log title="nginx">
 
 
+<changes ver="1.13.3" date="2017-07-11">
+
+<change type="security">
+<para lang="ru">
+специально созданный запрос мог вызвать целочисленное переполнение
+в range-фильтре и последующую некорректную обработку запрошенных диапазонов,
+что потенциально могло привести к утечке конфиденциальной информации
+(CVE-2017-7529).
+</para>
+<para lang="en">
+a specially crafted request might result in an integer overflow
+and incorrect processing of ranges in the range filter,
+potentially resulting in sensitive information leak
+(CVE-2017-7529).
+</para>
+</change>
+
+</changes>
+
+
 <changes ver="1.13.2" date="2017-06-27">
 
 <change type="change">
diff --git a/src/core/nginx.h b/src/core/nginx.h
index 9718bd2..a43efd5 100644
--- a/src/core/nginx.h
+++ b/src/core/nginx.h
@@ -13,8 +13,8 @@
 #define NGINX_NAME         "nginx"
 #endif
 
-#define nginx_version      1013002
-#define NGINX_VERSION      "1.13.2"
+#define nginx_version      1013003
+#define NGINX_VERSION      "1.13.3"
 #define NGINX_VER          NGINX_NAME "/" NGINX_VERSION
 
 #ifdef NGX_BUILD
diff --git a/src/core/ngx_resolver.c b/src/core/ngx_resolver.c
index 91f8a5e..cd55520 100644
--- a/src/core/ngx_resolver.c
+++ b/src/core/ngx_resolver.c
@@ -105,6 +105,8 @@
     ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel);
 static ngx_int_t ngx_resolver_copy(ngx_resolver_t *r, ngx_str_t *name,
     u_char *buf, u_char *src, u_char *last);
+static ngx_int_t ngx_resolver_set_timeout(ngx_resolver_t *r,
+    ngx_resolver_ctx_t *ctx);
 static void ngx_resolver_timeout_handler(ngx_event_t *ev);
 static void ngx_resolver_free_node(ngx_resolver_t *r, ngx_resolver_node_t *rn);
 static void *ngx_resolver_alloc(ngx_resolver_t *r, size_t size);
@@ -189,6 +191,7 @@
     r->event->handler = ngx_resolver_resend_handler;
     r->event->data = r;
     r->event->log = &cf->cycle->new_log;
+    r->event->cancelable = 1;
     r->ident = -1;
 
     r->resend_timeout = 5;
@@ -728,19 +731,8 @@
         }
 
         if (rn->waiting) {
-
-            if (ctx->event == NULL && ctx->timeout) {
-                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);
+            if (ngx_resolver_set_timeout(r, ctx) != NGX_OK) {
+                return NGX_ERROR;
             }
 
             last->next = rn->waiting;
@@ -864,18 +856,8 @@
         goto failed;
     }
 
-    if (ctx->event == NULL && ctx->timeout) {
-        ctx->event = ngx_resolver_calloc(r, sizeof(ngx_event_t));
-        if (ctx->event == NULL) {
-            goto failed;
-        }
-
-        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);
+    if (ngx_resolver_set_timeout(r, ctx) != NGX_OK) {
+        goto failed;
     }
 
     if (ngx_resolver_resend_empty(r)) {
@@ -1007,19 +989,8 @@
         }
 
         if (rn->waiting) {
-
-            if (ctx->event == NULL && ctx->timeout) {
-                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);
+            if (ngx_resolver_set_timeout(r, ctx) != NGX_OK) {
+                return NGX_ERROR;
             }
 
             ctx->next = rn->waiting;
@@ -1089,18 +1060,8 @@
         goto failed;
     }
 
-    if (ctx->event == NULL && ctx->timeout) {
-        ctx->event = ngx_resolver_calloc(r, sizeof(ngx_event_t));
-        if (ctx->event == NULL) {
-            goto failed;
-        }
-
-        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);
+    if (ngx_resolver_set_timeout(r, ctx) != NGX_OK) {
+        goto failed;
     }
 
     if (ngx_resolver_resend_empty(r)) {
@@ -3034,25 +2995,15 @@
 
         addrs = ngx_resolver_calloc(r, cctx->naddrs * sizeof(ngx_addr_t));
         if (addrs == NULL) {
-            ngx_resolve_name_done(cctx);
-
-            ctx->state = NGX_ERROR;
-            ctx->valid = ngx_time() + (r->valid ? r->valid : 10);
-
-            ctx->handler(ctx);
-            return;
+            srv->state = NGX_ERROR;
+            goto done;
         }
 
         sockaddr = ngx_resolver_alloc(r, cctx->naddrs * sizeof(ngx_sockaddr_t));
         if (sockaddr == NULL) {
             ngx_resolver_free(r, addrs);
-            ngx_resolve_name_done(cctx);
-
-            ctx->state = NGX_ERROR;
-            ctx->valid = ngx_time() + (r->valid ? r->valid : 10);
-
-            ctx->handler(ctx);
-            return;
+            srv->state = NGX_ERROR;
+            goto done;
         }
 
         for (i = 0; i < cctx->naddrs; i++) {
@@ -3069,6 +3020,8 @@
         srv->naddrs = cctx->naddrs;
     }
 
+done:
+
     ngx_resolve_name_done(cctx);
 
     if (ctx->count == 0) {
@@ -4041,6 +3994,30 @@
 }
 
 
+static ngx_int_t
+ngx_resolver_set_timeout(ngx_resolver_t *r, ngx_resolver_ctx_t *ctx)
+{
+    if (ctx->event || ctx->timeout == 0) {
+        return NGX_OK;
+    }
+
+    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->event->cancelable = ctx->cancelable;
+    ctx->ident = -1;
+
+    ngx_add_timer(ctx->event, ctx->timeout);
+
+    return NGX_OK;
+}
+
+
 static void
 ngx_resolver_timeout_handler(ngx_event_t *ev)
 {
@@ -4254,10 +4231,21 @@
     ngx_resolver_addr_t      *addrs;
     ngx_resolver_srv_name_t  *srvs;
 
+    srvs = ctx->srvs;
+    nsrvs = ctx->nsrvs;
+
     naddrs = 0;
 
-    for (i = 0; i < ctx->nsrvs; i++) {
-        naddrs += ctx->srvs[i].naddrs;
+    for (i = 0; i < nsrvs; i++) {
+        if (srvs[i].state == NGX_ERROR) {
+            ctx->state = NGX_ERROR;
+            ctx->valid = ngx_time() + (r->valid ? r->valid : 10);
+
+            ctx->handler(ctx);
+            return;
+        }
+
+        naddrs += srvs[i].naddrs;
     }
 
     if (naddrs == 0) {
@@ -4277,9 +4265,6 @@
         return;
     }
 
-    srvs = ctx->srvs;
-    nsrvs = ctx->nsrvs;
-
     i = 0;
     n = 0;
 
diff --git a/src/core/ngx_resolver.h b/src/core/ngx_resolver.h
index 6f099b7..0bd3921 100644
--- a/src/core/ngx_resolver.h
+++ b/src/core/ngx_resolver.h
@@ -220,6 +220,7 @@
 
     unsigned                  quick:1;
     unsigned                  async:1;
+    unsigned                  cancelable:1;
     ngx_uint_t                recursion;
     ngx_event_t              *event;
 };
diff --git a/src/core/ngx_slab.c b/src/core/ngx_slab.c
index 1d4ce2b..9e7796d 100644
--- a/src/core/ngx_slab.c
+++ b/src/core/ngx_slab.c
@@ -181,8 +181,8 @@
 ngx_slab_alloc_locked(ngx_slab_pool_t *pool, size_t size)
 {
     size_t            s;
-    uintptr_t         p, n, m, mask, *bitmap;
-    ngx_uint_t        i, slot, shift, map;
+    uintptr_t         p, m, mask, *bitmap;
+    ngx_uint_t        i, n, slot, shift, map;
     ngx_slab_page_t  *page, *prev, *slots;
 
     if (size > ngx_slab_max_size) {
@@ -226,7 +226,7 @@
 
             bitmap = (uintptr_t *) ngx_slab_page_addr(pool, page);
 
-            map = (ngx_pagesize >> shift) / (sizeof(uintptr_t) * 8);
+            map = (ngx_pagesize >> shift) / (8 * sizeof(uintptr_t));
 
             for (n = 0; n < map; n++) {
 
@@ -239,7 +239,7 @@
 
                         bitmap[n] |= m;
 
-                        i = (n * sizeof(uintptr_t) * 8 + i) << shift;
+                        i = (n * 8 * sizeof(uintptr_t) + i) << shift;
 
                         p = (uintptr_t) bitmap + i;
 
@@ -339,11 +339,17 @@
             }
 
             /* "n" elements for bitmap, plus one requested */
-            bitmap[0] = ((uintptr_t) 2 << n) - 1;
 
-            map = (ngx_pagesize >> shift) / (sizeof(uintptr_t) * 8);
+            for (i = 0; i < (n + 1) / (8 * sizeof(uintptr_t)); i++) {
+                bitmap[i] = NGX_SLAB_BUSY;
+            }
 
-            for (i = 1; i < map; i++) {
+            m = ((uintptr_t) 1 << ((n + 1) % (8 * sizeof(uintptr_t)))) - 1;
+            bitmap[i] = m;
+
+            map = (ngx_pagesize >> shift) / (8 * sizeof(uintptr_t));
+
+            for (i = i + 1; i < map; i++) {
                 bitmap[i] = 0;
             }
 
@@ -369,7 +375,7 @@
 
             slots[slot].next = page;
 
-            pool->stats[slot].total += sizeof(uintptr_t) * 8;
+            pool->stats[slot].total += 8 * sizeof(uintptr_t);
 
             p = ngx_slab_page_addr(pool, page);
 
@@ -480,8 +486,8 @@
         }
 
         n = ((uintptr_t) p & (ngx_pagesize - 1)) >> shift;
-        m = (uintptr_t) 1 << (n % (sizeof(uintptr_t) * 8));
-        n /= sizeof(uintptr_t) * 8;
+        m = (uintptr_t) 1 << (n % (8 * sizeof(uintptr_t)));
+        n /= 8 * sizeof(uintptr_t);
         bitmap = (uintptr_t *)
                              ((uintptr_t) p & ~((uintptr_t) ngx_pagesize - 1));
 
@@ -506,13 +512,16 @@
                 n = 1;
             }
 
-            if (bitmap[0] & ~(((uintptr_t) 1 << n) - 1)) {
+            i = n / (8 * sizeof(uintptr_t));
+            m = ((uintptr_t) 1 << (n % (8 * sizeof(uintptr_t)))) - 1;
+
+            if (bitmap[i] & ~m) {
                 goto done;
             }
 
-            map = (ngx_pagesize >> shift) / (sizeof(uintptr_t) * 8);
+            map = (ngx_pagesize >> shift) / (8 * sizeof(uintptr_t));
 
-            for (i = 1; i < map; i++) {
+            for (i = i + 1; i < map; i++) {
                 if (bitmap[i]) {
                     goto done;
                 }
@@ -558,7 +567,7 @@
 
             ngx_slab_free_pages(pool, page, 1);
 
-            pool->stats[slot].total -= sizeof(uintptr_t) * 8;
+            pool->stats[slot].total -= 8 * sizeof(uintptr_t);
 
             goto done;
         }
diff --git a/src/http/modules/ngx_http_proxy_module.c b/src/http/modules/ngx_http_proxy_module.c
index bc8d2a7..fae90e7 100644
--- a/src/http/modules/ngx_http_proxy_module.c
+++ b/src/http/modules/ngx_http_proxy_module.c
@@ -1150,8 +1150,8 @@
 static ngx_int_t
 ngx_http_proxy_create_request(ngx_http_request_t *r)
 {
-    size_t                        len, uri_len, loc_len, body_len;
-    size_t                        key_len, val_len;
+    size_t                        len, uri_len, loc_len, body_len,
+                                  key_len, val_len;
     uintptr_t                     escape;
     ngx_buf_t                    *b;
     ngx_str_t                     method;
@@ -1266,18 +1266,20 @@
     le.flushed = 1;
 
     while (*(uintptr_t *) le.ip) {
+
         lcode = *(ngx_http_script_len_code_pt *) le.ip;
         key_len = lcode(&le);
 
         for (val_len = 0; *(uintptr_t *) le.ip; val_len += lcode(&le)) {
             lcode = *(ngx_http_script_len_code_pt *) le.ip;
         }
+        le.ip += sizeof(uintptr_t);
 
-        if (val_len) {
-            len += key_len + sizeof(": ") - 1 + val_len + sizeof(CRLF) - 1;
+        if (val_len == 0) {
+            continue;
         }
 
-        le.ip += sizeof(uintptr_t);
+        len += key_len + sizeof(": ") - 1 + val_len + sizeof(CRLF) - 1;
     }
 
 
@@ -1377,34 +1379,41 @@
     le.ip = headers->lengths->elts;
 
     while (*(uintptr_t *) le.ip) {
+
         lcode = *(ngx_http_script_len_code_pt *) le.ip;
         (void) lcode(&le);
 
         for (val_len = 0; *(uintptr_t *) le.ip; val_len += lcode(&le)) {
             lcode = *(ngx_http_script_len_code_pt *) le.ip;
         }
-
         le.ip += sizeof(uintptr_t);
 
-        e.skip = (val_len == 0) ? 1 : 0;
+        if (val_len == 0) {
+            e.skip = 1;
+
+            while (*(uintptr_t *) e.ip) {
+                code = *(ngx_http_script_code_pt *) e.ip;
+                code((ngx_http_script_engine_t *) &e);
+            }
+            e.ip += sizeof(uintptr_t);
+
+            e.skip = 0;
+
+            continue;
+        }
 
         code = *(ngx_http_script_code_pt *) e.ip;
         code((ngx_http_script_engine_t *) &e);
 
-        if (!e.skip) {
-            *e.pos++ = ':'; *e.pos++ = ' ';
-        }
+        *e.pos++ = ':'; *e.pos++ = ' ';
 
         while (*(uintptr_t *) e.ip) {
             code = *(ngx_http_script_code_pt *) e.ip;
             code((ngx_http_script_engine_t *) &e);
         }
-
-        if (!e.skip) {
-            *e.pos++ = CR; *e.pos++ = LF;
-        }
-
         e.ip += sizeof(uintptr_t);
+
+        *e.pos++ = CR; *e.pos++ = LF;
     }
 
     b->last = e.pos;
@@ -3552,7 +3561,7 @@
 
         size = (sizeof(ngx_http_script_copy_code_t)
                 + src[i].key.len + sizeof(uintptr_t) - 1)
-                & ~(sizeof(uintptr_t) - 1);
+               & ~(sizeof(uintptr_t) - 1);
 
         copy = ngx_array_push_n(headers->values, size);
         if (copy == NULL) {
@@ -3565,44 +3574,16 @@
         p = (u_char *) copy + sizeof(ngx_http_script_copy_code_t);
         ngx_memcpy(p, src[i].key.data, src[i].key.len);
 
-        if (ngx_http_script_variables_count(&src[i].value) == 0) {
-            copy = ngx_array_push_n(headers->lengths,
-                                    sizeof(ngx_http_script_copy_code_t));
-            if (copy == NULL) {
-                return NGX_ERROR;
-            }
+        ngx_memzero(&sc, sizeof(ngx_http_script_compile_t));
 
-            copy->code = (ngx_http_script_code_pt)
-                                                 ngx_http_script_copy_len_code;
-            copy->len = src[i].value.len;
+        sc.cf = cf;
+        sc.source = &src[i].value;
+        sc.flushes = &headers->flushes;
+        sc.lengths = &headers->lengths;
+        sc.values = &headers->values;
 
-            size = (sizeof(ngx_http_script_copy_code_t)
-                    + src[i].value.len + sizeof(uintptr_t) - 1)
-                    & ~(sizeof(uintptr_t) - 1);
-
-            copy = ngx_array_push_n(headers->values, size);
-            if (copy == NULL) {
-                return NGX_ERROR;
-            }
-
-            copy->code = ngx_http_script_copy_code;
-            copy->len = src[i].value.len;
-
-            p = (u_char *) copy + sizeof(ngx_http_script_copy_code_t);
-            ngx_memcpy(p, src[i].value.data, src[i].value.len);
-
-        } else {
-            ngx_memzero(&sc, sizeof(ngx_http_script_compile_t));
-
-            sc.cf = cf;
-            sc.source = &src[i].value;
-            sc.flushes = &headers->flushes;
-            sc.lengths = &headers->lengths;
-            sc.values = &headers->values;
-
-            if (ngx_http_script_compile(&sc) != NGX_OK) {
-                return NGX_ERROR;
-            }
+        if (ngx_http_script_compile(&sc) != NGX_OK) {
+            return NGX_ERROR;
         }
 
         code = ngx_array_push_n(headers->lengths, sizeof(uintptr_t));
diff --git a/src/http/modules/ngx_http_range_filter_module.c b/src/http/modules/ngx_http_range_filter_module.c
index 7ad9db9..292a2b8 100644
--- a/src/http/modules/ngx_http_range_filter_module.c
+++ b/src/http/modules/ngx_http_range_filter_module.c
@@ -355,7 +355,7 @@
         }
 
         if (suffix) {
-            start = content_length - end;
+            start = (end < content_length) ? content_length - end : 0;
             end = content_length - 1;
         }
 
@@ -377,6 +377,10 @@
             range->start = start;
             range->end = end;
 
+            if (size > NGX_MAX_OFF_T_VALUE - (end - start)) {
+                return NGX_HTTP_RANGE_NOT_SATISFIABLE;
+            }
+
             size += end - start;
 
             if (ranges-- == 0) {
diff --git a/src/http/ngx_http_variables.c b/src/http/ngx_http_variables.c
index 4be6550..031bae4 100644
--- a/src/http/ngx_http_variables.c
+++ b/src/http/ngx_http_variables.c
@@ -1463,17 +1463,15 @@
 ngx_http_variable_is_args(ngx_http_request_t *r,
     ngx_http_variable_value_t *v, uintptr_t data)
 {
-    v->valid = 1;
-    v->no_cacheable = 0;
-    v->not_found = 0;
-
     if (r->args.len == 0) {
-        v->len = 0;
-        v->data = NULL;
+        *v = ngx_http_variable_null_value;
         return NGX_OK;
     }
 
     v->len = 1;
+    v->valid = 1;
+    v->no_cacheable = 0;
+    v->not_found = 0;
     v->data = (u_char *) "?";
 
     return NGX_OK;
@@ -1990,11 +1988,7 @@
         return NGX_OK;
     }
 
-    v->len = 0;
-    v->valid = 1;
-    v->no_cacheable = 0;
-    v->not_found = 0;
-    v->data = (u_char *) "";
+    *v = ngx_http_variable_null_value;
 
     return NGX_OK;
 }