From 427cfff79b6e41b26d3b34c3018432839a272d1e Mon Sep 17 00:00:00 2001 From: Maxim Dounin Date: Mon, 31 May 2021 16:36:12 +0300 Subject: Version bump. --- src/core/nginx.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/core/nginx.h b/src/core/nginx.h index d8c8289a8..c4cab7b7c 100644 --- a/src/core/nginx.h +++ b/src/core/nginx.h @@ -9,8 +9,8 @@ #define _NGINX_H_INCLUDED_ -#define nginx_version 1021000 -#define NGINX_VERSION "1.21.0" +#define nginx_version 1021001 +#define NGINX_VERSION "1.21.1" #define NGINX_VER "nginx/" NGINX_VERSION #ifdef NGX_BUILD -- cgit From 85a104aa4e86ab82fd14493933f01f8822e83ed9 Mon Sep 17 00:00:00 2001 From: Maxim Dounin Date: Mon, 31 May 2021 16:36:37 +0300 Subject: Core: disabled cloning sockets when testing config (ticket #2188). Since we anyway do not set SO_REUSEPORT when testing configuration (see ecb5cd305b06), trying to open additional sockets does not make much sense, as all these additional sockets are expected to result in EADDRINUSE errors from bind(). On the other hand, there are reports that trying to open these sockets takes significant time under load: total configuration testing time greater than 15s was observed in ticket #2188, compared to less than 1s without load. With this change, no additional sockets are opened during testing configuration. --- src/event/ngx_event.c | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) (limited to 'src') diff --git a/src/event/ngx_event.c b/src/event/ngx_event.c index 7777d043e..0d187ca33 100644 --- a/src/event/ngx_event.c +++ b/src/event/ngx_event.c @@ -441,20 +441,23 @@ ngx_event_init_conf(ngx_cycle_t *cycle, void *conf) #if (NGX_HAVE_REUSEPORT) - ls = cycle->listening.elts; - for (i = 0; i < cycle->listening.nelts; i++) { + if (!ngx_test_config) { - if (!ls[i].reuseport || ls[i].worker != 0) { - continue; - } + ls = cycle->listening.elts; + for (i = 0; i < cycle->listening.nelts; i++) { - if (ngx_clone_listening(cycle, &ls[i]) != NGX_OK) { - return NGX_CONF_ERROR; - } + if (!ls[i].reuseport || ls[i].worker != 0) { + continue; + } - /* cloning may change cycle->listening.elts */ + if (ngx_clone_listening(cycle, &ls[i]) != NGX_OK) { + return NGX_CONF_ERROR; + } - ls = cycle->listening.elts; + /* cloning may change cycle->listening.elts */ + + ls = cycle->listening.elts; + } } #endif -- cgit From 52cde89586caa3fffc677e7665f4765f7e7b0a2d Mon Sep 17 00:00:00 2001 From: Maxim Dounin Date: Mon, 31 May 2021 16:36:51 +0300 Subject: Core: disabled SO_REUSEADDR on UDP sockets while testing config. On Linux, SO_REUSEADDR allows completely duplicate UDP sockets, so using SO_REUSEADDR when testing configuration results in packets being dropped if there is an existing traffic on the sockets being tested (ticket #2187). While dropped packets are expected with UDP, it is better to avoid this when possible. With this change, SO_REUSEADDR is no longer set on datagram sockets when testing configuration. --- src/core/ngx_connection.c | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) (limited to 'src') diff --git a/src/core/ngx_connection.c b/src/core/ngx_connection.c index 8339e2bb7..fe729a78a 100644 --- a/src/core/ngx_connection.c +++ b/src/core/ngx_connection.c @@ -495,21 +495,24 @@ ngx_open_listening_sockets(ngx_cycle_t *cycle) return NGX_ERROR; } - if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, - (const void *) &reuseaddr, sizeof(int)) - == -1) - { - ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno, - "setsockopt(SO_REUSEADDR) %V failed", - &ls[i].addr_text); + if (ls[i].type != SOCK_DGRAM || !ngx_test_config) { - if (ngx_close_socket(s) == -1) { + if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, + (const void *) &reuseaddr, sizeof(int)) + == -1) + { ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno, - ngx_close_socket_n " %V failed", + "setsockopt(SO_REUSEADDR) %V failed", &ls[i].addr_text); - } - return NGX_ERROR; + if (ngx_close_socket(s) == -1) { + ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno, + ngx_close_socket_n " %V failed", + &ls[i].addr_text); + } + + return NGX_ERROR; + } } #if (NGX_HAVE_REUSEPORT) -- cgit From 235d2df1de6aba77db3d128c0c637c9d2e9a9d12 Mon Sep 17 00:00:00 2001 From: Maxim Dounin Date: Tue, 1 Jun 2021 17:37:49 +0300 Subject: SSL: ngx_ssl_shutdown() rework. Instead of calling SSL_free() with each return point, introduced a single place where cleanup happens. As a positive side effect, this fixes two potential memory leaks on ngx_handle_read_event() and ngx_handle_write_event() errors where there were no SSL_free() calls (though unlikely practical, as errors there are only expected to happen due to bugs or kernel issues). --- src/event/ngx_event_openssl.c | 43 +++++++++++++++++++++---------------------- 1 file changed, 21 insertions(+), 22 deletions(-) (limited to 'src') diff --git a/src/event/ngx_event_openssl.c b/src/event/ngx_event_openssl.c index d762d6b7f..06357834c 100644 --- a/src/event/ngx_event_openssl.c +++ b/src/event/ngx_event_openssl.c @@ -2896,9 +2896,12 @@ ngx_int_t ngx_ssl_shutdown(ngx_connection_t *c) { int n, sslerr, mode; + ngx_int_t rc; ngx_err_t err; ngx_uint_t tries; + rc = NGX_OK; + ngx_ssl_ocsp_cleanup(c); if (SSL_in_init(c->ssl->connection)) { @@ -2908,11 +2911,7 @@ ngx_ssl_shutdown(ngx_connection_t *c) * Avoid calling SSL_shutdown() if handshake wasn't completed. */ - SSL_free(c->ssl->connection); - c->ssl = NULL; - c->recv = ngx_recv; - - return NGX_OK; + goto done; } if (c->timedout || c->error || c->buffered) { @@ -2954,11 +2953,7 @@ ngx_ssl_shutdown(ngx_connection_t *c) ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, "SSL_shutdown: %d", n); if (n == 1) { - SSL_free(c->ssl->connection); - c->ssl = NULL; - c->recv = ngx_recv; - - return NGX_OK; + goto done; } if (n == 0 && tries-- > 1) { @@ -2984,11 +2979,11 @@ ngx_ssl_shutdown(ngx_connection_t *c) } if (ngx_handle_read_event(c->read, 0) != NGX_OK) { - return NGX_ERROR; + goto failed; } if (ngx_handle_write_event(c->write, 0) != NGX_OK) { - return NGX_ERROR; + goto failed; } ngx_add_timer(c->read, 3000); @@ -2997,23 +2992,27 @@ ngx_ssl_shutdown(ngx_connection_t *c) } if (sslerr == SSL_ERROR_ZERO_RETURN || ERR_peek_error() == 0) { - SSL_free(c->ssl->connection); - c->ssl = NULL; - c->recv = ngx_recv; - - return NGX_OK; + goto done; } err = (sslerr == SSL_ERROR_SYSCALL) ? ngx_errno : 0; ngx_ssl_connection_error(c, sslerr, err, "SSL_shutdown() failed"); - SSL_free(c->ssl->connection); - c->ssl = NULL; - c->recv = ngx_recv; - - return NGX_ERROR; + break; } + +failed: + + rc = NGX_ERROR; + +done: + + SSL_free(c->ssl->connection); + c->ssl = NULL; + c->recv = ngx_recv; + + return rc; } -- cgit From 5eadaf69e394c030056e4190d86dae0262f8617c Mon Sep 17 00:00:00 2001 From: Maxim Dounin Date: Tue, 1 Jun 2021 17:37:51 +0300 Subject: Fixed SSL logging with lingering close. Recent fixes to SSL shutdown with lingering close (554c6ae25ffc, 1.19.5) broke logging of SSL variables. To make sure logging of SSL variables works properly, avoid freeing c->ssl when doing an SSL shutdown before lingering close. Reported by Reinis Rozitis (http://mailman.nginx.org/pipermail/nginx/2021-May/060670.html). --- src/event/ngx_event_openssl.c | 6 ++++++ src/event/ngx_event_openssl.h | 1 + src/http/ngx_http_request.c | 2 ++ 3 files changed, 9 insertions(+) (limited to 'src') diff --git a/src/event/ngx_event_openssl.c b/src/event/ngx_event_openssl.c index 06357834c..396cc22b3 100644 --- a/src/event/ngx_event_openssl.c +++ b/src/event/ngx_event_openssl.c @@ -3008,6 +3008,12 @@ failed: done: + if (c->ssl->shutdown_without_free) { + c->ssl->shutdown_without_free = 0; + c->recv = ngx_recv; + return rc; + } + SSL_free(c->ssl->connection); c->ssl = NULL; c->recv = ngx_recv; diff --git a/src/event/ngx_event_openssl.h b/src/event/ngx_event_openssl.h index 329760d09..a415b4bda 100644 --- a/src/event/ngx_event_openssl.h +++ b/src/event/ngx_event_openssl.h @@ -100,6 +100,7 @@ struct ngx_ssl_connection_s { unsigned buffer:1; unsigned no_wait_shutdown:1; unsigned no_send_shutdown:1; + unsigned shutdown_without_free:1; unsigned handshake_buffer_set:1; unsigned try_early_data:1; unsigned in_early:1; diff --git a/src/http/ngx_http_request.c b/src/http/ngx_http_request.c index 81b27a386..0bb122ce0 100644 --- a/src/http/ngx_http_request.c +++ b/src/http/ngx_http_request.c @@ -3400,6 +3400,8 @@ ngx_http_set_lingering_close(ngx_connection_t *c) if (c->ssl) { ngx_int_t rc; + c->ssl->shutdown_without_free = 1; + rc = ngx_ssl_shutdown(c); if (rc == NGX_ERROR) { -- cgit From dcdf7ec096f0998e689b7f0b0f7541e197eeff6a Mon Sep 17 00:00:00 2001 From: Sergey Kandaurov Date: Thu, 17 Jun 2021 11:43:55 +0300 Subject: gRPC: handling GOAWAY with a higher last stream identifier. Previously, once received from upstream, it couldn't limit opening additional streams in a cached keepalive connection. --- src/http/modules/ngx_http_grpc_module.c | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'src') diff --git a/src/http/modules/ngx_http_grpc_module.c b/src/http/modules/ngx_http_grpc_module.c index 2e20e5ffd..42a540f19 100644 --- a/src/http/modules/ngx_http_grpc_module.c +++ b/src/http/modules/ngx_http_grpc_module.c @@ -121,6 +121,7 @@ typedef struct { unsigned done:1; unsigned status:1; unsigned rst:1; + unsigned goaway:1; ngx_http_request_t *request; @@ -1210,6 +1211,7 @@ ngx_http_grpc_reinit_request(ngx_http_request_t *r) ctx->done = 0; ctx->status = 0; ctx->rst = 0; + ctx->goaway = 0; ctx->connection = NULL; return NGX_OK; @@ -1565,6 +1567,7 @@ ngx_http_grpc_body_output_filter(void *data, ngx_chain_t *in) && ctx->out == NULL && ctx->output_closed && !ctx->output_blocked + && !ctx->goaway && ctx->state == ngx_http_grpc_st_start) { u->keepalive = 1; @@ -1714,6 +1717,8 @@ ngx_http_grpc_process_header(ngx_http_request_t *r) return NGX_HTTP_UPSTREAM_INVALID_HEADER; } + ctx->goaway = 1; + continue; } @@ -1907,6 +1912,7 @@ ngx_http_grpc_process_header(ngx_http_request_t *r) && ctx->out == NULL && ctx->output_closed && !ctx->output_blocked + && !ctx->goaway && b->last == b->pos) { u->keepalive = 1; @@ -2035,6 +2041,7 @@ ngx_http_grpc_filter(void *data, ssize_t bytes) if (ctx->in == NULL && ctx->output_closed && !ctx->output_blocked + && !ctx->goaway && ctx->state == ngx_http_grpc_st_start) { u->keepalive = 1; @@ -2204,6 +2211,8 @@ ngx_http_grpc_filter(void *data, ssize_t bytes) return NGX_ERROR; } + ctx->goaway = 1; + continue; } -- cgit From 693e4134a51b4fd30689ad1e31e6fdffe5ee1429 Mon Sep 17 00:00:00 2001 From: Sergey Kandaurov Date: Thu, 17 Jun 2021 11:44:06 +0300 Subject: gRPC: RST_STREAM(NO_ERROR) handling micro-optimization. After 2096b21fcd10, a single RST_STREAM(NO_ERROR) may not result in an error. This change removes several unnecessary ctx->type checks for such a case. --- src/http/modules/ngx_http_grpc_module.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'src') diff --git a/src/http/modules/ngx_http_grpc_module.c b/src/http/modules/ngx_http_grpc_module.c index 42a540f19..654bd17b9 100644 --- a/src/http/modules/ngx_http_grpc_module.c +++ b/src/http/modules/ngx_http_grpc_module.c @@ -2177,6 +2177,8 @@ ngx_http_grpc_filter(void *data, ssize_t bytes) } ctx->rst = 1; + + continue; } if (ctx->type == NGX_HTTP_V2_GOAWAY_FRAME) { @@ -3484,6 +3486,8 @@ ngx_http_grpc_parse_rst_stream(ngx_http_request_t *r, ngx_http_grpc_ctx_t *ctx, return NGX_AGAIN; } + ctx->state = ngx_http_grpc_st_start; + return NGX_OK; } -- cgit From a407583ef17d9afa9e48eb8d0749289a0af84388 Mon Sep 17 00:00:00 2001 From: Maxim Dounin Date: Fri, 18 Jun 2021 04:00:21 +0300 Subject: Fixed format strings for ngx_win32_version. --- src/os/win32/ngx_win32_init.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/os/win32/ngx_win32_init.c b/src/os/win32/ngx_win32_init.c index 3249fb293..de66a44eb 100644 --- a/src/os/win32/ngx_win32_init.c +++ b/src/os/win32/ngx_win32_init.c @@ -295,7 +295,7 @@ ngx_os_status(ngx_log_t *log) osviex_stub = (ngx_osviex_stub_t *) &osvi.wServicePackMinor; ngx_log_error(NGX_LOG_INFO, log, 0, - "OS: %ud build:%ud, \"%s\", suite:%Xd, type:%ud", + "OS: %ui build:%ud, \"%s\", suite:%Xd, type:%ud", ngx_win32_version, osvi.dwBuildNumber, osvi.szCSDVersion, osviex_stub->wSuiteMask, osviex_stub->wProductType); @@ -305,7 +305,7 @@ ngx_os_status(ngx_log_t *log) /* Win9x build */ ngx_log_error(NGX_LOG_INFO, log, 0, - "OS: %u build:%ud.%ud.%ud, \"%s\"", + "OS: %ui build:%ud.%ud.%ud, \"%s\"", ngx_win32_version, osvi.dwBuildNumber >> 24, (osvi.dwBuildNumber >> 16) & 0xff, @@ -321,7 +321,7 @@ ngx_os_status(ngx_log_t *log) * and we do not support VER_PLATFORM_WIN32s at all */ - ngx_log_error(NGX_LOG_INFO, log, 0, "OS: %ud build:%ud, \"%s\"", + ngx_log_error(NGX_LOG_INFO, log, 0, "OS: %ui build:%ud, \"%s\"", ngx_win32_version, osvi.dwBuildNumber, osvi.szCSDVersion); } -- cgit From 8b927107287094f018cc6f5addc543e79f88ec74 Mon Sep 17 00:00:00 2001 From: Vladimir Homutov Date: Mon, 21 Jun 2021 09:42:43 +0300 Subject: Core: added the ngx_rbtree_data() macro. --- src/core/ngx_rbtree.h | 3 +++ src/core/ngx_resolver.c | 4 +--- src/event/ngx_event_timer.c | 4 ++-- 3 files changed, 6 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/core/ngx_rbtree.h b/src/core/ngx_rbtree.h index 97f0e3e11..e8c358213 100644 --- a/src/core/ngx_rbtree.h +++ b/src/core/ngx_rbtree.h @@ -47,6 +47,9 @@ struct ngx_rbtree_s { (tree)->sentinel = s; \ (tree)->insert = i +#define ngx_rbtree_data(node, type, link) \ + (type *) ((u_char *) (node) - offsetof(type, link)) + void ngx_rbtree_insert(ngx_rbtree_t *tree, ngx_rbtree_node_t *node); void ngx_rbtree_delete(ngx_rbtree_t *tree, ngx_rbtree_node_t *node); diff --git a/src/core/ngx_resolver.c b/src/core/ngx_resolver.c index 58d5f3ec4..6d129e56a 100644 --- a/src/core/ngx_resolver.c +++ b/src/core/ngx_resolver.c @@ -51,9 +51,7 @@ typedef struct { } ngx_resolver_an_t; -#define ngx_resolver_node(n) \ - (ngx_resolver_node_t *) \ - ((u_char *) (n) - offsetof(ngx_resolver_node_t, node)) +#define ngx_resolver_node(n) ngx_rbtree_data(n, ngx_resolver_node_t, node) static ngx_int_t ngx_udp_connect(ngx_resolver_connection_t *rec); diff --git a/src/event/ngx_event_timer.c b/src/event/ngx_event_timer.c index 698b88fae..35052bc29 100644 --- a/src/event/ngx_event_timer.c +++ b/src/event/ngx_event_timer.c @@ -73,7 +73,7 @@ ngx_event_expire_timers(void) return; } - ev = (ngx_event_t *) ((char *) node - offsetof(ngx_event_t, timer)); + ev = ngx_rbtree_data(node, ngx_event_t, timer); ngx_log_debug2(NGX_LOG_DEBUG_EVENT, ev->log, 0, "event timer del: %d: %M", @@ -113,7 +113,7 @@ ngx_event_no_timers_left(void) node; node = ngx_rbtree_next(&ngx_event_timer_rbtree, node)) { - ev = (ngx_event_t *) ((char *) node - offsetof(ngx_event_t, timer)); + ev = ngx_rbtree_data(node, ngx_event_t, timer); if (!ev->cancelable) { return NGX_AGAIN; -- cgit From d9c1d1bae7ae2c83fb65ca00a47ad6c1199a691e Mon Sep 17 00:00:00 2001 From: Maxim Dounin Date: Mon, 28 Jun 2021 18:01:00 +0300 Subject: Moved TRACE method rejection to a better place. Previously, TRACE requests were rejected before parsing Transfer-Encoding. This is not important since keepalive is not enabled at this point anyway, though rejecting such requests after properly parsing other headers is less likely to cause issues in case of further code changes. --- src/http/ngx_http_request.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/src/http/ngx_http_request.c b/src/http/ngx_http_request.c index 0bb122ce0..b908e2941 100644 --- a/src/http/ngx_http_request.c +++ b/src/http/ngx_http_request.c @@ -1980,13 +1980,6 @@ ngx_http_process_request_header(ngx_http_request_t *r) } } - if (r->method == NGX_HTTP_TRACE) { - ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, - "client sent TRACE method"); - ngx_http_finalize_request(r, NGX_HTTP_NOT_ALLOWED); - return NGX_ERROR; - } - if (r->headers_in.transfer_encoding) { if (r->headers_in.transfer_encoding->value.len == 7 && ngx_strncasecmp(r->headers_in.transfer_encoding->value.data, @@ -2013,6 +2006,13 @@ ngx_http_process_request_header(ngx_http_request_t *r) } } + if (r->method == NGX_HTTP_TRACE) { + ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, + "client sent TRACE method"); + ngx_http_finalize_request(r, NGX_HTTP_NOT_ALLOWED); + return NGX_ERROR; + } + return NGX_OK; } -- cgit From 5f85bb3714a81d158f4d849ad5c61aec2737a9f0 Mon Sep 17 00:00:00 2001 From: Maxim Dounin Date: Mon, 28 Jun 2021 18:01:04 +0300 Subject: Added CONNECT method rejection. No valid CONNECT requests are expected to appear within nginx, since it is not a forward proxy. Further, request line parsing will reject proper CONNECT requests anyway, since we don't allow authority-form of request-target. On the other hand, RFC 7230 specifies separate message length rules for CONNECT which we don't support, so make sure to always reject CONNECTs to avoid potential abuse. --- src/http/ngx_http_parse.c | 5 +++++ src/http/ngx_http_request.c | 7 +++++++ src/http/ngx_http_request.h | 33 +++++++++++++++++---------------- src/http/v2/ngx_http_v2.c | 3 ++- 4 files changed, 31 insertions(+), 17 deletions(-) (limited to 'src') diff --git a/src/http/ngx_http_parse.c b/src/http/ngx_http_parse.c index 20ad89a77..71fa3c7a5 100644 --- a/src/http/ngx_http_parse.c +++ b/src/http/ngx_http_parse.c @@ -246,6 +246,11 @@ ngx_http_parse_request_line(ngx_http_request_t *r, ngx_buf_t *b) r->method = NGX_HTTP_OPTIONS; } + if (ngx_str7_cmp(m, 'C', 'O', 'N', 'N', 'E', 'C', 'T', ' ')) + { + r->method = NGX_HTTP_CONNECT; + } + break; case 8: diff --git a/src/http/ngx_http_request.c b/src/http/ngx_http_request.c index b908e2941..5b2613870 100644 --- a/src/http/ngx_http_request.c +++ b/src/http/ngx_http_request.c @@ -2006,6 +2006,13 @@ ngx_http_process_request_header(ngx_http_request_t *r) } } + if (r->method == NGX_HTTP_CONNECT) { + ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, + "client sent CONNECT method"); + ngx_http_finalize_request(r, NGX_HTTP_NOT_ALLOWED); + return NGX_ERROR; + } + if (r->method == NGX_HTTP_TRACE) { ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, "client sent TRACE method"); diff --git a/src/http/ngx_http_request.h b/src/http/ngx_http_request.h index 6dfb4a42f..fa4d5f99f 100644 --- a/src/http/ngx_http_request.h +++ b/src/http/ngx_http_request.h @@ -25,22 +25,23 @@ #define NGX_HTTP_VERSION_11 1001 #define NGX_HTTP_VERSION_20 2000 -#define NGX_HTTP_UNKNOWN 0x0001 -#define NGX_HTTP_GET 0x0002 -#define NGX_HTTP_HEAD 0x0004 -#define NGX_HTTP_POST 0x0008 -#define NGX_HTTP_PUT 0x0010 -#define NGX_HTTP_DELETE 0x0020 -#define NGX_HTTP_MKCOL 0x0040 -#define NGX_HTTP_COPY 0x0080 -#define NGX_HTTP_MOVE 0x0100 -#define NGX_HTTP_OPTIONS 0x0200 -#define NGX_HTTP_PROPFIND 0x0400 -#define NGX_HTTP_PROPPATCH 0x0800 -#define NGX_HTTP_LOCK 0x1000 -#define NGX_HTTP_UNLOCK 0x2000 -#define NGX_HTTP_PATCH 0x4000 -#define NGX_HTTP_TRACE 0x8000 +#define NGX_HTTP_UNKNOWN 0x00000001 +#define NGX_HTTP_GET 0x00000002 +#define NGX_HTTP_HEAD 0x00000004 +#define NGX_HTTP_POST 0x00000008 +#define NGX_HTTP_PUT 0x00000010 +#define NGX_HTTP_DELETE 0x00000020 +#define NGX_HTTP_MKCOL 0x00000040 +#define NGX_HTTP_COPY 0x00000080 +#define NGX_HTTP_MOVE 0x00000100 +#define NGX_HTTP_OPTIONS 0x00000200 +#define NGX_HTTP_PROPFIND 0x00000400 +#define NGX_HTTP_PROPPATCH 0x00000800 +#define NGX_HTTP_LOCK 0x00001000 +#define NGX_HTTP_UNLOCK 0x00002000 +#define NGX_HTTP_PATCH 0x00004000 +#define NGX_HTTP_TRACE 0x00008000 +#define NGX_HTTP_CONNECT 0x00010000 #define NGX_HTTP_CONNECTION_CLOSE 1 #define NGX_HTTP_CONNECTION_KEEP_ALIVE 2 diff --git a/src/http/v2/ngx_http_v2.c b/src/http/v2/ngx_http_v2.c index 3611a2e50..423667d47 100644 --- a/src/http/v2/ngx_http_v2.c +++ b/src/http/v2/ngx_http_v2.c @@ -3606,7 +3606,8 @@ ngx_http_v2_parse_method(ngx_http_request_t *r, ngx_str_t *value) { 4, "LOCK", NGX_HTTP_LOCK }, { 6, "UNLOCK", NGX_HTTP_UNLOCK }, { 5, "PATCH", NGX_HTTP_PATCH }, - { 5, "TRACE", NGX_HTTP_TRACE } + { 5, "TRACE", NGX_HTTP_TRACE }, + { 7, "CONNECT", NGX_HTTP_CONNECT } }, *test; if (r->method_name.len) { -- cgit From a6c109fea5c13b8aa13ed95ca00a64d62601042b Mon Sep 17 00:00:00 2001 From: Maxim Dounin Date: Mon, 28 Jun 2021 18:01:06 +0300 Subject: Disabled requests with both Content-Length and Transfer-Encoding. HTTP clients are not allowed to generate such requests since Transfer-Encoding introduction in RFC 2068, and they are not expected to appear in practice except in attempts to perform a request smuggling attack. While handling of such requests is strictly defined, the most secure approach seems to reject them. --- src/http/ngx_http_request.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/http/ngx_http_request.c b/src/http/ngx_http_request.c index 5b2613870..2614b998c 100644 --- a/src/http/ngx_http_request.c +++ b/src/http/ngx_http_request.c @@ -1985,8 +1985,15 @@ ngx_http_process_request_header(ngx_http_request_t *r) && ngx_strncasecmp(r->headers_in.transfer_encoding->value.data, (u_char *) "chunked", 7) == 0) { - r->headers_in.content_length = NULL; - r->headers_in.content_length_n = -1; + if (r->headers_in.content_length) { + ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, + "client sent \"Content-Length\" and " + "\"Transfer-Encoding\" headers " + "at the same time"); + ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST); + return NGX_ERROR; + } + r->headers_in.chunked = 1; } else { -- cgit From 31d1c34b394ee30b30084ff160133708d0d3b030 Mon Sep 17 00:00:00 2001 From: Maxim Dounin Date: Mon, 28 Jun 2021 18:01:09 +0300 Subject: Core: fixed comment about escaping in arguments. After 4954530db2af, the ";" character is escaped by ngx_escape_uri(NGX_ESCAPE_ARGS). --- src/core/ngx_string.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/core/ngx_string.c b/src/core/ngx_string.c index 5cc9b26f9..7ed3463bb 100644 --- a/src/core/ngx_string.c +++ b/src/core/ngx_string.c @@ -1513,7 +1513,7 @@ ngx_escape_uri(u_char *dst, u_char *src, size_t size, ngx_uint_t type) 0xffffffff /* 1111 1111 1111 1111 1111 1111 1111 1111 */ }; - /* " ", "#", "%", "&", "+", "?", %00-%1F, %7F-%FF */ + /* " ", "#", "%", "&", "+", ";", "?", %00-%1F, %7F-%FF */ static uint32_t args[] = { 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */ -- cgit From fee09fc49d510de0078f9bc7fc18dc179cceb62b Mon Sep 17 00:00:00 2001 From: Maxim Dounin Date: Mon, 28 Jun 2021 18:01:11 +0300 Subject: Core: escaping of chars not allowed in URIs per RFC 3986. Per RFC 3986 only the following characters are allowed in URIs unescaped: unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~" gen-delims = ":" / "/" / "?" / "#" / "[" / "]" / "@" sub-delims = "!" / "$" / "&" / "'" / "(" / ")" / "*" / "+" / "," / ";" / "=" And "%" can appear as a part of escaping itself. The following characters are not allowed and need to be escaped: %00-%1F, %7F-%FF, " ", """, "<", ">", "\", "^", "`", "{", "|", "}". Not escaping ">" is known to cause problems at least with MS Exchange (see http://nginx.org/pipermail/nginx-ru/2010-January/031261.html) and in Tomcat (ticket #2191). The patch adds escaping of the following chars in all URI parts: """, "<", ">", "\", "^", "`", "{", "|", "}". Note that comments are mostly preserved to outline important characters being escaped. --- src/core/ngx_string.c | 45 +++++++++++++++++++++++++++++---------------- 1 file changed, 29 insertions(+), 16 deletions(-) (limited to 'src') diff --git a/src/core/ngx_string.c b/src/core/ngx_string.c index 7ed3463bb..98f270aca 100644 --- a/src/core/ngx_string.c +++ b/src/core/ngx_string.c @@ -1493,19 +1493,32 @@ ngx_escape_uri(u_char *dst, u_char *src, size_t size, ngx_uint_t type) uint32_t *escape; static u_char hex[] = "0123456789ABCDEF"; - /* " ", "#", "%", "?", %00-%1F, %7F-%FF */ + /* + * Per RFC 3986 only the following chars are allowed in URIs unescaped: + * + * unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~" + * gen-delims = ":" / "/" / "?" / "#" / "[" / "]" / "@" + * sub-delims = "!" / "$" / "&" / "'" / "(" / ")" + * / "*" / "+" / "," / ";" / "=" + * + * And "%" can appear as a part of escaping itself. The following + * characters are not allowed and need to be escaped: %00-%1F, %7F-%FF, + * " ", """, "<", ">", "\", "^", "`", "{", "|", "}". + */ + + /* " ", "#", "%", "?", not allowed */ static uint32_t uri[] = { 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */ /* ?>=< ;:98 7654 3210 /.-, +*)( '&%$ #"! */ - 0x80000029, /* 1000 0000 0000 0000 0000 0000 0010 1001 */ + 0xd000002d, /* 1101 0000 0000 0000 0000 0000 0010 1101 */ /* _^]\ [ZYX WVUT SRQP ONML KJIH GFED CBA@ */ - 0x00000000, /* 0000 0000 0000 0000 0000 0000 0000 0000 */ + 0x50000000, /* 0101 0000 0000 0000 0000 0000 0000 0000 */ /* ~}| {zyx wvut srqp onml kjih gfed cba` */ - 0x80000000, /* 1000 0000 0000 0000 0000 0000 0000 0000 */ + 0xb8000001, /* 1011 1000 0000 0000 0000 0000 0000 0001 */ 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */ 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */ @@ -1513,19 +1526,19 @@ ngx_escape_uri(u_char *dst, u_char *src, size_t size, ngx_uint_t type) 0xffffffff /* 1111 1111 1111 1111 1111 1111 1111 1111 */ }; - /* " ", "#", "%", "&", "+", ";", "?", %00-%1F, %7F-%FF */ + /* " ", "#", "%", "&", "+", ";", "?", not allowed */ static uint32_t args[] = { 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */ /* ?>=< ;:98 7654 3210 /.-, +*)( '&%$ #"! */ - 0x88000869, /* 1000 1000 0000 0000 0000 1000 0110 1001 */ + 0xd800086d, /* 1101 1000 0000 0000 0000 1000 0110 1101 */ /* _^]\ [ZYX WVUT SRQP ONML KJIH GFED CBA@ */ - 0x00000000, /* 0000 0000 0000 0000 0000 0000 0000 0000 */ + 0x50000000, /* 0101 0000 0000 0000 0000 0000 0000 0000 */ /* ~}| {zyx wvut srqp onml kjih gfed cba` */ - 0x80000000, /* 1000 0000 0000 0000 0000 0000 0000 0000 */ + 0xb8000001, /* 1011 1000 0000 0000 0000 0000 0000 0001 */ 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */ 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */ @@ -1553,19 +1566,19 @@ ngx_escape_uri(u_char *dst, u_char *src, size_t size, ngx_uint_t type) 0xffffffff /* 1111 1111 1111 1111 1111 1111 1111 1111 */ }; - /* " ", "#", """, "%", "'", %00-%1F, %7F-%FF */ + /* " ", "#", """, "%", "'", not allowed */ static uint32_t html[] = { 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */ /* ?>=< ;:98 7654 3210 /.-, +*)( '&%$ #"! */ - 0x000000ad, /* 0000 0000 0000 0000 0000 0000 1010 1101 */ + 0x500000ad, /* 0101 0000 0000 0000 0000 0000 1010 1101 */ /* _^]\ [ZYX WVUT SRQP ONML KJIH GFED CBA@ */ - 0x00000000, /* 0000 0000 0000 0000 0000 0000 0000 0000 */ + 0x50000000, /* 0101 0000 0000 0000 0000 0000 0000 0000 */ /* ~}| {zyx wvut srqp onml kjih gfed cba` */ - 0x80000000, /* 1000 0000 0000 0000 0000 0000 0000 0000 */ + 0xb8000001, /* 1011 1000 0000 0000 0000 0000 0000 0001 */ 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */ 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */ @@ -1573,19 +1586,19 @@ ngx_escape_uri(u_char *dst, u_char *src, size_t size, ngx_uint_t type) 0xffffffff /* 1111 1111 1111 1111 1111 1111 1111 1111 */ }; - /* " ", """, "'", %00-%1F, %7F-%FF */ + /* " ", """, "'", not allowed */ static uint32_t refresh[] = { 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */ /* ?>=< ;:98 7654 3210 /.-, +*)( '&%$ #"! */ - 0x00000085, /* 0000 0000 0000 0000 0000 0000 1000 0101 */ + 0x50000085, /* 0101 0000 0000 0000 0000 0000 1000 0101 */ /* _^]\ [ZYX WVUT SRQP ONML KJIH GFED CBA@ */ - 0x00000000, /* 0000 0000 0000 0000 0000 0000 0000 0000 */ + 0x50000000, /* 0101 0000 0000 0000 0000 0000 0000 0000 */ /* ~}| {zyx wvut srqp onml kjih gfed cba` */ - 0x80000000, /* 1000 0000 0000 0000 0000 0000 0000 0000 */ + 0xd8000001, /* 1011 1000 0000 0000 0000 0000 0000 0001 */ 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */ 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */ -- cgit From 05395f4889cf0b66e8d049921ad19f1a08319150 Mon Sep 17 00:00:00 2001 From: Maxim Dounin Date: Mon, 28 Jun 2021 18:01:13 +0300 Subject: Disabled spaces in URIs (ticket #196). From now on, requests with spaces in URIs are immediately rejected rather than allowed. Spaces were allowed in 31e9677b15a1 (0.8.41) to handle bad clients. It is believed that now this behaviour causes more harm than good. --- src/http/modules/ngx_http_proxy_module.c | 4 +- src/http/ngx_http_parse.c | 72 ++++---------------------------- src/http/ngx_http_request.c | 2 +- src/http/ngx_http_request.h | 3 -- 4 files changed, 11 insertions(+), 70 deletions(-) (limited to 'src') diff --git a/src/http/modules/ngx_http_proxy_module.c b/src/http/modules/ngx_http_proxy_module.c index 64190f1a0..d82f5ea21 100644 --- a/src/http/modules/ngx_http_proxy_module.c +++ b/src/http/modules/ngx_http_proxy_module.c @@ -1186,7 +1186,7 @@ ngx_http_proxy_create_key(ngx_http_request_t *r) loc_len = (r->valid_location && ctx->vars.uri.len) ? plcf->location.len : 0; - if (r->quoted_uri || r->space_in_uri || r->internal) { + if (r->quoted_uri || r->internal) { escape = 2 * ngx_escape_uri(NULL, r->uri.data + loc_len, r->uri.len - loc_len, NGX_ESCAPE_URI); } else { @@ -1299,7 +1299,7 @@ ngx_http_proxy_create_request(ngx_http_request_t *r) loc_len = (r->valid_location && ctx->vars.uri.len) ? plcf->location.len : 0; - if (r->quoted_uri || r->space_in_uri || r->internal) { + if (r->quoted_uri || r->internal) { escape = 2 * ngx_escape_uri(NULL, r->uri.data + loc_len, r->uri.len - loc_len, NGX_ESCAPE_URI); } diff --git a/src/http/ngx_http_parse.c b/src/http/ngx_http_parse.c index 71fa3c7a5..8297a132b 100644 --- a/src/http/ngx_http_parse.c +++ b/src/http/ngx_http_parse.c @@ -116,10 +116,8 @@ ngx_http_parse_request_line(ngx_http_request_t *r, ngx_buf_t *b) sw_host_end, sw_host_ip_literal, sw_port, - sw_host_http_09, sw_after_slash_in_uri, sw_check_uri, - sw_check_uri_http_09, sw_uri, sw_http_09, sw_http_H, @@ -398,7 +396,7 @@ ngx_http_parse_request_line(ngx_http_request_t *r, ngx_buf_t *b) */ r->uri_start = r->schema_end + 1; r->uri_end = r->schema_end + 2; - state = sw_host_http_09; + state = sw_http_09; break; default: return NGX_HTTP_PARSE_INVALID_REQUEST; @@ -472,35 +470,13 @@ ngx_http_parse_request_line(ngx_http_request_t *r, ngx_buf_t *b) */ r->uri_start = r->schema_end + 1; r->uri_end = r->schema_end + 2; - state = sw_host_http_09; - break; - default: - return NGX_HTTP_PARSE_INVALID_REQUEST; - } - break; - - /* space+ after "http://host[:port] " */ - case sw_host_http_09: - switch (ch) { - case ' ': - break; - case CR: - r->http_minor = 9; - state = sw_almost_done; - break; - case LF: - r->http_minor = 9; - goto done; - case 'H': - r->http_protocol.data = p; - state = sw_http_H; + state = sw_http_09; break; default: return NGX_HTTP_PARSE_INVALID_REQUEST; } break; - /* check "/.", "//", "%", and "\" (Win32) in URI */ case sw_after_slash_in_uri: @@ -512,7 +488,7 @@ ngx_http_parse_request_line(ngx_http_request_t *r, ngx_buf_t *b) switch (ch) { case ' ': r->uri_end = p; - state = sw_check_uri_http_09; + state = sw_http_09; break; case CR: r->uri_end = p; @@ -584,7 +560,7 @@ ngx_http_parse_request_line(ngx_http_request_t *r, ngx_buf_t *b) break; case ' ': r->uri_end = p; - state = sw_check_uri_http_09; + state = sw_http_09; break; case CR: r->uri_end = p; @@ -621,31 +597,6 @@ ngx_http_parse_request_line(ngx_http_request_t *r, ngx_buf_t *b) } break; - /* space+ after URI */ - case sw_check_uri_http_09: - switch (ch) { - case ' ': - break; - case CR: - r->http_minor = 9; - state = sw_almost_done; - break; - case LF: - r->http_minor = 9; - goto done; - case 'H': - r->http_protocol.data = p; - state = sw_http_H; - break; - default: - r->space_in_uri = 1; - state = sw_check_uri; - p--; - break; - } - break; - - /* URI */ case sw_uri: @@ -692,10 +643,7 @@ ngx_http_parse_request_line(ngx_http_request_t *r, ngx_buf_t *b) state = sw_http_H; break; default: - r->space_in_uri = 1; - state = sw_uri; - p--; - break; + return NGX_HTTP_PARSE_INVALID_REQUEST; } break; @@ -1171,9 +1119,7 @@ ngx_http_parse_uri(ngx_http_request_t *r) switch (ch) { case ' ': - r->space_in_uri = 1; - state = sw_check_uri; - break; + return NGX_ERROR; case '.': r->complex_uri = 1; state = sw_uri; @@ -1232,8 +1178,7 @@ ngx_http_parse_uri(ngx_http_request_t *r) r->uri_ext = p + 1; break; case ' ': - r->space_in_uri = 1; - break; + return NGX_ERROR; #if (NGX_WIN32) case '\\': r->complex_uri = 1; @@ -1267,8 +1212,7 @@ ngx_http_parse_uri(ngx_http_request_t *r) switch (ch) { case ' ': - r->space_in_uri = 1; - break; + return NGX_ERROR; case '#': r->complex_uri = 1; break; diff --git a/src/http/ngx_http_request.c b/src/http/ngx_http_request.c index 2614b998c..7956610c4 100644 --- a/src/http/ngx_http_request.c +++ b/src/http/ngx_http_request.c @@ -1264,7 +1264,7 @@ ngx_http_process_request_uri(ngx_http_request_t *r) r->unparsed_uri.len = r->uri_end - r->uri_start; r->unparsed_uri.data = r->uri_start; - r->valid_unparsed_uri = (r->space_in_uri || r->empty_path_in_uri) ? 0 : 1; + r->valid_unparsed_uri = r->empty_path_in_uri ? 0 : 1; if (r->uri_ext) { if (r->args_start) { diff --git a/src/http/ngx_http_request.h b/src/http/ngx_http_request.h index fa4d5f99f..63576274e 100644 --- a/src/http/ngx_http_request.h +++ b/src/http/ngx_http_request.h @@ -468,9 +468,6 @@ struct ngx_http_request_s { /* URI with "+" */ unsigned plus_in_uri:1; - /* URI with " " */ - unsigned space_in_uri:1; - /* URI with empty path */ unsigned empty_path_in_uri:1; -- cgit From 0b66bd4be777a5b79c5ae0e7dff89fc6429da0fe Mon Sep 17 00:00:00 2001 From: Maxim Dounin Date: Mon, 28 Jun 2021 18:01:15 +0300 Subject: Disabled control characters in URIs. Control characters (0x00-0x1f, 0x7f) were never allowed in URIs, and must be percent-encoded by clients. Further, these are not believed to appear in practice. On the other hand, passing such characters might make various attacks possible or easier, despite the fact that currently allowed control characters are not significant for HTTP request parsing. --- src/http/ngx_http_parse.c | 42 ++++++++++++++++++++++++++++-------------- 1 file changed, 28 insertions(+), 14 deletions(-) (limited to 'src') diff --git a/src/http/ngx_http_parse.c b/src/http/ngx_http_parse.c index 8297a132b..0d36a44e5 100644 --- a/src/http/ngx_http_parse.c +++ b/src/http/ngx_http_parse.c @@ -11,7 +11,7 @@ static uint32_t usual[] = { - 0xffffdbfe, /* 1111 1111 1111 1111 1101 1011 1111 1110 */ + 0x00000000, /* 0000 0000 0000 0000 0000 0000 0000 0000 */ /* ?>=< ;:98 7654 3210 /.-, +*)( '&%$ #"! */ 0x7fff37d6, /* 0111 1111 1111 1111 0011 0111 1101 0110 */ @@ -24,7 +24,7 @@ static uint32_t usual[] = { #endif /* ~}| {zyx wvut srqp onml kjih gfed cba` */ - 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */ + 0x7fffffff, /* 0111 1111 1111 1111 1111 1111 1111 1111 */ 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */ 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */ @@ -528,9 +528,10 @@ ngx_http_parse_request_line(ngx_http_request_t *r, ngx_buf_t *b) case '+': r->plus_in_uri = 1; break; - case '\0': - return NGX_HTTP_PARSE_INVALID_REQUEST; default: + if (ch < 0x20 || ch == 0x7f) { + return NGX_HTTP_PARSE_INVALID_REQUEST; + } state = sw_check_uri; break; } @@ -592,8 +593,11 @@ ngx_http_parse_request_line(ngx_http_request_t *r, ngx_buf_t *b) case '+': r->plus_in_uri = 1; break; - case '\0': - return NGX_HTTP_PARSE_INVALID_REQUEST; + default: + if (ch < 0x20 || ch == 0x7f) { + return NGX_HTTP_PARSE_INVALID_REQUEST; + } + break; } break; @@ -621,8 +625,11 @@ ngx_http_parse_request_line(ngx_http_request_t *r, ngx_buf_t *b) case '#': r->complex_uri = 1; break; - case '\0': - return NGX_HTTP_PARSE_INVALID_REQUEST; + default: + if (ch < 0x20 || ch == 0x7f) { + return NGX_HTTP_PARSE_INVALID_REQUEST; + } + break; } break; @@ -1118,8 +1125,6 @@ ngx_http_parse_uri(ngx_http_request_t *r) } switch (ch) { - case ' ': - return NGX_ERROR; case '.': r->complex_uri = 1; state = sw_uri; @@ -1150,6 +1155,9 @@ ngx_http_parse_uri(ngx_http_request_t *r) r->plus_in_uri = 1; break; default: + if (ch <= 0x20 || ch == 0x7f) { + return NGX_ERROR; + } state = sw_check_uri; break; } @@ -1177,8 +1185,6 @@ ngx_http_parse_uri(ngx_http_request_t *r) case '.': r->uri_ext = p + 1; break; - case ' ': - return NGX_ERROR; #if (NGX_WIN32) case '\\': r->complex_uri = 1; @@ -1200,6 +1206,11 @@ ngx_http_parse_uri(ngx_http_request_t *r) case '+': r->plus_in_uri = 1; break; + default: + if (ch <= 0x20 || ch == 0x7f) { + return NGX_ERROR; + } + break; } break; @@ -1211,11 +1222,14 @@ ngx_http_parse_uri(ngx_http_request_t *r) } switch (ch) { - case ' ': - return NGX_ERROR; case '#': r->complex_uri = 1; break; + default: + if (ch <= 0x20 || ch == 0x7f) { + return NGX_ERROR; + } + break; } break; } -- cgit From 9ab4d368af63e9c4a0bebc0eda82d668adaa560a Mon Sep 17 00:00:00 2001 From: Maxim Dounin Date: Mon, 28 Jun 2021 18:01:18 +0300 Subject: Disabled control characters and space in header names. Control characters (0x00-0x1f, 0x7f), space, and colon were never allowed in header names. The only somewhat valid use is header continuation which nginx never supported and which is explicitly obsolete by RFC 7230. Previously, such headers were considered invalid and were ignored by default (as per ignore_invalid_headers directive). With this change, such headers are unconditionally rejected. It is expected to make nginx more resilient to various attacks, in particular, with ignore_invalid_headers switched off (which is inherently unsecure, though nevertheless sometimes used in the wild). --- src/http/modules/ngx_http_grpc_module.c | 2 +- src/http/ngx_http_parse.c | 4 ++-- src/http/v2/ngx_http_v2.c | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/http/modules/ngx_http_grpc_module.c b/src/http/modules/ngx_http_grpc_module.c index 654bd17b9..65bd1e6c3 100644 --- a/src/http/modules/ngx_http_grpc_module.c +++ b/src/http/modules/ngx_http_grpc_module.c @@ -3384,7 +3384,7 @@ ngx_http_grpc_validate_header_name(ngx_http_request_t *r, ngx_str_t *s) return NGX_ERROR; } - if (ch == '\0' || ch == CR || ch == LF) { + if (ch <= 0x20 || ch == 0x7f) { return NGX_ERROR; } } diff --git a/src/http/ngx_http_parse.c b/src/http/ngx_http_parse.c index 0d36a44e5..6af326dee 100644 --- a/src/http/ngx_http_parse.c +++ b/src/http/ngx_http_parse.c @@ -893,7 +893,7 @@ ngx_http_parse_header_line(ngx_http_request_t *r, ngx_buf_t *b, break; } - if (ch == '\0') { + if (ch <= 0x20 || ch == 0x7f || ch == ':') { return NGX_HTTP_PARSE_INVALID_HEADER; } @@ -961,7 +961,7 @@ ngx_http_parse_header_line(ngx_http_request_t *r, ngx_buf_t *b, break; } - if (ch == '\0') { + if (ch <= 0x20 || ch == 0x7f) { return NGX_HTTP_PARSE_INVALID_HEADER; } diff --git a/src/http/v2/ngx_http_v2.c b/src/http/v2/ngx_http_v2.c index 423667d47..3bef002bd 100644 --- a/src/http/v2/ngx_http_v2.c +++ b/src/http/v2/ngx_http_v2.c @@ -3457,7 +3457,7 @@ ngx_http_v2_validate_header(ngx_http_request_t *r, ngx_http_v2_header_t *header) continue; } - if (ch == '\0' || ch == LF || ch == CR || ch == ':' + if (ch <= 0x20 || ch == 0x7f || ch == ':' || (ch >= 'A' && ch <= 'Z')) { ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, -- cgit From 7587778a33bea0ce6f203a8c4de18e33f38b9582 Mon Sep 17 00:00:00 2001 From: Maxim Dounin Date: Mon, 28 Jun 2021 18:01:20 +0300 Subject: Improved logging of invalid headers. In 71edd9192f24 logging of invalid headers which were rejected with the NGX_HTTP_PARSE_INVALID_HEADER error was restricted to just the "client sent invalid header line" message, without any attempts to log the header itself. This patch returns logging of the header up to the invalid character and the character itself. The r->header_end pointer is now properly set in all cases to make logging possible. The same logging is also introduced when parsing headers from upstream servers. --- src/http/modules/ngx_http_fastcgi_module.c | 8 +++++--- src/http/modules/ngx_http_proxy_module.c | 8 +++++--- src/http/modules/ngx_http_scgi_module.c | 8 +++++--- src/http/modules/ngx_http_uwsgi_module.c | 8 +++++--- src/http/ngx_http_parse.c | 5 +++++ src/http/ngx_http_request.c | 4 +++- 6 files changed, 28 insertions(+), 13 deletions(-) (limited to 'src') diff --git a/src/http/modules/ngx_http_fastcgi_module.c b/src/http/modules/ngx_http_fastcgi_module.c index 5191880e3..69ac0f72c 100644 --- a/src/http/modules/ngx_http_fastcgi_module.c +++ b/src/http/modules/ngx_http_fastcgi_module.c @@ -2019,10 +2019,12 @@ ngx_http_fastcgi_process_header(ngx_http_request_t *r) break; } - /* there was error while a header line parsing */ + /* rc == NGX_HTTP_PARSE_INVALID_HEADER */ - ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, - "upstream sent invalid header"); + ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, + "upstream sent invalid header: \"%*s\\x%02xd...\"", + r->header_end - r->header_name_start, + r->header_name_start, *r->header_end); return NGX_HTTP_UPSTREAM_INVALID_HEADER; } diff --git a/src/http/modules/ngx_http_proxy_module.c b/src/http/modules/ngx_http_proxy_module.c index d82f5ea21..368297e77 100644 --- a/src/http/modules/ngx_http_proxy_module.c +++ b/src/http/modules/ngx_http_proxy_module.c @@ -2019,10 +2019,12 @@ ngx_http_proxy_process_header(ngx_http_request_t *r) return NGX_AGAIN; } - /* there was error while a header line parsing */ + /* rc == NGX_HTTP_PARSE_INVALID_HEADER */ - ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, - "upstream sent invalid header"); + ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, + "upstream sent invalid header: \"%*s\\x%02xd...\"", + r->header_end - r->header_name_start, + r->header_name_start, *r->header_end); return NGX_HTTP_UPSTREAM_INVALID_HEADER; } diff --git a/src/http/modules/ngx_http_scgi_module.c b/src/http/modules/ngx_http_scgi_module.c index 600999c88..570713df9 100644 --- a/src/http/modules/ngx_http_scgi_module.c +++ b/src/http/modules/ngx_http_scgi_module.c @@ -1140,10 +1140,12 @@ ngx_http_scgi_process_header(ngx_http_request_t *r) return NGX_AGAIN; } - /* there was error while a header line parsing */ + /* rc == NGX_HTTP_PARSE_INVALID_HEADER */ - ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, - "upstream sent invalid header"); + ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, + "upstream sent invalid header: \"%*s\\x%02xd...\"", + r->header_end - r->header_name_start, + r->header_name_start, *r->header_end); return NGX_HTTP_UPSTREAM_INVALID_HEADER; } diff --git a/src/http/modules/ngx_http_uwsgi_module.c b/src/http/modules/ngx_http_uwsgi_module.c index 655be98c7..40a06c78e 100644 --- a/src/http/modules/ngx_http_uwsgi_module.c +++ b/src/http/modules/ngx_http_uwsgi_module.c @@ -1361,10 +1361,12 @@ ngx_http_uwsgi_process_header(ngx_http_request_t *r) return NGX_AGAIN; } - /* there was error while a header line parsing */ + /* rc == NGX_HTTP_PARSE_INVALID_HEADER */ - ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, - "upstream sent invalid header"); + ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, + "upstream sent invalid header: \"%*s\\x%02xd...\"", + r->header_end - r->header_name_start, + r->header_name_start, *r->header_end); return NGX_HTTP_UPSTREAM_INVALID_HEADER; } diff --git a/src/http/ngx_http_parse.c b/src/http/ngx_http_parse.c index 6af326dee..6460da293 100644 --- a/src/http/ngx_http_parse.c +++ b/src/http/ngx_http_parse.c @@ -894,6 +894,7 @@ ngx_http_parse_header_line(ngx_http_request_t *r, ngx_buf_t *b, } if (ch <= 0x20 || ch == 0x7f || ch == ':') { + r->header_end = p; return NGX_HTTP_PARSE_INVALID_HEADER; } @@ -962,6 +963,7 @@ ngx_http_parse_header_line(ngx_http_request_t *r, ngx_buf_t *b, } if (ch <= 0x20 || ch == 0x7f) { + r->header_end = p; return NGX_HTTP_PARSE_INVALID_HEADER; } @@ -984,6 +986,7 @@ ngx_http_parse_header_line(ngx_http_request_t *r, ngx_buf_t *b, r->header_end = p; goto done; case '\0': + r->header_end = p; return NGX_HTTP_PARSE_INVALID_HEADER; default: r->header_start = p; @@ -1007,6 +1010,7 @@ ngx_http_parse_header_line(ngx_http_request_t *r, ngx_buf_t *b, r->header_end = p; goto done; case '\0': + r->header_end = p; return NGX_HTTP_PARSE_INVALID_HEADER; } break; @@ -1022,6 +1026,7 @@ ngx_http_parse_header_line(ngx_http_request_t *r, ngx_buf_t *b, case LF: goto done; case '\0': + r->header_end = p; return NGX_HTTP_PARSE_INVALID_HEADER; default: state = sw_value; diff --git a/src/http/ngx_http_request.c b/src/http/ngx_http_request.c index 7956610c4..2e7c30fb6 100644 --- a/src/http/ngx_http_request.c +++ b/src/http/ngx_http_request.c @@ -1522,7 +1522,9 @@ ngx_http_process_request_headers(ngx_event_t *rev) /* rc == NGX_HTTP_PARSE_INVALID_HEADER */ ngx_log_error(NGX_LOG_INFO, c->log, 0, - "client sent invalid header line"); + "client sent invalid header line: \"%*s\\x%02xd...\"", + r->header_end - r->header_name_start, + r->header_name_start, *r->header_end); ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST); break; -- cgit From 07c63a42640e59bf5e3399cfdafd498b61671780 Mon Sep 17 00:00:00 2001 From: Maxim Dounin Date: Mon, 28 Jun 2021 18:01:24 +0300 Subject: Disabled control characters in the Host header. Control characters (0x00-0x1f, 0x7f) and space are not expected to appear in the Host header. Requests with such characters in the Host header are now unconditionally rejected. --- src/http/ngx_http_request.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/http/ngx_http_request.c b/src/http/ngx_http_request.c index 2e7c30fb6..2d1845d02 100644 --- a/src/http/ngx_http_request.c +++ b/src/http/ngx_http_request.c @@ -2176,15 +2176,16 @@ ngx_http_validate_host(ngx_str_t *host, ngx_pool_t *pool, ngx_uint_t alloc) } break; - case '\0': - return NGX_DECLINED; - default: if (ngx_path_separator(ch)) { return NGX_DECLINED; } + if (ch <= 0x20 || ch == 0x7f) { + return NGX_DECLINED; + } + if (ch >= 'A' && ch <= 'Z') { alloc = 1; } -- cgit From b20768e61cd3569160a57e2f0e2e6d0def87792e Mon Sep 17 00:00:00 2001 From: Ruslan Ermilov Date: Mon, 5 Jul 2021 13:09:23 +0300 Subject: Use only preallocated memory in ngx_readv_chain() (ticket #1408). In d1bde5c3c5d2, the number of preallocated iovec's for ngx_readv_chain() was increased. Still, in some setups, the function might allocate memory for iovec's from a connection pool, which is only freed when closing the connection. The ngx_readv_chain() function was modified to use only preallocated memory, similarly to the ngx_writev_chain() change in 8e903522c17a. --- src/os/unix/ngx_readv_chain.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/os/unix/ngx_readv_chain.c b/src/os/unix/ngx_readv_chain.c index a3577ce19..b1ae4b51d 100644 --- a/src/os/unix/ngx_readv_chain.c +++ b/src/os/unix/ngx_readv_chain.c @@ -96,7 +96,7 @@ ngx_readv_chain(ngx_connection_t *c, ngx_chain_t *chain, off_t limit) iov->iov_len += n; } else { - if (vec.nelts >= IOV_MAX) { + if (vec.nelts == vec.nalloc) { break; } -- cgit From b445d1884fad722cc559b96791c93b445f597db9 Mon Sep 17 00:00:00 2001 From: Ruslan Ermilov Date: Mon, 5 Jul 2021 13:26:49 +0300 Subject: Win32: use only preallocated memory in send/recv chain functions. The ngx_wsasend_chain() and ngx_wsarecv_chain() functions were modified to use only preallocated memory, and the number of preallocated wsabufs was increased to 64. --- src/os/win32/ngx_wsarecv_chain.c | 6 +++++- src/os/win32/ngx_wsasend_chain.c | 26 +++++++++++++++----------- 2 files changed, 20 insertions(+), 12 deletions(-) (limited to 'src') diff --git a/src/os/win32/ngx_wsarecv_chain.c b/src/os/win32/ngx_wsarecv_chain.c index 87f023911..4f95d5a2b 100644 --- a/src/os/win32/ngx_wsarecv_chain.c +++ b/src/os/win32/ngx_wsarecv_chain.c @@ -10,7 +10,7 @@ #include -#define NGX_WSABUFS 8 +#define NGX_WSABUFS 64 ssize_t @@ -57,6 +57,10 @@ ngx_wsarecv_chain(ngx_connection_t *c, ngx_chain_t *chain, off_t limit) wsabuf->len += n; } else { + if (vec.nelts == vec.nalloc) { + break; + } + wsabuf = ngx_array_push(&vec); if (wsabuf == NULL) { return NGX_ERROR; diff --git a/src/os/win32/ngx_wsasend_chain.c b/src/os/win32/ngx_wsasend_chain.c index e2dde22c9..cd50e710c 100644 --- a/src/os/win32/ngx_wsasend_chain.c +++ b/src/os/win32/ngx_wsasend_chain.c @@ -10,7 +10,7 @@ #include -#define NGX_WSABUFS 8 +#define NGX_WSABUFS 64 ngx_chain_t * @@ -47,7 +47,7 @@ ngx_wsasend_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit) vec.elts = wsabufs; vec.size = sizeof(WSABUF); - vec.nalloc = NGX_WSABUFS; + vec.nalloc = ngx_min(NGX_WSABUFS, ngx_max_wsabufs); vec.pool = c->pool; for ( ;; ) { @@ -59,10 +59,8 @@ ngx_wsasend_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit) /* create the WSABUF and coalesce the neighbouring bufs */ - for (cl = in; - cl && vec.nelts < ngx_max_wsabufs && send < limit; - cl = cl->next) - { + for (cl = in; cl && send < limit; cl = cl->next) { + if (ngx_buf_special(cl->buf)) { continue; } @@ -77,6 +75,10 @@ ngx_wsasend_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit) wsabuf->len += cl->buf->last - cl->buf->pos; } else { + if (vec.nelts == vec.nalloc) { + break; + } + wsabuf = ngx_array_push(&vec); if (wsabuf == NULL) { return NGX_CHAIN_ERROR; @@ -169,7 +171,7 @@ ngx_overlapped_wsasend_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit) vec.elts = wsabufs; vec.nelts = 0; vec.size = sizeof(WSABUF); - vec.nalloc = NGX_WSABUFS; + vec.nalloc = ngx_min(NGX_WSABUFS, ngx_max_wsabufs); vec.pool = c->pool; send = 0; @@ -178,10 +180,8 @@ ngx_overlapped_wsasend_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit) /* create the WSABUF and coalesce the neighbouring bufs */ - for (cl = in; - cl && vec.nelts < ngx_max_wsabufs && send < limit; - cl = cl->next) - { + for (cl = in; cl && send < limit; cl = cl->next) { + if (ngx_buf_special(cl->buf)) { continue; } @@ -196,6 +196,10 @@ ngx_overlapped_wsasend_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit) wsabuf->len += cl->buf->last - cl->buf->pos; } else { + if (vec.nelts == vec.nalloc) { + break; + } + wsabuf = ngx_array_push(&vec); if (wsabuf == NULL) { return NGX_CHAIN_ERROR; -- cgit