From 16ebfa999baac42341da6589ffaa8550b25acb2e Mon Sep 17 00:00:00 2001 From: Roman Arutyunyan <arut@nginx.com> Date: Mon, 3 Jun 2019 20:33:26 +0300 Subject: [PATCH 01/33] Upstream: background cache update before cache send (ticket #1782). In case of filter finalization, essential request fields like r->uri, r->args etc could be changed, which affected the cache update subrequest. Also, after filter finalization r->cache could be set to NULL, leading to null pointer dereference in ngx_http_upstream_cache_background_update(). The fix is to create background cache update subrequest before sending the cached response. Since initial introduction in 1aeaae6e9446 (1.11.10) background cache update subrequest was created after sending the cached response because otherwise it blocked the parent request output. In 9552758a786e (1.13.1) background subrequests were introduced to eliminate the delay before sending the final part of the cached response. This also made it possible to create the background cache update subrequest before sending the response. Note that creating the subrequest earlier does not change the fact that in case of filter finalization the background cache update subrequest will likely not have enough time to successfully update the cache entry. Filter finalization leads to the main request termination as soon the current iteration of request processing is complete. --- src/http/ngx_http_upstream.c | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/src/http/ngx_http_upstream.c b/src/http/ngx_http_upstream.c index 925824366..ffb09a91f 100644 --- a/src/http/ngx_http_upstream.c +++ b/src/http/ngx_http_upstream.c @@ -597,10 +597,6 @@ ngx_http_upstream_init_request(ngx_http_request_t *r) u->cache_status = NGX_HTTP_CACHE_MISS; u->request_sent = 1; } - - if (ngx_http_upstream_cache_background_update(r, u) != NGX_OK) { - rc = NGX_ERROR; - } } if (rc != NGX_DECLINED) { @@ -902,9 +898,14 @@ ngx_http_upstream_cache(ngx_http_request_t *r, ngx_http_upstream_t *u) || c->stale_updating) && !r->background && u->conf->cache_background_update) { - r->cache->background = 1; - u->cache_status = rc; - rc = NGX_OK; + if (ngx_http_upstream_cache_background_update(r, u) == NGX_OK) { + r->cache->background = 1; + u->cache_status = rc; + rc = NGX_OK; + + } else { + rc = NGX_ERROR; + } } break; @@ -1106,10 +1107,6 @@ ngx_http_upstream_cache_background_update(ngx_http_request_t *r, { ngx_http_request_t *sr; - if (!r->cached || !r->cache->background) { - return NGX_OK; - } - if (r == r->main) { r->preserve_body = 1; } -- GitLab From dda58fc63b64227a19657ed92168b9f645c0c86e Mon Sep 17 00:00:00 2001 From: Roman Arutyunyan <arut@nginx.com> Date: Wed, 5 Jun 2019 19:55:27 +0300 Subject: [PATCH 02/33] Limit req: limit_req_dry_run directive. A new directive limit_req_dry_run allows enabling the dry run mode. In this mode requests are neither rejected nor delayed, but reject/delay status is logged as usual. --- src/http/modules/ngx_http_limit_req_module.c | 29 +++++++++++++++++--- 1 file changed, 25 insertions(+), 4 deletions(-) diff --git a/src/http/modules/ngx_http_limit_req_module.c b/src/http/modules/ngx_http_limit_req_module.c index e81d57ffb..806452296 100644 --- a/src/http/modules/ngx_http_limit_req_module.c +++ b/src/http/modules/ngx_http_limit_req_module.c @@ -53,6 +53,7 @@ typedef struct { ngx_uint_t limit_log_level; ngx_uint_t delay_log_level; ngx_uint_t status_code; + ngx_flag_t dry_run; } ngx_http_limit_req_conf_t; @@ -118,6 +119,13 @@ static ngx_command_t ngx_http_limit_req_commands[] = { offsetof(ngx_http_limit_req_conf_t, status_code), &ngx_http_limit_req_status_bounds }, + { ngx_string("limit_req_dry_run"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG, + ngx_conf_set_flag_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_limit_req_conf_t, dry_run), + NULL }, + ngx_null_command }; @@ -230,9 +238,10 @@ ngx_http_limit_req_handler(ngx_http_request_t *r) if (rc == NGX_BUSY) { ngx_log_error(lrcf->limit_log_level, r->connection->log, 0, - "limiting requests, excess: %ui.%03ui by zone \"%V\"", - excess / 1000, excess % 1000, - &limit->shm_zone->shm.name); + "limiting requests%s, excess: %ui.%03ui by zone \"%V\"", + lrcf->dry_run ? ", dry run" : "", + excess / 1000, excess % 1000, + &limit->shm_zone->shm.name); } while (n--) { @@ -251,6 +260,10 @@ ngx_http_limit_req_handler(ngx_http_request_t *r) ctx->node = NULL; } + if (lrcf->dry_run) { + return NGX_DECLINED; + } + return lrcf->status_code; } @@ -267,9 +280,14 @@ ngx_http_limit_req_handler(ngx_http_request_t *r) } ngx_log_error(lrcf->delay_log_level, r->connection->log, 0, - "delaying request, excess: %ui.%03ui, by zone \"%V\"", + "delaying request%s, excess: %ui.%03ui, by zone \"%V\"", + lrcf->dry_run ? ", dry run" : "", excess / 1000, excess % 1000, &limit->shm_zone->shm.name); + if (lrcf->dry_run) { + return NGX_DECLINED; + } + if (ngx_handle_read_event(r->connection->read, 0) != NGX_OK) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } @@ -711,6 +729,7 @@ ngx_http_limit_req_create_conf(ngx_conf_t *cf) conf->limit_log_level = NGX_CONF_UNSET_UINT; conf->status_code = NGX_CONF_UNSET_UINT; + conf->dry_run = NGX_CONF_UNSET; return conf; } @@ -735,6 +754,8 @@ ngx_http_limit_req_merge_conf(ngx_conf_t *cf, void *parent, void *child) ngx_conf_merge_uint_value(conf->status_code, prev->status_code, NGX_HTTP_SERVICE_UNAVAILABLE); + ngx_conf_merge_value(conf->dry_run, prev->dry_run, 0); + return NGX_CONF_OK; } -- GitLab From d9887ee2ae9069843eed67d5b5ea625a7faeedb1 Mon Sep 17 00:00:00 2001 From: Maxim Dounin <mdounin@mdounin.ru> Date: Mon, 17 Jun 2019 19:48:56 +0300 Subject: [PATCH 03/33] Perl: disabled not_modified filter (ticket #1786). Embedded perl does not set any request fields needed for conditional requests processing. Further, filter finalization in the not_modified filter can cause segmentation faults due to cleared ctx as in ticket #1786. Before 5fb1e57c758a (1.7.3) the not_modified filter was implicitly disabled for perl responses, as r->headers_out.last_modified_time was -1. This change restores this behaviour by using the explicit r->disable_not_modified flag. Note that this patch doesn't try to address perl module robustness against filter finalization and other errors returned from filter chains. It should be eventually reworked to handle errors instead of ignoring them. --- src/http/modules/perl/nginx.xs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/http/modules/perl/nginx.xs b/src/http/modules/perl/nginx.xs index ad1263287..848e50199 100644 --- a/src/http/modules/perl/nginx.xs +++ b/src/http/modules/perl/nginx.xs @@ -147,6 +147,8 @@ send_http_header(r, ...) } } + r->disable_not_modified = 1; + (void) ngx_http_send_header(r); -- GitLab From 32adc8534c4e461a1e519ee58e1a846249743872 Mon Sep 17 00:00:00 2001 From: Maxim Dounin <mdounin@mdounin.ru> Date: Tue, 25 Jun 2019 04:47:43 +0300 Subject: [PATCH 04/33] Updated OpenSSL used for win32 builds. --- misc/GNUmakefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/misc/GNUmakefile b/misc/GNUmakefile index 0391a3155..2a34ae553 100644 --- a/misc/GNUmakefile +++ b/misc/GNUmakefile @@ -6,7 +6,7 @@ TEMP = tmp CC = cl OBJS = objs.msvc8 -OPENSSL = openssl-1.1.1b +OPENSSL = openssl-1.1.1c ZLIB = zlib-1.2.11 PCRE = pcre-8.43 -- GitLab From c4613796af6102f5c6b2365f660ac4591808832b Mon Sep 17 00:00:00 2001 From: Maxim Dounin <mdounin@mdounin.ru> Date: Tue, 25 Jun 2019 15:19:45 +0300 Subject: [PATCH 05/33] nginx-1.17.1-RELEASE --- docs/xml/nginx/changes.xml | 56 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) diff --git a/docs/xml/nginx/changes.xml b/docs/xml/nginx/changes.xml index ae034bbaa..5963cd7d7 100644 --- a/docs/xml/nginx/changes.xml +++ b/docs/xml/nginx/changes.xml @@ -5,6 +5,62 @@ <change_log title="nginx"> +<changes ver="1.17.1" date="2019-06-25"> + +<change type="feature"> +<para lang="ru"> +Š´ŠøŃ€ŠµŠŗŃ‚ŠøŠ²Š° limit_req_dry_run. +</para> +<para lang="en"> +the "limit_req_dry_run" directive. +</para> +</change> + +<change type="feature"> +<para lang="ru"> +ŠæŃ€Šø ŠøŃŠæŠ¾Š»ŃŠ·Š¾Š²Š°Š½ŠøŠø Š´ŠøŃ€ŠµŠŗŃ‚ŠøŠ²Ń‹ hash Š² Š±Š»Š¾ŠŗŠµ upstream +ŠæŃŃŃ‚Š¾Š¹ ŠŗŠ»ŃˇŃ‡ хѨъøŃ€Š¾Š²Š°Š½ŠøѸ Ń‚ŠµŠæŠµŃ€Ń ŠæŃ€ŠøŠ²Š¾Š´ŠøŃ‚ Šŗ ŠæŠµŃ€ŠµŠŗŠ»ŃˇŃ‡ŠµŠ½Šøѡ +Š½Š° round-robin Š±Š°Š»Š°Š½ŃŠøŃ€Š¾Š²ŠŗŃ.<br/> +Š�ŠæŠ°ŃŠøŠ±Š¾ Niklas Keller. +</para> +<para lang="en"> +when using the "hash" directive inside the "upstream" block +an empty hash key now triggers round-robin balancing.<br/> +Thanks to Niklas Keller. +</para> +</change> + +<change type="bugfix"> +<para lang="ru"> +Š² Ń€Š°Š±Š¾Ń‡ŠµŠ¼ ŠæŃ€Š¾Ń†ŠµŃŃŠµ Š¼Š¾Š³ ŠæŃ€Š¾ŠøŠ·Š¾Š¹Ń‚Šø segmentation fault, +ŠµŃŠ»Šø ŠøŃŠæŠ¾Š»ŃŠ·Š¾Š²Š°Š»Š¾ŃŃ ŠŗѨъøŃ€Š¾Š²Š°Š½ŠøŠµ Šø Š´ŠøŃ€ŠµŠŗŃ‚ŠøŠ²Š° image_filter, +Š° Š¾ŃŠøŠ±ŠŗŠø Ń ŠŗŠ¾Š´Š¾Š¼ 415 ŠæŠµŃ€ŠµŠ½Š°ŠæŃ€Š°Š²Š»Ń¸Š»ŠøŃŃ Ń ŠæŠ¾Š¼Š¾Ń‰Ń Š´ŠøŃ€ŠµŠŗŃ‚ŠøŠ²Ń‹ error_page; +Š¾ŃŠøŠ±ŠŗŠ° ŠæŠ¾Ń¸Š²ŠøŠ»Š°ŃŃ Š² 1.11.10. +</para> +<para lang="en"> +a segmentation fault might occur in a worker process +if caching was used along with the "image_filter" directive, +and errors with code 415 were redirected with the "error_page" directive; +the bug had appeared in 1.11.10. +</para> +</change> + +<change type="bugfix"> +<para lang="ru"> +Š² Ń€Š°Š±Š¾Ń‡ŠµŠ¼ ŠæŃ€Š¾Ń†ŠµŃŃŠµ Š¼Š¾Š³ ŠæŃ€Š¾ŠøŠ·Š¾Š¹Ń‚Šø segmentation fault, +ŠµŃŠ»Šø ŠøŃŠæŠ¾Š»ŃŠ·Š¾Š²Š°Š»ŃѸ Š²ŃŃ‚Ń€Š¾ŠµŠ½Š½Ń‹Š¹ ŠæŠµŃ€Š»; +Š¾ŃŠøŠ±ŠŗŠ° ŠæŠ¾Ń¸Š²ŠøŠ»Š°ŃŃ Š² 1.7.3. +</para> +<para lang="en"> +a segmentation fault might occur in a worker process +if embedded perl was used; +the bug had appeared in 1.7.3. +</para> +</change> + +</changes> + + <changes ver="1.17.0" date="2019-05-21"> <change type="feature"> -- GitLab From 4722452e9cb42f1e0456da7c3d86808471c556b5 Mon Sep 17 00:00:00 2001 From: Maxim Dounin <mdounin@mdounin.ru> Date: Tue, 25 Jun 2019 15:19:45 +0300 Subject: [PATCH 06/33] release-1.17.1 tag --- .hgtags | 1 + 1 file changed, 1 insertion(+) diff --git a/.hgtags b/.hgtags index 5dd625bb4..10adccb73 100644 --- a/.hgtags +++ b/.hgtags @@ -439,3 +439,4 @@ d2fd76709909767fc727a5b4affcf1dc9ca488a7 release-1.15.9 5155d0296a5ef9841f035920527ffdb771076b44 release-1.15.11 0130ca3d58437b3c7c707cdddd813d530c68da9a release-1.15.12 054c1c46395caff79bb4caf16f40b331f71bb6dd release-1.17.0 +7816bd7dabf6ee86c53c073b90a7143161546e06 release-1.17.1 -- GitLab From 66e95b50e7e65dc16dcf2a5ca51219af3d4c8d9f Mon Sep 17 00:00:00 2001 From: Maxim Dounin <mdounin@mdounin.ru> Date: Tue, 9 Jul 2019 16:01:32 +0300 Subject: [PATCH 07/33] Version bump. --- src/core/nginx.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/core/nginx.h b/src/core/nginx.h index 71377bf16..25c5a729f 100644 --- a/src/core/nginx.h +++ b/src/core/nginx.h @@ -9,8 +9,8 @@ #define _NGINX_H_INCLUDED_ -#define nginx_version 1017001 -#define NGINX_VERSION "1.17.1" +#define nginx_version 1017002 +#define NGINX_VERSION "1.17.2" #define NGINX_VER "nginx/" NGINX_VERSION #ifdef NGX_BUILD -- GitLab From 18e063129a75d7bdb0e87dc982ab43a48bf9cf28 Mon Sep 17 00:00:00 2001 From: Maxim Dounin <mdounin@mdounin.ru> Date: Tue, 9 Jul 2019 16:03:25 +0300 Subject: [PATCH 08/33] Typo. --- docs/xml/nginx/changes.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/xml/nginx/changes.xml b/docs/xml/nginx/changes.xml index 5963cd7d7..60221ab55 100644 --- a/docs/xml/nginx/changes.xml +++ b/docs/xml/nginx/changes.xml @@ -34,7 +34,7 @@ Thanks to Niklas Keller. <para lang="ru"> Š² Ń€Š°Š±Š¾Ń‡ŠµŠ¼ ŠæŃ€Š¾Ń†ŠµŃŃŠµ Š¼Š¾Š³ ŠæŃ€Š¾ŠøŠ·Š¾Š¹Ń‚Šø segmentation fault, ŠµŃŠ»Šø ŠøŃŠæŠ¾Š»ŃŠ·Š¾Š²Š°Š»Š¾ŃŃ ŠŗѨъøŃ€Š¾Š²Š°Š½ŠøŠµ Šø Š´ŠøŃ€ŠµŠŗŃ‚ŠøŠ²Š° image_filter, -Š° Š¾ŃŠøŠ±ŠŗŠø Ń ŠŗŠ¾Š´Š¾Š¼ 415 ŠæŠµŃ€ŠµŠ½Š°ŠæŃ€Š°Š²Š»Ń¸Š»ŠøŃŃ Ń ŠæŠ¾Š¼Š¾Ń‰Ń Š´ŠøŃ€ŠµŠŗŃ‚ŠøŠ²Ń‹ error_page; +Š° Š¾ŃŠøŠ±ŠŗŠø Ń ŠŗŠ¾Š´Š¾Š¼ 415 ŠæŠµŃ€ŠµŠ½Š°ŠæŃ€Š°Š²Š»Ń¸Š»ŠøŃŃ Ń ŠæŠ¾Š¼Š¾Ń‰Ńѡ Š´ŠøŃ€ŠµŠŗŃ‚ŠøŠ²Ń‹ error_page; Š¾ŃŠøŠ±ŠŗŠ° ŠæŠ¾Ń¸Š²ŠøŠ»Š°ŃŃ Š² 1.11.10. </para> <para lang="en"> -- GitLab From 1e673c72dd9d0e88ec5918622e9656fe46b02403 Mon Sep 17 00:00:00 2001 From: Gena Makhomed <gmm@csdoc.com> Date: Sun, 30 Jun 2019 10:39:01 +0300 Subject: [PATCH 09/33] Contrib: vim syntax, update core and 3rd party module directives. --- contrib/vim/syntax/nginx.vim | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/contrib/vim/syntax/nginx.vim b/contrib/vim/syntax/nginx.vim index 6bee7a2e5..1a3a7b7d9 100644 --- a/contrib/vim/syntax/nginx.vim +++ b/contrib/vim/syntax/nginx.vim @@ -333,6 +333,7 @@ syn keyword ngxDirective contained js_access syn keyword ngxDirective contained js_content syn keyword ngxDirective contained js_filter syn keyword ngxDirective contained js_include +syn keyword ngxDirective contained js_path syn keyword ngxDirective contained js_preread syn keyword ngxDirective contained js_set syn keyword ngxDirective contained keepalive @@ -353,6 +354,7 @@ syn keyword ngxDirective contained limit_conn_zone syn keyword ngxDirective contained limit_rate syn keyword ngxDirective contained limit_rate_after syn keyword ngxDirective contained limit_req +syn keyword ngxDirective contained limit_req_dry_run syn keyword ngxDirective contained limit_req_log_level syn keyword ngxDirective contained limit_req_status syn keyword ngxDirective contained limit_req_zone @@ -472,6 +474,7 @@ syn keyword ngxDirective contained proxy_requests syn keyword ngxDirective contained proxy_responses syn keyword ngxDirective contained proxy_send_lowat syn keyword ngxDirective contained proxy_send_timeout +syn keyword ngxDirective contained proxy_session_drop syn keyword ngxDirective contained proxy_set_body syn keyword ngxDirective contained proxy_set_header syn keyword ngxDirective contained proxy_socket_keepalive @@ -1325,6 +1328,7 @@ syn keyword ngxDirectiveThirdParty contained lua_check_client_abort syn keyword ngxDirectiveThirdParty contained lua_code_cache syn keyword ngxDirectiveThirdParty contained lua_fake_shm syn keyword ngxDirectiveThirdParty contained lua_http10_buffering +syn keyword ngxDirectiveThirdParty contained lua_load_resty_core syn keyword ngxDirectiveThirdParty contained lua_malloc_trim syn keyword ngxDirectiveThirdParty contained lua_max_pending_timers syn keyword ngxDirectiveThirdParty contained lua_max_running_timers @@ -1779,6 +1783,7 @@ syn keyword ngxDirectiveThirdParty contained vod_expires_live_time_dependent syn keyword ngxDirectiveThirdParty contained vod_fallback_upstream_location syn keyword ngxDirectiveThirdParty contained vod_force_continuous_timestamps syn keyword ngxDirectiveThirdParty contained vod_force_playlist_type_vod +syn keyword ngxDirectiveThirdParty contained vod_force_sequence_index syn keyword ngxDirectiveThirdParty contained vod_gop_look_ahead syn keyword ngxDirectiveThirdParty contained vod_gop_look_behind syn keyword ngxDirectiveThirdParty contained vod_ignore_edit_list -- GitLab From 60e7480533480b6340cae596118aa0ac72c0fce9 Mon Sep 17 00:00:00 2001 From: Maxim Dounin <mdounin@mdounin.ru> Date: Thu, 11 Jul 2019 23:20:08 +0300 Subject: [PATCH 10/33] Perl: removed unneeded NGX_DONE test. The NGX_DONE test in ngx_http_perl_handle_request() was introduced in 1702:86bb52e28ce0, which also modified ngx_http_perl_call_handler() to return NGX_DONE with c->destroyed. The latter part was then removed in 3050:f54b02dbb12b, so NGX_DONE test is no longer needed. --- src/http/modules/perl/ngx_http_perl_module.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/http/modules/perl/ngx_http_perl_module.c b/src/http/modules/perl/ngx_http_perl_module.c index 6d3be9128..d06b43c75 100644 --- a/src/http/modules/perl/ngx_http_perl_module.c +++ b/src/http/modules/perl/ngx_http_perl_module.c @@ -228,11 +228,6 @@ ngx_http_perl_handle_request(ngx_http_request_t *r) ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "perl handler done: %i", rc); - if (rc == NGX_DONE) { - ngx_http_finalize_request(r, rc); - return; - } - if (rc > 600) { rc = NGX_OK; } -- GitLab From eae5e4dd01dfaff9d15c3dd7818f082e2995cc74 Mon Sep 17 00:00:00 2001 From: Maxim Dounin <mdounin@mdounin.ru> Date: Fri, 12 Jul 2019 11:29:22 +0300 Subject: [PATCH 11/33] Perl: reworked perl module to pass ctx instead of request. This ensures that correct ctx is always available, including after filter finalization. In particular, this fixes a segmentation fault with the following configuration: location / { image_filter test; perl 'sub { my $r = shift; $r->send_http_header(); $r->print("foo\n"); $r->print("bar\n"); }'; } This also seems to be the only way to correctly handle filter finalization in various complex cases, for example, when embedded perl is used both in the original handler and in an error page called after filter finalization. --- src/http/modules/perl/nginx.xs | 180 ++++++++++--------- src/http/modules/perl/ngx_http_perl_module.c | 26 ++- src/http/modules/perl/ngx_http_perl_module.h | 2 + 3 files changed, 114 insertions(+), 94 deletions(-) diff --git a/src/http/modules/perl/nginx.xs b/src/http/modules/perl/nginx.xs index 848e50199..2e9808f2b 100644 --- a/src/http/modules/perl/nginx.xs +++ b/src/http/modules/perl/nginx.xs @@ -15,8 +15,10 @@ #include "XSUB.h" -#define ngx_http_perl_set_request(r) \ - r = INT2PTR(ngx_http_request_t *, SvIV((SV *) SvRV(ST(0)))) +#define ngx_http_perl_set_request(r, ctx) \ + \ + ctx = INT2PTR(ngx_http_perl_ctx_t *, SvIV((SV *) SvRV(ST(0)))); \ + r = ctx->request #define ngx_http_perl_set_targ(p, len) \ @@ -64,14 +66,12 @@ ngx_http_perl_sv2str(pTHX_ ngx_http_request_t *r, ngx_str_t *s, SV *sv) static ngx_int_t -ngx_http_perl_output(ngx_http_request_t *r, ngx_buf_t *b) +ngx_http_perl_output(ngx_http_request_t *r, ngx_http_perl_ctx_t *ctx, + ngx_buf_t *b) { - ngx_chain_t out; + ngx_chain_t out; #if (NGX_HTTP_SSI) - ngx_chain_t *cl; - ngx_http_perl_ctx_t *ctx; - - ctx = ngx_http_get_module_ctx(r, ngx_http_perl_module); + ngx_chain_t *cl; if (ctx->ssi) { cl = ngx_alloc_chain_link(r->pool); @@ -105,9 +105,10 @@ void status(r, code) CODE: - ngx_http_request_t *r; + ngx_http_request_t *r; + ngx_http_perl_ctx_t *ctx; - ngx_http_perl_set_request(r); + ngx_http_perl_set_request(r, ctx); r->headers_out.status = SvIV(ST(1)); @@ -121,10 +122,11 @@ void send_http_header(r, ...) CODE: - ngx_http_request_t *r; - SV *sv; + ngx_http_request_t *r; + ngx_http_perl_ctx_t *ctx; + SV *sv; - ngx_http_perl_set_request(r); + ngx_http_perl_set_request(r, ctx); if (r->headers_out.status == 0) { r->headers_out.status = NGX_HTTP_OK; @@ -157,9 +159,10 @@ header_only(r) CODE: dXSTARG; - ngx_http_request_t *r; + ngx_http_request_t *r; + ngx_http_perl_ctx_t *ctx; - ngx_http_perl_set_request(r); + ngx_http_perl_set_request(r, ctx); sv_upgrade(TARG, SVt_IV); sv_setiv(TARG, r->header_only); @@ -172,9 +175,10 @@ uri(r) CODE: dXSTARG; - ngx_http_request_t *r; + ngx_http_request_t *r; + ngx_http_perl_ctx_t *ctx; - ngx_http_perl_set_request(r); + ngx_http_perl_set_request(r, ctx); ngx_http_perl_set_targ(r->uri.data, r->uri.len); ST(0) = TARG; @@ -185,9 +189,10 @@ args(r) CODE: dXSTARG; - ngx_http_request_t *r; + ngx_http_request_t *r; + ngx_http_perl_ctx_t *ctx; - ngx_http_perl_set_request(r); + ngx_http_perl_set_request(r, ctx); ngx_http_perl_set_targ(r->args.data, r->args.len); ST(0) = TARG; @@ -198,9 +203,10 @@ request_method(r) CODE: dXSTARG; - ngx_http_request_t *r; + ngx_http_request_t *r; + ngx_http_perl_ctx_t *ctx; - ngx_http_perl_set_request(r); + ngx_http_perl_set_request(r, ctx); ngx_http_perl_set_targ(r->method_name.data, r->method_name.len); ST(0) = TARG; @@ -211,9 +217,10 @@ remote_addr(r) CODE: dXSTARG; - ngx_http_request_t *r; + ngx_http_request_t *r; + ngx_http_perl_ctx_t *ctx; - ngx_http_perl_set_request(r); + ngx_http_perl_set_request(r, ctx); ngx_http_perl_set_targ(r->connection->addr_text.data, r->connection->addr_text.len); @@ -226,6 +233,7 @@ header_in(r, key) dXSTARG; ngx_http_request_t *r; + ngx_http_perl_ctx_t *ctx; SV *key; u_char *p, *lowcase_key, *value, sep; STRLEN len; @@ -237,7 +245,7 @@ header_in(r, key) ngx_http_header_t *hh; ngx_http_core_main_conf_t *cmcf; - ngx_http_perl_set_request(r); + ngx_http_perl_set_request(r, ctx); key = ST(1); @@ -374,13 +382,12 @@ has_request_body(r, next) ngx_http_request_t *r; ngx_http_perl_ctx_t *ctx; - ngx_http_perl_set_request(r); + ngx_http_perl_set_request(r, ctx); if (r->headers_in.content_length_n <= 0 && !r->headers_in.chunked) { XSRETURN_UNDEF; } - ctx = ngx_http_get_module_ctx(r, ngx_http_perl_module); ctx->next = SvRV(ST(1)); r->request_body_in_single_buf = 1; @@ -404,13 +411,14 @@ request_body(r) CODE: dXSTARG; - ngx_http_request_t *r; - u_char *p, *data; - size_t len; - ngx_buf_t *buf; - ngx_chain_t *cl; + ngx_http_request_t *r; + ngx_http_perl_ctx_t *ctx; + u_char *p, *data; + size_t len; + ngx_buf_t *buf; + ngx_chain_t *cl; - ngx_http_perl_set_request(r); + ngx_http_perl_set_request(r, ctx); if (r->request_body == NULL || r->request_body->temp_file @@ -465,9 +473,10 @@ request_body_file(r) CODE: dXSTARG; - ngx_http_request_t *r; + ngx_http_request_t *r; + ngx_http_perl_ctx_t *ctx; - ngx_http_perl_set_request(r); + ngx_http_perl_set_request(r, ctx); if (r->request_body == NULL || r->request_body->temp_file == NULL) { XSRETURN_UNDEF; @@ -483,9 +492,10 @@ void discard_request_body(r) CODE: - ngx_http_request_t *r; + ngx_http_request_t *r; + ngx_http_perl_ctx_t *ctx; - ngx_http_perl_set_request(r); + ngx_http_perl_set_request(r, ctx); ngx_http_discard_request_body(r); @@ -494,12 +504,13 @@ void header_out(r, key, value) CODE: - ngx_http_request_t *r; - SV *key; - SV *value; - ngx_table_elt_t *header; + ngx_http_request_t *r; + ngx_http_perl_ctx_t *ctx; + SV *key; + SV *value; + ngx_table_elt_t *header; - ngx_http_perl_set_request(r); + ngx_http_perl_set_request(r, ctx); key = ST(1); value = ST(2); @@ -542,13 +553,12 @@ filename(r) CODE: dXSTARG; - size_t root; ngx_http_request_t *r; ngx_http_perl_ctx_t *ctx; + size_t root; - ngx_http_perl_set_request(r); + ngx_http_perl_set_request(r, ctx); - ctx = ngx_http_get_module_ctx(r, ngx_http_perl_module); if (ctx->filename.data) { goto done; } @@ -571,15 +581,16 @@ void print(r, ...) CODE: - ngx_http_request_t *r; - SV *sv; - int i; - u_char *p; - size_t size; - STRLEN len; - ngx_buf_t *b; + ngx_http_request_t *r; + ngx_http_perl_ctx_t *ctx; + SV *sv; + int i; + u_char *p; + size_t size; + STRLEN len; + ngx_buf_t *b; - ngx_http_perl_set_request(r); + ngx_http_perl_set_request(r, ctx); if (items == 2) { @@ -660,7 +671,7 @@ print(r, ...) out: - (void) ngx_http_perl_output(r, b); + (void) ngx_http_perl_output(r, ctx, b); void @@ -668,6 +679,7 @@ sendfile(r, filename, offset = -1, bytes = 0) CODE: ngx_http_request_t *r; + ngx_http_perl_ctx_t *ctx; char *filename; off_t offset; size_t bytes; @@ -676,7 +688,7 @@ sendfile(r, filename, offset = -1, bytes = 0) ngx_open_file_info_t of; ngx_http_core_loc_conf_t *clcf; - ngx_http_perl_set_request(r); + ngx_http_perl_set_request(r, ctx); filename = SvPV_nolen(ST(1)); @@ -750,17 +762,18 @@ sendfile(r, filename, offset = -1, bytes = 0) b->file->log = r->connection->log; b->file->directio = of.is_directio; - (void) ngx_http_perl_output(r, b); + (void) ngx_http_perl_output(r, ctx, b); void flush(r) CODE: - ngx_http_request_t *r; - ngx_buf_t *b; + ngx_http_request_t *r; + ngx_http_perl_ctx_t *ctx; + ngx_buf_t *b; - ngx_http_perl_set_request(r); + ngx_http_perl_set_request(r, ctx); b = ngx_calloc_buf(r->pool); if (b == NULL) { @@ -771,7 +784,7 @@ flush(r) ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "$r->flush"); - (void) ngx_http_perl_output(r, b); + (void) ngx_http_perl_output(r, ctx, b); XSRETURN_EMPTY; @@ -781,16 +794,14 @@ internal_redirect(r, uri) CODE: ngx_http_request_t *r; + ngx_http_perl_ctx_t *ctx; SV *uri; ngx_uint_t i; - ngx_http_perl_ctx_t *ctx; - ngx_http_perl_set_request(r); + ngx_http_perl_set_request(r, ctx); uri = ST(1); - ctx = ngx_http_get_module_ctx(r, ngx_http_perl_module); - if (ngx_http_perl_sv2str(aTHX_ r, &ctx->redirect_uri, uri) != NGX_OK) { XSRETURN_EMPTY; } @@ -811,9 +822,10 @@ void allow_ranges(r) CODE: - ngx_http_request_t *r; + ngx_http_request_t *r; + ngx_http_perl_ctx_t *ctx; - ngx_http_perl_set_request(r); + ngx_http_perl_set_request(r, ctx); r->allow_ranges = 1; @@ -823,13 +835,14 @@ unescape(r, text, type = 0) CODE: dXSTARG; - ngx_http_request_t *r; - SV *text; - int type; - u_char *p, *dst, *src; - STRLEN len; + ngx_http_request_t *r; + ngx_http_perl_ctx_t *ctx; + SV *text; + int type; + u_char *p, *dst, *src; + STRLEN len; - ngx_http_perl_set_request(r); + ngx_http_perl_set_request(r, ctx); text = ST(1); @@ -858,16 +871,16 @@ variable(r, name, value = NULL) dXSTARG; ngx_http_request_t *r; + ngx_http_perl_ctx_t *ctx; SV *name, *value; u_char *p, *lowcase; STRLEN len; ngx_str_t var, val; ngx_uint_t i, hash; ngx_http_perl_var_t *v; - ngx_http_perl_ctx_t *ctx; ngx_http_variable_value_t *vv; - ngx_http_perl_set_request(r); + ngx_http_perl_set_request(r, ctx); name = ST(1); @@ -919,8 +932,6 @@ variable(r, name, value = NULL) if (vv->not_found) { - ctx = ngx_http_get_module_ctx(r, ngx_http_perl_module); - if (ctx->variables) { v = ctx->variables->elts; @@ -991,18 +1002,16 @@ sleep(r, sleep, next) CODE: ngx_http_request_t *r; - ngx_msec_t sleep; ngx_http_perl_ctx_t *ctx; + ngx_msec_t sleep; - ngx_http_perl_set_request(r); + ngx_http_perl_set_request(r, ctx); sleep = (ngx_msec_t) SvIV(ST(1)); ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "perl sleep: %M", sleep); - ctx = ngx_http_get_module_ctx(r, ngx_http_perl_module); - ctx->next = SvRV(ST(2)); r->connection->write->delayed = 1; @@ -1016,13 +1025,14 @@ void log_error(r, err, msg) CODE: - ngx_http_request_t *r; - SV *err, *msg; - u_char *p; - STRLEN len; - ngx_err_t e; + ngx_http_request_t *r; + ngx_http_perl_ctx_t *ctx; + SV *err, *msg; + u_char *p; + STRLEN len; + ngx_err_t e; - ngx_http_perl_set_request(r); + ngx_http_perl_set_request(r, ctx); err = ST(1); diff --git a/src/http/modules/perl/ngx_http_perl_module.c b/src/http/modules/perl/ngx_http_perl_module.c index d06b43c75..c2ef47048 100644 --- a/src/http/modules/perl/ngx_http_perl_module.c +++ b/src/http/modules/perl/ngx_http_perl_module.c @@ -43,7 +43,8 @@ static PerlInterpreter *ngx_http_perl_create_interpreter(ngx_conf_t *cf, static ngx_int_t ngx_http_perl_run_requires(pTHX_ ngx_array_t *requires, ngx_log_t *log); static ngx_int_t ngx_http_perl_call_handler(pTHX_ ngx_http_request_t *r, - HV *nginx, SV *sub, SV **args, ngx_str_t *handler, ngx_str_t *rv); + ngx_http_perl_ctx_t *ctx, HV *nginx, SV *sub, SV **args, + ngx_str_t *handler, ngx_str_t *rv); static void ngx_http_perl_eval_anon_sub(pTHX_ ngx_str_t *handler, SV **sv); static ngx_int_t ngx_http_perl_preconfiguration(ngx_conf_t *cf); @@ -199,6 +200,8 @@ ngx_http_perl_handle_request(ngx_http_request_t *r) } ngx_http_set_ctx(r, ctx, ngx_http_perl_module); + + ctx->request = r; } pmcf = ngx_http_get_module_main_conf(r, ngx_http_perl_module); @@ -220,8 +223,8 @@ ngx_http_perl_handle_request(ngx_http_request_t *r) ctx->next = NULL; } - rc = ngx_http_perl_call_handler(aTHX_ r, pmcf->nginx, sub, NULL, handler, - NULL); + rc = ngx_http_perl_call_handler(aTHX_ r, ctx, pmcf->nginx, sub, NULL, + handler, NULL); } @@ -309,6 +312,8 @@ ngx_http_perl_variable(ngx_http_request_t *r, ngx_http_variable_value_t *v, } ngx_http_set_ctx(r, ctx, ngx_http_perl_module); + + ctx->request = r; } pmcf = ngx_http_get_module_main_conf(r, ngx_http_perl_module); @@ -321,7 +326,7 @@ ngx_http_perl_variable(ngx_http_request_t *r, ngx_http_variable_value_t *v, PERL_SET_CONTEXT(pmcf->perl); PERL_SET_INTERP(pmcf->perl); - rc = ngx_http_perl_call_handler(aTHX_ r, pmcf->nginx, pv->sub, NULL, + rc = ngx_http_perl_call_handler(aTHX_ r, ctx, pmcf->nginx, pv->sub, NULL, &pv->handler, &value); } @@ -372,6 +377,8 @@ ngx_http_perl_ssi(ngx_http_request_t *r, ngx_http_ssi_ctx_t *ssi_ctx, } ngx_http_set_ctx(r, ctx, ngx_http_perl_module); + + ctx->request = r; } pmcf = ngx_http_get_module_main_conf(r, ngx_http_perl_module); @@ -430,8 +437,8 @@ ngx_http_perl_ssi(ngx_http_request_t *r, ngx_http_ssi_ctx_t *ssi_ctx, asv = NULL; } - rc = ngx_http_perl_call_handler(aTHX_ r, pmcf->nginx, sv, asv, handler, - NULL); + rc = ngx_http_perl_call_handler(aTHX_ r, ctx, pmcf->nginx, sv, asv, + handler, NULL); SvREFCNT_dec(sv); @@ -667,8 +674,9 @@ ngx_http_perl_run_requires(pTHX_ ngx_array_t *requires, ngx_log_t *log) static ngx_int_t -ngx_http_perl_call_handler(pTHX_ ngx_http_request_t *r, HV *nginx, SV *sub, - SV **args, ngx_str_t *handler, ngx_str_t *rv) +ngx_http_perl_call_handler(pTHX_ ngx_http_request_t *r, + ngx_http_perl_ctx_t *ctx, HV *nginx, SV *sub, SV **args, + ngx_str_t *handler, ngx_str_t *rv) { SV *sv; int n, status; @@ -687,7 +695,7 @@ ngx_http_perl_call_handler(pTHX_ ngx_http_request_t *r, HV *nginx, SV *sub, PUSHMARK(sp); - sv = sv_2mortal(sv_bless(newRV_noinc(newSViv(PTR2IV(r))), nginx)); + sv = sv_2mortal(sv_bless(newRV_noinc(newSViv(PTR2IV(ctx))), nginx)); XPUSHs(sv); if (args) { diff --git a/src/http/modules/perl/ngx_http_perl_module.h b/src/http/modules/perl/ngx_http_perl_module.h index 5e60b031e..4f1eaa3a2 100644 --- a/src/http/modules/perl/ngx_http_perl_module.h +++ b/src/http/modules/perl/ngx_http_perl_module.h @@ -21,6 +21,8 @@ typedef ngx_http_request_t *nginx; typedef struct { + ngx_http_request_t *request; + ngx_str_t filename; ngx_str_t redirect_uri; ngx_str_t redirect_args; -- GitLab From 4a0771f9a62eccf168e651a502e67ec17d1cd6c7 Mon Sep 17 00:00:00 2001 From: Maxim Dounin <mdounin@mdounin.ru> Date: Fri, 12 Jul 2019 13:56:21 +0300 Subject: [PATCH 12/33] Perl: propagate errors. When an error happens, the ctx->error bit is now set, and croak() is called to terminate further processing. The ctx->error bit is checked in ngx_http_perl_call_handler() to cancel further processing, and is also checked in various output functions - to make sure these won't be called if croak() was handled by an eval{} in perl code. In particular, this ensures that output chain won't be called after errors, as filters might not expect this to happen. This fixes some segmentation faults under low memory conditions. Also this stops request processing after filter finalization or request body reading errors. For cases where an HTTP error status can be additionally returned (for example, 416 (Requested Range Not Satisfiable) from the range filter), the ctx->status field is also added. --- src/http/modules/perl/nginx.xs | 72 ++++++++++++++++++-- src/http/modules/perl/ngx_http_perl_module.c | 20 ++++++ src/http/modules/perl/ngx_http_perl_module.h | 5 +- 3 files changed, 90 insertions(+), 7 deletions(-) diff --git a/src/http/modules/perl/nginx.xs b/src/http/modules/perl/nginx.xs index 2e9808f2b..8e17f6d57 100644 --- a/src/http/modules/perl/nginx.xs +++ b/src/http/modules/perl/nginx.xs @@ -125,9 +125,14 @@ send_http_header(r, ...) ngx_http_request_t *r; ngx_http_perl_ctx_t *ctx; SV *sv; + ngx_int_t rc; ngx_http_perl_set_request(r, ctx); + if (ctx->error) { + croak("send_http_header(): called after error"); + } + if (r->headers_out.status == 0) { r->headers_out.status = NGX_HTTP_OK; } @@ -151,7 +156,13 @@ send_http_header(r, ...) r->disable_not_modified = 1; - (void) ngx_http_send_header(r); + rc = ngx_http_send_header(r); + + if (rc == NGX_ERROR || rc > NGX_OK) { + ctx->error = 1; + ctx->status = rc; + croak("ngx_http_send_header() failed"); + } void @@ -381,6 +392,7 @@ has_request_body(r, next) dXSTARG; ngx_http_request_t *r; ngx_http_perl_ctx_t *ctx; + ngx_int_t rc; ngx_http_perl_set_request(r, ctx); @@ -398,7 +410,14 @@ has_request_body(r, next) r->request_body_file_log_level = 0; } - ngx_http_read_client_request_body(r, ngx_http_perl_handle_request); + rc = ngx_http_read_client_request_body(r, ngx_http_perl_handle_request); + + if (rc >= NGX_HTTP_SPECIAL_RESPONSE) { + ctx->error = 1; + ctx->status = rc; + ctx->next = NULL; + croak("ngx_http_read_client_request_body() failed"); + } sv_upgrade(TARG, SVt_IV); sv_setiv(TARG, 1); @@ -494,10 +513,17 @@ discard_request_body(r) ngx_http_request_t *r; ngx_http_perl_ctx_t *ctx; + ngx_int_t rc; ngx_http_perl_set_request(r, ctx); - ngx_http_discard_request_body(r); + rc = ngx_http_discard_request_body(r); + + if (rc != NGX_OK) { + ctx->error = 1; + ctx->status = rc; + croak("ngx_http_discard_request_body() failed"); + } void @@ -512,6 +538,10 @@ header_out(r, key, value) ngx_http_perl_set_request(r, ctx); + if (ctx->error) { + croak("header_out(): called after error"); + } + key = ST(1); value = ST(2); @@ -588,10 +618,15 @@ print(r, ...) u_char *p; size_t size; STRLEN len; + ngx_int_t rc; ngx_buf_t *b; ngx_http_perl_set_request(r, ctx); + if (ctx->error) { + croak("print(): called after error"); + } + if (items == 2) { /* @@ -671,7 +706,12 @@ print(r, ...) out: - (void) ngx_http_perl_output(r, ctx, b); + rc = ngx_http_perl_output(r, ctx, b); + + if (rc == NGX_ERROR) { + ctx->error = 1; + croak("ngx_http_perl_output() failed"); + } void @@ -683,6 +723,7 @@ sendfile(r, filename, offset = -1, bytes = 0) char *filename; off_t offset; size_t bytes; + ngx_int_t rc; ngx_str_t path; ngx_buf_t *b; ngx_open_file_info_t of; @@ -690,6 +731,10 @@ sendfile(r, filename, offset = -1, bytes = 0) ngx_http_perl_set_request(r, ctx); + if (ctx->error) { + croak("sendfile(): called after error"); + } + filename = SvPV_nolen(ST(1)); if (filename == NULL) { @@ -762,7 +807,12 @@ sendfile(r, filename, offset = -1, bytes = 0) b->file->log = r->connection->log; b->file->directio = of.is_directio; - (void) ngx_http_perl_output(r, ctx, b); + rc = ngx_http_perl_output(r, ctx, b); + + if (rc == NGX_ERROR) { + ctx->error = 1; + croak("ngx_http_perl_output() failed"); + } void @@ -771,10 +821,15 @@ flush(r) ngx_http_request_t *r; ngx_http_perl_ctx_t *ctx; + ngx_int_t rc; ngx_buf_t *b; ngx_http_perl_set_request(r, ctx); + if (ctx->error) { + croak("flush(): called after error"); + } + b = ngx_calloc_buf(r->pool); if (b == NULL) { XSRETURN_EMPTY; @@ -784,7 +839,12 @@ flush(r) ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "$r->flush"); - (void) ngx_http_perl_output(r, ctx, b); + rc = ngx_http_perl_output(r, ctx, b); + + if (rc == NGX_ERROR) { + ctx->error = 1; + croak("ngx_http_perl_output() failed"); + } XSRETURN_EMPTY; diff --git a/src/http/modules/perl/ngx_http_perl_module.c b/src/http/modules/perl/ngx_http_perl_module.c index c2ef47048..ac6a7a2a3 100644 --- a/src/http/modules/perl/ngx_http_perl_module.c +++ b/src/http/modules/perl/ngx_http_perl_module.c @@ -246,6 +246,11 @@ ngx_http_perl_handle_request(ngx_http_request_t *r) ctx->filename.data = NULL; ctx->redirect_uri.len = 0; + if (rc == NGX_ERROR) { + ngx_http_finalize_request(r, rc); + return; + } + if (ctx->done || ctx->next) { ngx_http_finalize_request(r, NGX_DONE); return; @@ -690,6 +695,9 @@ ngx_http_perl_call_handler(pTHX_ ngx_http_request_t *r, status = 0; + ctx->error = 0; + ctx->status = NGX_OK; + ENTER; SAVETMPS; @@ -739,6 +747,18 @@ ngx_http_perl_call_handler(pTHX_ ngx_http_request_t *r, FREETMPS; LEAVE; + if (ctx->error) { + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, + "call_sv: error, %d", ctx->status); + + if (ctx->status != NGX_OK) { + return ctx->status; + } + + return NGX_ERROR; + } + /* check $@ */ if (SvTRUE(ERRSV)) { diff --git a/src/http/modules/perl/ngx_http_perl_module.h b/src/http/modules/perl/ngx_http_perl_module.h index 4f1eaa3a2..5c967dfb3 100644 --- a/src/http/modules/perl/ngx_http_perl_module.h +++ b/src/http/modules/perl/ngx_http_perl_module.h @@ -29,7 +29,10 @@ typedef struct { SV *next; - ngx_uint_t done; /* unsigned done:1; */ + ngx_int_t status; + + unsigned done:1; + unsigned error:1; ngx_array_t *variables; /* array of ngx_http_perl_var_t */ -- GitLab From 9d266efbc0c1170215397ae669165911b5a828d6 Mon Sep 17 00:00:00 2001 From: Maxim Dounin <mdounin@mdounin.ru> Date: Fri, 12 Jul 2019 13:56:23 +0300 Subject: [PATCH 13/33] Perl: handling of allocation errors. Previously, allocation errors in nginx.xs were more or less ignored, potentially resulting in incorrect code execution in specific low-memory conditions. This is changed to use ctx->error bit and croak(), similarly to how output errors are now handled. Note that this is mostly a cosmetic change, as Perl itself exits on memory allocation errors, and hence nginx with Perl is hardly usable in low-memory conditions. --- src/http/modules/perl/nginx.xs | 76 +++++++++++++++++++++++----------- 1 file changed, 51 insertions(+), 25 deletions(-) diff --git a/src/http/modules/perl/nginx.xs b/src/http/modules/perl/nginx.xs index 8e17f6d57..104def1e8 100644 --- a/src/http/modules/perl/nginx.xs +++ b/src/http/modules/perl/nginx.xs @@ -143,14 +143,16 @@ send_http_header(r, ...) if (ngx_http_perl_sv2str(aTHX_ r, &r->headers_out.content_type, sv) != NGX_OK) { - XSRETURN_EMPTY; + ctx->error = 1; + croak("ngx_http_perl_sv2str() failed"); } r->headers_out.content_type_len = r->headers_out.content_type.len; } else { if (ngx_http_set_content_type(r) != NGX_OK) { - XSRETURN_EMPTY; + ctx->error = 1; + croak("ngx_http_set_content_type() failed"); } } @@ -270,7 +272,8 @@ header_in(r, key) lowcase_key = ngx_pnalloc(r->pool, len); if (lowcase_key == NULL) { - XSRETURN_UNDEF; + ctx->error = 1; + croak("ngx_pnalloc() failed"); } hash = ngx_hash_strlow(lowcase_key, p, len); @@ -330,7 +333,8 @@ header_in(r, key) value = ngx_pnalloc(r->pool, size); if (value == NULL) { - XSRETURN_UNDEF; + ctx->error = 1; + croak("ngx_pnalloc() failed"); } p = value; @@ -465,7 +469,8 @@ request_body(r) p = ngx_pnalloc(r->pool, len); if (p == NULL) { - XSRETURN_UNDEF; + ctx->error = 1; + croak("ngx_pnalloc() failed"); } data = p; @@ -547,19 +552,22 @@ header_out(r, key, value) header = ngx_list_push(&r->headers_out.headers); if (header == NULL) { - XSRETURN_EMPTY; + ctx->error = 1; + croak("ngx_list_push() failed"); } header->hash = 1; if (ngx_http_perl_sv2str(aTHX_ r, &header->key, key) != NGX_OK) { header->hash = 0; - XSRETURN_EMPTY; + ctx->error = 1; + croak("ngx_http_perl_sv2str() failed"); } if (ngx_http_perl_sv2str(aTHX_ r, &header->value, value) != NGX_OK) { header->hash = 0; - XSRETURN_EMPTY; + ctx->error = 1; + croak("ngx_http_perl_sv2str() failed"); } if (header->key.len == sizeof("Content-Length") - 1 @@ -594,7 +602,8 @@ filename(r) } if (ngx_http_map_uri_to_path(r, &ctx->filename, &root, 0) == NULL) { - XSRETURN_UNDEF; + ctx->error = 1; + croak("ngx_http_map_uri_to_path() failed"); } ctx->filename.len--; @@ -650,7 +659,8 @@ print(r, ...) b = ngx_calloc_buf(r->pool); if (b == NULL) { - XSRETURN_EMPTY; + ctx->error = 1; + croak("ngx_calloc_buf() failed"); } b->memory = 1; @@ -690,7 +700,8 @@ print(r, ...) b = ngx_create_temp_buf(r->pool, size); if (b == NULL) { - XSRETURN_EMPTY; + ctx->error = 1; + croak("ngx_create_temp_buf() failed"); } for (i = 1; i < items; i++) { @@ -746,19 +757,22 @@ sendfile(r, filename, offset = -1, bytes = 0) b = ngx_calloc_buf(r->pool); if (b == NULL) { - XSRETURN_EMPTY; + ctx->error = 1; + croak("ngx_calloc_buf() failed"); } b->file = ngx_pcalloc(r->pool, sizeof(ngx_file_t)); if (b->file == NULL) { - XSRETURN_EMPTY; + ctx->error = 1; + croak("ngx_pcalloc() failed"); } path.len = ngx_strlen(filename); path.data = ngx_pnalloc(r->pool, path.len + 1); if (path.data == NULL) { - XSRETURN_EMPTY; + ctx->error = 1; + croak("ngx_pnalloc() failed"); } (void) ngx_cpystrn(path.data, (u_char *) filename, path.len + 1); @@ -775,19 +789,23 @@ sendfile(r, filename, offset = -1, bytes = 0) of.events = clcf->open_file_cache_events; if (ngx_http_set_disable_symlinks(r, clcf, &path, &of) != NGX_OK) { - XSRETURN_EMPTY; + ctx->error = 1; + croak("ngx_http_set_disable_symlinks() failed"); } if (ngx_open_cached_file(clcf->open_file_cache, &path, &of, r->pool) != NGX_OK) { if (of.err == 0) { - XSRETURN_EMPTY; + ctx->error = 1; + croak("ngx_open_cached_file() failed"); } ngx_log_error(NGX_LOG_CRIT, r->connection->log, ngx_errno, "%s \"%s\" failed", of.failed, filename); - XSRETURN_EMPTY; + + ctx->error = 1; + croak("ngx_open_cached_file() failed"); } if (offset == -1) { @@ -832,7 +850,8 @@ flush(r) b = ngx_calloc_buf(r->pool); if (b == NULL) { - XSRETURN_EMPTY; + ctx->error = 1; + croak("ngx_calloc_buf() failed"); } b->flush = 1; @@ -863,7 +882,8 @@ internal_redirect(r, uri) uri = ST(1); if (ngx_http_perl_sv2str(aTHX_ r, &ctx->redirect_uri, uri) != NGX_OK) { - XSRETURN_EMPTY; + ctx->error = 1; + croak("ngx_http_perl_sv2str() failed"); } for (i = 0; i < ctx->redirect_uri.len; i++) { @@ -910,7 +930,8 @@ unescape(r, text, type = 0) p = ngx_pnalloc(r->pool, len + 1); if (p == NULL) { - XSRETURN_UNDEF; + ctx->error = 1; + croak("ngx_pnalloc() failed"); } dst = p; @@ -959,7 +980,8 @@ variable(r, name, value = NULL) } if (ngx_http_perl_sv2str(aTHX_ r, &val, value) != NGX_OK) { - XSRETURN_UNDEF; + ctx->error = 1; + croak("ngx_http_perl_sv2str() failed"); } } @@ -967,7 +989,8 @@ variable(r, name, value = NULL) lowcase = ngx_pnalloc(r->pool, len); if (lowcase == NULL) { - XSRETURN_UNDEF; + ctx->error = 1; + croak("ngx_pnalloc() failed"); } hash = ngx_hash_strlow(lowcase, p, len); @@ -987,7 +1010,8 @@ variable(r, name, value = NULL) vv = ngx_http_get_variable(r, &var, hash); if (vv == NULL) { - XSRETURN_UNDEF; + ctx->error = 1; + croak("ngx_http_get_variable() failed"); } if (vv->not_found) { @@ -1020,13 +1044,15 @@ variable(r, name, value = NULL) ctx->variables = ngx_array_create(r->pool, 1, sizeof(ngx_http_perl_var_t)); if (ctx->variables == NULL) { - XSRETURN_UNDEF; + ctx->error = 1; + croak("ngx_array_create() failed"); } } v = ngx_array_push(ctx->variables); if (v == NULL) { - XSRETURN_UNDEF; + ctx->error = 1; + croak("ngx_array_push() failed"); } v->hash = hash; -- GitLab From 19887831698e18149a45a8b9563e8fdcdaaea211 Mon Sep 17 00:00:00 2001 From: Maxim Dounin <mdounin@mdounin.ru> Date: Fri, 12 Jul 2019 15:34:37 +0300 Subject: [PATCH 14/33] Perl: protection against duplicate $r->sleep() calls. Duplicate $r->sleep() and/or $r->has_request_body() calls result in undefined behaviour (in practice, connection leaks were observed). To prevent this, croak() added in appropriate places. --- src/http/modules/perl/nginx.xs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/http/modules/perl/nginx.xs b/src/http/modules/perl/nginx.xs index 104def1e8..e9db2f7d6 100644 --- a/src/http/modules/perl/nginx.xs +++ b/src/http/modules/perl/nginx.xs @@ -400,6 +400,10 @@ has_request_body(r, next) ngx_http_perl_set_request(r, ctx); + if (ctx->next) { + croak("has_request_body(): another handler active"); + } + if (r->headers_in.content_length_n <= 0 && !r->headers_in.chunked) { XSRETURN_UNDEF; } @@ -1093,6 +1097,10 @@ sleep(r, sleep, next) ngx_http_perl_set_request(r, ctx); + if (ctx->next) { + croak("sleep(): another handler active"); + } + sleep = (ngx_msec_t) SvIV(ST(1)); ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, -- GitLab From cae2e689083a04b2ddbb93bef5313b136080df65 Mon Sep 17 00:00:00 2001 From: Maxim Dounin <mdounin@mdounin.ru> Date: Fri, 12 Jul 2019 15:35:31 +0300 Subject: [PATCH 15/33] Perl: disabled unrelated calls from variable handlers. Variable handlers are not expected to send anything to the client, cannot sleep or read body, and are not expected to modify the request. Added appropriate protection to prevent accidental foot shooting. --- src/http/modules/perl/nginx.xs | 44 ++++++++++++++++++++ src/http/modules/perl/ngx_http_perl_module.c | 5 +++ src/http/modules/perl/ngx_http_perl_module.h | 1 + 3 files changed, 50 insertions(+) diff --git a/src/http/modules/perl/nginx.xs b/src/http/modules/perl/nginx.xs index e9db2f7d6..67ec0a564 100644 --- a/src/http/modules/perl/nginx.xs +++ b/src/http/modules/perl/nginx.xs @@ -110,6 +110,10 @@ status(r, code) ngx_http_perl_set_request(r, ctx); + if (ctx->variable) { + croak("status(): cannot be used in variable handler"); + } + r->headers_out.status = SvIV(ST(1)); ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, @@ -133,6 +137,10 @@ send_http_header(r, ...) croak("send_http_header(): called after error"); } + if (ctx->variable) { + croak("send_http_header(): cannot be used in variable handler"); + } + if (r->headers_out.status == 0) { r->headers_out.status = NGX_HTTP_OK; } @@ -400,6 +408,10 @@ has_request_body(r, next) ngx_http_perl_set_request(r, ctx); + if (ctx->variable) { + croak("has_request_body(): cannot be used in variable handler"); + } + if (ctx->next) { croak("has_request_body(): another handler active"); } @@ -526,6 +538,10 @@ discard_request_body(r) ngx_http_perl_set_request(r, ctx); + if (ctx->variable) { + croak("discard_request_body(): cannot be used in variable handler"); + } + rc = ngx_http_discard_request_body(r); if (rc != NGX_OK) { @@ -551,6 +567,10 @@ header_out(r, key, value) croak("header_out(): called after error"); } + if (ctx->variable) { + croak("header_out(): cannot be used in variable handler"); + } + key = ST(1); value = ST(2); @@ -640,6 +660,10 @@ print(r, ...) croak("print(): called after error"); } + if (ctx->variable) { + croak("print(): cannot be used in variable handler"); + } + if (items == 2) { /* @@ -750,6 +774,10 @@ sendfile(r, filename, offset = -1, bytes = 0) croak("sendfile(): called after error"); } + if (ctx->variable) { + croak("sendfile(): cannot be used in variable handler"); + } + filename = SvPV_nolen(ST(1)); if (filename == NULL) { @@ -852,6 +880,10 @@ flush(r) croak("flush(): called after error"); } + if (ctx->variable) { + croak("flush(): cannot be used in variable handler"); + } + b = ngx_calloc_buf(r->pool); if (b == NULL) { ctx->error = 1; @@ -883,6 +915,10 @@ internal_redirect(r, uri) ngx_http_perl_set_request(r, ctx); + if (ctx->variable) { + croak("internal_redirect(): cannot be used in variable handler"); + } + uri = ST(1); if (ngx_http_perl_sv2str(aTHX_ r, &ctx->redirect_uri, uri) != NGX_OK) { @@ -911,6 +947,10 @@ allow_ranges(r) ngx_http_perl_set_request(r, ctx); + if (ctx->variable) { + croak("allow_ranges(): cannot be used in variable handler"); + } + r->allow_ranges = 1; @@ -1097,6 +1137,10 @@ sleep(r, sleep, next) ngx_http_perl_set_request(r, ctx); + if (ctx->variable) { + croak("sleep(): cannot be used in variable handler"); + } + if (ctx->next) { croak("sleep(): another handler active"); } diff --git a/src/http/modules/perl/ngx_http_perl_module.c b/src/http/modules/perl/ngx_http_perl_module.c index ac6a7a2a3..a383e9002 100644 --- a/src/http/modules/perl/ngx_http_perl_module.c +++ b/src/http/modules/perl/ngx_http_perl_module.c @@ -302,6 +302,7 @@ ngx_http_perl_variable(ngx_http_request_t *r, ngx_http_variable_value_t *v, ngx_int_t rc; ngx_str_t value; + ngx_uint_t saved; ngx_http_perl_ctx_t *ctx; ngx_http_perl_main_conf_t *pmcf; @@ -321,6 +322,9 @@ ngx_http_perl_variable(ngx_http_request_t *r, ngx_http_variable_value_t *v, ctx->request = r; } + saved = ctx->variable; + ctx->variable = 1; + pmcf = ngx_http_get_module_main_conf(r, ngx_http_perl_module); value.data = NULL; @@ -347,6 +351,7 @@ ngx_http_perl_variable(ngx_http_request_t *r, ngx_http_variable_value_t *v, v->not_found = 1; } + ctx->variable = saved; ctx->filename.data = NULL; ctx->redirect_uri.len = 0; diff --git a/src/http/modules/perl/ngx_http_perl_module.h b/src/http/modules/perl/ngx_http_perl_module.h index 5c967dfb3..b67ce137c 100644 --- a/src/http/modules/perl/ngx_http_perl_module.h +++ b/src/http/modules/perl/ngx_http_perl_module.h @@ -33,6 +33,7 @@ typedef struct { unsigned done:1; unsigned error:1; + unsigned variable:1; ngx_array_t *variables; /* array of ngx_http_perl_var_t */ -- GitLab From 12d6b3b4a1d024bd8098e20b43b0b7020e5286e6 Mon Sep 17 00:00:00 2001 From: Maxim Dounin <mdounin@mdounin.ru> Date: Fri, 12 Jul 2019 15:38:27 +0300 Subject: [PATCH 16/33] Perl: avoid redirects on errors. Previously, redirects scheduled with $r->internal_redirect() were followed even if the code then died. Now these are ignored and nginx will return an error instead. --- src/http/modules/perl/ngx_http_perl_module.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/http/modules/perl/ngx_http_perl_module.c b/src/http/modules/perl/ngx_http_perl_module.c index a383e9002..81b2526ad 100644 --- a/src/http/modules/perl/ngx_http_perl_module.c +++ b/src/http/modules/perl/ngx_http_perl_module.c @@ -778,6 +778,8 @@ ngx_http_perl_call_handler(pTHX_ ngx_http_request_t *r, return NGX_ERROR; } + ctx->redirect_uri.len = 0; + return NGX_HTTP_INTERNAL_SERVER_ERROR; } -- GitLab From 78b39bd631fc18fd5778090183776f5275005e21 Mon Sep 17 00:00:00 2001 From: Maxim Dounin <mdounin@mdounin.ru> Date: Fri, 12 Jul 2019 15:39:25 +0300 Subject: [PATCH 17/33] Perl: avoid returning 500 if header was already sent. Returning NGX_HTTP_INTERNAL_SERVER_ERROR if a perl code died after sending header will lead to a "header already sent" alert. To avoid it, we now check if header was already sent, and return NGX_ERROR instead if it was. --- src/http/modules/perl/nginx.xs | 2 ++ src/http/modules/perl/ngx_http_perl_module.c | 4 ++++ src/http/modules/perl/ngx_http_perl_module.h | 1 + 3 files changed, 7 insertions(+) diff --git a/src/http/modules/perl/nginx.xs b/src/http/modules/perl/nginx.xs index 67ec0a564..34ce9daed 100644 --- a/src/http/modules/perl/nginx.xs +++ b/src/http/modules/perl/nginx.xs @@ -164,6 +164,8 @@ send_http_header(r, ...) } } + ctx->header_sent = 1; + r->disable_not_modified = 1; rc = ngx_http_send_header(r); diff --git a/src/http/modules/perl/ngx_http_perl_module.c b/src/http/modules/perl/ngx_http_perl_module.c index 81b2526ad..dc2125935 100644 --- a/src/http/modules/perl/ngx_http_perl_module.c +++ b/src/http/modules/perl/ngx_http_perl_module.c @@ -780,6 +780,10 @@ ngx_http_perl_call_handler(pTHX_ ngx_http_request_t *r, ctx->redirect_uri.len = 0; + if (ctx->header_sent) { + return NGX_ERROR; + } + return NGX_HTTP_INTERNAL_SERVER_ERROR; } diff --git a/src/http/modules/perl/ngx_http_perl_module.h b/src/http/modules/perl/ngx_http_perl_module.h index b67ce137c..da3a16235 100644 --- a/src/http/modules/perl/ngx_http_perl_module.h +++ b/src/http/modules/perl/ngx_http_perl_module.h @@ -34,6 +34,7 @@ typedef struct { unsigned done:1; unsigned error:1; unsigned variable:1; + unsigned header_sent:1; ngx_array_t *variables; /* array of ngx_http_perl_var_t */ -- GitLab From 9e883a2e48ff8e55fcfb091284b44d8fa66fc007 Mon Sep 17 00:00:00 2001 From: Maxim Dounin <mdounin@mdounin.ru> Date: Fri, 12 Jul 2019 15:39:25 +0300 Subject: [PATCH 18/33] Perl: additional ctx->header_sent checks. As we now have ctx->header_sent flag, it is further used to prevent duplicate $r->send_http_header() calls, prevent output before sending header, and $r->internal_redirect() after sending header. Further, $r->send_http_header() protected from calls after $r->internal_redirect(). --- src/http/modules/perl/nginx.xs | 24 ++++++++++++++++++++ src/http/modules/perl/ngx_http_perl_module.c | 1 + 2 files changed, 25 insertions(+) diff --git a/src/http/modules/perl/nginx.xs b/src/http/modules/perl/nginx.xs index 34ce9daed..7370bf5fc 100644 --- a/src/http/modules/perl/nginx.xs +++ b/src/http/modules/perl/nginx.xs @@ -141,6 +141,14 @@ send_http_header(r, ...) croak("send_http_header(): cannot be used in variable handler"); } + if (ctx->header_sent) { + croak("send_http_header(): header already sent"); + } + + if (ctx->redirect_uri.len) { + croak("send_http_header(): cannot be used with internal_redirect()"); + } + if (r->headers_out.status == 0) { r->headers_out.status = NGX_HTTP_OK; } @@ -666,6 +674,10 @@ print(r, ...) croak("print(): cannot be used in variable handler"); } + if (!ctx->header_sent) { + croak("print(): header not sent"); + } + if (items == 2) { /* @@ -780,6 +792,10 @@ sendfile(r, filename, offset = -1, bytes = 0) croak("sendfile(): cannot be used in variable handler"); } + if (!ctx->header_sent) { + croak("sendfile(): header not sent"); + } + filename = SvPV_nolen(ST(1)); if (filename == NULL) { @@ -886,6 +902,10 @@ flush(r) croak("flush(): cannot be used in variable handler"); } + if (!ctx->header_sent) { + croak("flush(): header not sent"); + } + b = ngx_calloc_buf(r->pool); if (b == NULL) { ctx->error = 1; @@ -921,6 +941,10 @@ internal_redirect(r, uri) croak("internal_redirect(): cannot be used in variable handler"); } + if (ctx->header_sent) { + croak("internal_redirect(): header already sent"); + } + uri = ST(1); if (ngx_http_perl_sv2str(aTHX_ r, &ctx->redirect_uri, uri) != NGX_OK) { diff --git a/src/http/modules/perl/ngx_http_perl_module.c b/src/http/modules/perl/ngx_http_perl_module.c index dc2125935..d2a0dfae5 100644 --- a/src/http/modules/perl/ngx_http_perl_module.c +++ b/src/http/modules/perl/ngx_http_perl_module.c @@ -394,6 +394,7 @@ ngx_http_perl_ssi(ngx_http_request_t *r, ngx_http_ssi_ctx_t *ssi_ctx, pmcf = ngx_http_get_module_main_conf(r, ngx_http_perl_module); ctx->ssi = ssi_ctx; + ctx->header_sent = 1; handler = params[NGX_HTTP_PERL_SSI_SUB]; handler->data[handler->len] = '\0'; -- GitLab From 8df08b02b89c151e4bf04bc3c7c9a37e9ebcba9d Mon Sep 17 00:00:00 2001 From: Maxim Dounin <mdounin@mdounin.ru> Date: Fri, 12 Jul 2019 15:39:26 +0300 Subject: [PATCH 19/33] Perl: expect escaped URIs in $r->internal_redirect(). Similarly to the change in 5491:74bfa803a5aa (1.5.9), we should accept properly escaped URIs and unescape them as needed, else it is not possible to handle URIs with question marks. --- src/http/modules/perl/nginx.xs | 11 ----------- src/http/modules/perl/ngx_http_perl_module.c | 10 +++++++++- src/http/modules/perl/ngx_http_perl_module.h | 1 - 3 files changed, 9 insertions(+), 13 deletions(-) diff --git a/src/http/modules/perl/nginx.xs b/src/http/modules/perl/nginx.xs index 7370bf5fc..309b7cbfb 100644 --- a/src/http/modules/perl/nginx.xs +++ b/src/http/modules/perl/nginx.xs @@ -952,17 +952,6 @@ internal_redirect(r, uri) croak("ngx_http_perl_sv2str() failed"); } - for (i = 0; i < ctx->redirect_uri.len; i++) { - if (ctx->redirect_uri.data[i] == '?') { - - ctx->redirect_args.len = ctx->redirect_uri.len - (i + 1); - ctx->redirect_args.data = &ctx->redirect_uri.data[i + 1]; - ctx->redirect_uri.len = i; - - XSRETURN_EMPTY; - } - } - void allow_ranges(r) diff --git a/src/http/modules/perl/ngx_http_perl_module.c b/src/http/modules/perl/ngx_http_perl_module.c index d2a0dfae5..a123e3875 100644 --- a/src/http/modules/perl/ngx_http_perl_module.c +++ b/src/http/modules/perl/ngx_http_perl_module.c @@ -184,6 +184,7 @@ ngx_http_perl_handle_request(ngx_http_request_t *r) SV *sub; ngx_int_t rc; ngx_str_t uri, args, *handler; + ngx_uint_t flags; ngx_http_perl_ctx_t *ctx; ngx_http_perl_loc_conf_t *plcf; ngx_http_perl_main_conf_t *pmcf; @@ -237,7 +238,6 @@ ngx_http_perl_handle_request(ngx_http_request_t *r) if (ctx->redirect_uri.len) { uri = ctx->redirect_uri; - args = ctx->redirect_args; } else { uri.len = 0; @@ -257,6 +257,14 @@ ngx_http_perl_handle_request(ngx_http_request_t *r) } if (uri.len) { + ngx_str_null(&args); + flags = NGX_HTTP_LOG_UNSAFE; + + if (ngx_http_parse_unsafe_uri(r, &uri, &args, &flags) != NGX_OK) { + ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); + return; + } + ngx_http_internal_redirect(r, &uri, &args); ngx_http_finalize_request(r, NGX_DONE); return; diff --git a/src/http/modules/perl/ngx_http_perl_module.h b/src/http/modules/perl/ngx_http_perl_module.h index da3a16235..8fa59a4c5 100644 --- a/src/http/modules/perl/ngx_http_perl_module.h +++ b/src/http/modules/perl/ngx_http_perl_module.h @@ -25,7 +25,6 @@ typedef struct { ngx_str_t filename; ngx_str_t redirect_uri; - ngx_str_t redirect_args; SV *next; -- GitLab From 29fea7d9ec7b18d9f3c2e77bddd873dafbd10842 Mon Sep 17 00:00:00 2001 From: Maxim Dounin <mdounin@mdounin.ru> Date: Fri, 12 Jul 2019 15:39:28 +0300 Subject: [PATCH 20/33] Perl: named locations in $r->internal_redirect(). --- src/http/modules/perl/ngx_http_perl_module.c | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/src/http/modules/perl/ngx_http_perl_module.c b/src/http/modules/perl/ngx_http_perl_module.c index a123e3875..f3fc62947 100644 --- a/src/http/modules/perl/ngx_http_perl_module.c +++ b/src/http/modules/perl/ngx_http_perl_module.c @@ -257,15 +257,21 @@ ngx_http_perl_handle_request(ngx_http_request_t *r) } if (uri.len) { - ngx_str_null(&args); - flags = NGX_HTTP_LOG_UNSAFE; + if (uri.data[0] == '@') { + ngx_http_named_location(r, &uri); - if (ngx_http_parse_unsafe_uri(r, &uri, &args, &flags) != NGX_OK) { - ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); - return; + } else { + ngx_str_null(&args); + flags = NGX_HTTP_LOG_UNSAFE; + + if (ngx_http_parse_unsafe_uri(r, &uri, &args, &flags) != NGX_OK) { + ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); + return; + } + + ngx_http_internal_redirect(r, &uri, &args); } - ngx_http_internal_redirect(r, &uri, &args); ngx_http_finalize_request(r, NGX_DONE); return; } -- GitLab From cfa1316368dcc6dc1aa82e3d0b67ec0d1cf7eebb Mon Sep 17 00:00:00 2001 From: Ilya Leoshkevich <iii@linux.ibm.com> Date: Fri, 12 Jul 2019 12:43:08 +0200 Subject: [PATCH 21/33] Gzip: use zlib to write header and trailer. When nginx is used with zlib patched with [1], which provides integration with the future IBM Z hardware deflate acceleration, it ends up computing CRC32 twice: one time in hardware, which always does this, and one time in software by explicitly calling crc32(). crc32() calls were added in changesets 133:b27548f540ad ("nginx-0.0.1- 2003-09-24-23:51:12 import") and 134:d57c6835225c ("nginx-0.0.1- 2003-09-26-09:45:21 import") as part of gzip wrapping feature - back then zlib did not support it. However, since then gzip wrapping was implemented in zlib v1.2.0.4, and it's already being used by nginx for log compression. This patch replaces hand-written gzip wrapping with the one provided by zlib. It simplifies the code, and makes it avoid computing CRC32 twice when using hardware acceleration. [1] https://github.com/madler/zlib/pull/410 --- .../modules/ngx_http_gzip_filter_module.c | 124 +----------------- 1 file changed, 7 insertions(+), 117 deletions(-) diff --git a/src/http/modules/ngx_http_gzip_filter_module.c b/src/http/modules/ngx_http_gzip_filter_module.c index e4c343c9b..48f3dd7c7 100644 --- a/src/http/modules/ngx_http_gzip_filter_module.c +++ b/src/http/modules/ngx_http_gzip_filter_module.c @@ -55,44 +55,23 @@ typedef struct { unsigned redo:1; unsigned done:1; unsigned nomem:1; - unsigned gzheader:1; unsigned buffering:1; unsigned intel:1; size_t zin; size_t zout; - uint32_t crc32; z_stream zstream; ngx_http_request_t *request; } ngx_http_gzip_ctx_t; -#if (NGX_HAVE_LITTLE_ENDIAN && NGX_HAVE_NONALIGNED) - -struct gztrailer { - uint32_t crc32; - uint32_t zlen; -}; - -#else /* NGX_HAVE_BIG_ENDIAN || !NGX_HAVE_NONALIGNED */ - -struct gztrailer { - u_char crc32[4]; - u_char zlen[4]; -}; - -#endif - - static void ngx_http_gzip_filter_memory(ngx_http_request_t *r, ngx_http_gzip_ctx_t *ctx); static ngx_int_t ngx_http_gzip_filter_buffer(ngx_http_gzip_ctx_t *ctx, ngx_chain_t *in); static ngx_int_t ngx_http_gzip_filter_deflate_start(ngx_http_request_t *r, ngx_http_gzip_ctx_t *ctx); -static ngx_int_t ngx_http_gzip_filter_gzheader(ngx_http_request_t *r, - ngx_http_gzip_ctx_t *ctx); static ngx_int_t ngx_http_gzip_filter_add_data(ngx_http_request_t *r, ngx_http_gzip_ctx_t *ctx); static ngx_int_t ngx_http_gzip_filter_get_buf(ngx_http_request_t *r, @@ -446,12 +425,6 @@ ngx_http_gzip_body_filter(ngx_http_request_t *r, ngx_chain_t *in) return ctx->busy ? NGX_AGAIN : NGX_OK; } - if (!ctx->gzheader) { - if (ngx_http_gzip_filter_gzheader(r, ctx) != NGX_OK) { - goto failed; - } - } - rc = ngx_http_next_body_filter(r, ctx->out); if (rc == NGX_ERROR) { @@ -643,7 +616,7 @@ ngx_http_gzip_filter_deflate_start(ngx_http_request_t *r, ctx->zstream.opaque = ctx; rc = deflateInit2(&ctx->zstream, (int) conf->level, Z_DEFLATED, - - ctx->wbits, ctx->memlevel, Z_DEFAULT_STRATEGY); + ctx->wbits + 16, ctx->memlevel, Z_DEFAULT_STRATEGY); if (rc != Z_OK) { ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0, @@ -652,45 +625,12 @@ ngx_http_gzip_filter_deflate_start(ngx_http_request_t *r, } ctx->last_out = &ctx->out; - ctx->crc32 = crc32(0L, Z_NULL, 0); ctx->flush = Z_NO_FLUSH; return NGX_OK; } -static ngx_int_t -ngx_http_gzip_filter_gzheader(ngx_http_request_t *r, ngx_http_gzip_ctx_t *ctx) -{ - ngx_buf_t *b; - ngx_chain_t *cl; - static u_char gzheader[10] = - { 0x1f, 0x8b, Z_DEFLATED, 0, 0, 0, 0, 0, 0, 3 }; - - b = ngx_calloc_buf(r->pool); - if (b == NULL) { - return NGX_ERROR; - } - - b->memory = 1; - b->pos = gzheader; - b->last = b->pos + 10; - - cl = ngx_alloc_chain_link(r->pool); - if (cl == NULL) { - return NGX_ERROR; - } - - cl->buf = b; - cl->next = ctx->out; - ctx->out = cl; - - ctx->gzheader = 1; - - return NGX_OK; -} - - static ngx_int_t ngx_http_gzip_filter_add_data(ngx_http_request_t *r, ngx_http_gzip_ctx_t *ctx) { @@ -743,14 +683,9 @@ ngx_http_gzip_filter_add_data(ngx_http_request_t *r, ngx_http_gzip_ctx_t *ctx) } else if (ctx->in_buf->flush) { ctx->flush = Z_SYNC_FLUSH; - } - - if (ctx->zstream.avail_in) { - ctx->crc32 = crc32(ctx->crc32, ctx->zstream.next_in, - ctx->zstream.avail_in); - - } else if (ctx->flush == Z_NO_FLUSH) { + } else if (ctx->zstream.avail_in == 0) { + /* ctx->flush == Z_NO_FLUSH */ return NGX_AGAIN; } @@ -932,13 +867,11 @@ static ngx_int_t ngx_http_gzip_filter_deflate_end(ngx_http_request_t *r, ngx_http_gzip_ctx_t *ctx) { - int rc; - ngx_buf_t *b; - ngx_chain_t *cl; - struct gztrailer *trailer; + int rc; + ngx_chain_t *cl; ctx->zin = ctx->zstream.total_in; - ctx->zout = 10 + ctx->zstream.total_out + 8; + ctx->zout = ctx->zstream.total_out; rc = deflateEnd(&ctx->zstream); @@ -960,50 +893,7 @@ ngx_http_gzip_filter_deflate_end(ngx_http_request_t *r, *ctx->last_out = cl; ctx->last_out = &cl->next; - if (ctx->zstream.avail_out >= 8) { - trailer = (struct gztrailer *) ctx->out_buf->last; - ctx->out_buf->last += 8; - ctx->out_buf->last_buf = 1; - - } else { - b = ngx_create_temp_buf(r->pool, 8); - if (b == NULL) { - return NGX_ERROR; - } - - b->last_buf = 1; - - cl = ngx_alloc_chain_link(r->pool); - if (cl == NULL) { - return NGX_ERROR; - } - - cl->buf = b; - cl->next = NULL; - *ctx->last_out = cl; - ctx->last_out = &cl->next; - trailer = (struct gztrailer *) b->pos; - b->last += 8; - } - -#if (NGX_HAVE_LITTLE_ENDIAN && NGX_HAVE_NONALIGNED) - - trailer->crc32 = ctx->crc32; - trailer->zlen = ctx->zin; - -#else - - trailer->crc32[0] = (u_char) (ctx->crc32 & 0xff); - trailer->crc32[1] = (u_char) ((ctx->crc32 >> 8) & 0xff); - trailer->crc32[2] = (u_char) ((ctx->crc32 >> 16) & 0xff); - trailer->crc32[3] = (u_char) ((ctx->crc32 >> 24) & 0xff); - - trailer->zlen[0] = (u_char) (ctx->zin & 0xff); - trailer->zlen[1] = (u_char) ((ctx->zin >> 8) & 0xff); - trailer->zlen[2] = (u_char) ((ctx->zin >> 16) & 0xff); - trailer->zlen[3] = (u_char) ((ctx->zin >> 24) & 0xff); - -#endif + ctx->out_buf->last_buf = 1; ctx->zstream.avail_in = 0; ctx->zstream.avail_out = 0; -- GitLab From 676d1a0e947c8f39e2606997a3628ec6bdea177d Mon Sep 17 00:00:00 2001 From: Maxim Dounin <mdounin@mdounin.ru> Date: Wed, 17 Jul 2019 17:00:57 +0300 Subject: [PATCH 22/33] Perl: removed unused variable, forgotten in 975d7ab37b39. --- src/http/modules/perl/nginx.xs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/http/modules/perl/nginx.xs b/src/http/modules/perl/nginx.xs index 309b7cbfb..caf7c084a 100644 --- a/src/http/modules/perl/nginx.xs +++ b/src/http/modules/perl/nginx.xs @@ -933,7 +933,6 @@ internal_redirect(r, uri) ngx_http_request_t *r; ngx_http_perl_ctx_t *ctx; SV *uri; - ngx_uint_t i; ngx_http_perl_set_request(r, ctx); -- GitLab From 551640703a502a252b24c84d1b9e6541ee88de34 Mon Sep 17 00:00:00 2001 From: Maxim Dounin <mdounin@mdounin.ru> Date: Thu, 18 Jul 2019 18:27:44 +0300 Subject: [PATCH 23/33] Core: fixed segfault with too large bucket sizes (ticket #1806). To save memory hash code uses u_short to store resulting bucket sizes, so maximum bucket size is limited to 65536 minus ngx_cacheline_size (larger values will be aligned to 65536 which will overflow u_short). However, there were no checks to enforce this, and using larger bucket sizes resulted in overflows and segmentation faults. Appropriate safety checks to enforce this added to ngx_hash_init(). --- src/core/ngx_hash.c | 30 +++++++++++++++++++++++++----- 1 file changed, 25 insertions(+), 5 deletions(-) diff --git a/src/core/ngx_hash.c b/src/core/ngx_hash.c index 1944c7a21..d684e7057 100644 --- a/src/core/ngx_hash.c +++ b/src/core/ngx_hash.c @@ -265,6 +265,14 @@ ngx_hash_init(ngx_hash_init_t *hinit, ngx_hash_key_t *names, ngx_uint_t nelts) return NGX_ERROR; } + if (hinit->bucket_size > 65536 - ngx_cacheline_size) { + ngx_log_error(NGX_LOG_EMERG, hinit->pool->log, 0, + "could not build %s, too large " + "%s_bucket_size: %i", + hinit->name, hinit->name, hinit->bucket_size); + return NGX_ERROR; + } + for (n = 0; n < nelts; n++) { if (hinit->bucket_size < NGX_HASH_ELT_SIZE(&names[n]) + sizeof(void *)) { @@ -300,17 +308,19 @@ ngx_hash_init(ngx_hash_init_t *hinit, ngx_hash_key_t *names, ngx_uint_t nelts) } key = names[n].key_hash % size; - test[key] = (u_short) (test[key] + NGX_HASH_ELT_SIZE(&names[n])); + len = test[key] + NGX_HASH_ELT_SIZE(&names[n]); #if 0 ngx_log_error(NGX_LOG_ALERT, hinit->pool->log, 0, - "%ui: %ui %ui \"%V\"", - size, key, test[key], &names[n].key); + "%ui: %ui %uz \"%V\"", + size, key, len, &names[n].key); #endif - if (test[key] > (u_short) bucket_size) { + if (len > bucket_size) { goto next; } + + test[key] = (u_short) len; } goto found; @@ -341,7 +351,17 @@ found: } key = names[n].key_hash % size; - test[key] = (u_short) (test[key] + NGX_HASH_ELT_SIZE(&names[n])); + len = test[key] + NGX_HASH_ELT_SIZE(&names[n]); + + if (len > 65536 - ngx_cacheline_size) { + ngx_log_error(NGX_LOG_EMERG, hinit->pool->log, 0, + "could not build %s, you should " + "increase %s_max_size: %i", + hinit->name, hinit->name, hinit->max_size); + return NGX_ERROR; + } + + test[key] = (u_short) len; } len = 0; -- GitLab From 36dfa020f256dfc5beed3366be099d99543ad5b2 Mon Sep 17 00:00:00 2001 From: Maxim Dounin <mdounin@mdounin.ru> Date: Thu, 18 Jul 2019 18:27:50 +0300 Subject: [PATCH 24/33] HTTP/2: return error on output on closed stream. Without this, an (incorrect) output on a closed stream could result in a socket leak. --- src/http/v2/ngx_http_v2_filter_module.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/http/v2/ngx_http_v2_filter_module.c b/src/http/v2/ngx_http_v2_filter_module.c index 853faefd3..81e6c513a 100644 --- a/src/http/v2/ngx_http_v2_filter_module.c +++ b/src/http/v2/ngx_http_v2_filter_module.c @@ -1444,6 +1444,12 @@ ngx_http_v2_send_chain(ngx_connection_t *fc, ngx_chain_t *in, off_t limit) if (in == NULL || stream->out_closed) { + if (size) { + ngx_log_error(NGX_LOG_ERR, fc->log, 0, + "output on closed stream"); + return NGX_CHAIN_ERROR; + } + if (stream->queued) { fc->write->active = 1; fc->write->ready = 0; -- GitLab From 20c8c4fe35d290abe298cea9a4f1756fcfec19f4 Mon Sep 17 00:00:00 2001 From: Maxim Dounin <mdounin@mdounin.ru> Date: Thu, 18 Jul 2019 18:27:52 +0300 Subject: [PATCH 25/33] Upstream: fixed EOF handling in unbuffered and upgraded modes. With level-triggered event methods it is important to specify the NGX_CLOSE_EVENT flag to ngx_handle_read_event(), otherwise the event won't be removed, resulting in CPU hog. Reported by Patrick Wollgast. --- src/http/ngx_http_upstream.c | 29 ++++++++++++++++++++++++++--- 1 file changed, 26 insertions(+), 3 deletions(-) diff --git a/src/http/ngx_http_upstream.c b/src/http/ngx_http_upstream.c index ffb09a91f..89e1319f9 100644 --- a/src/http/ngx_http_upstream.c +++ b/src/http/ngx_http_upstream.c @@ -3334,6 +3334,7 @@ ngx_http_upstream_process_upgraded(ngx_http_request_t *r, size_t size; ssize_t n; ngx_buf_t *b; + ngx_uint_t flags; ngx_connection_t *c, *downstream, *upstream, *dst, *src; ngx_http_upstream_t *u; ngx_http_core_loc_conf_t *clcf; @@ -3472,7 +3473,14 @@ ngx_http_upstream_process_upgraded(ngx_http_request_t *r, ngx_del_timer(upstream->write); } - if (ngx_handle_read_event(upstream->read, 0) != NGX_OK) { + if (upstream->read->eof || upstream->read->error) { + flags = NGX_CLOSE_EVENT; + + } else { + flags = 0; + } + + if (ngx_handle_read_event(upstream->read, flags) != NGX_OK) { ngx_http_upstream_finalize_request(r, u, NGX_ERROR); return; } @@ -3491,7 +3499,14 @@ ngx_http_upstream_process_upgraded(ngx_http_request_t *r, return; } - if (ngx_handle_read_event(downstream->read, 0) != NGX_OK) { + if (downstream->read->eof || downstream->read->error) { + flags = NGX_CLOSE_EVENT; + + } else { + flags = 0; + } + + if (ngx_handle_read_event(downstream->read, flags) != NGX_OK) { ngx_http_upstream_finalize_request(r, u, NGX_ERROR); return; } @@ -3563,6 +3578,7 @@ ngx_http_upstream_process_non_buffered_request(ngx_http_request_t *r, ssize_t n; ngx_buf_t *b; ngx_int_t rc; + ngx_uint_t flags; ngx_connection_t *downstream, *upstream; ngx_http_upstream_t *u; ngx_http_core_loc_conf_t *clcf; @@ -3666,7 +3682,14 @@ ngx_http_upstream_process_non_buffered_request(ngx_http_request_t *r, ngx_del_timer(downstream->write); } - if (ngx_handle_read_event(upstream->read, 0) != NGX_OK) { + if (upstream->read->eof || upstream->read->error) { + flags = NGX_CLOSE_EVENT; + + } else { + flags = 0; + } + + if (ngx_handle_read_event(upstream->read, flags) != NGX_OK) { ngx_http_upstream_finalize_request(r, u, NGX_ERROR); return; } -- GitLab From ad42d70fed67c1e7098055fb25721ab904db2389 Mon Sep 17 00:00:00 2001 From: Maxim Dounin <mdounin@mdounin.ru> Date: Thu, 18 Jul 2019 18:27:53 +0300 Subject: [PATCH 26/33] SSI: avoid potential buffer overflow. When "-" follows a parameter of maximum length, a single byte buffer overflow happens, since the error branch does not check parameter length. Fix is to avoid saving "-" to the parameter key, and instead use an error message with "-" explicitly written. The message is mostly identical to one used in similar cases in the preequal state. Reported by Patrick Wollgast. --- src/http/modules/ngx_http_ssi_filter_module.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/http/modules/ngx_http_ssi_filter_module.c b/src/http/modules/ngx_http_ssi_filter_module.c index d608df9df..6737965d1 100644 --- a/src/http/modules/ngx_http_ssi_filter_module.c +++ b/src/http/modules/ngx_http_ssi_filter_module.c @@ -1254,9 +1254,9 @@ ngx_http_ssi_parse(ngx_http_request_t *r, ngx_http_ssi_ctx_t *ctx) case '-': state = ssi_error_end0_state; - ctx->param->key.data[ctx->param->key.len++] = ch; ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, - "invalid \"%V\" parameter in \"%V\" SSI command", + "unexpected \"-\" symbol after \"%V\" " + "parameter in \"%V\" SSI command", &ctx->param->key, &ctx->command); break; -- GitLab From 2187586207e1465d289ae64cedc829719a048a39 Mon Sep 17 00:00:00 2001 From: Maxim Dounin <mdounin@mdounin.ru> Date: Thu, 18 Jul 2019 18:27:54 +0300 Subject: [PATCH 27/33] Xslt: fixed potential buffer overflow with null character. Due to shortcomings of the ccv->zero flag implementation in complex value interface, length of the resulting string from ngx_http_complex_value() might either not include terminating null character or include it, so the only safe way to work with the result is to use it as a null-terminated string. Reported by Patrick Wollgast. --- src/http/modules/ngx_http_xslt_filter_module.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/http/modules/ngx_http_xslt_filter_module.c b/src/http/modules/ngx_http_xslt_filter_module.c index ea7ce2a5c..b2f107dc0 100644 --- a/src/http/modules/ngx_http_xslt_filter_module.c +++ b/src/http/modules/ngx_http_xslt_filter_module.c @@ -628,7 +628,7 @@ static ngx_int_t ngx_http_xslt_params(ngx_http_request_t *r, ngx_http_xslt_filter_ctx_t *ctx, ngx_array_t *params, ngx_uint_t final) { - u_char *p, *last, *value, *dst, *src, **s; + u_char *p, *value, *dst, *src, **s; size_t len; ngx_uint_t i; ngx_str_t string; @@ -698,8 +698,6 @@ ngx_http_xslt_params(ngx_http_request_t *r, ngx_http_xslt_filter_ctx_t *ctx, ngx_memcpy(p, string.data, string.len + 1); } - last = p + string.len; - while (p && *p) { value = p; @@ -729,7 +727,7 @@ ngx_http_xslt_params(ngx_http_request_t *r, ngx_http_xslt_filter_ctx_t *ctx, *p++ = '\0'; } else { - len = last - value; + len = ngx_strlen(value); } ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, -- GitLab From c3fd5f7e76343c899747ec58ae703540e7e9e69a Mon Sep 17 00:00:00 2001 From: Maxim Dounin <mdounin@mdounin.ru> Date: Fri, 19 Jul 2019 17:50:00 +0300 Subject: [PATCH 28/33] Core: fixed memory leak on error, missed in c3f60d618c17. Found by Coverity (CID 1451664). --- src/core/ngx_hash.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/core/ngx_hash.c b/src/core/ngx_hash.c index d684e7057..d9c157c1d 100644 --- a/src/core/ngx_hash.c +++ b/src/core/ngx_hash.c @@ -358,6 +358,7 @@ found: "could not build %s, you should " "increase %s_max_size: %i", hinit->name, hinit->name, hinit->max_size); + ngx_free(test); return NGX_ERROR; } -- GitLab From 3eb7ef4e203809ebab49e0ae488890b6a901e014 Mon Sep 17 00:00:00 2001 From: Maxim Dounin <mdounin@mdounin.ru> Date: Tue, 23 Jul 2019 15:01:47 +0300 Subject: [PATCH 29/33] nginx-1.17.2-RELEASE --- docs/xml/nginx/changes.xml | 89 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 89 insertions(+) diff --git a/docs/xml/nginx/changes.xml b/docs/xml/nginx/changes.xml index 60221ab55..416de1f6c 100644 --- a/docs/xml/nginx/changes.xml +++ b/docs/xml/nginx/changes.xml @@ -5,6 +5,95 @@ <change_log title="nginx"> +<changes ver="1.17.2" date="2019-07-23"> + +<change type="change"> +<para lang="ru"> +Š¼ŠøŠ½ŠøŠ¼Š°Š»ŃŠ½Š°Ń¸ ŠæŠ¾Š´Š´ŠµŃ€Š¶ŠøŠ²Š°ŠµŠ¼Š°Ń¸ Š²ŠµŃ€ŃŠøѸ zlib—1.2.0.4.<br/> +Š�ŠæŠ°ŃŠøŠ±Š¾ ŠŠ»ŃŠµ Š›ŠµŠ¾ŃŠŗŠµŠ²ŠøчŃ. +</para> +<para lang="en"> +minimum supported zlib version is 1.2.0.4.<br/> +Thanks to Ilya Leoshkevich. +</para> +</change> + +<change type="change"> +<para lang="ru"> +Š¼ŠµŃ‚Š¾Š´ $r->internal_redirect() Š²ŃŃ‚Ń€Š¾ŠµŠ½Š½Š¾Š³Š¾ ŠæŠµŃ€Š»Š° +Ń‚ŠµŠæŠµŃ€Ń Š¾Š¶ŠøŠ´Š°ŠµŃ‚ Š·Š°ŠŗŠ¾Š´ŠøŃ€Š¾Š²Š°Š½Š½Ń‹Š¹ URI. +</para> +<para lang="en"> +the $r->internal_redirect() embedded perl method +now expects escaped URIs. +</para> +</change> + +<change type="feature"> +<para lang="ru"> +Ń‚ŠµŠæŠµŃ€Ń Ń ŠæŠ¾Š¼Š¾Ń‰Ńѡ Š¼ŠµŃ‚Š¾Š´Š° $r->internal_redirect() Š²ŃŃ‚Ń€Š¾ŠµŠ½Š½Š¾Š³Š¾ ŠæŠµŃ€Š»Š° +Š¼Š¾Š¶Š½Š¾ ŠæŠµŃ€ŠµŠ¹Ń‚Šø Š² ŠøŠ¼ŠµŠ½Š¾Š²Š°Š½Š½Ń‹Š¹ location. +</para> +<para lang="en"> +it is now possible to switch to a named location +using the $r->internal_redirect() embedded perl method. +</para> +</change> + +<change type="bugfix"> +<para lang="ru"> +Š² Š¾Š±Ń€Š°Š±Š¾Ń‚ŠŗŠµ Š¾ŃŠøŠ±Š¾Šŗ Š²Š¾ Š²ŃŃ‚Ń€Š¾ŠµŠ½Š½Š¾Š¼ ŠæŠµŃ€Š»Šµ. +</para> +<para lang="en"> +in error handling in embedded perl. +</para> +</change> + +<change type="bugfix"> +<para lang="ru"> +Š½Š° ŃŃ‚Š°Ń€Ń‚Šµ ŠøŠ»Šø Š²Š¾ Š²Ń€ŠµŠ¼Ń¸ ŠæŠµŃ€ŠµŠŗŠ¾Š½Ń„ŠøŠ³ŃŃ€Š°Ń†ŠøŠø Š¼Š¾Š³ ŠæŃ€Š¾ŠøŠ·Š¾Š¹Ń‚Šø segmentation fault, +ŠµŃŠ»Šø Š² ŠŗŠ¾Š½Ń„ŠøŠ³ŃŃ€Š°Ń†ŠøŠø ŠøŃŠæŠ¾Š»ŃŠ·Š¾Š²Š°Š»Š¾ŃŃ Š·Š½Š°Ń‡ŠµŠ½ŠøŠµ hash bucket size Š±Š¾Š»ŃŃŠµ 64 ŠŗŠøŠ»Š¾Š±Š°Š¹Ń‚. +</para> +<para lang="en"> +a segmentation fault might occur on start or during reconfiguration +if hash bucket size larger than 64 kilobytes was used in the configuration. +</para> +</change> + +<change type="bugfix"> +<para lang="ru"> +ŠæŃ€Šø ŠøŃŠæŠ¾Š»ŃŠ·Š¾Š²Š°Š½ŠøŠø Š¼ŠµŃ‚Š¾Š´Š¾Š² Š¾Š±Ń€Š°Š±Š¾Ń‚ŠŗŠø ŃŠ¾ŠµŠ´ŠøŠ½ŠµŠ½ŠøŠ¹ select, poll Šø /dev/poll +nginx Š¼Š¾Š³ Š½Š°Š³Ń€ŃŠ¶Š°Ń‚Ń ŠæŃ€Š¾Ń†ŠµŃŃŠ¾Ń€ Š²Š¾ Š²Ń€ŠµŠ¼Ń¸ Š½ŠµŠ±ŃŃ„ŠµŃ€ŠøŠ·Š¾Š²Š°Š½Š½Š¾Š³Š¾ ŠæŃ€Š¾ŠŗŃŠøŃ€Š¾Š²Š°Š½ŠøѸ +Šø ŠæŃ€Šø ŠæŃ€Š¾ŠŗŃŠøŃ€Š¾Š²Š°Š½ŠøŠø WebSocket-ŃŠ¾ŠµŠ´ŠøŠ½ŠµŠ½ŠøŠ¹. +</para> +<para lang="en"> +nginx might hog CPU during unbuffered proxying +and when proxying WebSocket connections +if the select, poll, or /dev/poll methods were used. +</para> +</change> + +<change type="bugfix"> +<para lang="ru"> +Š² Š¼Š¾Š´ŃŠ»Šµ ngx_http_xslt_filter_module. +</para> +<para lang="en"> +in the ngx_http_xslt_filter_module. +</para> +</change> + +<change type="bugfix"> +<para lang="ru"> +Š² Š¼Š¾Š´ŃŠ»Šµ ngx_http_ssi_filter_module. +</para> +<para lang="en"> +in the ngx_http_ssi_filter_module. +</para> +</change> + +</changes> + + <changes ver="1.17.1" date="2019-06-25"> <change type="feature"> -- GitLab From e957ae888a986290dc789d71d31299fe5463e2fb Mon Sep 17 00:00:00 2001 From: Maxim Dounin <mdounin@mdounin.ru> Date: Tue, 23 Jul 2019 15:01:47 +0300 Subject: [PATCH 30/33] release-1.17.2 tag --- .hgtags | 1 + 1 file changed, 1 insertion(+) diff --git a/.hgtags b/.hgtags index 10adccb73..7f2d14e33 100644 --- a/.hgtags +++ b/.hgtags @@ -440,3 +440,4 @@ d2fd76709909767fc727a5b4affcf1dc9ca488a7 release-1.15.9 0130ca3d58437b3c7c707cdddd813d530c68da9a release-1.15.12 054c1c46395caff79bb4caf16f40b331f71bb6dd release-1.17.0 7816bd7dabf6ee86c53c073b90a7143161546e06 release-1.17.1 +2fc9f853a6b7cd29dc84e0af2ed3cf78e0da6ca8 release-1.17.2 -- GitLab From 6179b98ed537e2ad39eff11ee1689bf4700e59af Mon Sep 17 00:00:00 2001 From: Maxim Dounin <mdounin@mdounin.ru> Date: Wed, 31 Jul 2019 17:28:41 +0300 Subject: [PATCH 31/33] Version bump. --- src/core/nginx.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/core/nginx.h b/src/core/nginx.h index 25c5a729f..40dbe4e05 100644 --- a/src/core/nginx.h +++ b/src/core/nginx.h @@ -9,8 +9,8 @@ #define _NGINX_H_INCLUDED_ -#define nginx_version 1017002 -#define NGINX_VERSION "1.17.2" +#define nginx_version 1017003 +#define NGINX_VERSION "1.17.3" #define NGINX_VER "nginx/" NGINX_VERSION #ifdef NGX_BUILD -- GitLab From 39c40428f93db246a9a27e7a109413fae46e195d Mon Sep 17 00:00:00 2001 From: Maxim Dounin <mdounin@mdounin.ru> Date: Wed, 31 Jul 2019 17:29:00 +0300 Subject: [PATCH 32/33] Gzip: fixed "zero size buf" alerts after ac5a741d39cf. After ac5a741d39cf it is now possible that after zstream.avail_out reaches 0 and we allocate additional buffer, there will be no more data to put into this buffer, triggering "zero size buf" alert. Fix is to reset b->temporary flag in this case. Additionally, an optimization added to avoid allocating additional buffer in this case, by checking if last deflate() call returned Z_STREAM_END. Note that checking for Z_STREAM_END by itself is not enough to fix alerts, as deflate() can return Z_STREAM_END without producing any output if the buffer is smaller than gzip trailer. Reported by Witold Filipczyk, http://mailman.nginx.org/pipermail/nginx-devel/2019-July/012469.html. --- src/http/modules/ngx_http_gzip_filter_module.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/src/http/modules/ngx_http_gzip_filter_module.c b/src/http/modules/ngx_http_gzip_filter_module.c index 48f3dd7c7..c75169c53 100644 --- a/src/http/modules/ngx_http_gzip_filter_module.c +++ b/src/http/modules/ngx_http_gzip_filter_module.c @@ -778,7 +778,7 @@ ngx_http_gzip_filter_deflate(ngx_http_request_t *r, ngx_http_gzip_ctx_t *ctx) ctx->out_buf->last = ctx->zstream.next_out; - if (ctx->zstream.avail_out == 0) { + if (ctx->zstream.avail_out == 0 && rc != Z_STREAM_END) { /* zlib wants to output some more gzipped data */ @@ -868,6 +868,7 @@ ngx_http_gzip_filter_deflate_end(ngx_http_request_t *r, ngx_http_gzip_ctx_t *ctx) { int rc; + ngx_buf_t *b; ngx_chain_t *cl; ctx->zin = ctx->zstream.total_in; @@ -888,13 +889,19 @@ ngx_http_gzip_filter_deflate_end(ngx_http_request_t *r, return NGX_ERROR; } - cl->buf = ctx->out_buf; + b = ctx->out_buf; + + if (ngx_buf_size(b) == 0) { + b->temporary = 0; + } + + b->last_buf = 1; + + cl->buf = b; cl->next = NULL; *ctx->last_out = cl; ctx->last_out = &cl->next; - ctx->out_buf->last_buf = 1; - ctx->zstream.avail_in = 0; ctx->zstream.avail_out = 0; -- GitLab From abe660636c93315b4acb8531b83aec8d309d2eca Mon Sep 17 00:00:00 2001 From: Maxim Dounin <mdounin@mdounin.ru> Date: Thu, 1 Aug 2019 13:50:07 +0300 Subject: [PATCH 33/33] Mail: fixed duplicate resolving. When using SMTP with SSL and resolver, read events might be enabled during address resolving, leading to duplicate ngx_mail_ssl_handshake_handler() calls if something arrives from the client, and duplicate session initialization - including starting another resolving. This can lead to a segmentation fault if the session is closed after first resolving finished. Fix is to block read events while resolving. Reported by Robert Norris, http://mailman.nginx.org/pipermail/nginx/2019-July/058204.html. --- src/mail/ngx_mail_smtp_handler.c | 43 ++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/src/mail/ngx_mail_smtp_handler.c b/src/mail/ngx_mail_smtp_handler.c index 939fb1a51..f1017e0d8 100644 --- a/src/mail/ngx_mail_smtp_handler.c +++ b/src/mail/ngx_mail_smtp_handler.c @@ -15,6 +15,7 @@ static void ngx_mail_smtp_resolve_addr_handler(ngx_resolver_ctx_t *ctx); static void ngx_mail_smtp_resolve_name(ngx_event_t *rev); static void ngx_mail_smtp_resolve_name_handler(ngx_resolver_ctx_t *ctx); +static void ngx_mail_smtp_block_reading(ngx_event_t *rev); static void ngx_mail_smtp_greeting(ngx_mail_session_t *s, ngx_connection_t *c); static void ngx_mail_smtp_invalid_pipelining(ngx_event_t *rev); static ngx_int_t ngx_mail_smtp_create_buffer(ngx_mail_session_t *s, @@ -88,6 +89,9 @@ ngx_mail_smtp_init_session(ngx_mail_session_t *s, ngx_connection_t *c) ctx->data = s; ctx->timeout = cscf->resolver_timeout; + s->resolver_ctx = ctx; + c->read->handler = ngx_mail_smtp_block_reading; + if (ngx_resolve_addr(ctx) != NGX_OK) { ngx_mail_close_connection(c); } @@ -169,6 +173,9 @@ ngx_mail_smtp_resolve_name(ngx_event_t *rev) ctx->data = s; ctx->timeout = cscf->resolver_timeout; + s->resolver_ctx = ctx; + c->read->handler = ngx_mail_smtp_block_reading; + if (ngx_resolve_name(ctx) != NGX_OK) { ngx_mail_close_connection(c); } @@ -238,6 +245,38 @@ found: } +static void +ngx_mail_smtp_block_reading(ngx_event_t *rev) +{ + ngx_connection_t *c; + ngx_mail_session_t *s; + ngx_resolver_ctx_t *ctx; + + c = rev->data; + s = c->data; + + ngx_log_debug0(NGX_LOG_DEBUG_MAIL, c->log, 0, "smtp reading blocked"); + + if (ngx_handle_read_event(rev, 0) != NGX_OK) { + + if (s->resolver_ctx) { + ctx = s->resolver_ctx; + + if (ctx->handler == ngx_mail_smtp_resolve_addr_handler) { + ngx_resolve_addr_done(ctx); + + } else if (ctx->handler == ngx_mail_smtp_resolve_name_handler) { + ngx_resolve_name_done(ctx); + } + + s->resolver_ctx = NULL; + } + + ngx_mail_close_connection(c); + } +} + + static void ngx_mail_smtp_greeting(ngx_mail_session_t *s, ngx_connection_t *c) { @@ -258,6 +297,10 @@ ngx_mail_smtp_greeting(ngx_mail_session_t *s, ngx_connection_t *c) ngx_mail_close_connection(c); } + if (c->read->ready) { + ngx_post_event(c->read, &ngx_posted_events); + } + if (sscf->greeting_delay) { c->read->handler = ngx_mail_smtp_invalid_pipelining; return; -- GitLab