diff --git a/source/CHANGES.txt b/source/CHANGES.txt index 7195f0cf..ec621f40 100644 --- a/source/CHANGES.txt +++ b/source/CHANGES.txt @@ -1,3 +1,263 @@ +Changes with FreeUnit 1.36.0 16 Jul 2026 + + *) Bugfix: the controller crashed in debug builds when a control-socket + connection closed after the active-connection tracking change, and + leaked the accepted file descriptor when a control connection failed + during initialization or body allocation; connection tracking and + teardown now route through the engine's tracking macros and the + close path. + + *) Bugfix: ignore a malformed incoming "traceparent" header and restart + the trace per W3C Trace Context instead of rejecting the request + with HTTP 500; the malformed header is dropped instead of being + forwarded alongside the restarted one, and context accepted from a + valid duplicate is preserved. Values are now validated in full + (segment lengths, lowercase hex, no all-zero ids, no "ff" version), + so content-invalid values restart the trace instead of being + re-emitted verbatim. An inbound "tracestate" is dropped together + with the rejected context (kept when the traceparent is inherited). + The injected "traceparent" fields are now zero-initialized; garbage + flag bits could get the header randomly dropped from proxied + requests and responses. + + *) Bugfix: reject empty values and embedded NUL bytes in configuration + strings that are later used as NUL-terminated C strings ("user", + "group", "working_directory", "stdout", "stderr", "executable", and + the per-language application targets) and in pathname unix socket + addresses, closing a silent-truncation target confusion. + + *) Bugfix: reject empty values and embedded NUL bytes in the remaining + configuration strings used as NUL-terminated C strings outside + application options: the "access_log" path (string and object + forms), the TLS "certificate" and njs "js_module" store names, and + the PHP "options.file" php.ini path. + + *) Bugfix: reject an embedded NUL byte in a templated static-serving + path ("share" and "chroot") after it is resolved from + request-controlled variables and before it reaches open()/openat2(), + preventing a silent truncation that could serve a different file + than the resolved path. + + *) Bugfix: mount rootfs automount destinations onto the openat2 + validated descriptor via "/proc/self/fd" instead of re-resolving the + path, closing a check-to-use window in which a destination component + could be swapped for a symlink escaping the rootfs. + + *) Bugfix: treat duplicate upstream "Content-Length" headers in a + proxied response as inconsistent — both headers are dropped and the + body is read to EOF instead of trusting either length, preventing a + response-smuggling desynchronization. + + *) Bugfix: keep downstream keepalive disabled after a duplicate or invalid + upstream "Content-Length"; a clean upstream close no longer re-enables + it, so an HTTP/1.1 client cannot reuse the connection past the re-framed + response. The complete body still ends with its terminal chunk — body + truncation is now tracked separately from the inconsistent flag. + + *) Bugfix: bound the request-header fields region against the shared + memory message size in libunit, validate every field name/value + serialized pointer and the cached header-field indexes before use, + and range-check off/len in the Java InputStream read() binding, + preventing out-of-bounds access on a malformed request. + + *) Bugfix: fix a libunit port-fd double-close race in the Go language + module: getUnixConn() wrapped the raw shared-port descriptor (which + net.FileConn dups) and a deferred Close() closed the original + descriptor number while libunit still owned it, an intermittent + double-close that raised an EBADF alert or, worse, closed an + unrelated reused live descriptor. Go now dup(2)s the descriptor and + wraps only the dup, so libunit remains the sole owner and closer; + libunit additionally holds a port reference across the out-of-mutex + add_port callback window so a concurrent destroy cannot free the + port mid-callback. + + *) Feature: SIGQUIT now performs a graceful stop — application workers + drain in-flight requests before exiting; SIGTERM remains the fast + exit that drops them. + + *) Change: upgrade the wasm-wasi-component wasmtime crates from 35.0.0 + to 36.0.12, clearing the wasmtime sandbox-escape advisories, with the + accompanying WasiView/WasiHttpView source migration. + + *) Change: upgrade contrib njs to 1.0.0. + + *) Feature: two-phase listener close — reconfiguration disarms a removed + listener first and releases its descriptor only after pending accept + references drain, instead of resetting them. + + *) Change: the event engine now tracks in-flight connections on a + dedicated active connections queue, symmetric with idle tracking — + groundwork for graceful connection draining; connection accounting + in the "/status" API is exact on all close paths. + + *) Change: broaden the regression test suite — proxy Content-Length and + chunked-response relay framing, OpenTelemetry 5xx tracing and inbound + traceparent handling, and Java ServletInputStream bounds — and run + the C unit-test suite in CI, which was previously compiled but never + executed. + + *) Bugfix: authorize privileged IPC message types by the kernel-validated + sender PID (SCM_CREDENTIALS), close any received descriptors on every + rejected privileged message, and cap port queue item size at the slot + data bound. + + *) Bugfix: reject control characters (CR, LF, NUL, DEL) in "set_headers" + names and values at configuration load, including the literal + segments of templated values. + + *) Bugfix: handle buffer-allocation failure in the port read handlers + with an orderly teardown instead of a NULL-pointer dereference, route + a connection write error after a partial send to the error handler + immediately, and free the timer batching array on engine teardown. + + *) Feature: upgrade the OpenTelemetry Rust crates from 0.24 to 0.32 and + rewrite the OTLP trace exporter on the stable, dedicated-thread batch + span processor (blocking reqwest client, no tokio runtime). + + *) Feature: W3C traceparent header inheritance now correctly propagates + the upstream sampling decision; the sampler wraps TraceIdRatioBased + inside ParentBased so that remote parent trace flags are honoured. + + *) Feature: add fake_otlp mock OTLP collector (test/fake_otlp/) and the + test_otel.py test suite covering span export, traceparent + propagation, sampling, and configuration validation over both the + OTLP/HTTP and OTLP/gRPC transports. + + *) Feature: reintroduce OTLP/gRPC trace export. Both transports are + compiled into every "--otel" build and the + "settings/telemetry/protocol" option selects "http" (OTLP/HTTP) or + "grpc" (OTLP/gRPC) at runtime, as in upstream Unit. gRPC uses tonic + over a small tokio runtime; v1 is plaintext h2c only (no TLS to the + collector, like the HTTP path). + + *) Change: rename the default OTel service name from "NGINX Unit" to + "FreeUnit". + + *) Bugfix: add validation bounds for "batch_size" (1-65536) and + "sampling_ratio" (0-1) in the OpenTelemetry configuration; previously + invalid values were silently rejected without an error message. + + *) Bugfix: replace eprintln! error output in the OTel Rust layer with + the C log callback (nxt_otel_log_cb), so errors flow through the + standard Unit logging infrastructure. + + *) Bugfix: remove unreachable Protocol::HttpJson dead-code arm from the + OTel exporter; only HttpBinary was ever selected. + + *) Bugfix: fix a rootfs automount reload race: sever the worker's mount + namespace propagation (MS_REC|MS_PRIVATE) before mounting and let a + per-worker automount be reaped with the namespace instead of being + unmounted from the host, so a configuration reload no longer races the + previous worker generation's teardown against the new prototype's + procfs mount (freeunitorg/freeunit#83). + + *) Bugfix: validate that a loaded TLS private key matches its certificate + at config time, and guard the wildcard-name SAN matcher against a + zero-length SAN entry. + + *) Bugfix: correct IPv4 /32 CIDR fallthrough, symmetric URI/pattern + decoding, the PCRE2 match-data ovector size, and short port-range + parsing in HTTP routing; document the case-insensitive host matcher + and the capset stance. + + *) Bugfix: tighten file-descriptor and CLOEXEC lifetime — CLOEXEC-protect + accepted sockets and pipe ends, close the pipe end on + nxt_fd_nonblocking() failure and the source fd on compression mmap + failure, and narrow the accept4() fallback to ENOSYS. + + *) Bugfix: tighten WebSocket frame-bound checks — reject truncated + extended-length frames in libunit, validate the 64-bit extended-length + MSB (RFC 6455), fix a no-op frame-size decrement that could copy bytes + beyond the declared payload, bound the Java sendWsFrame JNI arguments, + and guard pending_payload_len overflow in the Python ASGI handler. + + *) Bugfix: bounds-check peer-supplied shared-memory offsets — range-check + chunk_id and chunk_id+nchunks in incoming mmap messages, close a + lookup/dereference window on the incoming-mmap handler, reject + response-buffer size overflow, and validate request sptr offsets + before use. + + *) Bugfix: bounds-check app-supplied arguments across the language + bindings (PHP header skip / realpath / PATH_INFO; Python WSGI and ASGI + checks; Perl ERRSV scrub; Java InputStream.readLine off/len; WASM + guest offsets). + + *) Bugfix: tighten isolation boundaries — require a matching peer UID + (root or Unit's own effective UID) on the unix control socket, so the + "control-user", "control-group", and "control-mode" permissions are + defense-in-depth rather than a means to delegate control-API access; + resolve mount destinations with openat2(RESOLVE_BENEATH); and resolve + relative cgroup paths against the child's /proc//cgroup. + + *) Bugfix: reject embedded NUL bytes in the "rootfs" and cgroup "path" + isolation options, and validate "rootfs" as an absolute path other + than "/" at configuration time. + + *) Bugfix: fix an ineffective truncation guard when building the + cgroup.procs pathname: snprintf()'s return value overwrote the + original directory length before the bounds comparison, so a long + cgroup directory path could overflow the check. The append now + preserves the original length and fails with ENAMETOOLONG when + "/cgroup.procs" plus the trailing NUL cannot fit. + + *) Bugfix: fail cgroup setup when the per-process pool allocation that + caches the created directory for cleanup fails; the directory is now + removed and setup errors out, rather than moving the process into a + cgroup that could never be cleaned up — a cgroup directory leak under + memory pressure. + + *) Bugfix: reject a "rootfs" that lexically resolves to "/" (such as + "/.", "/..", or "/foo/.."); chroot("/") is a no-op and would silently + defeat rootfs isolation. + + *) Bugfix: cap JSON parser depth and element counts in the controller, + scrub PHP TrueAsync exception state before the prototype fork, and bind + the Ruby rack.input / rack.errors handles to their originating request. + + *) Bugfix: bound proxy Content-Length and URI/string helpers — truncate a + proxied response body that exceeds its Content-Length and close the + connection, flag invalid or oversized upstream Content-Length, fix an + nxt_is_complex_uri_encoded() off-by-one, and reject over-long lengths + in nxt_rmemstrn(). + + *) Feature: enforce the runtime/OS end-of-life policy automatically — the + unit-eol-check tool now fails when a shipped variant has outlived its + support window (supported_until past EOL + grace), and a new + eol-check GitHub workflow validates pkg/eol.json against endoflife.date + on every relevant pull request and weekly on a schedule. + + +Changes with FreeUnit 1.35.5 29 May 2026 + + *) Feature: automatically convert chunked request bodies to Content-Length + when forwarding to upstream servers via proxy action. This enables + compatibility with backends that do not support Transfer-Encoding: + chunked (e.g., Gitea, servers requiring Content-Length). Fixes + freeunitorg/freeunit#58, resolves nginx/unit#445 (client chunked), + nginx/unit#1088 (duplicate TE), and nginx/unit#1278 (RFC 9112 epic). + + *) Change: chunked_transform feature is no longer experimental. Chunked + request bodies can be accepted and transparently converted to + Content-Length via configuration: { "settings": { "http": + { "chunked_transform": true } } } + + *) Bugfix: fix TLS library busy-loop on peer-initiated close in SSL_write + when connection is aborted by remote peer; prevents high CPU usage and + ensures proper connection cleanup. + + *) Feature: add unfreeze-sync.sh script for automated migration of issues + from nginx/unit to freeunitorg/freeunit with label mapping, deduplication, + and dry-run preview support. + + *) Change: upgrade contrib njs to 0.9.8. + + *) Bugfix: fix mem-pool retain leak in cert/script-store IPC paths + (router side) and fd/buffer leaks in cert/script/socket/access-log + reply paths and the controller config-store path (main process + side); all reachable when nxt_port_msg_alloc fails inside the + port machinery. + + Changes with FreeUnit 1.35.4 30 Apr 2026 *) Security: all official Docker images now ship diff --git a/source/conf.py b/source/conf.py index 37efa1f1..493bd297 100644 --- a/source/conf.py +++ b/source/conf.py @@ -5,8 +5,8 @@ project = 'FreeUnit' author = 'FreeUnit Community' copyright = '2026' -version = '1.35.4' -release_date = 'Apr 30, 2026' +version = '1.36.0' +release_date = 'Jul 16, 2026' release = version needs_sphinx = '6.2' diff --git a/source/news/2026/index.rst b/source/news/2026/index.rst index 35d9d09e..cd77a1ea 100644 --- a/source/news/2026/index.rst +++ b/source/news/2026/index.rst @@ -5,6 +5,28 @@ News of 2026 News archive for the year 2026. +.. nxt_news_entry:: + :author: FreeUnit Team + :description: Security and correctness hardening — config NUL/empty + rejection, rootfs mount TOCTOU, proxy response-smuggling, + libunit/Java bounds; SIGQUIT graceful stop; wasmtime 36. + Two advisories: GHSA-768w-qrh2-jjvh and GHSA-g6v8-r577-76jm. + :email: team@freeunit.org + :title: Unit 1.36.0 Released + :url: news/2026/unit-1.36.0-released + :date: 2026-07-16 + +.. nxt_news_entry:: + :author: FreeUnit Team + :description: Promote chunked_transform out of experimental (auto-convert + chunked request bodies to Content-Length); fix a TLS SSL_write + busy-loop on peer close; plug cert/script-store and + port-machinery memory/fd leaks; upgrade njs to 0.9.8. + :email: team@freeunit.org + :title: Unit 1.35.5 Released + :url: news/2026/unit-1.35.5-released + :date: 2026-05-29 + .. nxt_news_entry:: :author: FreeUnit Team :description: Fix router CPU spin and connection hang under port scanning diff --git a/source/news/2026/unit-1.35.5-released.rst b/source/news/2026/unit-1.35.5-released.rst new file mode 100644 index 00000000..c82eebdf --- /dev/null +++ b/source/news/2026/unit-1.35.5-released.rst @@ -0,0 +1,80 @@ +:orphan: + +#################### +Unit 1.35.5 Released +#################### + +FreeUnit 1.35.5 promotes chunked request-body transformation out of +experimental status, fixes a TLS busy-loop on peer-initiated close, plugs a +set of memory and file-descriptor leaks in the port machinery, and upgrades +njs. + +**Proxy / HTTP** + +- Chunked request bodies are now automatically converted to ``Content-Length`` + when forwarded upstream via a ``proxy`` action, for backends that do not + accept ``Transfer-Encoding: chunked`` (e.g. Gitea). Resolves the client-side + chunked, duplicate ``Transfer-Encoding``, and RFC 9112 framing issues. +- The ``chunked_transform`` setting is **no longer experimental** — enable it + with ``{"settings": {"http": {"chunked_transform": true}}}``. + +**TLS** + +- Fixed a busy-loop in ``SSL_write`` on a peer-initiated close when the + connection is aborted by the remote peer, which caused high CPU usage; + the connection is now cleaned up properly. + +**Reliability** + +- Fixed a mem-pool retain leak in the cert/script-store IPC paths (router + side) and fd/buffer leaks in the cert/script/socket/access-log reply paths + and the controller config-store path (main process side) — all reachable + when ``nxt_port_msg_alloc`` fails inside the port machinery. + +**Tooling** + +- Added ``unfreeze-sync.sh`` for automated migration of issues from + ``nginx/unit`` to ``freeunitorg/freeunit`` with label mapping, deduplication, + and dry-run preview. + +**Dependencies** + +- Upgraded contrib njs to 0.9.8. + +************** +Full Changelog +************** + +.. code-block:: none + + Changes with FreeUnit 1.35.5 29 May 2026 + + *) Feature: automatically convert chunked request bodies to Content-Length + when forwarding to upstream servers via proxy action. This enables + compatibility with backends that do not support Transfer-Encoding: + chunked (e.g., Gitea, servers requiring Content-Length). Fixes + freeunitorg/freeunit#58, resolves nginx/unit#445 (client chunked), + nginx/unit#1088 (duplicate TE), and nginx/unit#1278 (RFC 9112 epic). + + *) Change: chunked_transform feature is no longer experimental. Chunked + request bodies can be accepted and transparently converted to + Content-Length via configuration: { "settings": { "http": + { "chunked_transform": true } } } + + *) Bugfix: fix TLS library busy-loop on peer-initiated close in SSL_write + when connection is aborted by remote peer; prevents high CPU usage and + ensures proper connection cleanup. + + *) Feature: add unfreeze-sync.sh script for automated migration of issues + from nginx/unit to freeunitorg/freeunit with label mapping, deduplication, + and dry-run preview support. + + *) Change: upgrade contrib njs to 0.9.8. + + *) Bugfix: fix mem-pool retain leak in cert/script-store IPC paths + (router side) and fd/buffer leaks in cert/script/socket/access-log + reply paths and the controller config-store path (main process + side); all reachable when nxt_port_msg_alloc fails inside the + port machinery. + + diff --git a/source/news/2026/unit-1.36.0-released.rst b/source/news/2026/unit-1.36.0-released.rst new file mode 100644 index 00000000..2eea259c --- /dev/null +++ b/source/news/2026/unit-1.36.0-released.rst @@ -0,0 +1,293 @@ +:orphan: + +#################### +Unit 1.36.0 Released +#################### + +FreeUnit 1.36.0 is a security and correctness hardening release. It closes a +set of local privilege-boundary and memory-safety issues (covered by two +security advisories), adds a graceful ``SIGQUIT`` stop that drains in-flight +requests before exit, and upgrades the WebAssembly runtime. + +**Security hardening** + +- **Config validation:** reject empty values and embedded NUL bytes in + configuration strings later used as NUL-terminated C strings (``user``, + ``group``, ``working_directory``, ``stdout``/``stderr``, ``executable``, + the per-language application targets, ``access_log``, the TLS certificate, + the njs ``js_module``, and PHP ``options.file``) and in pathname unix + socket addresses — closing a silent-truncation target confusion. +- **Static serving:** reject embedded NUL bytes in templated ``share`` and + ``chroot`` paths after variable resolution, before ``open()``/``openat2()``. +- **Isolation:** mount rootfs automount destinations through ``/proc/self/fd`` + on the ``openat2``-validated descriptor, closing a symlink-swap TOCTOU that + could escape the rootfs. +- **Proxy:** treat a duplicate upstream ``Content-Length`` as inconsistent + (drop both, read to EOF) to prevent a response-smuggling desync, and keep + downstream keep-alive disabled afterward so an HTTP/1.1 client cannot reuse + the connection past the re-framed response. +- **libunit:** bound the request header-fields region against the shared + memory message size, validate serialized pointers and cached header + indexes, and range-check the Java ``InputStream.read()`` binding — + preventing out-of-bounds access on malformed requests. +- **Controller:** fix a debug-build crash and an accepted-fd leak on + control-connection close and failure paths. +- **OpenTelemetry:** restart a malformed W3C ``traceparent`` instead of + failing the request with HTTP 500, and zero-initialize injected trace + fields (garbage flag bits could otherwise drop the header at random). +- **Go module:** fix a libunit port-fd double-close race. + +Two advisories were published with this release (CVEs pending): + +- `GHSA-768w-qrh2-jjvh `_ + — control-socket peer-authentication bypass, cgroup-namespace TOCTOU, and + mount-destination TOCTOU (CVSS 8.8). +- `GHSA-g6v8-r577-76jm `_ + — WebSocket out-of-bounds read and cross-frame data disclosure (CVSS 7.5). + +Both are fixed in 1.36.0 and backported to the 1.34.x LTS line. + +**Graceful shutdown** + +- ``SIGQUIT`` now performs a graceful stop: application workers drain their + in-flight requests before exiting. ``SIGTERM`` remains the fast exit. + +**Dependencies** + +- wasm-wasi-component wasmtime crates upgraded 35.0.0 → 36.0.12, clearing the + sandbox-escape advisories. + +************** +Full Changelog +************** + +.. code-block:: none + + Changes with FreeUnit 1.36.0 16 Jul 2026 + + *) Bugfix: the controller crashed in debug builds when a control-socket + connection closed after the active-connection tracking change, and + leaked the accepted file descriptor when a control connection failed + during initialization or body allocation; connection tracking and + teardown now route through the engine's tracking macros and the + close path. + + *) Bugfix: ignore a malformed incoming "traceparent" header and restart + the trace per W3C Trace Context instead of rejecting the request + with HTTP 500; the malformed header is dropped instead of being + forwarded alongside the restarted one, and context accepted from a + valid duplicate is preserved. Values are now validated in full + (segment lengths, lowercase hex, no all-zero ids, no "ff" version), + so content-invalid values restart the trace instead of being + re-emitted verbatim. An inbound "tracestate" is dropped together + with the rejected context (kept when the traceparent is inherited). + The injected "traceparent" fields are now zero-initialized; garbage + flag bits could get the header randomly dropped from proxied + requests and responses. + + *) Bugfix: reject empty values and embedded NUL bytes in configuration + strings that are later used as NUL-terminated C strings ("user", + "group", "working_directory", "stdout", "stderr", "executable", and + the per-language application targets) and in pathname unix socket + addresses, closing a silent-truncation target confusion. + + *) Bugfix: reject empty values and embedded NUL bytes in the remaining + configuration strings used as NUL-terminated C strings outside + application options: the "access_log" path (string and object + forms), the TLS "certificate" and njs "js_module" store names, and + the PHP "options.file" php.ini path. + + *) Bugfix: reject an embedded NUL byte in a templated static-serving + path ("share" and "chroot") after it is resolved from + request-controlled variables and before it reaches open()/openat2(), + preventing a silent truncation that could serve a different file + than the resolved path. + + *) Bugfix: mount rootfs automount destinations onto the openat2 + validated descriptor via "/proc/self/fd" instead of re-resolving the + path, closing a check-to-use window in which a destination component + could be swapped for a symlink escaping the rootfs. + + *) Bugfix: treat duplicate upstream "Content-Length" headers in a + proxied response as inconsistent — both headers are dropped and the + body is read to EOF instead of trusting either length, preventing a + response-smuggling desynchronization. + + *) Bugfix: keep downstream keepalive disabled after a duplicate or invalid + upstream "Content-Length"; a clean upstream close no longer re-enables + it, so an HTTP/1.1 client cannot reuse the connection past the re-framed + response. The complete body still ends with its terminal chunk — body + truncation is now tracked separately from the inconsistent flag. + + *) Bugfix: bound the request-header fields region against the shared + memory message size in libunit, validate every field name/value + serialized pointer and the cached header-field indexes before use, + and range-check off/len in the Java InputStream read() binding, + preventing out-of-bounds access on a malformed request. + + *) Bugfix: fix a libunit port-fd double-close race in the Go language + module: getUnixConn() wrapped the raw shared-port descriptor (which + net.FileConn dups) and a deferred Close() closed the original + descriptor number while libunit still owned it, an intermittent + double-close that raised an EBADF alert or, worse, closed an + unrelated reused live descriptor. Go now dup(2)s the descriptor and + wraps only the dup, so libunit remains the sole owner and closer; + libunit additionally holds a port reference across the out-of-mutex + add_port callback window so a concurrent destroy cannot free the + port mid-callback. + + *) Feature: SIGQUIT now performs a graceful stop — application workers + drain in-flight requests before exiting; SIGTERM remains the fast + exit that drops them. + + *) Change: upgrade the wasm-wasi-component wasmtime crates from 35.0.0 + to 36.0.12, clearing the wasmtime sandbox-escape advisories, with the + accompanying WasiView/WasiHttpView source migration. + + *) Change: upgrade contrib njs to 1.0.0. + + *) Feature: two-phase listener close — reconfiguration disarms a removed + listener first and releases its descriptor only after pending accept + references drain, instead of resetting them. + + *) Change: the event engine now tracks in-flight connections on a + dedicated active connections queue, symmetric with idle tracking — + groundwork for graceful connection draining; connection accounting + in the "/status" API is exact on all close paths. + + *) Change: broaden the regression test suite — proxy Content-Length and + chunked-response relay framing, OpenTelemetry 5xx tracing and inbound + traceparent handling, and Java ServletInputStream bounds — and run + the C unit-test suite in CI, which was previously compiled but never + executed. + + *) Bugfix: authorize privileged IPC message types by the kernel-validated + sender PID (SCM_CREDENTIALS), close any received descriptors on every + rejected privileged message, and cap port queue item size at the slot + data bound. + + *) Bugfix: reject control characters (CR, LF, NUL, DEL) in "set_headers" + names and values at configuration load, including the literal + segments of templated values. + + *) Bugfix: handle buffer-allocation failure in the port read handlers + with an orderly teardown instead of a NULL-pointer dereference, route + a connection write error after a partial send to the error handler + immediately, and free the timer batching array on engine teardown. + + *) Feature: upgrade the OpenTelemetry Rust crates from 0.24 to 0.32 and + rewrite the OTLP trace exporter on the stable, dedicated-thread batch + span processor (blocking reqwest client, no tokio runtime). + + *) Feature: W3C traceparent header inheritance now correctly propagates + the upstream sampling decision; the sampler wraps TraceIdRatioBased + inside ParentBased so that remote parent trace flags are honoured. + + *) Feature: add fake_otlp mock OTLP collector (test/fake_otlp/) and the + test_otel.py test suite covering span export, traceparent + propagation, sampling, and configuration validation over both the + OTLP/HTTP and OTLP/gRPC transports. + + *) Feature: reintroduce OTLP/gRPC trace export. Both transports are + compiled into every "--otel" build and the + "settings/telemetry/protocol" option selects "http" (OTLP/HTTP) or + "grpc" (OTLP/gRPC) at runtime, as in upstream Unit. gRPC uses tonic + over a small tokio runtime; v1 is plaintext h2c only (no TLS to the + collector, like the HTTP path). + + *) Change: rename the default OTel service name from "NGINX Unit" to + "FreeUnit". + + *) Bugfix: add validation bounds for "batch_size" (1-65536) and + "sampling_ratio" (0-1) in the OpenTelemetry configuration; previously + invalid values were silently rejected without an error message. + + *) Bugfix: replace eprintln! error output in the OTel Rust layer with + the C log callback (nxt_otel_log_cb), so errors flow through the + standard Unit logging infrastructure. + + *) Bugfix: remove unreachable Protocol::HttpJson dead-code arm from the + OTel exporter; only HttpBinary was ever selected. + + *) Bugfix: fix a rootfs automount reload race: sever the worker's mount + namespace propagation (MS_REC|MS_PRIVATE) before mounting and let a + per-worker automount be reaped with the namespace instead of being + unmounted from the host, so a configuration reload no longer races the + previous worker generation's teardown against the new prototype's + procfs mount (freeunitorg/freeunit#83). + + *) Bugfix: validate that a loaded TLS private key matches its certificate + at config time, and guard the wildcard-name SAN matcher against a + zero-length SAN entry. + + *) Bugfix: correct IPv4 /32 CIDR fallthrough, symmetric URI/pattern + decoding, the PCRE2 match-data ovector size, and short port-range + parsing in HTTP routing; document the case-insensitive host matcher + and the capset stance. + + *) Bugfix: tighten file-descriptor and CLOEXEC lifetime — CLOEXEC-protect + accepted sockets and pipe ends, close the pipe end on + nxt_fd_nonblocking() failure and the source fd on compression mmap + failure, and narrow the accept4() fallback to ENOSYS. + + *) Bugfix: tighten WebSocket frame-bound checks — reject truncated + extended-length frames in libunit, validate the 64-bit extended-length + MSB (RFC 6455), fix a no-op frame-size decrement that could copy bytes + beyond the declared payload, bound the Java sendWsFrame JNI arguments, + and guard pending_payload_len overflow in the Python ASGI handler. + + *) Bugfix: bounds-check peer-supplied shared-memory offsets — range-check + chunk_id and chunk_id+nchunks in incoming mmap messages, close a + lookup/dereference window on the incoming-mmap handler, reject + response-buffer size overflow, and validate request sptr offsets + before use. + + *) Bugfix: bounds-check app-supplied arguments across the language + bindings (PHP header skip / realpath / PATH_INFO; Python WSGI and ASGI + checks; Perl ERRSV scrub; Java InputStream.readLine off/len; WASM + guest offsets). + + *) Bugfix: tighten isolation boundaries — require a matching peer UID + (root or Unit's own effective UID) on the unix control socket, so the + "control-user", "control-group", and "control-mode" permissions are + defense-in-depth rather than a means to delegate control-API access; + resolve mount destinations with openat2(RESOLVE_BENEATH); and resolve + relative cgroup paths against the child's /proc//cgroup. + + *) Bugfix: reject embedded NUL bytes in the "rootfs" and cgroup "path" + isolation options, and validate "rootfs" as an absolute path other + than "/" at configuration time. + + *) Bugfix: fix an ineffective truncation guard when building the + cgroup.procs pathname: snprintf()'s return value overwrote the + original directory length before the bounds comparison, so a long + cgroup directory path could overflow the check. The append now + preserves the original length and fails with ENAMETOOLONG when + "/cgroup.procs" plus the trailing NUL cannot fit. + + *) Bugfix: fail cgroup setup when the per-process pool allocation that + caches the created directory for cleanup fails; the directory is now + removed and setup errors out, rather than moving the process into a + cgroup that could never be cleaned up — a cgroup directory leak under + memory pressure. + + *) Bugfix: reject a "rootfs" that lexically resolves to "/" (such as + "/.", "/..", or "/foo/.."); chroot("/") is a no-op and would silently + defeat rootfs isolation. + + *) Bugfix: cap JSON parser depth and element counts in the controller, + scrub PHP TrueAsync exception state before the prototype fork, and bind + the Ruby rack.input / rack.errors handles to their originating request. + + *) Bugfix: bound proxy Content-Length and URI/string helpers — truncate a + proxied response body that exceeds its Content-Length and close the + connection, flag invalid or oversized upstream Content-Length, fix an + nxt_is_complex_uri_encoded() off-by-one, and reject over-long lengths + in nxt_rmemstrn(). + + *) Feature: enforce the runtime/OS end-of-life policy automatically — the + unit-eol-check tool now fails when a shipped variant has outlived its + support window (supported_until past EOL + grace), and a new + eol-check GitHub workflow validates pkg/eol.json against endoflife.date + on every relevant pull request and weekly on a schedule. +