From mdounin at mdounin.ru Fri Mar 6 04:08:55 2026 From: mdounin at mdounin.ru (=?iso-8859-1?q?Maxim_Dounin?=) Date: Fri, 06 Mar 2026 07:08:55 +0300 Subject: [nginx] Version bump. Message-ID: details: http://freenginx.org/hg/nginx/rev/01b69364693c branches: changeset: 9468:01b69364693c user: Maxim Dounin date: Fri Mar 06 06:54:11 2026 +0300 description: Version bump. diffstat: src/core/nginx.h | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) diffs (14 lines): diff --git a/src/core/nginx.h b/src/core/nginx.h --- a/src/core/nginx.h +++ b/src/core/nginx.h @@ -9,8 +9,8 @@ #define _NGINX_H_INCLUDED_ -#define nginx_version 1029005 -#define NGINX_VERSION "1.29.5" +#define nginx_version 1029006 +#define NGINX_VERSION "1.29.6" #define freenginx 1 From mdounin at mdounin.ru Fri Mar 6 04:08:56 2026 From: mdounin at mdounin.ru (=?iso-8859-1?q?Maxim_Dounin?=) Date: Fri, 06 Mar 2026 07:08:56 +0300 Subject: [nginx] Upstream: silenced "temporary disabled" warnings with va... Message-ID: details: http://freenginx.org/hg/nginx/rev/52a4d08af7a5 branches: changeset: 9469:52a4d08af7a5 user: Maxim Dounin date: Fri Mar 06 06:54:13 2026 +0300 description: Upstream: silenced "temporary disabled" warnings with variables. Previously, if a server within a runtime-created upstream, as used for proxy_pass with variables, failed, the "upstream server temporarily disabled" warning was logged. For runtime-created upstreams the warning is useless and confusing, since such upstreams are never used for other requests. To disable the warning, max_fails is now set to 0 for runtime-created upstreams. Additionally, fail_timeout is also set to 0, for consistency. diffstat: src/http/ngx_http_upstream_round_robin.c | 8 ++++---- src/stream/ngx_stream_upstream_round_robin.c | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diffs (50 lines): diff --git a/src/http/ngx_http_upstream_round_robin.c b/src/http/ngx_http_upstream_round_robin.c --- a/src/http/ngx_http_upstream_round_robin.c +++ b/src/http/ngx_http_upstream_round_robin.c @@ -356,8 +356,8 @@ ngx_http_upstream_create_round_robin_pee peer[0].effective_weight = 1; peer[0].current_weight = 0; peer[0].max_conns = 0; - peer[0].max_fails = 1; - peer[0].fail_timeout = 10; + peer[0].max_fails = 0; + peer[0].fail_timeout = 0; peers->peer = peer; } else { @@ -390,8 +390,8 @@ ngx_http_upstream_create_round_robin_pee peer[i].effective_weight = 1; peer[i].current_weight = 0; peer[i].max_conns = 0; - peer[i].max_fails = 1; - peer[i].fail_timeout = 10; + peer[i].max_fails = 0; + peer[i].fail_timeout = 0; *peerp = &peer[i]; peerp = &peer[i].next; } diff --git a/src/stream/ngx_stream_upstream_round_robin.c b/src/stream/ngx_stream_upstream_round_robin.c --- a/src/stream/ngx_stream_upstream_round_robin.c +++ b/src/stream/ngx_stream_upstream_round_robin.c @@ -366,8 +366,8 @@ ngx_stream_upstream_create_round_robin_p peer[0].effective_weight = 1; peer[0].current_weight = 0; peer[0].max_conns = 0; - peer[0].max_fails = 1; - peer[0].fail_timeout = 10; + peer[0].max_fails = 0; + peer[0].fail_timeout = 0; peers->peer = peer; } else { @@ -400,8 +400,8 @@ ngx_stream_upstream_create_round_robin_p peer[i].effective_weight = 1; peer[i].current_weight = 0; peer[i].max_conns = 0; - peer[i].max_fails = 1; - peer[i].fail_timeout = 10; + peer[i].max_fails = 0; + peer[i].fail_timeout = 0; *peerp = &peer[i]; peerp = &peer[i].next; } From mdounin at mdounin.ru Fri Mar 6 04:10:24 2026 From: mdounin at mdounin.ru (=?iso-8859-1?q?Maxim_Dounin?=) Date: Fri, 06 Mar 2026 07:10:24 +0300 Subject: [nginx] gRPC: reinitialization of in, out, and busy chains. Message-ID: details: http://freenginx.org/hg/nginx/rev/3de452bb4b91 branches: changeset: 9470:3de452bb4b91 user: Maxim Dounin date: Fri Mar 06 07:09:06 2026 +0300 description: gRPC: reinitialization of in, out, and busy chains. If an error happens with data buffered in ctx->in (or control frames queued in ctx->out), keeping these while switching to the next upstream server will result in incorrect data sent to the new connection, likely causing a failure. Similarly, if there are buffers in ctx->busy, switching to the next upstream server will reinitialize ngx_chain_writer() context, u->writer, and these buffers will be forgotten. Still, since they are in ctx->busy and not marked as fully sent, ngx_chain_update_chains() won't look any further, thus breaking buffers reuse and causing excessive memory usage on long-running requests. The fix is to clear ctx->in, ctx->out, and ctx->busy chains on request reinitialization. Prodded by David Carlier, https://freenginx.org/pipermail/nginx-devel/2026-February/000934.html diffstat: src/http/modules/ngx_http_grpc_module.c | 3 +++ 1 files changed, 3 insertions(+), 0 deletions(-) diffs (13 lines): diff --git a/src/http/modules/ngx_http_grpc_module.c b/src/http/modules/ngx_http_grpc_module.c --- a/src/http/modules/ngx_http_grpc_module.c +++ b/src/http/modules/ngx_http_grpc_module.c @@ -1217,6 +1217,9 @@ ngx_http_grpc_reinit_request(ngx_http_re ctx->rst = 0; ctx->goaway = 0; ctx->connection = NULL; + ctx->in = NULL; + ctx->out = NULL; + ctx->busy = NULL; ctx->pings = 0; ctx->settings = 0; ctx->headers = 0; From mdounin at mdounin.ru Fri Mar 6 04:23:33 2026 From: mdounin at mdounin.ru (=?iso-8859-1?q?Maxim_Dounin?=) Date: Fri, 06 Mar 2026 07:23:33 +0300 Subject: [nginx] Xslt: fixed vsnprintf() usage. Message-ID: details: http://freenginx.org/hg/nginx/rev/2dbab7b19453 branches: changeset: 9471:2dbab7b19453 user: Maxim Dounin date: Fri Mar 06 07:11:33 2026 +0300 description: Xslt: fixed vsnprintf() usage. Previously, vsnprintf(), as used to handle error messages from the libxml2 library in ngx_http_xslt_sax_error(), was used incorrectly: the code assumed that vsnprintf() returns the number of bytes actually printed, and never fails. But vsnprintf(), as originally introduced in 4.4BSD and later standardized in C99, returns the number of characters that would have been written with a sufficiently large buffer, and "if the return value is greater than or equal to the size argument, the string was too short and some of the printed characters were discarded". Additionally, vsnprintf() might theoretically result in a zero-length error message, or might fail (for example, due to an incorrect format specification in libxml2). Most notably, this can result in out-of-bounds reads and segmentation faults in the worker process on very long error messages. The fix is to check the value returned by vsnprintf() and properly handle too long error messages, as well as zero-length error messages and vsnprintf() failures. diffstat: src/http/modules/ngx_http_xslt_filter_module.c | 21 +++++++++++++++++---- 1 files changed, 17 insertions(+), 4 deletions(-) diffs (44 lines): diff --git a/src/http/modules/ngx_http_xslt_filter_module.c b/src/http/modules/ngx_http_xslt_filter_module.c --- a/src/http/modules/ngx_http_xslt_filter_module.c +++ b/src/http/modules/ngx_http_xslt_filter_module.c @@ -540,23 +540,36 @@ ngx_http_xslt_sax_error(void *data, cons { xmlParserCtxtPtr ctxt = data; - size_t n; + int n; va_list args; + ngx_uint_t truncated; ngx_http_xslt_filter_ctx_t *ctx; u_char buf[NGX_MAX_ERROR_STR]; ctx = ctxt->sax->_private; buf[0] = '\0'; + truncated = 0; va_start(args, msg); - n = (size_t) vsnprintf((char *) buf, NGX_MAX_ERROR_STR, msg, args); + n = vsnprintf((char *) buf, NGX_MAX_ERROR_STR, msg, args); va_end(args); - while (--n && (buf[n] == CR || buf[n] == LF)) { /* void */ } + if (n < 0) { + n = 0; + truncated = 1; + } + + if (n >= NGX_MAX_ERROR_STR) { + n = NGX_MAX_ERROR_STR - 1; + truncated = 1; + } + + while (n && (buf[n - 1] == CR || buf[n - 1] == LF)) { n--; } ngx_log_error(NGX_LOG_ERR, ctx->request->connection->log, 0, - "libxml2 error: \"%*s\"", n + 1, buf); + "libxml2 error: \"%*s%s\"", + (size_t) n, buf, truncated ? "..." : ""); } From mdounin at mdounin.ru Fri Mar 6 04:23:33 2026 From: mdounin at mdounin.ru (=?iso-8859-1?q?Maxim_Dounin?=) Date: Fri, 06 Mar 2026 07:23:33 +0300 Subject: [nginx] Xslt: proper logging of long errors. Message-ID: details: http://freenginx.org/hg/nginx/rev/d7e6f90ec255 branches: changeset: 9472:d7e6f90ec255 user: Maxim Dounin date: Fri Mar 06 07:11:37 2026 +0300 description: Xslt: proper logging of long errors. To ensure that long error messages from the libxml2 library can be properly logged by ngx_http_xslt_sax_error(), the buffer size was changed to NGX_MAX_CONF_ERRSTR. It is smaller than NGX_MAX_ERROR_STR, the size of the low-level buffer used during logging, and therefore reserves some space for other information. Similar approach is used in ngx_conf_log_error(), where the macro comes from, as well as various other places, such as ngx_ssl_error(). diffstat: src/http/modules/ngx_http_xslt_filter_module.c | 8 ++++---- 1 files changed, 4 insertions(+), 4 deletions(-) diffs (32 lines): diff --git a/src/http/modules/ngx_http_xslt_filter_module.c b/src/http/modules/ngx_http_xslt_filter_module.c --- a/src/http/modules/ngx_http_xslt_filter_module.c +++ b/src/http/modules/ngx_http_xslt_filter_module.c @@ -544,7 +544,7 @@ ngx_http_xslt_sax_error(void *data, cons va_list args; ngx_uint_t truncated; ngx_http_xslt_filter_ctx_t *ctx; - u_char buf[NGX_MAX_ERROR_STR]; + u_char buf[NGX_MAX_CONF_ERRSTR]; ctx = ctxt->sax->_private; @@ -552,7 +552,7 @@ ngx_http_xslt_sax_error(void *data, cons truncated = 0; va_start(args, msg); - n = vsnprintf((char *) buf, NGX_MAX_ERROR_STR, msg, args); + n = vsnprintf((char *) buf, NGX_MAX_CONF_ERRSTR, msg, args); va_end(args); if (n < 0) { @@ -560,8 +560,8 @@ ngx_http_xslt_sax_error(void *data, cons truncated = 1; } - if (n >= NGX_MAX_ERROR_STR) { - n = NGX_MAX_ERROR_STR - 1; + if (n >= NGX_MAX_CONF_ERRSTR) { + n = NGX_MAX_CONF_ERRSTR - 1; truncated = 1; } From mdounin at mdounin.ru Fri Mar 6 04:29:52 2026 From: mdounin at mdounin.ru (=?iso-8859-1?q?Maxim_Dounin?=) Date: Fri, 06 Mar 2026 07:29:52 +0300 Subject: [nginx] SSL: added missing "goto failed" in ECH handling with Bo... Message-ID: details: http://freenginx.org/hg/nginx/rev/87c2bbf0e078 branches: changeset: 9473:87c2bbf0e078 user: Maxim Dounin date: Fri Mar 06 07:29:10 2026 +0300 description: SSL: added missing "goto failed" in ECH handling with BoringSSL. The "goto failed" statement was missed in the EVP_HPKE_KEY_new() error handling, as used during configuration of Encrypted Client Hello (ECH) with BoringSSL, resulting in segmentation fault in EVP_HPKE_KEY_init() if memory allocation in EVP_HPKE_KEY_new() failed. Missed in 9422:deb1ec630f7c (1.29.2). Reported by Yu Zhu, https://github.com/freenginx/nginx/issues/16 diffstat: src/event/ngx_event_openssl.c | 1 + 1 files changed, 1 insertions(+), 0 deletions(-) diffs (11 lines): diff --git a/src/event/ngx_event_openssl.c b/src/event/ngx_event_openssl.c --- a/src/event/ngx_event_openssl.c +++ b/src/event/ngx_event_openssl.c @@ -2023,6 +2023,7 @@ failed: if (hpkey == NULL) { ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0, "EVP_HPKE_KEY_new() failed"); + goto failed; } if (EVP_HPKE_KEY_init(hpkey, EVP_hpke_x25519_hkdf_sha256(), From mdounin at mdounin.ru Fri Mar 6 04:33:30 2026 From: mdounin at mdounin.ru (=?utf-8?q?Maxim_Dounin?=) Date: Fri, 06 Mar 2026 07:33:30 +0300 Subject: [PATCH] Fixed clcf->auto_redirect in uwsgi_pass/scgi_pass with variables Message-ID: <02261aeedb0857c562fa.1772771610@vm-bsd.mdounin.ru> # HG changeset patch # User Maxim Dounin # Date 1772771457 -10800 # Fri Mar 06 07:30:57 2026 +0300 # Node ID 02261aeedb0857c562fac989bc7d3233fbdd2beb # Parent 87c2bbf0e078ab8e52100a1324cf7ebb64b6b96d Fixed clcf->auto_redirect in uwsgi_pass/scgi_pass with variables. Previously, clcf->auto_redirect was only set (for locations ending with "/") when uwsgi_pass and scgi_pass were used without variables, but not with variables. For proxy_pass and fastcgi_pass this was fixed in 2989:dff9764eaca2 (0.8.7). It was not, however, fixed in ngx_http_uwsgi_module (as imported later, in 3541:21452748d165, 0.8.40) and ngx_http_scgi_module (introduced shortly after, in 3637:d656caa72ec9, 0.8.42). The fix is mostly identical to the one in 2989:dff9764eaca2 (0.8.7) and ensures that clcf->auto_redirect is set both with and without variables. diff --git a/src/http/modules/ngx_http_scgi_module.c b/src/http/modules/ngx_http_scgi_module.c --- a/src/http/modules/ngx_http_scgi_module.c +++ b/src/http/modules/ngx_http_scgi_module.c @@ -1921,8 +1921,13 @@ ngx_http_scgi_pass(ngx_conf_t *cf, ngx_c } clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module); + clcf->handler = ngx_http_scgi_handler; + if (clcf->name.len && clcf->name.data[clcf->name.len - 1] == '/') { + clcf->auto_redirect = 1; + } + value = cf->args->elts; url = &value[1]; @@ -1958,10 +1963,6 @@ ngx_http_scgi_pass(ngx_conf_t *cf, ngx_c return NGX_CONF_ERROR; } - if (clcf->name.len && clcf->name.data[clcf->name.len - 1] == '/') { - clcf->auto_redirect = 1; - } - return NGX_CONF_OK; } diff --git a/src/http/modules/ngx_http_uwsgi_module.c b/src/http/modules/ngx_http_uwsgi_module.c --- a/src/http/modules/ngx_http_uwsgi_module.c +++ b/src/http/modules/ngx_http_uwsgi_module.c @@ -2221,8 +2221,13 @@ ngx_http_uwsgi_pass(ngx_conf_t *cf, ngx_ } clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module); + clcf->handler = ngx_http_uwsgi_handler; + if (clcf->name.len && clcf->name.data[clcf->name.len - 1] == '/') { + clcf->auto_redirect = 1; + } + value = cf->args->elts; url = &value[1]; @@ -2281,10 +2286,6 @@ ngx_http_uwsgi_pass(ngx_conf_t *cf, ngx_ return NGX_CONF_ERROR; } - if (clcf->name.len && clcf->name.data[clcf->name.len - 1] == '/') { - clcf->auto_redirect = 1; - } - return NGX_CONF_OK; } From mdounin at mdounin.ru Sun Mar 8 02:43:38 2026 From: mdounin at mdounin.ru (=?utf-8?q?Maxim_Dounin?=) Date: Sun, 08 Mar 2026 05:43:38 +0300 Subject: [PATCH 1 of 3] Mp4: fixed ngx_http_mp4_seek_key_frame() Message-ID: # HG changeset patch # User Maxim Dounin # Date 1772936214 -10800 # Sun Mar 08 05:16:54 2026 +0300 # Node ID a98f57c9c8fb0e760d43fe9b507cd51e7da427cc # Parent 87c2bbf0e078ab8e52100a1324cf7ebb64b6b96d Mp4: fixed ngx_http_mp4_seek_key_frame(). Previously, ngx_http_mp4_seek_key_frame() might return key frame prefix larger than start_sample provided in function arguments, notably on an invalid stss entry with zero sample_number. This resulted in backwards loop in ngx_http_mp4_crop_stts_data() to incorrectly access data before the stts atom entries (and stop at the stts atom header mostly by chance). The fix is to make sure ngx_http_mp4_seek_key_frame() always returns a value equal or smaller than start_sample provided, regardless of the stss entries. Invalid entries with zero sample_number now will be interpreted as if there very large sample_number, so the previous one will be returned. diff --git a/src/http/modules/ngx_http_mp4_module.c b/src/http/modules/ngx_http_mp4_module.c --- a/src/http/modules/ngx_http_mp4_module.c +++ b/src/http/modules/ngx_http_mp4_module.c @@ -2528,13 +2528,14 @@ ngx_http_mp4_seek_key_frame(ngx_http_mp4 entry = (uint32_t *) data->pos; end = (uint32_t *) data->last; - /* sync samples starts from 1 */ - start_sample++; - key_prefix = 0; while (entry < end) { sample = ngx_mp4_get_32value(entry); + + /* sync samples starts from 1 */ + sample--; + if (sample > start_sample) { break; } From mdounin at mdounin.ru Sun Mar 8 02:43:39 2026 From: mdounin at mdounin.ru (=?utf-8?q?Maxim_Dounin?=) Date: Sun, 08 Mar 2026 05:43:39 +0300 Subject: [PATCH 2 of 3] Mp4: fixed entries tests on 32-bit platforms In-Reply-To: References: Message-ID: <76e10dcd0806af147216.1772937819@vm-bsd.mdounin.ru> # HG changeset patch # User Maxim Dounin # Date 1772936216 -10800 # Sun Mar 08 05:16:56 2026 +0300 # Node ID 76e10dcd0806af14721671ced78b13dfbe4cd437 # Parent a98f57c9c8fb0e760d43fe9b507cd51e7da427cc Mp4: fixed entries tests on 32-bit platforms. Previously, tests for the number of entries in various atom read functions used the "entries * sizeof(uint32_t)" construct, with entries being uint32_t. On platforms with 32-bit sizeof() this will overflow, leading to a smaller result. This isn't a real issue in most cases, since the same construct is used to calculate atom_end pointer. Still, in some cases the number of entries is used directly, such as in stco/co64 atom updating, and a large value might result in segmentation faults. The fix is to cast "entries" to uint64_t before the multiplication to avoid the overflow. diff --git a/src/http/modules/ngx_http_mp4_module.c b/src/http/modules/ngx_http_mp4_module.c --- a/src/http/modules/ngx_http_mp4_module.c +++ b/src/http/modules/ngx_http_mp4_module.c @@ -2302,7 +2302,7 @@ ngx_http_mp4_read_stts_atom(ngx_http_mp4 "mp4 time-to-sample entries:%uD", entries); if (ngx_mp4_atom_data_size(ngx_mp4_stts_atom_t) - + entries * sizeof(ngx_mp4_stts_entry_t) > atom_data_size) + + (uint64_t) entries * sizeof(ngx_mp4_stts_entry_t) > atom_data_size) { ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0, "\"%s\" mp4 stts atom too small", mp4->file.name.data); @@ -2606,7 +2606,7 @@ ngx_http_mp4_read_stss_atom(ngx_http_mp4 atom->last = atom_table; if (ngx_mp4_atom_data_size(ngx_http_mp4_stss_atom_t) - + entries * sizeof(uint32_t) > atom_data_size) + + (uint64_t) entries * sizeof(uint32_t) > atom_data_size) { ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0, "\"%s\" mp4 stss atom too small", mp4->file.name.data); @@ -2811,7 +2811,7 @@ ngx_http_mp4_read_ctts_atom(ngx_http_mp4 atom->last = atom_table; if (ngx_mp4_atom_data_size(ngx_mp4_ctts_atom_t) - + entries * sizeof(ngx_mp4_ctts_entry_t) > atom_data_size) + + (uint64_t) entries * sizeof(ngx_mp4_ctts_entry_t) > atom_data_size) { ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0, "\"%s\" mp4 ctts atom too small", mp4->file.name.data); @@ -2993,7 +2993,7 @@ ngx_http_mp4_read_stsc_atom(ngx_http_mp4 "sample-to-chunk entries:%uD", entries); if (ngx_mp4_atom_data_size(ngx_mp4_stsc_atom_t) - + entries * sizeof(ngx_mp4_stsc_entry_t) > atom_data_size) + + (uint64_t) entries * sizeof(ngx_mp4_stsc_entry_t) > atom_data_size) { ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0, "\"%s\" mp4 stsc atom too small", mp4->file.name.data); @@ -3363,7 +3363,7 @@ ngx_http_mp4_read_stsz_atom(ngx_http_mp4 if (size == 0) { if (ngx_mp4_atom_data_size(ngx_mp4_stsz_atom_t) - + entries * sizeof(uint32_t) > atom_data_size) + + (uint64_t) entries * sizeof(uint32_t) > atom_data_size) { ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0, "\"%s\" mp4 stsz atom too small", @@ -3536,7 +3536,7 @@ ngx_http_mp4_read_stco_atom(ngx_http_mp4 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, "chunks:%uD", entries); if (ngx_mp4_atom_data_size(ngx_mp4_stco_atom_t) - + entries * sizeof(uint32_t) > atom_data_size) + + (uint64_t) entries * sizeof(uint32_t) > atom_data_size) { ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0, "\"%s\" mp4 stco atom too small", mp4->file.name.data); @@ -3754,7 +3754,7 @@ ngx_http_mp4_read_co64_atom(ngx_http_mp4 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, "chunks:%uD", entries); if (ngx_mp4_atom_data_size(ngx_mp4_co64_atom_t) - + entries * sizeof(uint64_t) > atom_data_size) + + (uint64_t) entries * sizeof(uint64_t) > atom_data_size) { ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0, "\"%s\" mp4 co64 atom too small", mp4->file.name.data); From mdounin at mdounin.ru Sun Mar 8 02:43:40 2026 From: mdounin at mdounin.ru (=?utf-8?q?Maxim_Dounin?=) Date: Sun, 08 Mar 2026 05:43:40 +0300 Subject: [PATCH 3 of 3] Mp4: fixed off-by-one in stco/co64 chunk number tests In-Reply-To: References: Message-ID: <2ba8f363ec1d6529dedc.1772937820@vm-bsd.mdounin.ru> # HG changeset patch # User Maxim Dounin # Date 1772936218 -10800 # Sun Mar 08 05:16:58 2026 +0300 # Node ID 2ba8f363ec1d6529dedc278100abc9e07609f3ee # Parent 76e10dcd0806af14721671ced78b13dfbe4cd437 Mp4: fixed off-by-one in stco/co64 chunk number tests. Previously, if trak->start_chunk was exactly equal to the number of entries in the stco/co64 atom (trak->chunks), it wasn't rejected by the tests in ngx_http_mp4_update_stco_atom() (and ngx_http_mp4_update_co64_atom()), and the following code accessed a value past the stco/co64 atom, potentially resulting in segmentation faults. diff --git a/src/http/modules/ngx_http_mp4_module.c b/src/http/modules/ngx_http_mp4_module.c --- a/src/http/modules/ngx_http_mp4_module.c +++ b/src/http/modules/ngx_http_mp4_module.c @@ -3606,7 +3606,7 @@ ngx_http_mp4_update_stco_atom(ngx_http_m return NGX_ERROR; } - if (trak->start_chunk > trak->chunks) { + if (trak->start_chunk >= trak->chunks) { ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0, "start time is out mp4 stco chunks in \"%s\"", mp4->file.name.data); @@ -3823,7 +3823,7 @@ ngx_http_mp4_update_co64_atom(ngx_http_m return NGX_ERROR; } - if (trak->start_chunk > trak->chunks) { + if (trak->start_chunk >= trak->chunks) { ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0, "start time is out mp4 co64 chunks in \"%s\"", mp4->file.name.data); From mdounin at mdounin.ru Sun Mar 8 02:46:23 2026 From: mdounin at mdounin.ru (=?utf-8?q?Maxim_Dounin?=) Date: Sun, 08 Mar 2026 05:46:23 +0300 Subject: [PATCH 1 of 2] Tests: moved bad mp4 test to a separate file In-Reply-To: References: Message-ID: # HG changeset patch # User Maxim Dounin # Date 1772937917 -10800 # Sun Mar 08 05:45:17 2026 +0300 # Node ID c92474d354a0248fd1d5712d91bfc28d8583ffa9 # Parent cccd744b91590b480f4e06ce27eaa69b038d26b3 Tests: moved bad mp4 test to a separate file. diff --git a/mp4.t b/mp4.t --- a/mp4.t +++ b/mp4.t @@ -65,23 +65,7 @@ system('ffmpeg -nostdin -loglevel quiet . "${\($t->testdir())}/no_mdat.mp4") == 0 or die "Can't create mp4 file: $!"; -my $sbad = <<'EOF'; -00000000: 00 00 00 1c 66 74 79 70 69 73 6f 6d 00 00 02 00 |....ftypisom....| -00000010: 69 73 6f 6d 69 73 6f 32 6d 70 34 31 00 00 00 09 |isomiso2mp41....| -00000020: 6d 64 61 74 00 00 00 00 94 6d 6f 6f 76 00 00 00 |mdat.....moov...| -00000030: 8c 74 72 61 6b 00 00 00 84 6d 64 69 61 00 00 00 |.trak....mdia...| -00000040: 7c 6d 69 6e 66 00 00 00 74 73 74 62 6c 00 00 00 ||minf...tstbl...| -00000050: 18 73 74 74 73 00 00 00 00 00 00 00 01 00 00 03 |.stts...........| -00000060: 3a 00 00 04 00 00 00 00 28 73 74 73 63 00 00 00 |:.......(stsc...| -00000070: 00 00 00 00 02 00 00 00 01 00 00 03 0f 00 00 00 |................| -00000080: 01 00 00 00 02 00 00 00 2b 00 00 00 01 00 00 00 |........+.......| -00000090: 14 73 74 73 7a 00 00 00 00 00 00 05 a9 00 00 03 |.stsz...........| -000000a0: 3b 00 00 00 18 63 6f 36 34 00 00 00 00 00 00 00 |;....co64.......| -000000b0: 01 ff ff ff ff f0 0f fb e7 |.........| -EOF - -$t->write_file('bad.mp4', unhex($sbad)); -$t->run()->plan(27); +$t->run()->plan(26); ############################################################################### @@ -115,10 +99,6 @@ like(http_head("$test_uri?start=21"), qr $test_uri = '/no_mdat.mp4', goto again unless $test_uri eq '/no_mdat.mp4'; -# corrupted formats - -like(http_get("/bad.mp4?start=0.5"), qr/500 Internal/, 'co64 chunk beyond EOF'); - ############################################################################### sub durations { @@ -143,17 +123,4 @@ sub durations { sprintf "%.1f %.1f", $r =~ /duration=(\d+\.\d+)/g; } -sub unhex { - my ($input) = @_; - my $buffer = ''; - - for my $l ($input =~ m/: +((?:[0-9a-f]{2,4} +)+) /gms) { - for my $v ($l =~ m/[0-9a-f]{2}/g) { - $buffer .= chr(hex($v)); - } - } - - return $buffer; -} - ############################################################################### diff --git a/mp4.t b/mp4_bad.t copy from mp4.t copy to mp4_bad.t --- a/mp4.t +++ b/mp4_bad.t @@ -1,10 +1,10 @@ #!/usr/bin/perl +# (C) Maxim Dounin # (C) Sergey Kandaurov # (C) Nginx, Inc. -# Tests for mp4 module. -# Ensures that requested stream duration is given with sane accuracy. +# Tests for mp4 module, various bad mp4 files. ############################################################################### @@ -16,15 +16,14 @@ use Test::More; BEGIN { use FindBin; chdir($FindBin::Bin); } use lib 'lib'; -use Test::Nginx qw/ :DEFAULT http_content /; +use Test::Nginx; ############################################################################### select STDERR; $| = 1; select STDOUT; $| = 1; -my $t = Test::Nginx->new()->has(qw/http mp4/)->has_daemon('ffprobe') - ->has_daemon('ffmpeg') +my $t = Test::Nginx->new()->has(qw/http mp4/)->plan(1) ->write_file_expand('nginx.conf', <<'EOF'); %%TEST_GLOBALS%% @@ -49,100 +48,39 @@ http { EOF -plan(skip_all => 'no lavfi') - unless grep /lavfi/, `ffmpeg -loglevel quiet -formats`; -system('ffmpeg -nostdin -loglevel quiet -y ' - . '-f lavfi -i testsrc=duration=10:size=320x200:rate=15 ' - . '-f lavfi -i testsrc=duration=20:size=320x200:rate=15 ' - . '-map 0:0 -map 1:0 -pix_fmt yuv420p -g 15 -c:v mpeg4 ' - . "${\($t->testdir())}/test.mp4") == 0 - or die "Can't create mp4 file: $!"; -system('ffmpeg -nostdin -loglevel quiet -y ' - . '-f lavfi -i testsrc=duration=10:size=320x200:rate=15 ' - . '-f lavfi -i testsrc=duration=20:size=320x200:rate=15 ' - . '-map 0:0 -map 1:0 -pix_fmt yuv420p -g 15 -c:v mpeg4 ' - . '-movflags +faststart ' - . "${\($t->testdir())}/no_mdat.mp4") == 0 - or die "Can't create mp4 file: $!"; +# chunk offset in stco/co64 atom beyond the end of file -my $sbad = <<'EOF'; +my $bad_co64 = <<'EOF'; 00000000: 00 00 00 1c 66 74 79 70 69 73 6f 6d 00 00 02 00 |....ftypisom....| -00000010: 69 73 6f 6d 69 73 6f 32 6d 70 34 31 00 00 00 09 |isomiso2mp41....| -00000020: 6d 64 61 74 00 00 00 00 94 6d 6f 6f 76 00 00 00 |mdat.....moov...| -00000030: 8c 74 72 61 6b 00 00 00 84 6d 64 69 61 00 00 00 |.trak....mdia...| -00000040: 7c 6d 69 6e 66 00 00 00 74 73 74 62 6c 00 00 00 ||minf...tstbl...| -00000050: 18 73 74 74 73 00 00 00 00 00 00 00 01 00 00 03 |.stts...........| -00000060: 3a 00 00 04 00 00 00 00 28 73 74 73 63 00 00 00 |:.......(stsc...| -00000070: 00 00 00 00 02 00 00 00 01 00 00 03 0f 00 00 00 |................| -00000080: 01 00 00 00 02 00 00 00 2b 00 00 00 01 00 00 00 |........+.......| -00000090: 14 73 74 73 7a 00 00 00 00 00 00 05 a9 00 00 03 |.stsz...........| -000000a0: 3b 00 00 00 18 63 6f 36 34 00 00 00 00 00 00 00 |;....co64.......| -000000b0: 01 ff ff ff ff f0 0f fb e7 |.........| +00000000: 69 73 6f 6d 69 73 6f 32 6d 70 34 31 |isomiso2mp41| +00000000: 00 00 00 08 6d 64 61 74 |....mdat| +00000000: 00 00 00 94 6d 6f 6f 76 |....moov| +00000000: 00 00 00 8c 74 72 61 6b |....trak| +00000000: 00 00 00 84 6d 64 69 61 |....mdia| +00000000: 00 00 00 7c 6d 69 6e 66 |....minf| +00000000: 00 00 00 74 73 74 62 6c |....stbl| +00000000: 00 00 00 18 73 74 74 73 00 00 00 00 00 00 00 01 |....stts........| +00000000: 00 00 03 3a 00 00 04 00 |........| +00000000: 00 00 00 28 73 74 73 63 00 00 00 00 00 00 00 01 |....stsc........| +00000000: 00 00 00 01 ff ff ff ff 00 00 00 00 |............| +00000000: 00 00 00 02 ff ff ff ff 00 00 00 00 |............| +00000000: 00 00 00 14 73 74 73 7a 00 00 00 00 00 00 05 a9 |....stsz........| +00000000: 00 00 03 3b |....| +00000000: 00 00 00 18 63 6f 36 34 00 00 00 00 00 00 00 01 |....co64........| +00000000: ff ff ff ff f0 0f fb e7 |........| EOF -$t->write_file('bad.mp4', unhex($sbad)); -$t->run()->plan(27); +$t->write_file('bad_co64.mp4', unhex($bad_co64)); + +$t->run(); ############################################################################### -my $test_uri = '/test.mp4'; - -again: - -is(durations($t, 0.0), '10.0 20.0', 'start zero'); -is(durations($t, 2), '8.0 18.0', 'start integer'); -is(durations($t, 7.1), '2.9 12.9', 'start float'); - -is(durations($t, 6, 9), '3.0 3.0', 'start end integer'); -is(durations($t, 2.7, 5.6), '2.9 2.9', 'start end float'); - -is(durations($t, undef, 9), '9.0 9.0', 'end integer'); -is(durations($t, undef, 5.6), '5.6 5.6', 'end float'); - -# invalid range results in ignoring end argument - -like(http_head("$test_uri?start=1&end=1"), qr/200 OK/, 'zero range'); -like(http_head("$test_uri?start=1&end=0"), qr/200 OK/, 'negative range'); - -# start/end values exceeding track/file duration - -unlike(http_head("$test_uri?end=11"), qr!HTTP/1.1 500!, - 'end beyond short track'); -unlike(http_head("$test_uri?end=21"), qr!HTTP/1.1 500!, 'end beyond EOF'); -unlike(http_head("$test_uri?start=11"), qr!HTTP/1.1 500!, - 'start beyond short track'); -like(http_head("$test_uri?start=21"), qr!HTTP/1.1 500!, 'start beyond EOF'); - -$test_uri = '/no_mdat.mp4', goto again unless $test_uri eq '/no_mdat.mp4'; - -# corrupted formats - -like(http_get("/bad.mp4?start=0.5"), qr/500 Internal/, 'co64 chunk beyond EOF'); +like(http_get("/bad_co64.mp4?start=0.5"), qr/500 Internal/, + 'co64 chunk after eof'); ############################################################################### -sub durations { - my ($t, $start, $end) = @_; - my $path = $t->{_testdir} . '/frag.mp4'; - - my $uri = $test_uri; - if (defined $start) { - $uri .= "?start=$start"; - if (defined $end) { - $uri .= "&end=$end"; - } - - } elsif (defined $end) { - $uri .= "?end=$end"; - } - - $t->write_file('frag.mp4', http_content(http_get($uri))); - - my $r = `ffprobe -show_streams $path 2>/dev/null`; - Test::Nginx::log_core('||', $r); - sprintf "%.1f %.1f", $r =~ /duration=(\d+\.\d+)/g; -} - sub unhex { my ($input) = @_; my $buffer = ''; From mdounin at mdounin.ru Sun Mar 8 02:46:24 2026 From: mdounin at mdounin.ru (=?utf-8?q?Maxim_Dounin?=) Date: Sun, 08 Mar 2026 05:46:24 +0300 Subject: [PATCH 2 of 2] Tests: additional tests for various mp4 issues In-Reply-To: References: Message-ID: # HG changeset patch # User Maxim Dounin # Date 1772937920 -10800 # Sun Mar 08 05:45:20 2026 +0300 # Node ID e9c5bc1ae12bb62cce7289339b9638fa277ae5ab # Parent c92474d354a0248fd1d5712d91bfc28d8583ffa9 Tests: additional tests for various mp4 issues. diff --git a/mp4_bad.t b/mp4_bad.t --- a/mp4_bad.t +++ b/mp4_bad.t @@ -23,7 +23,7 @@ use Test::Nginx; select STDERR; $| = 1; select STDOUT; $| = 1; -my $t = Test::Nginx->new()->has(qw/http mp4/)->plan(1) +my $t = Test::Nginx->new()->has(qw/http mp4/)->plan(4) ->write_file_expand('nginx.conf', <<'EOF'); %%TEST_GLOBALS%% @@ -42,6 +42,8 @@ http { location / { mp4; + mp4_start_key_frame on; + postpone_output 0; } } } @@ -70,7 +72,106 @@ 00000000: 00 00 00 18 63 6f 36 34 00 0 00000000: ff ff ff ff f0 0f fb e7 |........| EOF +# zero entry in stss causes incorrect access during stts processing + +my $bad_key_frame = <<'EOF'; +00000000: 00 00 00 1c 66 74 79 70 69 73 6f 6d 00 00 02 00 |....ftypisom....| +00000000: 69 73 6f 6d 69 73 6f 32 6d 70 34 31 |isomiso2mp41| +00000000: 00 00 00 08 6d 64 61 74 |....mdat| +00000000: 00 00 00 b4 6d 6f 6f 76 |....moov| +00000000: 00 00 00 ac 74 72 61 6b |....trak| +00000000: 00 00 00 a4 6d 64 69 61 |....mdia| +00000000: 00 00 00 9c 6d 69 6e 66 |....minf| +00000000: 00 00 00 94 73 74 62 6c |....stbl| +00000000: 00 00 00 18 73 74 74 73 00 00 00 00 00 00 00 01 |....stts........| +00000000: 00 00 03 3a 00 00 04 00 |........| +00000000: 00 00 00 28 73 74 73 63 00 00 00 00 00 00 00 02 |....stsc........| +00000000: 00 00 00 01 ff ff ff ff 00 00 00 00 |............| +00000000: 00 00 00 02 ff ff ff ff 00 00 00 00 |............| +00000000: 00 00 00 14 73 74 73 7a 00 00 00 00 00 00 05 a9 |....stsz........| +00000000: 00 00 03 3b |....| +00000000: 00 00 00 18 73 74 63 6f 00 00 00 00 00 00 00 02 |....stco........| +00000000: 00 00 00 00 00 00 ff ff |........| +00000000: 00 00 00 20 73 74 73 73 00 00 00 00 00 00 00 01 |....stss........| +00000000: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| +EOF + +# entries check overflow on 32bit platforms + +my $bad_entries_overflow = <<'EOF'; +00000000: 00 00 00 1c 66 74 79 70 69 73 6f 6d 00 00 02 00 |....ftypisom....| +00000000: 69 73 6f 6d 69 73 6f 32 6d 70 34 31 |isomiso2mp41| +00000000: 00 00 00 08 6d 64 61 74 |....mdat| +00000000: 00 00 00 c4 6d 6f 6f 76 |....moov| +00000000: 00 00 00 bc 74 72 61 6b |....trak| +00000000: 00 00 00 b4 6d 64 69 61 |....mdia| +00000000: 00 00 00 20 6d 64 68 64 00 00 00 00 |....mdhd....| +00000000: 00 00 00 00 00 00 00 00 00 00 03 e8 ff ff ff ff |................| +00000000: 00 00 00 00 |....| +00000000: 00 00 00 8c 6d 69 6e 66 |....minf| +00000000: 00 00 00 84 73 74 62 6c |....stbl| +00000000: 00 00 00 18 73 74 74 73 00 00 00 00 00 00 00 01 |....stts........| +00000000: ff ff ff ff 00 00 00 01 |........| +00000000: 00 00 00 28 73 74 73 63 00 00 00 00 00 00 00 01 |....stsc........| +00000000: 00 00 00 01 00 00 00 01 00 00 00 00 |............| +00000000: 00 ff ff ff 00 00 00 ff 00 00 00 00 |............| +00000000: 00 00 00 14 73 74 73 7a 00 00 00 00 00 00 05 a9 |....stsz........| +00000000: 00 00 03 3b |....| +00000000: 00 00 00 28 73 74 63 6f 00 00 00 00 40 00 00 01 |....stco........| +00000000: 00 00 00 00 00 00 00 00 |........| +00000000: 00 00 00 00 00 00 00 00 |........| +00000000: 00 00 00 00 00 00 00 00 |........| +EOF + +# stco/co64 entries check off-by-one + +my $bad_entries_offbyone = <<'EOF'; +00000000: 00 00 00 1c 66 74 79 70 69 73 6f 6d 00 00 02 00 |....ftypisom....| +00000000: 69 73 6f 6d 69 73 6f 32 6d 70 34 31 |isomiso2mp41| +00000000: 00 00 00 08 6d 64 61 74 |....mdat| +00000000: 00 00 01 80 6d 6f 6f 76 |....moov| +00000000: 00 00 00 bc 74 72 61 6b |....trak| +00000000: 00 00 00 b4 6d 64 69 61 |....mdia| +00000000: 00 00 00 20 6d 64 68 64 00 00 00 00 |....mdhd....| +00000000: 00 00 00 00 00 00 00 00 00 00 03 e8 ff ff ff ff |................| +00000000: 00 00 00 00 |....| +00000000: 00 00 00 8c 6d 69 6e 66 |....minf| +00000000: 00 00 00 84 73 74 62 6c |....stbl| +00000000: 00 00 00 18 73 74 74 73 00 00 00 00 00 00 00 01 |....stts........| +00000000: ff ff ff ff 00 00 00 01 |........| +00000000: 00 00 00 28 73 74 73 63 00 00 00 00 00 00 00 02 |....stsc........| +00000000: 00 00 00 01 00 00 00 01 00 00 00 00 |............| +00000000: 00 ff ff ff 00 00 00 ff 00 00 00 00 |............| +00000000: 00 00 00 14 73 74 73 7a 00 00 00 00 00 00 05 a9 |....stsz........| +00000000: 00 00 03 3b |....| +00000000: 00 00 00 28 73 74 63 6f 00 00 00 00 00 00 00 06 |....stco........| +00000000: 00 00 00 00 00 00 00 00 |........| +00000000: 00 00 00 00 00 00 00 00 |........| +00000000: 00 00 00 00 00 00 00 00 |........| +00000000: 00 00 00 bc 74 72 61 6b |....trak| +00000000: 00 00 00 b4 6d 64 69 61 |....mdia| +00000000: 00 00 00 20 6d 64 68 64 00 00 00 00 |....mdhd....| +00000000: 00 00 00 00 00 00 00 00 00 00 03 e8 ff ff ff ff |................| +00000000: 00 00 00 00 |....| +00000000: 00 00 00 8c 6d 69 6e 66 |....minf| +00000000: 00 00 00 84 73 74 62 6c |....stbl| +00000000: 00 00 00 18 73 74 74 73 00 00 00 00 00 00 00 01 |....stts........| +00000000: ff ff ff ff 00 00 00 01 |........| +00000000: 00 00 00 28 73 74 73 63 00 00 00 00 00 00 00 02 |....stsc........| +00000000: 00 00 00 01 00 00 00 01 00 00 00 00 |............| +00000000: 00 ff ff ff 00 00 00 ff 00 00 00 00 |............| +00000000: 00 00 00 14 73 74 73 7a 00 00 00 00 00 00 05 a9 |....stsz........| +00000000: 00 00 03 3b |....| +00000000: 00 00 00 28 73 74 63 6f 00 00 00 00 00 00 00 01 |....stco........| +00000000: 00 00 00 00 00 00 00 00 |........| +00000000: 00 00 00 00 00 00 00 00 |........| +00000000: 00 00 00 00 00 00 00 00 |........| +EOF + $t->write_file('bad_co64.mp4', unhex($bad_co64)); +$t->write_file('bad_key_frame.mp4', unhex($bad_key_frame)); +$t->write_file('bad_entries_overflow.mp4', unhex($bad_entries_overflow)); +$t->write_file('bad_entries_offbyone.mp4', unhex($bad_entries_offbyone)); $t->run(); @@ -79,6 +180,21 @@ EOF like(http_get("/bad_co64.mp4?start=0.5"), qr/500 Internal/, 'co64 chunk after eof'); +TODO: { +local $TODO = 'not yet', $t->todo_alerts() + unless $t->has_version('1.29.6'); + +like(http_get("/bad_key_frame.mp4?start=0.5"), qr/200 OK/, + 'stss with zero entry'); + +like(http_get("/bad_entries_overflow.mp4?start=0.005"), qr/500 Internal/, + 'stco entries 32bit overflow'); + +like(http_get("/bad_entries_offbyone.mp4?start=0.001"), qr/500 Internal/, + 'stco entries off-by-one'); + +} + ############################################################################### sub unhex { From mdounin at mdounin.ru Tue Mar 10 01:07:24 2026 From: mdounin at mdounin.ru (=?iso-8859-1?q?Maxim_Dounin?=) Date: Tue, 10 Mar 2026 04:07:24 +0300 Subject: [nginx] Fixed clcf->auto_redirect in uwsgi_pass/scgi_pass with v... Message-ID: details: http://freenginx.org/hg/nginx/rev/6ea8697c0740 branches: changeset: 9474:6ea8697c0740 user: Maxim Dounin date: Tue Mar 10 03:50:52 2026 +0300 description: Fixed clcf->auto_redirect in uwsgi_pass/scgi_pass with variables. Previously, clcf->auto_redirect was only set (for locations ending with "/") when uwsgi_pass and scgi_pass were used without variables, but not with variables. For proxy_pass and fastcgi_pass this was fixed in 2989:dff9764eaca2 (0.8.7). It was not, however, fixed in ngx_http_uwsgi_module (as imported later, in 3541:21452748d165, 0.8.40) and ngx_http_scgi_module (introduced shortly after, in 3637:d656caa72ec9, 0.8.42). The fix is mostly identical to the one in 2989:dff9764eaca2 (0.8.7) and ensures that clcf->auto_redirect is set both with and without variables. diffstat: src/http/modules/ngx_http_scgi_module.c | 9 +++++---- src/http/modules/ngx_http_uwsgi_module.c | 9 +++++---- 2 files changed, 10 insertions(+), 8 deletions(-) diffs (56 lines): diff --git a/src/http/modules/ngx_http_scgi_module.c b/src/http/modules/ngx_http_scgi_module.c --- a/src/http/modules/ngx_http_scgi_module.c +++ b/src/http/modules/ngx_http_scgi_module.c @@ -1921,8 +1921,13 @@ ngx_http_scgi_pass(ngx_conf_t *cf, ngx_c } clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module); + clcf->handler = ngx_http_scgi_handler; + if (clcf->name.len && clcf->name.data[clcf->name.len - 1] == '/') { + clcf->auto_redirect = 1; + } + value = cf->args->elts; url = &value[1]; @@ -1958,10 +1963,6 @@ ngx_http_scgi_pass(ngx_conf_t *cf, ngx_c return NGX_CONF_ERROR; } - if (clcf->name.len && clcf->name.data[clcf->name.len - 1] == '/') { - clcf->auto_redirect = 1; - } - return NGX_CONF_OK; } diff --git a/src/http/modules/ngx_http_uwsgi_module.c b/src/http/modules/ngx_http_uwsgi_module.c --- a/src/http/modules/ngx_http_uwsgi_module.c +++ b/src/http/modules/ngx_http_uwsgi_module.c @@ -2221,8 +2221,13 @@ ngx_http_uwsgi_pass(ngx_conf_t *cf, ngx_ } clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module); + clcf->handler = ngx_http_uwsgi_handler; + if (clcf->name.len && clcf->name.data[clcf->name.len - 1] == '/') { + clcf->auto_redirect = 1; + } + value = cf->args->elts; url = &value[1]; @@ -2281,10 +2286,6 @@ ngx_http_uwsgi_pass(ngx_conf_t *cf, ngx_ return NGX_CONF_ERROR; } - if (clcf->name.len && clcf->name.data[clcf->name.len - 1] == '/') { - clcf->auto_redirect = 1; - } - return NGX_CONF_OK; } From mdounin at mdounin.ru Tue Mar 10 01:39:22 2026 From: mdounin at mdounin.ru (=?iso-8859-1?q?Maxim_Dounin?=) Date: Tue, 10 Mar 2026 04:39:22 +0300 Subject: [nginx] Mp4: fixed ngx_http_mp4_seek_key_frame(). Message-ID: details: http://freenginx.org/hg/nginx/rev/a181973aa820 branches: changeset: 9475:a181973aa820 user: Maxim Dounin date: Tue Mar 10 04:31:25 2026 +0300 description: Mp4: fixed ngx_http_mp4_seek_key_frame(). Previously, ngx_http_mp4_seek_key_frame() might return key frame prefix larger than start_sample provided in function arguments, notably on an invalid stss entry with zero sample_number. This resulted in backwards loop in ngx_http_mp4_crop_stts_data() to incorrectly access data before the stts atom entries (and stop at the stts atom header mostly by chance). The fix is to make sure ngx_http_mp4_seek_key_frame() always returns a value equal or smaller than start_sample provided, regardless of the stss entries. Invalid entries with zero sample_number now will be interpreted as if there very large sample_number, so the previous one will be returned. diffstat: src/http/modules/ngx_http_mp4_module.c | 7 ++++--- 1 files changed, 4 insertions(+), 3 deletions(-) diffs (21 lines): diff --git a/src/http/modules/ngx_http_mp4_module.c b/src/http/modules/ngx_http_mp4_module.c --- a/src/http/modules/ngx_http_mp4_module.c +++ b/src/http/modules/ngx_http_mp4_module.c @@ -2528,13 +2528,14 @@ ngx_http_mp4_seek_key_frame(ngx_http_mp4 entry = (uint32_t *) data->pos; end = (uint32_t *) data->last; - /* sync samples starts from 1 */ - start_sample++; - key_prefix = 0; while (entry < end) { sample = ngx_mp4_get_32value(entry); + + /* sync samples starts from 1 */ + sample--; + if (sample > start_sample) { break; } From mdounin at mdounin.ru Tue Mar 10 01:39:22 2026 From: mdounin at mdounin.ru (=?iso-8859-1?q?Maxim_Dounin?=) Date: Tue, 10 Mar 2026 04:39:22 +0300 Subject: [nginx] Mp4: fixed entries tests on 32-bit platforms. Message-ID: details: http://freenginx.org/hg/nginx/rev/efe2b1c11265 branches: changeset: 9476:efe2b1c11265 user: Maxim Dounin date: Tue Mar 10 04:31:28 2026 +0300 description: Mp4: fixed entries tests on 32-bit platforms. Previously, tests for the number of entries in various atom read functions used the "entries * sizeof(uint32_t)" construct, with entries being uint32_t. On platforms with 32-bit sizeof() this will overflow, leading to a smaller result. This isn't a real issue in most cases, since the same construct is used to calculate atom_end pointer. Still, in some cases the number of entries is used directly, such as in stco/co64 atom updating, and a large value might result in segmentation faults. The fix is to cast "entries" to uint64_t before the multiplication to avoid the overflow. diffstat: src/http/modules/ngx_http_mp4_module.c | 14 +++++++------- 1 files changed, 7 insertions(+), 7 deletions(-) diffs (66 lines): diff --git a/src/http/modules/ngx_http_mp4_module.c b/src/http/modules/ngx_http_mp4_module.c --- a/src/http/modules/ngx_http_mp4_module.c +++ b/src/http/modules/ngx_http_mp4_module.c @@ -2302,7 +2302,7 @@ ngx_http_mp4_read_stts_atom(ngx_http_mp4 "mp4 time-to-sample entries:%uD", entries); if (ngx_mp4_atom_data_size(ngx_mp4_stts_atom_t) - + entries * sizeof(ngx_mp4_stts_entry_t) > atom_data_size) + + (uint64_t) entries * sizeof(ngx_mp4_stts_entry_t) > atom_data_size) { ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0, "\"%s\" mp4 stts atom too small", mp4->file.name.data); @@ -2606,7 +2606,7 @@ ngx_http_mp4_read_stss_atom(ngx_http_mp4 atom->last = atom_table; if (ngx_mp4_atom_data_size(ngx_http_mp4_stss_atom_t) - + entries * sizeof(uint32_t) > atom_data_size) + + (uint64_t) entries * sizeof(uint32_t) > atom_data_size) { ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0, "\"%s\" mp4 stss atom too small", mp4->file.name.data); @@ -2811,7 +2811,7 @@ ngx_http_mp4_read_ctts_atom(ngx_http_mp4 atom->last = atom_table; if (ngx_mp4_atom_data_size(ngx_mp4_ctts_atom_t) - + entries * sizeof(ngx_mp4_ctts_entry_t) > atom_data_size) + + (uint64_t) entries * sizeof(ngx_mp4_ctts_entry_t) > atom_data_size) { ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0, "\"%s\" mp4 ctts atom too small", mp4->file.name.data); @@ -2993,7 +2993,7 @@ ngx_http_mp4_read_stsc_atom(ngx_http_mp4 "sample-to-chunk entries:%uD", entries); if (ngx_mp4_atom_data_size(ngx_mp4_stsc_atom_t) - + entries * sizeof(ngx_mp4_stsc_entry_t) > atom_data_size) + + (uint64_t) entries * sizeof(ngx_mp4_stsc_entry_t) > atom_data_size) { ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0, "\"%s\" mp4 stsc atom too small", mp4->file.name.data); @@ -3363,7 +3363,7 @@ ngx_http_mp4_read_stsz_atom(ngx_http_mp4 if (size == 0) { if (ngx_mp4_atom_data_size(ngx_mp4_stsz_atom_t) - + entries * sizeof(uint32_t) > atom_data_size) + + (uint64_t) entries * sizeof(uint32_t) > atom_data_size) { ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0, "\"%s\" mp4 stsz atom too small", @@ -3536,7 +3536,7 @@ ngx_http_mp4_read_stco_atom(ngx_http_mp4 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, "chunks:%uD", entries); if (ngx_mp4_atom_data_size(ngx_mp4_stco_atom_t) - + entries * sizeof(uint32_t) > atom_data_size) + + (uint64_t) entries * sizeof(uint32_t) > atom_data_size) { ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0, "\"%s\" mp4 stco atom too small", mp4->file.name.data); @@ -3754,7 +3754,7 @@ ngx_http_mp4_read_co64_atom(ngx_http_mp4 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, "chunks:%uD", entries); if (ngx_mp4_atom_data_size(ngx_mp4_co64_atom_t) - + entries * sizeof(uint64_t) > atom_data_size) + + (uint64_t) entries * sizeof(uint64_t) > atom_data_size) { ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0, "\"%s\" mp4 co64 atom too small", mp4->file.name.data); From mdounin at mdounin.ru Tue Mar 10 01:39:22 2026 From: mdounin at mdounin.ru (=?iso-8859-1?q?Maxim_Dounin?=) Date: Tue, 10 Mar 2026 04:39:22 +0300 Subject: [nginx] Mp4: fixed off-by-one in stco/co64 chunk number tests. Message-ID: details: http://freenginx.org/hg/nginx/rev/a7c60a17c215 branches: changeset: 9477:a7c60a17c215 user: Maxim Dounin date: Tue Mar 10 04:31:31 2026 +0300 description: Mp4: fixed off-by-one in stco/co64 chunk number tests. Previously, if trak->start_chunk was exactly equal to the number of entries in the stco/co64 atom (trak->chunks), it wasn't rejected by the tests in ngx_http_mp4_update_stco_atom() (and ngx_http_mp4_update_co64_atom()), and the following code accessed a value past the stco/co64 atom, potentially resulting in segmentation faults. diffstat: src/http/modules/ngx_http_mp4_module.c | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) diffs (21 lines): diff --git a/src/http/modules/ngx_http_mp4_module.c b/src/http/modules/ngx_http_mp4_module.c --- a/src/http/modules/ngx_http_mp4_module.c +++ b/src/http/modules/ngx_http_mp4_module.c @@ -3606,7 +3606,7 @@ ngx_http_mp4_update_stco_atom(ngx_http_m return NGX_ERROR; } - if (trak->start_chunk > trak->chunks) { + if (trak->start_chunk >= trak->chunks) { ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0, "start time is out mp4 stco chunks in \"%s\"", mp4->file.name.data); @@ -3823,7 +3823,7 @@ ngx_http_mp4_update_co64_atom(ngx_http_m return NGX_ERROR; } - if (trak->start_chunk > trak->chunks) { + if (trak->start_chunk >= trak->chunks) { ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0, "start time is out mp4 co64 chunks in \"%s\"", mp4->file.name.data); From mdounin at mdounin.ru Tue Mar 10 01:41:14 2026 From: mdounin at mdounin.ru (=?iso-8859-1?q?Maxim_Dounin?=) Date: Tue, 10 Mar 2026 04:41:14 +0300 Subject: [nginx-tests] Tests: moved bad mp4 test to a separate file. Message-ID: details: http://freenginx.org/hg/nginx-tests/rev/d6429eb46e37 branches: changeset: 2042:d6429eb46e37 user: Maxim Dounin date: Tue Mar 10 04:32:36 2026 +0300 description: Tests: moved bad mp4 test to a separate file. diffstat: mp4.t | 35 +------------------ mp4_bad.t | 116 ++++++++++++++----------------------------------------------- 2 files changed, 28 insertions(+), 123 deletions(-) diffs (217 lines): diff --git a/mp4.t b/mp4.t --- a/mp4.t +++ b/mp4.t @@ -65,23 +65,7 @@ system('ffmpeg -nostdin -loglevel quiet . "${\($t->testdir())}/no_mdat.mp4") == 0 or die "Can't create mp4 file: $!"; -my $sbad = <<'EOF'; -00000000: 00 00 00 1c 66 74 79 70 69 73 6f 6d 00 00 02 00 |....ftypisom....| -00000010: 69 73 6f 6d 69 73 6f 32 6d 70 34 31 00 00 00 09 |isomiso2mp41....| -00000020: 6d 64 61 74 00 00 00 00 94 6d 6f 6f 76 00 00 00 |mdat.....moov...| -00000030: 8c 74 72 61 6b 00 00 00 84 6d 64 69 61 00 00 00 |.trak....mdia...| -00000040: 7c 6d 69 6e 66 00 00 00 74 73 74 62 6c 00 00 00 ||minf...tstbl...| -00000050: 18 73 74 74 73 00 00 00 00 00 00 00 01 00 00 03 |.stts...........| -00000060: 3a 00 00 04 00 00 00 00 28 73 74 73 63 00 00 00 |:.......(stsc...| -00000070: 00 00 00 00 02 00 00 00 01 00 00 03 0f 00 00 00 |................| -00000080: 01 00 00 00 02 00 00 00 2b 00 00 00 01 00 00 00 |........+.......| -00000090: 14 73 74 73 7a 00 00 00 00 00 00 05 a9 00 00 03 |.stsz...........| -000000a0: 3b 00 00 00 18 63 6f 36 34 00 00 00 00 00 00 00 |;....co64.......| -000000b0: 01 ff ff ff ff f0 0f fb e7 |.........| -EOF - -$t->write_file('bad.mp4', unhex($sbad)); -$t->run()->plan(27); +$t->run()->plan(26); ############################################################################### @@ -115,10 +99,6 @@ like(http_head("$test_uri?start=21"), qr $test_uri = '/no_mdat.mp4', goto again unless $test_uri eq '/no_mdat.mp4'; -# corrupted formats - -like(http_get("/bad.mp4?start=0.5"), qr/500 Internal/, 'co64 chunk beyond EOF'); - ############################################################################### sub durations { @@ -143,17 +123,4 @@ sub durations { sprintf "%.1f %.1f", $r =~ /duration=(\d+\.\d+)/g; } -sub unhex { - my ($input) = @_; - my $buffer = ''; - - for my $l ($input =~ m/: +((?:[0-9a-f]{2,4} +)+) /gms) { - for my $v ($l =~ m/[0-9a-f]{2}/g) { - $buffer .= chr(hex($v)); - } - } - - return $buffer; -} - ############################################################################### diff --git a/mp4.t b/mp4_bad.t copy from mp4.t copy to mp4_bad.t --- a/mp4.t +++ b/mp4_bad.t @@ -1,10 +1,10 @@ #!/usr/bin/perl +# (C) Maxim Dounin # (C) Sergey Kandaurov # (C) Nginx, Inc. -# Tests for mp4 module. -# Ensures that requested stream duration is given with sane accuracy. +# Tests for mp4 module, various bad mp4 files. ############################################################################### @@ -16,15 +16,14 @@ use Test::More; BEGIN { use FindBin; chdir($FindBin::Bin); } use lib 'lib'; -use Test::Nginx qw/ :DEFAULT http_content /; +use Test::Nginx; ############################################################################### select STDERR; $| = 1; select STDOUT; $| = 1; -my $t = Test::Nginx->new()->has(qw/http mp4/)->has_daemon('ffprobe') - ->has_daemon('ffmpeg') +my $t = Test::Nginx->new()->has(qw/http mp4/)->plan(1) ->write_file_expand('nginx.conf', <<'EOF'); %%TEST_GLOBALS%% @@ -49,100 +48,39 @@ http { EOF -plan(skip_all => 'no lavfi') - unless grep /lavfi/, `ffmpeg -loglevel quiet -formats`; -system('ffmpeg -nostdin -loglevel quiet -y ' - . '-f lavfi -i testsrc=duration=10:size=320x200:rate=15 ' - . '-f lavfi -i testsrc=duration=20:size=320x200:rate=15 ' - . '-map 0:0 -map 1:0 -pix_fmt yuv420p -g 15 -c:v mpeg4 ' - . "${\($t->testdir())}/test.mp4") == 0 - or die "Can't create mp4 file: $!"; -system('ffmpeg -nostdin -loglevel quiet -y ' - . '-f lavfi -i testsrc=duration=10:size=320x200:rate=15 ' - . '-f lavfi -i testsrc=duration=20:size=320x200:rate=15 ' - . '-map 0:0 -map 1:0 -pix_fmt yuv420p -g 15 -c:v mpeg4 ' - . '-movflags +faststart ' - . "${\($t->testdir())}/no_mdat.mp4") == 0 - or die "Can't create mp4 file: $!"; +# chunk offset in stco/co64 atom beyond the end of file -my $sbad = <<'EOF'; +my $bad_co64 = <<'EOF'; 00000000: 00 00 00 1c 66 74 79 70 69 73 6f 6d 00 00 02 00 |....ftypisom....| -00000010: 69 73 6f 6d 69 73 6f 32 6d 70 34 31 00 00 00 09 |isomiso2mp41....| -00000020: 6d 64 61 74 00 00 00 00 94 6d 6f 6f 76 00 00 00 |mdat.....moov...| -00000030: 8c 74 72 61 6b 00 00 00 84 6d 64 69 61 00 00 00 |.trak....mdia...| -00000040: 7c 6d 69 6e 66 00 00 00 74 73 74 62 6c 00 00 00 ||minf...tstbl...| -00000050: 18 73 74 74 73 00 00 00 00 00 00 00 01 00 00 03 |.stts...........| -00000060: 3a 00 00 04 00 00 00 00 28 73 74 73 63 00 00 00 |:.......(stsc...| -00000070: 00 00 00 00 02 00 00 00 01 00 00 03 0f 00 00 00 |................| -00000080: 01 00 00 00 02 00 00 00 2b 00 00 00 01 00 00 00 |........+.......| -00000090: 14 73 74 73 7a 00 00 00 00 00 00 05 a9 00 00 03 |.stsz...........| -000000a0: 3b 00 00 00 18 63 6f 36 34 00 00 00 00 00 00 00 |;....co64.......| -000000b0: 01 ff ff ff ff f0 0f fb e7 |.........| +00000000: 69 73 6f 6d 69 73 6f 32 6d 70 34 31 |isomiso2mp41| +00000000: 00 00 00 08 6d 64 61 74 |....mdat| +00000000: 00 00 00 94 6d 6f 6f 76 |....moov| +00000000: 00 00 00 8c 74 72 61 6b |....trak| +00000000: 00 00 00 84 6d 64 69 61 |....mdia| +00000000: 00 00 00 7c 6d 69 6e 66 |....minf| +00000000: 00 00 00 74 73 74 62 6c |....stbl| +00000000: 00 00 00 18 73 74 74 73 00 00 00 00 00 00 00 01 |....stts........| +00000000: 00 00 03 3a 00 00 04 00 |........| +00000000: 00 00 00 28 73 74 73 63 00 00 00 00 00 00 00 01 |....stsc........| +00000000: 00 00 00 01 ff ff ff ff 00 00 00 00 |............| +00000000: 00 00 00 02 ff ff ff ff 00 00 00 00 |............| +00000000: 00 00 00 14 73 74 73 7a 00 00 00 00 00 00 05 a9 |....stsz........| +00000000: 00 00 03 3b |....| +00000000: 00 00 00 18 63 6f 36 34 00 00 00 00 00 00 00 01 |....co64........| +00000000: ff ff ff ff f0 0f fb e7 |........| EOF -$t->write_file('bad.mp4', unhex($sbad)); -$t->run()->plan(27); +$t->write_file('bad_co64.mp4', unhex($bad_co64)); + +$t->run(); ############################################################################### -my $test_uri = '/test.mp4'; - -again: - -is(durations($t, 0.0), '10.0 20.0', 'start zero'); -is(durations($t, 2), '8.0 18.0', 'start integer'); -is(durations($t, 7.1), '2.9 12.9', 'start float'); - -is(durations($t, 6, 9), '3.0 3.0', 'start end integer'); -is(durations($t, 2.7, 5.6), '2.9 2.9', 'start end float'); - -is(durations($t, undef, 9), '9.0 9.0', 'end integer'); -is(durations($t, undef, 5.6), '5.6 5.6', 'end float'); - -# invalid range results in ignoring end argument - -like(http_head("$test_uri?start=1&end=1"), qr/200 OK/, 'zero range'); -like(http_head("$test_uri?start=1&end=0"), qr/200 OK/, 'negative range'); - -# start/end values exceeding track/file duration - -unlike(http_head("$test_uri?end=11"), qr!HTTP/1.1 500!, - 'end beyond short track'); -unlike(http_head("$test_uri?end=21"), qr!HTTP/1.1 500!, 'end beyond EOF'); -unlike(http_head("$test_uri?start=11"), qr!HTTP/1.1 500!, - 'start beyond short track'); -like(http_head("$test_uri?start=21"), qr!HTTP/1.1 500!, 'start beyond EOF'); - -$test_uri = '/no_mdat.mp4', goto again unless $test_uri eq '/no_mdat.mp4'; - -# corrupted formats - -like(http_get("/bad.mp4?start=0.5"), qr/500 Internal/, 'co64 chunk beyond EOF'); +like(http_get("/bad_co64.mp4?start=0.5"), qr/500 Internal/, + 'co64 chunk after eof'); ############################################################################### -sub durations { - my ($t, $start, $end) = @_; - my $path = $t->{_testdir} . '/frag.mp4'; - - my $uri = $test_uri; - if (defined $start) { - $uri .= "?start=$start"; - if (defined $end) { - $uri .= "&end=$end"; - } - - } elsif (defined $end) { - $uri .= "?end=$end"; - } - - $t->write_file('frag.mp4', http_content(http_get($uri))); - - my $r = `ffprobe -show_streams $path 2>/dev/null`; - Test::Nginx::log_core('||', $r); - sprintf "%.1f %.1f", $r =~ /duration=(\d+\.\d+)/g; -} - sub unhex { my ($input) = @_; my $buffer = ''; From mdounin at mdounin.ru Tue Mar 10 01:41:14 2026 From: mdounin at mdounin.ru (=?iso-8859-1?q?Maxim_Dounin?=) Date: Tue, 10 Mar 2026 04:41:14 +0300 Subject: [nginx-tests] Tests: additional tests for various mp4 issues. Message-ID: details: http://freenginx.org/hg/nginx-tests/rev/cbb91250b488 branches: changeset: 2043:cbb91250b488 user: Maxim Dounin date: Tue Mar 10 04:32:38 2026 +0300 description: Tests: additional tests for various mp4 issues. diffstat: mp4_bad.t | 118 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 files changed, 117 insertions(+), 1 deletions(-) diffs (150 lines): diff --git a/mp4_bad.t b/mp4_bad.t --- a/mp4_bad.t +++ b/mp4_bad.t @@ -23,7 +23,7 @@ use Test::Nginx; select STDERR; $| = 1; select STDOUT; $| = 1; -my $t = Test::Nginx->new()->has(qw/http mp4/)->plan(1) +my $t = Test::Nginx->new()->has(qw/http mp4/)->plan(4) ->write_file_expand('nginx.conf', <<'EOF'); %%TEST_GLOBALS%% @@ -42,6 +42,8 @@ http { location / { mp4; + mp4_start_key_frame on; + postpone_output 0; } } } @@ -70,7 +72,106 @@ 00000000: 00 00 00 18 63 6f 36 34 00 0 00000000: ff ff ff ff f0 0f fb e7 |........| EOF +# zero entry in stss causes incorrect access during stts processing + +my $bad_key_frame = <<'EOF'; +00000000: 00 00 00 1c 66 74 79 70 69 73 6f 6d 00 00 02 00 |....ftypisom....| +00000000: 69 73 6f 6d 69 73 6f 32 6d 70 34 31 |isomiso2mp41| +00000000: 00 00 00 08 6d 64 61 74 |....mdat| +00000000: 00 00 00 b4 6d 6f 6f 76 |....moov| +00000000: 00 00 00 ac 74 72 61 6b |....trak| +00000000: 00 00 00 a4 6d 64 69 61 |....mdia| +00000000: 00 00 00 9c 6d 69 6e 66 |....minf| +00000000: 00 00 00 94 73 74 62 6c |....stbl| +00000000: 00 00 00 18 73 74 74 73 00 00 00 00 00 00 00 01 |....stts........| +00000000: 00 00 03 3a 00 00 04 00 |........| +00000000: 00 00 00 28 73 74 73 63 00 00 00 00 00 00 00 02 |....stsc........| +00000000: 00 00 00 01 ff ff ff ff 00 00 00 00 |............| +00000000: 00 00 00 02 ff ff ff ff 00 00 00 00 |............| +00000000: 00 00 00 14 73 74 73 7a 00 00 00 00 00 00 05 a9 |....stsz........| +00000000: 00 00 03 3b |....| +00000000: 00 00 00 18 73 74 63 6f 00 00 00 00 00 00 00 02 |....stco........| +00000000: 00 00 00 00 00 00 ff ff |........| +00000000: 00 00 00 20 73 74 73 73 00 00 00 00 00 00 00 01 |....stss........| +00000000: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| +EOF + +# entries check overflow on 32bit platforms + +my $bad_entries_overflow = <<'EOF'; +00000000: 00 00 00 1c 66 74 79 70 69 73 6f 6d 00 00 02 00 |....ftypisom....| +00000000: 69 73 6f 6d 69 73 6f 32 6d 70 34 31 |isomiso2mp41| +00000000: 00 00 00 08 6d 64 61 74 |....mdat| +00000000: 00 00 00 c4 6d 6f 6f 76 |....moov| +00000000: 00 00 00 bc 74 72 61 6b |....trak| +00000000: 00 00 00 b4 6d 64 69 61 |....mdia| +00000000: 00 00 00 20 6d 64 68 64 00 00 00 00 |....mdhd....| +00000000: 00 00 00 00 00 00 00 00 00 00 03 e8 ff ff ff ff |................| +00000000: 00 00 00 00 |....| +00000000: 00 00 00 8c 6d 69 6e 66 |....minf| +00000000: 00 00 00 84 73 74 62 6c |....stbl| +00000000: 00 00 00 18 73 74 74 73 00 00 00 00 00 00 00 01 |....stts........| +00000000: ff ff ff ff 00 00 00 01 |........| +00000000: 00 00 00 28 73 74 73 63 00 00 00 00 00 00 00 01 |....stsc........| +00000000: 00 00 00 01 00 00 00 01 00 00 00 00 |............| +00000000: 00 ff ff ff 00 00 00 ff 00 00 00 00 |............| +00000000: 00 00 00 14 73 74 73 7a 00 00 00 00 00 00 05 a9 |....stsz........| +00000000: 00 00 03 3b |....| +00000000: 00 00 00 28 73 74 63 6f 00 00 00 00 40 00 00 01 |....stco........| +00000000: 00 00 00 00 00 00 00 00 |........| +00000000: 00 00 00 00 00 00 00 00 |........| +00000000: 00 00 00 00 00 00 00 00 |........| +EOF + +# stco/co64 entries check off-by-one + +my $bad_entries_offbyone = <<'EOF'; +00000000: 00 00 00 1c 66 74 79 70 69 73 6f 6d 00 00 02 00 |....ftypisom....| +00000000: 69 73 6f 6d 69 73 6f 32 6d 70 34 31 |isomiso2mp41| +00000000: 00 00 00 08 6d 64 61 74 |....mdat| +00000000: 00 00 01 80 6d 6f 6f 76 |....moov| +00000000: 00 00 00 bc 74 72 61 6b |....trak| +00000000: 00 00 00 b4 6d 64 69 61 |....mdia| +00000000: 00 00 00 20 6d 64 68 64 00 00 00 00 |....mdhd....| +00000000: 00 00 00 00 00 00 00 00 00 00 03 e8 ff ff ff ff |................| +00000000: 00 00 00 00 |....| +00000000: 00 00 00 8c 6d 69 6e 66 |....minf| +00000000: 00 00 00 84 73 74 62 6c |....stbl| +00000000: 00 00 00 18 73 74 74 73 00 00 00 00 00 00 00 01 |....stts........| +00000000: ff ff ff ff 00 00 00 01 |........| +00000000: 00 00 00 28 73 74 73 63 00 00 00 00 00 00 00 02 |....stsc........| +00000000: 00 00 00 01 00 00 00 01 00 00 00 00 |............| +00000000: 00 ff ff ff 00 00 00 ff 00 00 00 00 |............| +00000000: 00 00 00 14 73 74 73 7a 00 00 00 00 00 00 05 a9 |....stsz........| +00000000: 00 00 03 3b |....| +00000000: 00 00 00 28 73 74 63 6f 00 00 00 00 00 00 00 06 |....stco........| +00000000: 00 00 00 00 00 00 00 00 |........| +00000000: 00 00 00 00 00 00 00 00 |........| +00000000: 00 00 00 00 00 00 00 00 |........| +00000000: 00 00 00 bc 74 72 61 6b |....trak| +00000000: 00 00 00 b4 6d 64 69 61 |....mdia| +00000000: 00 00 00 20 6d 64 68 64 00 00 00 00 |....mdhd....| +00000000: 00 00 00 00 00 00 00 00 00 00 03 e8 ff ff ff ff |................| +00000000: 00 00 00 00 |....| +00000000: 00 00 00 8c 6d 69 6e 66 |....minf| +00000000: 00 00 00 84 73 74 62 6c |....stbl| +00000000: 00 00 00 18 73 74 74 73 00 00 00 00 00 00 00 01 |....stts........| +00000000: ff ff ff ff 00 00 00 01 |........| +00000000: 00 00 00 28 73 74 73 63 00 00 00 00 00 00 00 02 |....stsc........| +00000000: 00 00 00 01 00 00 00 01 00 00 00 00 |............| +00000000: 00 ff ff ff 00 00 00 ff 00 00 00 00 |............| +00000000: 00 00 00 14 73 74 73 7a 00 00 00 00 00 00 05 a9 |....stsz........| +00000000: 00 00 03 3b |....| +00000000: 00 00 00 28 73 74 63 6f 00 00 00 00 00 00 00 01 |....stco........| +00000000: 00 00 00 00 00 00 00 00 |........| +00000000: 00 00 00 00 00 00 00 00 |........| +00000000: 00 00 00 00 00 00 00 00 |........| +EOF + $t->write_file('bad_co64.mp4', unhex($bad_co64)); +$t->write_file('bad_key_frame.mp4', unhex($bad_key_frame)); +$t->write_file('bad_entries_overflow.mp4', unhex($bad_entries_overflow)); +$t->write_file('bad_entries_offbyone.mp4', unhex($bad_entries_offbyone)); $t->run(); @@ -79,6 +180,21 @@ EOF like(http_get("/bad_co64.mp4?start=0.5"), qr/500 Internal/, 'co64 chunk after eof'); +TODO: { +local $TODO = 'not yet', $t->todo_alerts() + unless $t->has_version('1.29.6'); + +like(http_get("/bad_key_frame.mp4?start=0.5"), qr/200 OK/, + 'stss with zero entry'); + +like(http_get("/bad_entries_overflow.mp4?start=0.005"), qr/500 Internal/, + 'stco entries 32bit overflow'); + +like(http_get("/bad_entries_offbyone.mp4?start=0.001"), qr/500 Internal/, + 'stco entries off-by-one'); + +} + ############################################################################### sub unhex { From mdounin at mdounin.ru Tue Mar 10 03:54:50 2026 From: mdounin at mdounin.ru (Maxim Dounin) Date: Tue, 10 Mar 2026 06:54:50 +0300 Subject: freenginx-1.29.6 changes draft Message-ID: Hello! Changes with freenginx 1.29.6 10 Mar 2026 *) Bugfix: incorrect "upstream server temporarily disabled" messages might be logged when using variables in the "proxy_pass" directive. *) Bugfix: retrying a request to the next gRPC upstream server might not work correctly. Thanks to David Carlier. *) Bugfix: a segmentation fault might occur in a worker process if the ngx_http_xslt_filter_module was used. *) Bugfix: a segmentation fault might occur in a worker process if the ngx_http_mp4_module was used. *) Bugfix: in the ngx_http_uwsgi_module and ngx_http_scgi_module modules. *) Bugfix: in memory allocation error handling. ????????? ? freenginx 1.29.6 10.03.2026 *) ???????????: ??? ????????????? ?????????? ? proxy_pass ? ??? ????? ???????? ???????????? ????????? "upstream server temporarily disabled". *) ???????????: ????????? ???????? ??????? ?? ?????? gRPC-?????? ????? ???????? ???????????. ??????? David Carlier. *) ???????????: ? ??????? ???????? ??? ????????? segmentation fault, ???? ????????????? ?????? ngx_http_xslt_filter_module. *) ???????????: ? ??????? ???????? ??? ????????? segmentation fault, ???? ????????????? ?????? ngx_http_mp4_module. *) ???????????: ? ??????? ngx_http_uwsgi_module ? ngx_http_scgi_module. *) ???????????: ? ????????? ?????? ????????? ??????. -- Maxim Dounin http://mdounin.ru/ From osa at freebsd.org.ru Tue Mar 10 14:22:01 2026 From: osa at freebsd.org.ru (Sergey A. Osokin) Date: Tue, 10 Mar 2026 17:22:01 +0300 Subject: freenginx-1.29.6 changes draft In-Reply-To: References: Message-ID: Hi Maxim, On Tue, Mar 10, 2026 at 06:54:50AM +0300, Maxim Dounin wrote: > > Changes with freenginx 1.29.6 10 Mar 2026 > > *) Bugfix: incorrect "upstream server temporarily disabled" messages > might be logged when using variables in the "proxy_pass" directive. > > *) Bugfix: retrying a request to the next gRPC upstream server might not > work correctly. > Thanks to David Carlier. > > *) Bugfix: a segmentation fault might occur in a worker process if the > ngx_http_xslt_filter_module was used. > > *) Bugfix: a segmentation fault might occur in a worker process if the > ngx_http_mp4_module was used. > > *) Bugfix: in the ngx_http_uwsgi_module and ngx_http_scgi_module > modules. > > *) Bugfix: in memory allocation error handling. > > > ????????? ? freenginx 1.29.6 10.03.2026 > > *) ???????????: ??? ????????????? ?????????? ? proxy_pass ? ??? ????? > ???????? ???????????? ????????? "upstream server temporarily > disabled". > > *) ???????????: ????????? ???????? ??????? ?? ?????? gRPC-?????? ????? > ???????? ???????????. > ??????? David Carlier. > > *) ???????????: ? ??????? ???????? ??? ????????? segmentation fault, > ???? ????????????? ?????? ngx_http_xslt_filter_module. > > *) ???????????: ? ??????? ???????? ??? ????????? segmentation fault, > ???? ????????????? ?????? ngx_http_mp4_module. > > *) ???????????: ? ??????? ngx_http_uwsgi_module ? ngx_http_scgi_module. > > *) ???????????: ? ????????? ?????? ????????? ??????. Looks good to me, thank you! -- Sergey A. Osokin https://tipi.work/ From mdounin at mdounin.ru Tue Mar 10 14:49:10 2026 From: mdounin at mdounin.ru (=?iso-8859-1?q?Maxim_Dounin?=) Date: Tue, 10 Mar 2026 17:49:10 +0300 Subject: [nginx] Updated zlib used for win32 builds. Message-ID: details: http://freenginx.org/hg/nginx/rev/4f89350ba20b branches: changeset: 9478:4f89350ba20b user: Maxim Dounin date: Tue Mar 10 07:06:10 2026 +0300 description: Updated zlib used for win32 builds. diffstat: misc/GNUmakefile | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diffs (12 lines): diff --git a/misc/GNUmakefile b/misc/GNUmakefile --- a/misc/GNUmakefile +++ b/misc/GNUmakefile @@ -7,7 +7,7 @@ TEMP = tmp CC = cl OBJS = objs.msvc8 OPENSSL = openssl-3.0.19 -ZLIB = zlib-1.3.1 +ZLIB = zlib-1.3.2 PCRE = pcre2-10.47 From mdounin at mdounin.ru Tue Mar 10 14:49:10 2026 From: mdounin at mdounin.ru (=?iso-8859-1?q?Maxim_Dounin?=) Date: Tue, 10 Mar 2026 17:49:10 +0300 Subject: [nginx] freenginx-1.29.6-RELEASE Message-ID: details: http://freenginx.org/hg/nginx/rev/e4207f631186 branches: changeset: 9479:e4207f631186 user: Maxim Dounin date: Tue Mar 10 17:42:16 2026 +0300 description: freenginx-1.29.6-RELEASE diffstat: docs/xml/nginx/changes.xml | 71 ++++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 71 insertions(+), 0 deletions(-) diffs (81 lines): diff --git a/docs/xml/nginx/changes.xml b/docs/xml/nginx/changes.xml --- a/docs/xml/nginx/changes.xml +++ b/docs/xml/nginx/changes.xml @@ -7,6 +7,77 @@
+ + + + +??? ????????????? ?????????? ? proxy_pass +? ??? ????? ???????? ???????????? ????????? +"upstream server temporarily disabled". + + +incorrect "upstream server temporarily disabled" +messages might be logged +when using variables in the "proxy_pass" directive. + + + + + +????????? ???????? ??????? ?? ?????? gRPC-?????? +????? ???????? ???????????.
+??????? David Carlier. +
+ +retrying a request to the next gRPC upstream server +might not work correctly.
+Thanks to David Carlier. +
+
+ + + +? ??????? ???????? ??? ????????? segmentation fault, +???? ????????????? ?????? ngx_http_xslt_filter_module. + + +a segmentation fault might occur in a worker process +if the ngx_http_xslt_filter_module was used. + + + + + +? ??????? ???????? ??? ????????? segmentation fault, +???? ????????????? ?????? ngx_http_mp4_module. + + +a segmentation fault might occur in a worker process +if the ngx_http_mp4_module was used. + + + + + +? ??????? ngx_http_uwsgi_module ? ngx_http_scgi_module. + + +in the ngx_http_uwsgi_module and ngx_http_scgi_module modules. + + + + + +? ????????? ?????? ????????? ??????. + + +in memory allocation error handling. + + + +
+ + From mdounin at mdounin.ru Tue Mar 10 14:49:11 2026 From: mdounin at mdounin.ru (=?iso-8859-1?q?Maxim_Dounin?=) Date: Tue, 10 Mar 2026 17:49:11 +0300 Subject: [nginx] release-1.29.6 tag Message-ID: details: http://freenginx.org/hg/nginx/rev/66b28e8ff0cb branches: changeset: 9480:66b28e8ff0cb user: Maxim Dounin date: Tue Mar 10 17:42:17 2026 +0300 description: release-1.29.6 tag diffstat: .hgtags | 1 + 1 files changed, 1 insertions(+), 0 deletions(-) diffs (8 lines): diff --git a/.hgtags b/.hgtags --- a/.hgtags +++ b/.hgtags @@ -491,3 +491,4 @@ 56d817adaa1dd4f522114e921b1ff599c2ab4db2 2175d3bea2a84f7265b90c6f9efea7fb9b41bdd7 release-1.29.3 567870bfeb23f2e9c91e2a110d6d332c27c1ceb1 release-1.29.4 4f4280557d20bc46ebbdc240ffd365f5ca6ce939 release-1.29.5 +e4207f631186855d37ac286799c8cd4c9477d166 release-1.29.6 From mdounin at mdounin.ru Tue Mar 10 14:49:39 2026 From: mdounin at mdounin.ru (=?iso-8859-1?q?Maxim_Dounin?=) Date: Tue, 10 Mar 2026 17:49:39 +0300 Subject: [nginx-site] freenginx-1.29.6 Message-ID: details: http://freenginx.org/hg/nginx-site/rev/4978a58d1538 branches: changeset: 3129:4978a58d1538 user: Maxim Dounin date: Tue Mar 10 17:47:02 2026 +0300 description: freenginx-1.29.6 diffstat: text/en/CHANGES | 21 +++++++++++++++++++++ text/ru/CHANGES.ru | 21 +++++++++++++++++++++ xml/index.xml | 7 +++++++ xml/versions.xml | 1 + 4 files changed, 50 insertions(+), 0 deletions(-) diffs (86 lines): diff --git a/text/en/CHANGES b/text/en/CHANGES --- a/text/en/CHANGES +++ b/text/en/CHANGES @@ -1,4 +1,25 @@ +Changes with freenginx 1.29.6 10 Mar 2026 + + *) Bugfix: incorrect "upstream server temporarily disabled" messages + might be logged when using variables in the "proxy_pass" directive. + + *) Bugfix: retrying a request to the next gRPC upstream server might not + work correctly. + Thanks to David Carlier. + + *) Bugfix: a segmentation fault might occur in a worker process if the + ngx_http_xslt_filter_module was used. + + *) Bugfix: a segmentation fault might occur in a worker process if the + ngx_http_mp4_module was used. + + *) Bugfix: in the ngx_http_uwsgi_module and ngx_http_scgi_module + modules. + + *) Bugfix: in memory allocation error handling. + + Changes with freenginx 1.29.5 10 Feb 2026 *) Feature: optimized SSL_sendfile() usage on FreeBSD. diff --git a/text/ru/CHANGES.ru b/text/ru/CHANGES.ru --- a/text/ru/CHANGES.ru +++ b/text/ru/CHANGES.ru @@ -1,4 +1,25 @@ +????????? ? freenginx 1.29.6 10.03.2026 + + *) ???????????: ??? ????????????? ?????????? ? proxy_pass ? ??? ????? + ???????? ???????????? ????????? "upstream server temporarily + disabled". + + *) ???????????: ????????? ???????? ??????? ?? ?????? gRPC-?????? ????? + ???????? ???????????. + ??????? David Carlier. + + *) ???????????: ? ??????? ???????? ??? ????????? segmentation fault, + ???? ????????????? ?????? ngx_http_xslt_filter_module. + + *) ???????????: ? ??????? ???????? ??? ????????? segmentation fault, + ???? ????????????? ?????? ngx_http_mp4_module. + + *) ???????????: ? ??????? ngx_http_uwsgi_module ? ngx_http_scgi_module. + + *) ???????????: ? ????????? ?????? ????????? ??????. + + ????????? ? freenginx 1.29.5 10.02.2026 *) ??????????: ??????????? ????????????? SSL_sendfile() ?? FreeBSD. diff --git a/xml/index.xml b/xml/index.xml --- a/xml/index.xml +++ b/xml/index.xml @@ -8,6 +8,13 @@ + + +freenginx-1.29.6 +mainline version has been released. + + + freenginx-1.29.5 diff --git a/xml/versions.xml b/xml/versions.xml --- a/xml/versions.xml +++ b/xml/versions.xml @@ -9,6 +9,7 @@ + From mdounin at mdounin.ru Tue Mar 10 14:56:56 2026 From: mdounin at mdounin.ru (Maxim Dounin) Date: Tue, 10 Mar 2026 17:56:56 +0300 Subject: freenginx-1.29.6 changes draft In-Reply-To: References: Message-ID: Hello! On Tue, Mar 10, 2026 at 05:22:01PM +0300, Sergey A. Osokin wrote: > On Tue, Mar 10, 2026 at 06:54:50AM +0300, Maxim Dounin wrote: > > > > Changes with freenginx 1.29.6 10 Mar 2026 > > > > *) Bugfix: incorrect "upstream server temporarily disabled" messages > > might be logged when using variables in the "proxy_pass" directive. > > > > *) Bugfix: retrying a request to the next gRPC upstream server might not > > work correctly. > > Thanks to David Carlier. > > > > *) Bugfix: a segmentation fault might occur in a worker process if the > > ngx_http_xslt_filter_module was used. > > > > *) Bugfix: a segmentation fault might occur in a worker process if the > > ngx_http_mp4_module was used. > > > > *) Bugfix: in the ngx_http_uwsgi_module and ngx_http_scgi_module > > modules. > > > > *) Bugfix: in memory allocation error handling. > > > > > > ????????? ? freenginx 1.29.6 10.03.2026 > > > > *) ???????????: ??? ????????????? ?????????? ? proxy_pass ? ??? ????? > > ???????? ???????????? ????????? "upstream server temporarily > > disabled". > > > > *) ???????????: ????????? ???????? ??????? ?? ?????? gRPC-?????? ????? > > ???????? ???????????. > > ??????? David Carlier. > > > > *) ???????????: ? ??????? ???????? ??? ????????? segmentation fault, > > ???? ????????????? ?????? ngx_http_xslt_filter_module. > > > > *) ???????????: ? ??????? ???????? ??? ????????? segmentation fault, > > ???? ????????????? ?????? ngx_http_mp4_module. > > > > *) ???????????: ? ??????? ngx_http_uwsgi_module ? ngx_http_scgi_module. > > > > *) ???????????: ? ????????? ?????? ????????? ??????. > > Looks good to me, thank you! Thanks for looking, released. -- Maxim Dounin http://mdounin.ru/