changeset 6986:0cdee26605f3

Cleaned up r->headers_out.headers allocation error handling. If initialization of a header failed for some reason after ngx_list_push(), leaving the header as is can result in uninitialized memory access by the header filter or the log module. The fix is to clear partially initialized headers in case of errors. For the Cache-Control header, the fix is to postpone pushing r->headers_out.cache_control until its value is completed.
author Sergey Kandaurov <pluknet@nginx.com>
date Thu, 20 Apr 2017 18:26:37 +0300
parents 23ecffd5bcfe
children 5116cfea1e9a
files src/http/modules/ngx_http_auth_basic_module.c src/http/modules/ngx_http_dav_module.c src/http/modules/ngx_http_headers_filter_module.c src/http/modules/ngx_http_range_filter_module.c src/http/modules/ngx_http_static_module.c src/http/modules/perl/nginx.xs src/http/ngx_http_core_module.c src/http/ngx_http_upstream.c
diffstat 8 files changed, 28 insertions(+), 15 deletions(-) [+]
line wrap: on
line diff
--- a/src/http/modules/ngx_http_auth_basic_module.c
+++ b/src/http/modules/ngx_http_auth_basic_module.c
@@ -361,6 +361,8 @@ ngx_http_auth_basic_set_realm(ngx_http_r
 
     basic = ngx_pnalloc(r->pool, len);
     if (basic == NULL) {
+        r->headers_out.www_authenticate->hash = 0;
+        r->headers_out.www_authenticate = NULL;
         return NGX_HTTP_INTERNAL_SERVER_ERROR;
     }
 
--- a/src/http/modules/ngx_http_dav_module.c
+++ b/src/http/modules/ngx_http_dav_module.c
@@ -1080,6 +1080,7 @@ ngx_http_dav_location(ngx_http_request_t
     } else {
         location = ngx_pnalloc(r->pool, r->uri.len);
         if (location == NULL) {
+            ngx_http_clear_location(r);
             return NGX_ERROR;
         }
 
--- a/src/http/modules/ngx_http_headers_filter_module.c
+++ b/src/http/modules/ngx_http_headers_filter_module.c
@@ -271,11 +271,6 @@ ngx_http_set_expires(ngx_http_request_t 
             return NGX_ERROR;
         }
 
-        ccp = ngx_array_push(&r->headers_out.cache_control);
-        if (ccp == NULL) {
-            return NGX_ERROR;
-        }
-
         cc = ngx_list_push(&r->headers_out.headers);
         if (cc == NULL) {
             return NGX_ERROR;
@@ -283,6 +278,12 @@ ngx_http_set_expires(ngx_http_request_t 
 
         cc->hash = 1;
         ngx_str_set(&cc->key, "Cache-Control");
+
+        ccp = ngx_array_push(&r->headers_out.cache_control);
+        if (ccp == NULL) {
+            return NGX_ERROR;
+        }
+
         *ccp = cc;
 
     } else {
@@ -470,11 +471,6 @@ ngx_http_add_cache_control(ngx_http_requ
         }
     }
 
-    ccp = ngx_array_push(&r->headers_out.cache_control);
-    if (ccp == NULL) {
-        return NGX_ERROR;
-    }
-
     cc = ngx_list_push(&r->headers_out.headers);
     if (cc == NULL) {
         return NGX_ERROR;
@@ -484,6 +480,11 @@ ngx_http_add_cache_control(ngx_http_requ
     ngx_str_set(&cc->key, "Cache-Control");
     cc->value = *value;
 
+    ccp = ngx_array_push(&r->headers_out.cache_control);
+    if (ccp == NULL) {
+        return NGX_ERROR;
+    }
+
     *ccp = cc;
 
     return NGX_OK;
--- a/src/http/modules/ngx_http_range_filter_module.c
+++ b/src/http/modules/ngx_http_range_filter_module.c
@@ -425,6 +425,8 @@ ngx_http_range_singlepart_header(ngx_htt
     content_range->value.data = ngx_pnalloc(r->pool,
                                     sizeof("bytes -/") - 1 + 3 * NGX_OFF_T_LEN);
     if (content_range->value.data == NULL) {
+        content_range->hash = 0;
+        r->headers_out.content_range = NULL;
         return NGX_ERROR;
     }
 
@@ -594,6 +596,8 @@ ngx_http_range_not_satisfiable(ngx_http_
     content_range->value.data = ngx_pnalloc(r->pool,
                                        sizeof("bytes */") - 1 + NGX_OFF_T_LEN);
     if (content_range->value.data == NULL) {
+        content_range->hash = 0;
+        r->headers_out.content_range = NULL;
         return NGX_ERROR;
     }
 
--- a/src/http/modules/ngx_http_static_module.c
+++ b/src/http/modules/ngx_http_static_module.c
@@ -169,6 +169,7 @@ ngx_http_static_handler(ngx_http_request
 
             location = ngx_pnalloc(r->pool, len);
             if (location == NULL) {
+                ngx_http_clear_location(r);
                 return NGX_HTTP_INTERNAL_SERVER_ERROR;
             }
 
--- a/src/http/modules/perl/nginx.xs
+++ b/src/http/modules/perl/nginx.xs
@@ -510,10 +510,12 @@ header_out(r, key, value)
     header->hash = 1;
 
     if (ngx_http_perl_sv2str(aTHX_ r, &header->key, key) != NGX_OK) {
+        header->hash = 0;
         XSRETURN_EMPTY;
     }
 
     if (ngx_http_perl_sv2str(aTHX_ r, &header->value, value) != NGX_OK) {
+        header->hash = 0;
         XSRETURN_EMPTY;
     }
 
--- a/src/http/ngx_http_core_module.c
+++ b/src/http/ngx_http_core_module.c
@@ -1002,6 +1002,7 @@ ngx_http_core_find_config_phase(ngx_http
             p = ngx_pnalloc(r->pool, len);
 
             if (p == NULL) {
+                ngx_http_clear_location(r);
                 ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
                 return NGX_OK;
             }
--- a/src/http/ngx_http_upstream.c
+++ b/src/http/ngx_http_upstream.c
@@ -4897,17 +4897,18 @@ ngx_http_upstream_copy_multi_header_line
         }
     }
 
-    ph = ngx_array_push(pa);
-    if (ph == NULL) {
-        return NGX_ERROR;
-    }
-
     ho = ngx_list_push(&r->headers_out.headers);
     if (ho == NULL) {
         return NGX_ERROR;
     }
 
     *ho = *h;
+
+    ph = ngx_array_push(pa);
+    if (ph == NULL) {
+        return NGX_ERROR;
+    }
+
     *ph = ho;
 
     return NGX_OK;