]> git.kaiwu.me - nginx.git/log
nginx.git
3 weeks agoControl API: log errors from accepted socket setup
Oskar Eichler [Fri, 4 Sep 2026 15:52:07 +0000 (22:52 +0700)]
Control API: log errors from accepted socket setup

Accepted control connections discarded errno when setting close-on-exec,
nonblocking I/O, or signal ownership. The error log identified the failed
fcntl() operation but omitted the operating system reason.

Pass ngx_socket_errno to the three error logs, consistently with listener
setup and inherited socket handling.

3 weeks agoWin32: removed unused winsock extension function pointers
Vadim Zhestikov [Mon, 5 Oct 2026 20:28:14 +0000 (13:28 -0700)]
Win32: removed unused winsock extension function pointers

3 weeks agoWin32: removed the iocp event module
Vadim Zhestikov [Mon, 5 Oct 2026 20:27:47 +0000 (13:27 -0700)]
Win32: removed the iocp event module

The I/O completion ports event method has never been completed: the
module is compiled into Windows builds, but is not documented or
supported.

Prodded by Marek Ludha.

3 weeks agoHTTP/3: avoid undefined behaviour with empty encoder field values
dgprivate [Sat, 29 Aug 2026 05:53:38 +0000 (05:53 +0000)]
HTTP/3: avoid undefined behaviour with empty encoder field values

A zero length field value in encoder stream instructions left the value
data pointer NULL, passed then to ngx_memcpy() in ngx_http_v3_insert().
For the reasons outlined in b0a4d0fb8, it is now set to an empty string.

3 weeks agoVersion bump
Sergey Kandaurov [Thu, 15 Oct 2026 11:46:43 +0000 (15:46 +0400)]
Version bump

5 weeks agonginx-1.31.7-RELEASE release-1.31.7
Roman Arutyunyan [Wed, 30 Sep 2026 14:34:53 +0000 (18:34 +0400)]
nginx-1.31.7-RELEASE

5 weeks agoAvoid post-rewrite URI to path mapping with alias
Roman Arutyunyan [Fri, 10 Jul 2026 16:10:12 +0000 (20:10 +0400)]
Avoid post-rewrite URI to path mapping with alias

Previously, after a "rewrite" had changed the URI, and before a new
location was chosen, the new URI might not match the current location
prefix.  This becomes a problem when the location uses "alias", which
is why normally such inconsistency is detected by checking the
r->valid_location flag.  Meanwhile this flag only handles the
inconsistency when using the "break" directive or parameter.  However
in absence of those, there's still an inconsistency window from URI
change up until the end of the current set of rewrite directives.
URI to path mapping within this window might result in a buffer
overflow if location's prefix was longer than the rewritten URI.

The following example resulted in a buffer overflow with the request
"/foo/1":

location /foo/ {
    alias /bar/;
    rewrite ^/foo/.*$ /x;
    return 200 $request_filename;
}

Alternatively, $request_filename might be used in access log format,
"set", "if", "add_header", etc.

The fix is to reject URI mapping in ngx_http_map_uri_to_path() if the
r->uri_changed flag is set.

5 weeks agoScript: reserved memory overrun protection in ngx_http_script_run()
Roman Arutyunyan [Wed, 29 Jul 2026 12:57:59 +0000 (16:57 +0400)]
Script: reserved memory overrun protection in ngx_http_script_run()

In b76754049 buffer overrun protection in script was introduced.
However in ngx_http_script_run() data could still spill over to the
reserved area.  This had no visible effects except the return value
which could extend beyond the maximum formatted string size.  This
value is however currently unused in the nginx code.

Later in a8289aa69 string length recalculation was implemented to
protect against buffer underwrite.  Considering a possible spillover to
the reserved area, the final string size could become larger than the
allocated buffer size.  This could later result in writing beyond
the buffer boundaries.  Maximum buffer overflow is the size of the
reserved area.

This could affect calculating document root from variables in HTTP
or using access logging in HTTP or Stream.  In the case of access
logging a possible impact is limited by an off-by-one write of a null
byte.

Reported by Matt Suiche of Tolmo Inc.

5 weeks agoSSL: synced all session ticket keys to the worker process
Vadim Zhestikov [Wed, 22 Jul 2026 23:48:37 +0000 (16:48 -0700)]
SSL: synced all session ticket keys to the worker process

The per-worker ticket key mirror is allocated with three slots
(ngx_array_push_n(keys, 3)), matching the shared memory
ticket_keys[3] array and the decrypt callback, which scans all
keys->nelts slots by key name.  Key rotation, however, synced
only two slots from shared memory, leaving the third slot's
name, hmac_key, and aes_key uninitialized.

A ticket whose key name matched the uninitialized slot (which
holds unspecified pool memory, all zero in the best case) could
therefore be HMAC-verified and decrypted with uninitialized key
material, allowing a forged session.

Sync all keys->nelts slots, as ngx_ssl_ticket_keys_cleanup()
already assumes.

Reported by PhiNode Labs.

5 weeks agoHTTP/3: kept the skipped frame length separate from data length
Vadim Zhestikov [Thu, 23 Jul 2026 00:48:55 +0000 (17:48 -0700)]
HTTP/3: kept the skipped frame length separate from data length

ngx_http_v3_parse_data() stored the remaining length of a skipped
(unknown) frame in st->length -- the same field the request body
filter uses for the number of DATA payload bytes to pass on as
request body.  When an unknown frame was split across parser
invocations, the skip was interrupted with st->length holding the
skip remainder; on the next buffer the body filter, which calls
the parser only while st->length == 0, treated that remainder as
request body.

When proxying, this could result in sending unframed bytes, potentially
allowing for bypass of client_max_body_size, which is enforced only on
the DATA path, or an injection.

The fix is to keep unknown frame payload in a separate st->skip counter.

Reported by Hansol Lee of GOTROOT.

5 weeks agoLimited the number of pending operations per request
Vadim Zhestikov [Mon, 17 Aug 2026 16:19:46 +0000 (09:19 -0700)]
Limited the number of pending operations per request

Each pending asynchronous operation holds a reference in
r->main->blocked, an 8-bit field, and the increments were not checked.
With 256 operations pending on a single request the counter wrapped to
zero, after which the request could be freed while those operations
still referenced its pool.  This is the same overflow that 4ec67cf86
addressed for r->main->count, and left unaddressed for r->main->blocked.

Operations beyond the limit are now performed synchronously where a
synchronous path exists, and refused otherwise, so that the counter
cannot overflow.

Reported by cyberlancer.

5 weeks agoUpstream: fixed X-Accel-Redirect handling from cache files.
Maxim Dounin [Mon, 19 Feb 2024 22:23:43 +0000 (01:23 +0300)]
Upstream: fixed X-Accel-Redirect handling from cache files.

The X-Accel-Redirect header might appear in cache files if its handling
is ignored with the "proxy_ignore_headers" directive.  If the cache file
is later served with different settings, ngx_http_upstream_process_headers()
used to call ngx_http_upstream_finalize_request(NGX_DECLINED), which
is not expected to happen before the cleanup handler is installed and
resulted in ngx_http_finalize_request(NGX_DONE) (after 2b032e8df,
nginx 1.7.11), leading to unexpected request counter decrement, "request
count is zero" alerts, and segmentation faults.

Similarly, errors in ngx_http_upstream_process_headers() resulted in
ngx_http_upstream_finalize_request(NGX_HTTP_INTERNAL_SERVER_ERROR) being
called.  This is also not expected to happen before the cleanup handler is
installed, and resulted in ngx_http_finalize_request(NGX_DONE) without
proper request finalization.

Fix is to avoid calling ngx_http_upstream_finalize_request() from
ngx_http_upstream_process_headers(), notably when the cleanup handler
is not yet installed.  Errors are now simply return NGX_ERROR, so the
caller is responsible for proper finalization by calling either
ngx_http_finalize_request() or ngx_http_upstream_finalize_request().
And X-Accel-Redirect handling now does not call
ngx_http_upstream_finalize_request(NGX_DECLINED) if no cleanup handler
is installed.

Reported by Jiří Setnička
(https://mailman.nginx.org/pipermail/nginx-devel/2024-February/HWLYHOO3DDB3XTFT6X3GRMXIEJ3SJRUA.html).

6 weeks agoGeoIP: support for the MaxMind DB (MMDB) databases
Sergey Kandaurov [Tue, 8 Sep 2026 19:56:49 +0000 (19:56 +0000)]
GeoIP: support for the MaxMind DB (MMDB) databases

The MaxMind DB format is now recognized, with the fallback to the
legacy format (reached End-of-Life in May 2022).  Migration requires
switching to MMDB database files:

    geoip_country  /usr/share/GeoIP/GeoLite2-Country.mmdb;
    geoip_city     /usr/share/GeoIP/GeoLite2-City.mmdb;
    geoip_org      /usr/share/GeoIP/GeoLite2-ASN.mmdb;

Either libmaxminddb or libGeoIP is sufficient to build the modules;
configure fails if neither is found.

Notes on the MMDB lookups:

*) $geoip_country_code3 and $geoip_city_country_code3 are converted from
   the alpha-2 codes with a compiled-in ISO 3166-1 table, as the MMDB
   databases provide alpha-2 codes only.

*) $geoip_org looks up "autonomous_system_organization", "isp",
   "organization", and "domain" in turn, to match the legacy ASNum, ISP,
   Org, and Domain database editions.

*) $geoip_area_code has no MMDB counterpart and is never found.

*) $geoip_region and $geoip_region_name come from subdivisions[0], and
   thus may differ in value from the legacy ones.

*) $geoip_dma_code comes from location.metro_code, which is deprecated
   by MaxMind and may be absent.

Co-authored-by: Nitin Swami <n.swami@f5.com>
6 weeks agoUpdated OpenSSL and PCRE used for win32 builds
Sergey Kandaurov [Wed, 30 Sep 2026 13:23:05 +0000 (17:23 +0400)]
Updated OpenSSL and PCRE used for win32 builds

6 weeks agoQUIC: fixed binary upgrade from older versions
Ivan Ovchinnikov [Tue, 29 Sep 2026 21:09:54 +0000 (21:09 +0000)]
QUIC: fixed binary upgrade from older versions

Before 63af971a1 (1.31.7), the NGINX_BPF_MAPS environment variable
was passed to the new binary on binary upgrade whenever the quic_bpf
module was built, even if "quic_bpf" was not enabled, with an empty
value if there were no QUIC BPF socket groups.

Since 63af971a1, such an empty value was treated as inherited maps,
and the new binary refused to start: with the "cannot be disabled
during binary upgrade" error if "quic_bpf" was not enabled, or with
a parsing error otherwise.

The fix is to ignore an empty value, which means there are no maps
to inherit.

6 weeks agoQUIC: support BPF reload and binary upgrade
Sai Krishna Kumar Reddy YADAMAKANTI [Tue, 29 Sep 2026 15:07:24 +0000 (15:07 +0000)]
QUIC: support BPF reload and binary upgrade

The SO_COOKIE dependency is removed.  QUIC BPF dispatching now uses
separate sockets for new and established connections: listener sockets
handle new connections, while per-worker sockets handle established
ones.  Server connection IDs encode a random worker key, which BPF
uses to route established packets directly to the correct worker
socket.  New connections are routed through listen keys using a
dual slot scheme that enables both reload and binary upgrade.

On reload, new workers register new sockets and keys while old workers
continue receiving established connections through their encoded keys.
On binary upgrade, the new master uses the opposite slot, and exiting
masters clear their entries so traffic shifts to the surviving
instance.

Co-authored-by: Roman Arutyunyan <arut@nginx.com>
6 weeks agoQUIC: added BPF packet data fallback
Sai Krishna Kumar Reddy YADAMAKANTI [Tue, 29 Sep 2026 15:04:37 +0000 (15:04 +0000)]
QUIC: added BPF packet data fallback

Use bpf_skb_load_bytes() in the reuseport BPF helper when the required
QUIC header bytes are not available through direct packet access.  This
keeps the direct access fast path while allowing the helper to parse the
flags byte, DCID length byte, and DCID key from non linear skb data.

A similar approach was implemented in [1].

[1] https://git.angie.software/web-server/angie/commit/4b527f5

6 weeks agoHTTP/2: switch to RFC 9218 priorities
Andrew Clayton [Thu, 24 Sep 2026 15:40:33 +0000 (16:40 +0100)]
HTTP/2: switch to RFC 9218 priorities

Advertise SETTINGS_NO_RFC7540_PRIORITIES (0x9) in the initial SETTINGS
frame and order the output by the RFC 9218 effective priority instead of
the RFC 7540 dependency tree, which is removed in the same step.
Placing the switch last keeps it self-contained and easy to revert.

RFC 9218, Section 2.1: a server can send SETTINGS_NO_RFC7540_PRIORITIES
with a value of 1 to indicate that it will ignore RFC 7540 priority
signals.  A received value other than 0 or 1 is a connection error.

Frames are ordered by urgency first, then non-incremental ahead of
incremental, then by stream id, which keeps streams of equal priority
in the order their requests arrived (RFC 8941, Section 4.2).  The same
order is applied to ngx_http_v2_waiting_queue().

The RFC 7540 priority scheme is removed: PRIORITY frames are validated
for framing errors and then ignored, the priority fields of a HEADERS
frame are skipped, and the dependency tree (node parent/children/weight,
the dependencies queue, ngx_http_v2_set_dependency(),
ngx_http_v2_node_children_update() and the per-connection
priority_limit) is gone.  RFC 9113, Sections 5.3.1 and 5.3.2, deprecate
stream prioritization: it proved complex, was implemented unevenly and
widely ignored, and its protocol elements are retained for wire
compatibility only.

With the tree gone, a buffered PRIORITY_UPDATE node no longer needs to
be attached to it, so the set_dependency() call from the buffering path
falls away, leaving the node parked in h2c->closed on its own.

Assisted-by: opencode:claude-opus-4.8
6 weeks agoHTTP/2: merge upstream Priority header for proxied requests
Andrew Clayton [Tue, 22 Sep 2026 00:53:10 +0000 (01:53 +0100)]
HTTP/2: merge upstream Priority header for proxied requests

When nginx proxies a request over HTTP/2 and the upstream returns a
Priority response header, record it as the stream's server priority and
recompute the effective priority by merging it with the client's value
(RFC 9218, Section 8): a parameter present in the response overrides the
client's, a parameter absent leaves it unchanged.  The client and server
inputs are kept separate so a later client PRIORITY_UPDATE does not
discard the server hint.

The merge affects only how this hop schedules the stream; the Priority
header forwarded to the client is left unchanged, so
$upstream_http_priority continues to report what the origin sent.

Assisted-by: opencode:claude-opus-4.8
6 weeks agoHTTP/2: parse Priority request header
Andrew Clayton [Tue, 22 Sep 2026 00:52:41 +0000 (01:52 +0100)]
HTTP/2: parse Priority request header

Parse the RFC 9218 Priority request header, an RFC 8941 Structured
Fields Dictionary such as "u=3, i".

The header lines are collected during header block processing and, once
the block is complete, combined into a single value and parsed once in
ngx_http_v2_run_request(), as RFC 8941, Section 4.2, requires all field
lines of the same field to be combined before parsing.  This mirrors how
cookies are handled.  The header is still passed through to the request
so it stays visible to variables and proxying.

A malformed field is ignored, leaving the defaults.  A PRIORITY_UPDATE
frame overrides the header (RFC 9218, Section 7): if a frame has already
been applied to the stream the header is not consulted.

Assisted-by: opencode:claude-opus-4.8
6 weeks agoHTTP/2: handle PRIORITY_UPDATE frames
Andrew Clayton [Wed, 23 Sep 2026 20:17:33 +0000 (21:17 +0100)]
HTTP/2: handle PRIORITY_UPDATE frames

Implement the RFC 9218 PRIORITY_UPDATE frame (type 0x10).  The frame is
sent on stream 0 and carries a prioritized stream id and a Priority
Field Value; it is validated for framing errors and dispatched from
ngx_http_v2_state_head().

A PRIORITY_UPDATE conveys a complete set of parameters (RFC 9218,
Section 7): omitted parameters reset to their defaults, so the value
replaces any earlier signal.  A frame for a stream that already exists
is applied at once.  A frame for a not-yet-created stream is buffered on
its node until the HEADERS frame arrives; the node is parked in
h2c->closed and, while the RFC 7540 tree is still present, attached to
the root as is done for a PRIORITY frame with a zero dependency.  The
number of buffered signals is bounded by the node reuse budget.

A malformed value is logged and ignored, leaving the current priority
untouched.  A value that does not fit the state buffer while the frame
is fragmented is skipped.

The signals are only collected here; the scheduler still uses the
RFC 7540 dependency tree until the switch to RFC 9218.

Assisted-by: opencode:claude-opus-4.8
6 weeks agoAdd RFC 9218 priority types and parser
Andrew Clayton [Wed, 23 Sep 2026 20:09:36 +0000 (21:09 +0100)]
Add RFC 9218 priority types and parser

Implement a strict RFC 8941 Structured Fields Dictionary parser for the
RFC 9218 Extensible Prioritization Scheme, shared by HTTP/2 (and, later,
HTTP/3).

New files:
- ngx_http_priority.h: the ngx_http_priority_t and
  ngx_http_priority_state_t types and the parse/state API.
- ngx_http_priority.c: the parser plus ngx_http_priority_state_init()
  and ngx_http_priority_state_update() (client/server merge).

The field is parsed strictly: a syntax error fails the whole field
(RFC 8941, Section 4.2, treats it as absent), and only on a successful
parse are the RFC 9218, Section 4, rules applied, ignoring unknown
members, out-of-range urgency and members of an unexpected type.  On
error the caller keeps any previously signalled priority.  The parser
bounds the number of members, inner-list items and parameters, and the
length of individual strings, tokens and byte sequences, that it will
accept.

The sources are built only with HTTP/2 (for now), alongside the Huffman
sources, rather than unconditionally into the core HTTP module.

Assisted-by: opencode:claude-opus-4.8
6 weeks agoQUIC: fixed frame threshold with a small stream buffer size
Sourav Bhowmik [Wed, 23 Sep 2026 18:31:48 +0000 (11:31 -0700)]
QUIC: fixed frame threshold with a small stream buffer size

Since 2fb32ff (1.27.5), the connection frame threshold degraded to a
few or zero frames when using a small stream buffer.  The previously
hardcoded minimum of 10000 frames is now used.

6 weeks agoRejected zero size in buffer-size directives
Sourav Bhowmik [Thu, 13 Aug 2026 12:40:29 +0000 (05:40 -0700)]
Rejected zero size in buffer-size directives

When set to zero, this resulted in a buffer with no room to read into.
As there is no meaningful interpretation of a zero-sized buffer, such
configuration is explicitly rejected.

Reported by kh-lee

6 weeks agoSSL: avoid matching IP addresses in dNSName and commonName
Eugene Grebenschikov [Mon, 21 Sep 2026 20:32:36 +0000 (13:32 -0700)]
SSL: avoid matching IP addresses in dNSName and commonName

OpenSSL 1.0.2+ validates IP addresses only against iPAddress
subjectAltName entries via X509_check_ip().  For older OpenSSL
versions, equivalent validation is now performed.

Note that dNSName entries are still logged when checking an IP
address, they are not used for matching.

Co-authored-by: Sergey Kandaurov <pluknet@nginx.com>
6 weeks agoSSL: support for iPAddress subjectAltName in certificates.
Maxim Dounin [Thu, 21 Aug 2025 01:41:27 +0000 (04:41 +0300)]
SSL: support for iPAddress subjectAltName in certificates.

Known public services with iPAddress subject altnames include 1.1.1.1
and 8.8.8.8.  IP address certificates from Let's Encrypt are expected
to be available soon:

https://letsencrypt.org/2025/07/01/issuing-our-first-ip-address-certificate

Origin: <https://freenginx.org/hg/nginx/rev/5e23335edf67>
Co-authored-by: Eugene Grebenschikov <e.grebenshchikov@f5.com>
Co-authored-by: Sergey Kandaurov <pluknet@nginx.com>
6 weeks agoSSL: fixed subjectAltName and commonName debug logging.
Maxim Dounin [Thu, 21 Aug 2025 01:40:59 +0000 (04:40 +0300)]
SSL: fixed subjectAltName and commonName debug logging.

Previously, ASN1_STRING_length() was used as a length for "%*s" format
specifier, which is wrong, since string length is expected to be "size_t",
and ASN1_STRING_length() returns "int".

Origin: <https://freenginx.org/hg/nginx/rev/a540fac7e04a>
Signed-off-by: Eugene Grebenschikov <e.grebenshchikov@f5.com>
6 weeks agoSSL: avoid writing to a connection with a failed read
Sergey Kandaurov [Mon, 14 Sep 2026 13:34:42 +0000 (13:34 +0000)]
SSL: avoid writing to a connection with a failed read

It is possible to receive application data together with socket close.
In this case, SSL_read() may return SSL_ERROR_SYSCALL with ECONNRESET,
specifically after OpenSSL sent TLSv1.3 tickets on a closed connection.

Before OpenSSL 4.0, a subsequent SSL_write() returned SSL_ERROR_SYSCALL
with EPIPE in this case.  The behaviour was changed to remember the
error state and handle such a call as a protocol error, see for details
https://github.com/openssl/openssl/issues/30631.  This makes SSL_write()
return SSL_ERROR_SSL with the empty error queue, which results in
"[crit] ... SSL_write() failed" errors, as caught by ssl_stapling.t.

The fix is to check the result of the last read stored in c->ssl->last,
to avoid calling SSL_write() after a failed read.  For consistency, the
check is added to ngx_ssl_sendfile(): SSL_sendfile() resets the error
state the same way SSL_write() does, though it does not seem to be
reachable in http.

Based on a patch by Maxim Dounin.

Signed-off-by: Sergey Kandaurov <pluknet@nginx.com>
Origin: <https://freenginx.org/hg/nginx/rev/ff5becaf5444>

6 weeks agoSSL: clarified clean shutdown condition
Maxim Dounin [Mon, 14 Sep 2026 13:34:20 +0000 (13:34 +0000)]
SSL: clarified clean shutdown condition

OpenSSL up to 3.0, when a TCP connection is closed by the peer, returns
SSL_ERROR_SYSCALL without an error queue and with errno set to 0.  Since
OpenSSL 3.0 with SSL_OP_IGNORE_UNEXPECTED_EOF, which nginx sets, this is
reported as SSL_ERROR_ZERO_RETURN instead.

Closing a connection without the close_notify alert is incorrect, yet
common enough in the real world to be handled as a non-error condition.
Truncation attacks are expected to be prevented at the protocol level;
notably, they are not possible for HTTP/1.x requests at all, and only
possible for HTTP/1.x responses if neither Content-Length nor chunked
transfer encoding is used.

Previously, "ERR_peek_error() == 0" was used to detect this, which is
too broad: it also matches TCP-level errors, such as ECONNRESET, which
are better reported as errors, the way the plain TCP code does it in
ngx_unix_recv().

Now only a clean TCP close is treated as a clean connection close.  Most
notably, connection resets now result in "SSL_read() failed" errors.

This change is a modified version of a patch by Maxim Dounin.  The
modifications include resolved conflicts and the refined commit log.

Signed-off-by: Sergey Kandaurov <pluknet@nginx.com>
Origin: <https://freenginx.org/hg/nginx/rev/4c0b66b5046f>

8 weeks agoVersion bump
Sergey Kandaurov [Wed, 16 Sep 2026 12:11:52 +0000 (16:11 +0400)]
Version bump

8 weeks agoDav: destination validation for COPY and MOVE with "alias".
Maxim Dounin [Fri, 11 Sep 2026 15:18:36 +0000 (08:18 -0700)]
Dav: destination validation for COPY and MOVE with "alias".

If COPY or MOVE methods are enabled, the DAV module assumes that it is
configured for the whole server, and does not try validate that the
destination URI is within the particular location.  This, however, does
not work well if it is in fact configured in a non-root location, and
this location uses the "alias" directive, such as in the following
configuration:

    location /prefix/ {
        dav_methods COPY;
        alias /foo/;
    }

In particular, if the destination URI is shorter than the aliased
location prefix, calling ngx_http_map_uri_to_path() with such
destination URI used to result in segmentation faults (9739e755b).  And
if the destination URI is longer than the aliased location prefix, but
does not match it, calling ngx_http_map_uri_to_path() resulted in
unexpected path values, including ones above the "alias" directory
specified.

The fix is to check destination URI prefix if "alias" is used, similarly
to what we do with "try_files".  Additionally, the
ngx_http_map_uri_to_path() function was updated with additional sanity
checking to prevent similar issues.

This change is a modified version of a patch by Maxim Dounin.  The
modifications include skipping the prefix check if the URI was
rewritten, which preserves the "alias" diagnostics of
ngx_http_map_uri_to_path().

Signed-off-by: Vadim Zhestikov <v.zhestikov@f5.com>
Origin: <https://freenginx.org/hg/nginx/rev/aae28b083279>

8 weeks agonginx-1.31.6-RELEASE release-1.31.6
Sergey Kandaurov [Tue, 15 Sep 2026 11:28:07 +0000 (11:28 +0000)]
nginx-1.31.6-RELEASE

8 weeks agoQUIC: ignore the QUIC extension received in TLS handshake
Sergey Kandaurov [Thu, 10 Sep 2026 14:38:31 +0000 (18:38 +0400)]
QUIC: ignore the QUIC extension received in TLS handshake

Instead of failing the handshake, it is now accepted and ignored like
any other unknown extension.  Unlike stated in RFC 9001, Section 8.2,
this represents less strict behaviour following RFC 8446, Section 4.2.

8 weeks agoQUIC: registering the compat extension in all SSL contexts
Sergey Kandaurov [Tue, 8 Sep 2026 19:56:38 +0000 (19:56 +0000)]
QUIC: registering the compat extension in all SSL contexts

With the OpenSSL compatibility layer, the transport parameters custom
TLS extension used to be registered only in SSL contexts of virtual
servers reachable over QUIC.

The ClientHello callback introduced in 0373fe5d9 (1.29.2) is called
by OpenSSL between collecting and parsing extensions, so the custom
extensions may not match the expected number if the SSL context was
replaced with SSL_set_SSL_CTX().

The fix is to register the extension in all SSL contexts, including
those that cannot be reached over QUIC, so that the array bounds are
preserved; the compatibility layer as a whole is initialized only
if the configuration has QUIC listeners.  The keylog callback,
meaningful for QUIC connections, is kept on QUIC addresses.

Reported by Banny Liao.

2 months agoGeo: check binary base CRC32 before relocation
Sergey Kandaurov [Mon, 7 Sep 2026 15:47:51 +0000 (19:47 +0400)]
Geo: check binary base CRC32 before relocation

This provides safe pointer handling in the event of a corrupted file.

2 months agoControl API: fixed socket inheritance on binary upgrade
Sergey Kandaurov [Thu, 10 Sep 2026 21:07:12 +0000 (21:07 +0000)]
Control API: fixed socket inheritance on binary upgrade

The environment may be replaced while parsing configuration, as it
happens with the perl module, which calls ngx_set_environment() when
creating an interpreter.  As a result, the control socket was not
inherited on binary upgrade.

The variable is now read before ngx_init_cycle(), similarly to
inherited listening sockets.

2 months agoHandle nested location lookup error
Roman Arutyunyan [Wed, 9 Sep 2026 14:23:22 +0000 (18:23 +0400)]
Handle nested location lookup error

Previously, when looking up a nested location after a prefix location
match, the nested regex or predicate match error could be ignored if
more regex or predicate locations were configured at the current level.
Now such error leads to request finalization.

2 months agoHandle predicate location variable error
Roman Arutyunyan [Wed, 9 Sep 2026 13:32:34 +0000 (17:32 +0400)]
Handle predicate location variable error

Previously, the error was ignored and the predicate was treated as
false.  Now the error leads to the request finalization.

2 months agoRemoved non-existing support link in the man page
Sergey Kandaurov [Fri, 4 Sep 2026 12:34:57 +0000 (16:34 +0400)]
Removed non-existing support link in the man page

2 months agoAdded -l option to the man page
Sergey Kandaurov [Fri, 4 Sep 2026 12:10:24 +0000 (16:10 +0400)]
Added -l option to the man page

Fixes 4bc459a15.

2 months agoVersion bump
Sergey Kandaurov [Mon, 7 Sep 2026 16:00:22 +0000 (20:00 +0400)]
Version bump

2 months agonginx-1.31.5-RELEASE release-1.31.5
Roman Arutyunyan [Fri, 28 Aug 2026 11:52:47 +0000 (15:52 +0400)]
nginx-1.31.5-RELEASE

2 months agoUpdated OpenSSL and PCRE used for win32 builds
Roman Arutyunyan [Tue, 1 Sep 2026 17:51:10 +0000 (21:51 +0400)]
Updated OpenSSL and PCRE used for win32 builds

2 months agoControl API: in memory config dump.
Ava Hahn [Thu, 5 Feb 2026 22:25:19 +0000 (22:25 +0000)]
Control API: in memory config dump.

The /control/config endpoint returns the currently parsed and running
configuration on GET request.

Example:

$ curl 127.0.0.1:1234/1/control/config | jq
[
  {
    "name": "/path/to/nginx.conf",
    "content": "..."
  },
  {
    "name": "/path/to/included.conf",
    "content": "..."
  }
]

Co-authored-by: Pavel Pautov <p.pautov@f5.com>
2 months agoControl API: reload support.
Ava Hahn [Tue, 30 Dec 2025 19:35:18 +0000 (19:35 +0000)]
Control API: reload support.

A new /control/config endpoint provides configuration reload function
with feedback returned to the user on the outcome.

Example:

$ curl 127.0.0.1:1234/1/control/config -X PATCH -v | jq
< HTTP/1.1 200 OK
< ...
<
{
  "logs": []
}

$ curl 127.0.0.1:1234/1/control/config -X PATCH -v | jq
< HTTP/1.1 422 Unprocessable Entity
< ...
<
{
  "logs": [
  "...: invalid number of arguments in \"listen\" directive"
  ]
}

Co-authored-by: Pavel Pautov <p.pautov@f5.com>
2 months agoControl API.
Ava Hahn [Wed, 25 Mar 2026 01:08:25 +0000 (01:08 +0000)]
Control API.

A new nginx option -l specifies control socket listen address.
The socket is providing an HTTP/1 REST API for retrieving information
about running nginx instance.

Example:

$ nginx -l 127.0.0.1:1234

$ curl 127.0.0.1:1234/1/control/processes | jq
[
  {
    "pid": 41536,
    "name": "worker process",
    "exiting": false
  }
]

Co-authored-by: Roman Arutyunyan <arut@nginx.com>
Co-authored-by: Pavel Pautov <p.pautov@f5.com>
Co-authored-by: Dmitry Plotnikov <d.plotnikov@f5.com>
Co-authored-by: Sergey Kandaurov <pluknet@nginx.com>
Co-authored-by: Ivan Ovchinnikov <i.ovchinnikov@f5.com>
2 months agoJSON: fixed overflow detection in length calculation
Dmitry Plotnikov [Tue, 18 Aug 2026 01:40:08 +0000 (01:40 +0000)]
JSON: fixed overflow detection in length calculation

2 months agoPredicate locations
Roman Arutyunyan [Sun, 29 Mar 2026 06:47:49 +0000 (10:47 +0400)]
Predicate locations

A predicate location name starts with '$' and is interpreted as a
string evaluated at runtime, and its value is used to route the
request into the location.  A predicate location matches if the
string evaluates to a non-empty value not equal to "0".  At each
nesting level, the first matching predicate location in the
configuration order is chosen.  Predicate locations are matched
after prefix and regex locations.  They are not matched if an exact
or a regex location matched, or if the longest matching prefix location
has the "^~" modifier.  Predicate locations can be nested inside
other location types and can contain nested locations of their own.

Example:

map $arg_foo $pred {
    bar  1;
    qux  1;
}

location $pred {
    root html;
}

2 months agoEvent pipe: do not free buffers still used by the downstream
Ivan Ovchinnikov [Fri, 21 Aug 2026 20:48:15 +0000 (20:48 +0000)]
Event pipe: do not free buffers still used by the downstream

When a body filter returned an error, ngx_event_pipe_drain_chains()
returned all buffers to p->free_raw_bufs, including those in p->busy,
which are still owned by the downstream. If upstream EOF was detected
in the same ngx_event_pipe() pass, ngx_event_pipe_read_upstream() then
freed them while still referenced. With HTTP/2 only the stream's fake
connection is marked on error, so ngx_http_v2_send_output_queue() kept
sending DATA frames pointing at the freed buffers, a use-after-free.

Fixed by keeping the p->busy chains intact, the buffers are freed with
the request pool.  This also stops the pipe from reusing them for new
upstream reads, which previously could overwrite response body data
still queued for the client.  Additionally, the pipe no longer treats
a downstream it has given up on as merely blocked, so the loop is
still guaranteed to terminate.

Co-authored-by: Roman Arutyunyan <arut@nginx.com>
2 months agoSlice filter: overflow protection in slice range requests
Vadim Zhestikov [Tue, 11 Aug 2026 21:06:19 +0000 (14:06 -0700)]
Slice filter: overflow protection in slice range requests

When the byte range is passed in the client Range header, the range
start is accepted up to NGX_MAX_OFF_T_VALUE, while
ngx_http_slice_range_variable() adds the slice size to it when
formatting the slice end.  With start values close to the maximum
this overflowed.

Now such range starts are ignored, similarly to other ranges not
handled by ngx_http_slice_get_start().

2 months agoQUIC: rejected CRYPTO frames received in 1-RTT packets
Vadim Zhestikov [Wed, 12 Aug 2026 19:41:54 +0000 (12:41 -0700)]
QUIC: rejected CRYPTO frames received in 1-RTT packets

If a CRYPTO frame was received after the handshake, ngx_quic_handshake()
ran the handshake completion for the second time.  With the check added
in 6f8c520f4, this is limited to short header packets.

Since a client has nothing to send in a CRYPTO frame once the handshake
is complete, such frames are now rejected with the "unexpected_message"
connection error, as does TLS 1.3 for handshake messages received out of
order, and QUIC requires for KeyUpdate.

2 months agoMemcached: respect the end marker in the maximum supported length
Vadim Zhestikov [Tue, 11 Aug 2026 18:06:28 +0000 (11:06 -0700)]
Memcached: respect the end marker in the maximum supported length

The length in the "VALUE" line was accepted up to NGX_MAX_OFF_T_VALUE,
while ngx_http_memcached_filter_init() adds the size of the end marker
to it.  With lengths close to the maximum this overflowed u->length.

Now such lengths are rejected, similarly to other invalid lengths.

2 months agoCore: delete accept timer on worker shutdown
Roman Arutyunyan [Thu, 20 Aug 2026 12:53:42 +0000 (16:53 +0400)]
Core: delete accept timer on worker shutdown

Previously, when the worker file descriptor table was full, a listen
connection might be disabled and a timeout might be set for re-enabling
it.  If during this period the worker received the NGX_CMD_QUIT signal,
the accept connection would be recycled, but the timer would remain set.
On timer expiration, an attempt to accept a new connection would result
in "accept4() failed (9: Bad file descriptor)" alert because c->fd was
reset to -1.

Fix is to delete accept timer when closing listen connections.

2 months agoCore: make channel file descriptor errors non-fatal
Roman Arutyunyan [Tue, 18 Aug 2026 16:58:42 +0000 (20:58 +0400)]
Core: make channel file descriptor errors non-fatal

If a worker process' file descriptor table is full, recvmsg() is not
able to read out the channel fd sent from the master.  This results in
different behavior on different platforms.

On Linux, recvmsg() succeeds, returns the payload and drops the fd.
On BSD systems, the first recvmsg() call fails with EMSGSIZE/EMFILE,
but the next call succeeds and returns the payload without the fd.
On Solaris, recvmsg() fails with EMFILE and drops both the payload
and the fd.

Previously, all of these paths resulted in fatal errors.  The worker
channel was closed and the worker was no longer capable of receiving
messages from the master.  In particular, the NGX_CMD_QUIT command
could not be delivered anymore.  As a result, the worker never exited
after nginx reload and kept running and accepting new connections
forever until killed by a signal.

Fix is to consider those errors non-fatal.  An additional check is
added to the NGX_CMD_CLOSE_CHANNEL handler to make sure the worker
has received a file descriptor for this entry before. Also, the
MSG_CTRUNC check is removed since a proper ancillary data size
validation is now implemented.

2 months agoAdded the json parser module
Roman Semenov [Wed, 12 Aug 2026 16:52:08 +0000 (09:52 -0700)]
Added the json parser module

Added the http_json_module with a json_set directive that
extracts values from JSON stored in nginx variables and exposes them
as new nginx variables.  Parsed results are cached per request, so
multiple json_set directives using the same source expression trigger
only one parse.  The directive is available in the http main context.

Example usage:

    http {
        json_set $user_name $arg_data user.name;
        json_set $user_age  $arg_data user.age;
        json_set $tag0      $arg_data tags[0];

        server {
            listen 8080;

            location / {
                return 200 "name=$user_name age=$user_age "
                           "tag0=$tag0\n";
            }
        }

        # quoted keys for names containing '.', '[', ']', or that
        # are empty; the whole argument is single-quoted so that the
        # inner '"' reach the path parser intact
        json_set $host      $arg_data '["a.b.com"]';
        json_set $nested    $arg_data 'obj["a.b"].c[2]';
        json_set $quoted    $arg_data 'obj["a\\"b"]';
    }

Co-authored-by: Dmitry Volyntsev <d.volyntsev@f5.com>
2 months agoCore: allowed top-level scalars in the JSON parser
Roman Semenov [Wed, 12 Aug 2026 16:42:28 +0000 (09:42 -0700)]
Core: allowed top-level scalars in the JSON parser

RFC 8259 permits any JSON value as a complete document, not just
objects and arrays.  The start state now accepts strings, numbers,
and the true/false/null literals as well.  A bare top-level number,
having no closing delimiter, is emitted when input ends.

2 months agoCore: added json parser
Roman Semenov [Wed, 12 Aug 2026 16:40:34 +0000 (09:40 -0700)]
Core: added json parser

An event-driven JSON parser implementing the grammar of RFC 8259.
The full grammar is recognized: objects, arrays, strings with \uXXXX
escapes (including UTF-16 surrogate pairs), numbers, and the
true/false/null literals.  Tokens are reported to a caller-supplied
handler, with nesting bounded by a configurable maximum depth.

Based on previous work by Maxim Dounin.

Co-authored-by: Dmitry Volyntsev <d.volyntsev@f5.com>
2 months agoCore: added JSON unescape functionality
Roman Semenov [Wed, 12 Aug 2026 16:39:11 +0000 (09:39 -0700)]
Core: added JSON unescape functionality

Decodes JSON string escape sequences in place as defined by
RFC 8259, Section 7: the two-character escapes and \uXXXX,
with non-BMP code points encoded as UTF-16 surrogate pairs
and emitted as UTF-8.

2 months agoAdded client_body_early_read directive
Roman Arutyunyan [Wed, 8 Apr 2026 17:07:15 +0000 (21:07 +0400)]
Added client_body_early_read directive

The directive accepts predicates.  When enabled, request body is read
immediately after the headers and before choosing a location.
Body read settings from the server block are used in this case.

Example:

http {

    map $http_content_type $is_json {
        application/json 1;
    }

    server {
        listen 8000;

        client_body_early_read $is_json;
        client_max_body_size 256;
        client_body_buffer_size 256;

        return 200 $request_body;
    }
}

2 months agoUwsgi: support for multibyte parameter name lengths.
Vadim Zhestikov [Wed, 19 Aug 2026 19:41:08 +0000 (12:41 -0700)]
Uwsgi: support for multibyte parameter name lengths.

The name length of a configured parameter was truncated to one byte
before the per-parameter length field was written, so that a
uwsgi_param name of 256 bytes or longer was encoded with a wrong
length while the name itself was copied in full.  The resulting request
was malformed, and upstream servers responded by closing the connection.

While long names are barely used in practice, it is easy to support
them.  The length is now properly encoded up to the allowed length.

2 months agoFastCGI: support for multibyte parameter name lengths.
Vadim Zhestikov [Wed, 19 Aug 2026 19:41:08 +0000 (12:41 -0700)]
FastCGI: support for multibyte parameter name lengths.

The name length of a configured parameter was truncated to one byte
before the per-parameter length field was written, so that a
fastcgi_param name of 128 bytes or longer was encoded with a wrong
length while the name itself was copied in full.  The resulting request
was malformed, and upstream servers responded by closing the connection.

While long names are barely used in practice, it is easy to support
them.  The length is now properly encoded up to the allowed length.

2 months agoVersion bump
Vadim Zhestikov [Thu, 20 Aug 2026 02:17:38 +0000 (19:17 -0700)]
Version bump

3 months agonginx-1.31.4-RELEASE release-1.31.4
Sergey Kandaurov [Tue, 11 Aug 2026 19:49:38 +0000 (23:49 +0400)]
nginx-1.31.4-RELEASE

3 months agoMail: PROXY protocol v2 support to backends
Sergey Kandaurov [Mon, 10 Aug 2026 16:53:52 +0000 (20:53 +0400)]
Mail: PROXY protocol v2 support to backends

Version 1 remains the default.  This may be changed with the
"proxy_protocol v2;" directive.

3 months agoStream: PROXY protocol v2 support to backends
Sergey Kandaurov [Mon, 10 Aug 2026 16:53:44 +0000 (20:53 +0400)]
Stream: PROXY protocol v2 support to backends

Version 1 remains the default.  This may be changed with the
"proxy_protocol v2;" directive.

3 months agoCore: PROXY protocol v2 write support
Sergey Kandaurov [Mon, 10 Aug 2026 14:10:44 +0000 (18:10 +0400)]
Core: PROXY protocol v2 write support

Add ngx_proxy_protocol_v2_write() that writes the fixed 16-byte
PPv2 header and address block, and appends a list of TLVs.

An address block is written using IPv4/IPv6 mixed-family promotion:
the highest family present on either side (IPv6 > IPv4) is used for
the header, and the other address is promoted into it.  Both v4-mapped
addresses are demoted to IPv4.

When PROXY protocol v2 is configured and the downstream connection
is SSL, standard PROXY protocol v2 TLVs are populated:

    PP2_TYPE_ALPN              from SSL_get0_alpn_selected()
    PP2_TYPE_AUTHORITY         from SSL_get_servername()
    PP2_SUBTYPE_SSL_VERSION    from SSL_get_version()
    PP2_SUBTYPE_SSL_CIPHER     from SSL_get_cipher_name()
    PP2_SUBTYPE_SSL_CN         from client cert subject CN
    PP2_SUBTYPE_SSL_SIG_ALG    from server certificate
    PP2_SUBTYPE_SSL_KEY_ALG    from server certificate

The CRC32c TLV is written last and covers the entire header in place.

Co-authored-by: Vadim Zhestikov <v.zhestikov@f5.com>
3 months agoCore: PROXY protocol v2 macros
Sergey Kandaurov [Tue, 11 Aug 2026 13:03:46 +0000 (17:03 +0400)]
Core: PROXY protocol v2 macros

3 months agoCore: CRC32c (Castagnoli93) implementation
Vadim Zhestikov [Thu, 16 Apr 2026 18:45:23 +0000 (11:45 -0700)]
Core: CRC32c (Castagnoli93) implementation

This change implements the Castagnoli polynomial code 0x11EDC6F41,
as described in RFC4960, Appendix B.  It will be used to calculate
PROXY protocol v2 CRC32c checksums.

3 months agoUpstream: reserved padding in state structures
Dmitry Plotnikov [Fri, 7 Aug 2026 22:20:38 +0000 (22:20 +0000)]
Upstream: reserved padding in state structures

3 months agoUpstream: fixed MSVC compilation after dea68dbf126f.
Vadim Zhestikov [Mon, 10 Aug 2026 21:17:08 +0000 (14:17 -0700)]
Upstream: fixed MSVC compilation after dea68dbf126f.

3 months agoCore: added data model and JSON serialization libraries.
Henry Yuan [Thu, 16 Jul 2026 22:00:32 +0000 (22:00 +0000)]
Core: added data model and JSON serialization libraries.

Co-authored-by: Valentin Bartenev <vbart@nginx.com>
Co-authored-by: Ruslan Ermilov <ru@nginx.com>
Co-authored-by: Vladimir Homutov <vl@nginx.com>
Co-authored-by: Evgeny Shirykalov <e.shirykalov@f5.com>
Co-authored-by: Dmitry Plotnikov <d.plotnikov@f5.com>
3 months agoUpstream: reject zero WINDOW_UPDATE increments
felix h [Wed, 5 Aug 2026 17:07:20 +0000 (19:07 +0200)]
Upstream: reject zero WINDOW_UPDATE increments

The HTTP/2 proxy and gRPC upstream clients accepted WINDOW_UPDATE
frames with a zero flow-control window increment.  RFC 9113 requires
such frames to be handled as PROTOCOL_ERROR at stream or connection
scope.

Reject these frames as invalid upstream responses.

3 months agoUpstream: special handling of the "Host" header in proxy and gRPC
Roman Arutyunyan [Tue, 21 Jul 2026 14:14:39 +0000 (18:14 +0400)]
Upstream: special handling of the "Host" header in proxy and gRPC

HTTP/2 and gRPC requests are now always sent with the ":authority"
pseudo-header, while the "Host" header is no longer passed.
Where a host value is set explicitly with "proxy_set_header Host"
or "grpc_set_header Host", that value is conveyed in ":authority".
As per RFC 9113, Section 8.3.1, clients and intermediaries MUST
generate an ":authority" pseudo-header to convey authority information.

For HTTP/1.1, HTTP/2 and gRPC, if the explicit value is empty, then
the value of $proxy_host is used instead.  As per RFC 9110, Sections
4.2.1 and 4.2.2, the "http" and "https" URI schemes MUST contain a
non-empty host identifier.  The change enforces this rule by
introducing a default.

Closes: https://github.com/nginx/nginx/issues/1426
3 months agoFixed overflow detection in chunked parser
Sergey Kandaurov [Thu, 6 Aug 2026 17:14:27 +0000 (21:14 +0400)]
Fixed overflow detection in chunked parser

This was broken in f405ef11f (1.29.4).

Reported by Matt Suiche, Tolmo Inc.

3 months agogRPC: narrowed special handling of "trailer only" responses
Vinay Kumar Tokala [Wed, 22 Jul 2026 06:23:09 +0000 (23:23 -0700)]
gRPC: narrowed special handling of "trailer only" responses

Previously, the response length was explicitly set to zero if the
initial HEADERS frame was seen with the END_STREAM flag.  This was
meant to properly pass responses in the Trailers-Only format as
introduced in 6559a420134b.  This handling was too broad though,
passing incomplete responses that carry a non-zero Content-Length
to the client as if they were complete and empty.

Now such responses are caught by the existing checks later on and
are passed as incomplete, similarly to how this is handled elsewhere.
For instance, on HTTP/2 client connections this now results in proper
signalling, an incomplete stream followed by stream reset.

3 months agoScript: improved compatibility of complex value codes
Aleksei Bavshin [Thu, 16 Jul 2026 15:53:21 +0000 (08:53 -0700)]
Script: improved compatibility of complex value codes

In a8289aa69c74, we introduced a new code to finalize the evaluation of
a complex value, deferring the stack update to this new code.  However,
the change inadvertently broke compatibility with several third-party
modules that were reusing ngx_http_script_complex_value_code.

This change relegates omitted ngx_http_script_complex_value_end_code
from crash to a potential read of uninitialized bytes at the end of the
allocated buffer.

3 months agoQUIC: log RESET_STREAM final size as a decimal number
Roman Arutyunyan [Tue, 28 Jul 2026 15:04:28 +0000 (19:04 +0400)]
QUIC: log RESET_STREAM final size as a decimal number

Previously, it was logged as a hexadecimal number.

3 months agoQUIC: always validate stream final size
Roman Arutyunyan [Tue, 28 Jul 2026 14:34:36 +0000 (18:34 +0400)]
QUIC: always validate stream final size

As per RFC 9000, Section 4.5:

Once a final size for a stream is known, it cannot change. If a
RESET_STREAM or STREAM frame is received indicating a change in the
final size for the stream, an endpoint SHOULD respond with an error of
type FINAL_SIZE_ERROR.  A receiver SHOULD treat receipt of data at or
beyond the final size as an error of type FINAL_SIZE_ERROR, even after
a stream is closed.

Previously, the stream final size was validated only after other checks
that could return earlier and skip validation: the receive state check
and, for STREAM frames, the check for data below the current receive
offset.  As a result, a STREAM or RESET_STREAM frame carrying a final
size error was silently ignored once the receiving part of the stream
had reached a state in which the frame would otherwise be discarded, or
when a STREAM frame did not advance the receive offset.  Now the final
size is validated first, so a FINAL_SIZE_ERROR is generated in these
cases as well.

3 months agoQUIC: apply stream flow control to RESET_STREAM final_size
Roman Arutyunyan [Thu, 23 Jul 2026 07:33:13 +0000 (11:33 +0400)]
QUIC: apply stream flow control to RESET_STREAM final_size

Previously, stream flow control was not applied to the RESET_STREAM
final_size, which allowed a client to exceed it.  The excess had to be
within the connection flow control limits anyway.

Reported by Tony Wang.

3 months agoGH: restrict the mark_stale job to nginx/nginx
Amin Vakil [Sun, 26 Jul 2026 08:19:50 +0000 (11:49 +0330)]
GH: restrict the mark_stale job to nginx/nginx

3 months agoFormat specifier fixes in error logging
Sergey Kandaurov [Wed, 22 Jul 2026 16:11:50 +0000 (20:11 +0400)]
Format specifier fixes in error logging

Co-authored-by: Nishat Shabbir <nishat@bugqore.com>
3 months agoEvents: validate descriptor before FD_SET()
Sourav Bhowmik [Wed, 22 Jul 2026 16:12:28 +0000 (09:12 -0700)]
Events: validate descriptor before FD_SET()

The check in ngx_select_init_conf() can be insufficient because it
doesn't cover descriptors for local files, which are not accounted
for in cycle->connection_n.  For instance, to reach this condition
with new connections, no reusable connections must be available for
recycling in ngx_get_connection().

The fix adopts a similar code from the win32 select module.

3 months agoPerl: fixed $r->print() zero copy with mutable scalars
David Carlier [Tue, 21 Jul 2026 03:35:57 +0000 (04:35 +0100)]
Perl: fixed $r->print() zero copy with mutable scalars

Since d9b7669666c8, the single-SV zero copy path in $r->print() no
longer required the SV to be read-only.  Reference counting introduced
by that change keeps the SV alive, but not its string buffer: modifying
a mutable scalar after $r->print() overwrites the buffer in place or
reallocates it, while nginx might still have it queued in r->out, since
small responses are postponed by ngx_http_write_filter().  This resulted
in corrupted responses, and in freed memory being sent to the client
when the scalar was grown.

The SV is now required to be read-only again.  Reference counting is
still needed here, as a read-only SV in an eval() might be freed with
the eval's op tree.

3 months agoAutoindex: use temporary pool for directory entries
Srujan Rai [Mon, 4 May 2026 11:32:43 +0000 (17:02 +0530)]
Autoindex: use temporary pool for directory entries

Directory listing entries (file names, metadata) were allocated
from the request pool and lived until request teardown.  Use a
temporary pool instead, destroying it immediately after the
response buffer is built.

3 months agoUpdated security policy report methods
Sergey Kandaurov [Tue, 21 Jul 2026 17:18:54 +0000 (21:18 +0400)]
Updated security policy report methods

3 months agoImage filter: fixed reading past the received data
Vadim Zhestikov [Fri, 17 Jul 2026 20:16:08 +0000 (13:16 -0700)]
Image filter: fixed reading past the received data

The size parser and the image decoders used ctx->length, which is the
allocation size (set to image_filter_buffer when the upstream response
omits Content-Length), as the amount of valid data, so a truncated
response without Content-Length could be parsed or decoded past the
received bytes into uninitialized buffer memory.

The length is now adjusted to the actually-read size once the response
body has been read.

Reported by dukesp69 and YLChen-007.

3 months agoXslt: xmlCreatePushParserCtxt() error handling
Vadim Zhestikov [Thu, 16 Jul 2026 00:45:35 +0000 (17:45 -0700)]
Xslt: xmlCreatePushParserCtxt() error handling

On parser allocation failure, context was left uninitialized
resulting in null pointer dereference.

3 months agoVersion bump
Vadim Zhestikov [Thu, 16 Jul 2026 19:21:48 +0000 (12:21 -0700)]
Version bump

3 months agonginx-1.31.3-RELEASE release-1.31.3
Roman Arutyunyan [Wed, 15 Jul 2026 13:12:37 +0000 (17:12 +0400)]
nginx-1.31.3-RELEASE

3 months agoAvoid duplicate subrequest finalization
Roman Arutyunyan [Mon, 29 Jun 2026 17:49:27 +0000 (21:49 +0400)]
Avoid duplicate subrequest finalization

Previously, if a subrequest was posted twice, it could be finalized in
both calls, excessively reducing r->main->count and potentially leading
to a use-after-free.

The fix is to avoid posting a request if it's already posted.  Also,
as a hardening measure, r->write_event_handler is now reset to a no-op
handler during active subrequest finalization.

The problem manifests itself in ngx_http_ssi_filter_module during
unbuffered proxying.  If a subrequest is created for an SSI include
statement while the main request has some data postponed by another
include, this subrequest becomes double-posted when the main request
data is flushed.  The first post comes from ngx_http_subrequest() and
the second one comes from ngx_http_postpone_filter().  In case of a
quick subrequest finalization, the above mentioned problem happens.

Reported by P4P3R-HAK.

3 months agoFixed uninitialized memory read caused by stale regex captures.
Pavel Pautov [Fri, 15 May 2026 07:48:50 +0000 (00:48 -0700)]
Fixed uninitialized memory read caused by stale regex captures.

When ngx_http_regex_exec() reallocates r->captures array, it doesn't update
r->ncaptures value, if regex didn't match. So the next use of unnamed regex
capture triggers uninitialized read and potential buffer overrun.

This config demonstrates the issue:
    map test $my_map {
        volatile;

        ~mismatch(.*) 1; # reallocates r->captures in subrequests

        default "";
    }

    server {
        location ~(.*) { # sets r->ncaptures
            slice 50;

            # $1 will read from uninitialized memory in slice subrequests
            proxy_set_header Test $my_map$1;

            proxy_set_header Range $slice_range;
            proxy_pass http://backend;
        }
    }

The issue was introduced by 746fba0d79c6.

3 months agoScript: avoid garbage at the end of the result string
Roman Arutyunyan [Fri, 3 Jul 2026 11:11:09 +0000 (15:11 +0400)]
Script: avoid garbage at the end of the result string

If the script result turned out to be shorter than its predicted
length, the result string contained uninitialized bytes at the end.
The fix is to cut the result string by its actual size.

The following locations returned trailing garbage to the client with
URI "/1234abcd".

    map $uri $foo {
        ~^/(?<bar>[0-9]).*$ $bar;
    }

    location ~(?<bar>[0-9]*)[a-z]*$ {
        return 200 $1:$foo;
    }

    location ~(?<bar>[0-9]*)[a-z]*$ {
        set $qux $1:$foo;
        return 200 $qux;
    }

3 months agoScript: buffer overrun protection in direct script usage.
Maxim Dounin [Fri, 19 Jun 2026 19:54:46 +0000 (22:54 +0300)]
Script: buffer overrun protection in direct script usage.

Following the previous change, this change adds script overrun
protection to direct script evaluation in the proxy, fastcgi, scgi,
uwsgi, grpc proxy, index, and try_files modules.

This change is a modified version of a patch by Maxim Dounin.  The
modifications include ngx_http_proxy_v2_module and hardened size checks.

Signed-off-by: Roman Arutyunyan <arut@nginx.com>
Origin: <https://freenginx.org/hg/nginx/rev/7e4d7feb4c77>

3 months agoAccess log: buffer overrun protection.
Maxim Dounin [Fri, 19 Jun 2026 19:55:38 +0000 (22:55 +0300)]
Access log: buffer overrun protection.

Similarly to generic script operations, access log script copy operations
now check if there is enough room in the buffer.

Signed-off-by: Roman Arutyunyan <arut@nginx.com>
Origin: <https://freenginx.org/hg/nginx/rev/ceff7ca7785a>

3 months agoScript: buffer overrun protection.
Maxim Dounin [Fri, 19 Jun 2026 19:54:27 +0000 (22:54 +0300)]
Script: buffer overrun protection.

With this change, all script copy operations now check if there is
enough room in the buffer.  To do so, the script engine now provides the
e->end pointer, which specifies expected buffer end, and each copy
operation is checked against it with the ngx_http_script_check_length()
function.

The e->end pointer is optional and only checked when set, thus
introducing no incompatible API changes.  All standard functions were
updated to use it, notably ngx_http_complex_value(), ngx_http_script_run(),
ngx_http_script_regex_start_code(), ngx_http_script_complex_value_code().
Direct script evaluation in the proxy, fastcgi, scgi, uwsgi, grpc proxy,
index, and try_files modules will be updated by a separate patch.

In particular, this catches issues as observed when evaluating variables
with side effects, such as in the following configuration:

    map $uri $map {
        ~(?<capture>.*) $capture;
    }

    set $capture "";
    set $temp "$capture $map";

As well as when evaluating non-cacheable variables, where length of a
variable might change between length and copy codes, such as in the
following configuration:

    map prefix:$capture $map_volatile {
        volatile;
        ~(?<capture>.*) $capture;
    }

    set $capture "";
    set $temp "$map_volatile";

Similar changes were made in the stream module.

Signed-off-by: Roman Arutyunyan <arut@nginx.com>
Origin: <https://freenginx.org/hg/nginx/rev/d172f506ab5f>

3 months agoScript: simplified copy capture codes.
Maxim Dounin [Fri, 19 Jun 2026 19:54:19 +0000 (22:54 +0300)]
Script: simplified copy capture codes.

Signed-off-by: Roman Arutyunyan <arut@nginx.com>
Origin: <https://freenginx.org/hg/nginx/rev/0fd5e6155817>

3 months agoDisable HTTP keepalive for HTTP CONNECT requests
Roman Arutyunyan [Mon, 13 Jul 2026 18:16:34 +0000 (22:16 +0400)]
Disable HTTP keepalive for HTTP CONNECT requests

As per RFC 2817 Section 5.2:

Like any other pipelined HTTP/1.1 request, data to be tunneled may be
sent immediately after the blank line. The usual caveats also apply:
data may be discarded if the eventual response is negative, and the
connection may be reset with no response if more than one TCP segment
is outstanding.

3 months agoReject HTTP CONNECT requests with body
Roman Arutyunyan [Thu, 2 Jul 2026 11:09:35 +0000 (15:09 +0400)]
Reject HTTP CONNECT requests with body

As per RFC 9110, Section 9.3.6:

A CONNECT request message does not have content.

Also, as per Section 8.6:

A user agent SHOULD NOT send a Content-Length header field when the
request message does not contain content and the method semantics do
not anticipate such data.

3 months agoTunnel: ignore request body
Roman Arutyunyan [Fri, 5 Jun 2026 11:26:21 +0000 (15:26 +0400)]
Tunnel: ignore request body

Previously, client request body was considered tunnel payload.

Reported by NiubiKlasLi.

3 months agoStream: proxy_socket_sndbuf and proxy_socket_rcvbuf directives
Patrik Wall [Mon, 27 Apr 2026 11:22:16 +0000 (13:22 +0200)]
Stream: proxy_socket_sndbuf and proxy_socket_rcvbuf directives

Similarly to "listen ... sndbuf/rcvbuf", proxy_socket_sndbuf and
proxy_socket_rcvbuf can be used to set the SO_SNDBUF and SO_RCVBUF
socket options, respectively, on upstream connections.  By default,
the values are left unchanged.

Closes: https://github.com/nginx/nginx/issues/1297