Skip to content

Commit 2428a57

Browse files
andypostclaude
andcommitted
docs(release): 1.36.0 site update
Bump the documented version to 1.36.0 (Jul 16, 2026) in conf.py — this cascades through |version| across the site — refresh source/CHANGES.txt from the main repo (adds the 1.36.0 entry and the previously-missing 1.35.5 entry), and add the "Unit 1.36.0 Released" news announcement with the two security advisories (GHSA-768w-qrh2-jjvh, GHSA-g6v8-r577-76jm) and the full changelog. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DYcuURscruaF1yNVHJHW3C
1 parent f03c594 commit 2428a57

5 files changed

Lines changed: 657 additions & 2 deletions

File tree

source/CHANGES.txt

Lines changed: 260 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,263 @@
1+
Changes with FreeUnit 1.36.0 16 Jul 2026
2+
3+
*) Bugfix: the controller crashed in debug builds when a control-socket
4+
connection closed after the active-connection tracking change, and
5+
leaked the accepted file descriptor when a control connection failed
6+
during initialization or body allocation; connection tracking and
7+
teardown now route through the engine's tracking macros and the
8+
close path.
9+
10+
*) Bugfix: ignore a malformed incoming "traceparent" header and restart
11+
the trace per W3C Trace Context instead of rejecting the request
12+
with HTTP 500; the malformed header is dropped instead of being
13+
forwarded alongside the restarted one, and context accepted from a
14+
valid duplicate is preserved. Values are now validated in full
15+
(segment lengths, lowercase hex, no all-zero ids, no "ff" version),
16+
so content-invalid values restart the trace instead of being
17+
re-emitted verbatim. An inbound "tracestate" is dropped together
18+
with the rejected context (kept when the traceparent is inherited).
19+
The injected "traceparent" fields are now zero-initialized; garbage
20+
flag bits could get the header randomly dropped from proxied
21+
requests and responses.
22+
23+
*) Bugfix: reject empty values and embedded NUL bytes in configuration
24+
strings that are later used as NUL-terminated C strings ("user",
25+
"group", "working_directory", "stdout", "stderr", "executable", and
26+
the per-language application targets) and in pathname unix socket
27+
addresses, closing a silent-truncation target confusion.
28+
29+
*) Bugfix: reject empty values and embedded NUL bytes in the remaining
30+
configuration strings used as NUL-terminated C strings outside
31+
application options: the "access_log" path (string and object
32+
forms), the TLS "certificate" and njs "js_module" store names, and
33+
the PHP "options.file" php.ini path.
34+
35+
*) Bugfix: reject an embedded NUL byte in a templated static-serving
36+
path ("share" and "chroot") after it is resolved from
37+
request-controlled variables and before it reaches open()/openat2(),
38+
preventing a silent truncation that could serve a different file
39+
than the resolved path.
40+
41+
*) Bugfix: mount rootfs automount destinations onto the openat2
42+
validated descriptor via "/proc/self/fd" instead of re-resolving the
43+
path, closing a check-to-use window in which a destination component
44+
could be swapped for a symlink escaping the rootfs.
45+
46+
*) Bugfix: treat duplicate upstream "Content-Length" headers in a
47+
proxied response as inconsistent — both headers are dropped and the
48+
body is read to EOF instead of trusting either length, preventing a
49+
response-smuggling desynchronization.
50+
51+
*) Bugfix: keep downstream keepalive disabled after a duplicate or invalid
52+
upstream "Content-Length"; a clean upstream close no longer re-enables
53+
it, so an HTTP/1.1 client cannot reuse the connection past the re-framed
54+
response. The complete body still ends with its terminal chunk — body
55+
truncation is now tracked separately from the inconsistent flag.
56+
57+
*) Bugfix: bound the request-header fields region against the shared
58+
memory message size in libunit, validate every field name/value
59+
serialized pointer and the cached header-field indexes before use,
60+
and range-check off/len in the Java InputStream read() binding,
61+
preventing out-of-bounds access on a malformed request.
62+
63+
*) Bugfix: fix a libunit port-fd double-close race in the Go language
64+
module: getUnixConn() wrapped the raw shared-port descriptor (which
65+
net.FileConn dups) and a deferred Close() closed the original
66+
descriptor number while libunit still owned it, an intermittent
67+
double-close that raised an EBADF alert or, worse, closed an
68+
unrelated reused live descriptor. Go now dup(2)s the descriptor and
69+
wraps only the dup, so libunit remains the sole owner and closer;
70+
libunit additionally holds a port reference across the out-of-mutex
71+
add_port callback window so a concurrent destroy cannot free the
72+
port mid-callback.
73+
74+
*) Feature: SIGQUIT now performs a graceful stop — application workers
75+
drain in-flight requests before exiting; SIGTERM remains the fast
76+
exit that drops them.
77+
78+
*) Change: upgrade the wasm-wasi-component wasmtime crates from 35.0.0
79+
to 36.0.12, clearing the wasmtime sandbox-escape advisories, with the
80+
accompanying WasiView/WasiHttpView source migration.
81+
82+
*) Change: upgrade contrib njs to 1.0.0.
83+
84+
*) Feature: two-phase listener close — reconfiguration disarms a removed
85+
listener first and releases its descriptor only after pending accept
86+
references drain, instead of resetting them.
87+
88+
*) Change: the event engine now tracks in-flight connections on a
89+
dedicated active connections queue, symmetric with idle tracking —
90+
groundwork for graceful connection draining; connection accounting
91+
in the "/status" API is exact on all close paths.
92+
93+
*) Change: broaden the regression test suite — proxy Content-Length and
94+
chunked-response relay framing, OpenTelemetry 5xx tracing and inbound
95+
traceparent handling, and Java ServletInputStream bounds — and run
96+
the C unit-test suite in CI, which was previously compiled but never
97+
executed.
98+
99+
*) Bugfix: authorize privileged IPC message types by the kernel-validated
100+
sender PID (SCM_CREDENTIALS), close any received descriptors on every
101+
rejected privileged message, and cap port queue item size at the slot
102+
data bound.
103+
104+
*) Bugfix: reject control characters (CR, LF, NUL, DEL) in "set_headers"
105+
names and values at configuration load, including the literal
106+
segments of templated values.
107+
108+
*) Bugfix: handle buffer-allocation failure in the port read handlers
109+
with an orderly teardown instead of a NULL-pointer dereference, route
110+
a connection write error after a partial send to the error handler
111+
immediately, and free the timer batching array on engine teardown.
112+
113+
*) Feature: upgrade the OpenTelemetry Rust crates from 0.24 to 0.32 and
114+
rewrite the OTLP trace exporter on the stable, dedicated-thread batch
115+
span processor (blocking reqwest client, no tokio runtime).
116+
117+
*) Feature: W3C traceparent header inheritance now correctly propagates
118+
the upstream sampling decision; the sampler wraps TraceIdRatioBased
119+
inside ParentBased so that remote parent trace flags are honoured.
120+
121+
*) Feature: add fake_otlp mock OTLP collector (test/fake_otlp/) and the
122+
test_otel.py test suite covering span export, traceparent
123+
propagation, sampling, and configuration validation over both the
124+
OTLP/HTTP and OTLP/gRPC transports.
125+
126+
*) Feature: reintroduce OTLP/gRPC trace export. Both transports are
127+
compiled into every "--otel" build and the
128+
"settings/telemetry/protocol" option selects "http" (OTLP/HTTP) or
129+
"grpc" (OTLP/gRPC) at runtime, as in upstream Unit. gRPC uses tonic
130+
over a small tokio runtime; v1 is plaintext h2c only (no TLS to the
131+
collector, like the HTTP path).
132+
133+
*) Change: rename the default OTel service name from "NGINX Unit" to
134+
"FreeUnit".
135+
136+
*) Bugfix: add validation bounds for "batch_size" (1-65536) and
137+
"sampling_ratio" (0-1) in the OpenTelemetry configuration; previously
138+
invalid values were silently rejected without an error message.
139+
140+
*) Bugfix: replace eprintln! error output in the OTel Rust layer with
141+
the C log callback (nxt_otel_log_cb), so errors flow through the
142+
standard Unit logging infrastructure.
143+
144+
*) Bugfix: remove unreachable Protocol::HttpJson dead-code arm from the
145+
OTel exporter; only HttpBinary was ever selected.
146+
147+
*) Bugfix: fix a rootfs automount reload race: sever the worker's mount
148+
namespace propagation (MS_REC|MS_PRIVATE) before mounting and let a
149+
per-worker automount be reaped with the namespace instead of being
150+
unmounted from the host, so a configuration reload no longer races the
151+
previous worker generation's teardown against the new prototype's
152+
procfs mount (freeunitorg/freeunit#83).
153+
154+
*) Bugfix: validate that a loaded TLS private key matches its certificate
155+
at config time, and guard the wildcard-name SAN matcher against a
156+
zero-length SAN entry.
157+
158+
*) Bugfix: correct IPv4 /32 CIDR fallthrough, symmetric URI/pattern
159+
decoding, the PCRE2 match-data ovector size, and short port-range
160+
parsing in HTTP routing; document the case-insensitive host matcher
161+
and the capset stance.
162+
163+
*) Bugfix: tighten file-descriptor and CLOEXEC lifetime — CLOEXEC-protect
164+
accepted sockets and pipe ends, close the pipe end on
165+
nxt_fd_nonblocking() failure and the source fd on compression mmap
166+
failure, and narrow the accept4() fallback to ENOSYS.
167+
168+
*) Bugfix: tighten WebSocket frame-bound checks — reject truncated
169+
extended-length frames in libunit, validate the 64-bit extended-length
170+
MSB (RFC 6455), fix a no-op frame-size decrement that could copy bytes
171+
beyond the declared payload, bound the Java sendWsFrame JNI arguments,
172+
and guard pending_payload_len overflow in the Python ASGI handler.
173+
174+
*) Bugfix: bounds-check peer-supplied shared-memory offsets — range-check
175+
chunk_id and chunk_id+nchunks in incoming mmap messages, close a
176+
lookup/dereference window on the incoming-mmap handler, reject
177+
response-buffer size overflow, and validate request sptr offsets
178+
before use.
179+
180+
*) Bugfix: bounds-check app-supplied arguments across the language
181+
bindings (PHP header skip / realpath / PATH_INFO; Python WSGI and ASGI
182+
checks; Perl ERRSV scrub; Java InputStream.readLine off/len; WASM
183+
guest offsets).
184+
185+
*) Bugfix: tighten isolation boundaries — require a matching peer UID
186+
(root or Unit's own effective UID) on the unix control socket, so the
187+
"control-user", "control-group", and "control-mode" permissions are
188+
defense-in-depth rather than a means to delegate control-API access;
189+
resolve mount destinations with openat2(RESOLVE_BENEATH); and resolve
190+
relative cgroup paths against the child's /proc/<pid>/cgroup.
191+
192+
*) Bugfix: reject embedded NUL bytes in the "rootfs" and cgroup "path"
193+
isolation options, and validate "rootfs" as an absolute path other
194+
than "/" at configuration time.
195+
196+
*) Bugfix: fix an ineffective truncation guard when building the
197+
cgroup.procs pathname: snprintf()'s return value overwrote the
198+
original directory length before the bounds comparison, so a long
199+
cgroup directory path could overflow the check. The append now
200+
preserves the original length and fails with ENAMETOOLONG when
201+
"/cgroup.procs" plus the trailing NUL cannot fit.
202+
203+
*) Bugfix: fail cgroup setup when the per-process pool allocation that
204+
caches the created directory for cleanup fails; the directory is now
205+
removed and setup errors out, rather than moving the process into a
206+
cgroup that could never be cleaned up — a cgroup directory leak under
207+
memory pressure.
208+
209+
*) Bugfix: reject a "rootfs" that lexically resolves to "/" (such as
210+
"/.", "/..", or "/foo/.."); chroot("/") is a no-op and would silently
211+
defeat rootfs isolation.
212+
213+
*) Bugfix: cap JSON parser depth and element counts in the controller,
214+
scrub PHP TrueAsync exception state before the prototype fork, and bind
215+
the Ruby rack.input / rack.errors handles to their originating request.
216+
217+
*) Bugfix: bound proxy Content-Length and URI/string helpers — truncate a
218+
proxied response body that exceeds its Content-Length and close the
219+
connection, flag invalid or oversized upstream Content-Length, fix an
220+
nxt_is_complex_uri_encoded() off-by-one, and reject over-long lengths
221+
in nxt_rmemstrn().
222+
223+
*) Feature: enforce the runtime/OS end-of-life policy automatically — the
224+
unit-eol-check tool now fails when a shipped variant has outlived its
225+
support window (supported_until past EOL + grace), and a new
226+
eol-check GitHub workflow validates pkg/eol.json against endoflife.date
227+
on every relevant pull request and weekly on a schedule.
228+
229+
230+
Changes with FreeUnit 1.35.5 29 May 2026
231+
232+
*) Feature: automatically convert chunked request bodies to Content-Length
233+
when forwarding to upstream servers via proxy action. This enables
234+
compatibility with backends that do not support Transfer-Encoding:
235+
chunked (e.g., Gitea, servers requiring Content-Length). Fixes
236+
freeunitorg/freeunit#58, resolves nginx/unit#445 (client chunked),
237+
nginx/unit#1088 (duplicate TE), and nginx/unit#1278 (RFC 9112 epic).
238+
239+
*) Change: chunked_transform feature is no longer experimental. Chunked
240+
request bodies can be accepted and transparently converted to
241+
Content-Length via configuration: { "settings": { "http":
242+
{ "chunked_transform": true } } }
243+
244+
*) Bugfix: fix TLS library busy-loop on peer-initiated close in SSL_write
245+
when connection is aborted by remote peer; prevents high CPU usage and
246+
ensures proper connection cleanup.
247+
248+
*) Feature: add unfreeze-sync.sh script for automated migration of issues
249+
from nginx/unit to freeunitorg/freeunit with label mapping, deduplication,
250+
and dry-run preview support.
251+
252+
*) Change: upgrade contrib njs to 0.9.8.
253+
254+
*) Bugfix: fix mem-pool retain leak in cert/script-store IPC paths
255+
(router side) and fd/buffer leaks in cert/script/socket/access-log
256+
reply paths and the controller config-store path (main process
257+
side); all reachable when nxt_port_msg_alloc fails inside the
258+
port machinery.
259+
260+
1261
Changes with FreeUnit 1.35.4 30 Apr 2026
2262

3263
*) Security: all official Docker images now ship

source/conf.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@
55
project = 'FreeUnit'
66
author = 'FreeUnit Community'
77
copyright = '2026'
8-
version = '1.35.4'
9-
release_date = 'Apr 30, 2026'
8+
version = '1.36.0'
9+
release_date = 'Jul 16, 2026'
1010
release = version
1111
needs_sphinx = '6.2'
1212

source/news/2026/index.rst

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,28 @@ News of 2026
55

66
News archive for the year 2026.
77

8+
.. nxt_news_entry::
9+
:author: FreeUnit Team
10+
:description: Security and correctness hardening — config NUL/empty
11+
rejection, rootfs mount TOCTOU, proxy response-smuggling,
12+
libunit/Java bounds; SIGQUIT graceful stop; wasmtime 36.
13+
Two advisories: GHSA-768w-qrh2-jjvh and GHSA-g6v8-r577-76jm.
14+
:email: team@freeunit.org
15+
:title: Unit 1.36.0 Released
16+
:url: news/2026/unit-1.36.0-released
17+
:date: 2026-07-16
18+
19+
.. nxt_news_entry::
20+
:author: FreeUnit Team
21+
:description: Promote chunked_transform out of experimental (auto-convert
22+
chunked request bodies to Content-Length); fix a TLS SSL_write
23+
busy-loop on peer close; plug cert/script-store and
24+
port-machinery memory/fd leaks; upgrade njs to 0.9.8.
25+
:email: team@freeunit.org
26+
:title: Unit 1.35.5 Released
27+
:url: news/2026/unit-1.35.5-released
28+
:date: 2026-05-29
29+
830
.. nxt_news_entry::
931
:author: FreeUnit Team
1032
:description: Fix router CPU spin and connection hang under port scanning
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
:orphan:
2+
3+
####################
4+
Unit 1.35.5 Released
5+
####################
6+
7+
FreeUnit 1.35.5 promotes chunked request-body transformation out of
8+
experimental status, fixes a TLS busy-loop on peer-initiated close, plugs a
9+
set of memory and file-descriptor leaks in the port machinery, and upgrades
10+
njs.
11+
12+
**Proxy / HTTP**
13+
14+
- Chunked request bodies are now automatically converted to ``Content-Length``
15+
when forwarded upstream via a ``proxy`` action, for backends that do not
16+
accept ``Transfer-Encoding: chunked`` (e.g. Gitea). Resolves the client-side
17+
chunked, duplicate ``Transfer-Encoding``, and RFC 9112 framing issues.
18+
- The ``chunked_transform`` setting is **no longer experimental** — enable it
19+
with ``{"settings": {"http": {"chunked_transform": true}}}``.
20+
21+
**TLS**
22+
23+
- Fixed a busy-loop in ``SSL_write`` on a peer-initiated close when the
24+
connection is aborted by the remote peer, which caused high CPU usage;
25+
the connection is now cleaned up properly.
26+
27+
**Reliability**
28+
29+
- Fixed a mem-pool retain leak in the cert/script-store IPC paths (router
30+
side) and fd/buffer leaks in the cert/script/socket/access-log reply paths
31+
and the controller config-store path (main process side) — all reachable
32+
when ``nxt_port_msg_alloc`` fails inside the port machinery.
33+
34+
**Tooling**
35+
36+
- Added ``unfreeze-sync.sh`` for automated migration of issues from
37+
``nginx/unit`` to ``freeunitorg/freeunit`` with label mapping, deduplication,
38+
and dry-run preview.
39+
40+
**Dependencies**
41+
42+
- Upgraded contrib njs to 0.9.8.
43+
44+
**************
45+
Full Changelog
46+
**************
47+
48+
.. code-block:: none
49+
50+
Changes with FreeUnit 1.35.5 29 May 2026
51+
52+
*) Feature: automatically convert chunked request bodies to Content-Length
53+
when forwarding to upstream servers via proxy action. This enables
54+
compatibility with backends that do not support Transfer-Encoding:
55+
chunked (e.g., Gitea, servers requiring Content-Length). Fixes
56+
freeunitorg/freeunit#58, resolves nginx/unit#445 (client chunked),
57+
nginx/unit#1088 (duplicate TE), and nginx/unit#1278 (RFC 9112 epic).
58+
59+
*) Change: chunked_transform feature is no longer experimental. Chunked
60+
request bodies can be accepted and transparently converted to
61+
Content-Length via configuration: { "settings": { "http":
62+
{ "chunked_transform": true } } }
63+
64+
*) Bugfix: fix TLS library busy-loop on peer-initiated close in SSL_write
65+
when connection is aborted by remote peer; prevents high CPU usage and
66+
ensures proper connection cleanup.
67+
68+
*) Feature: add unfreeze-sync.sh script for automated migration of issues
69+
from nginx/unit to freeunitorg/freeunit with label mapping, deduplication,
70+
and dry-run preview support.
71+
72+
*) Change: upgrade contrib njs to 0.9.8.
73+
74+
*) Bugfix: fix mem-pool retain leak in cert/script-store IPC paths
75+
(router side) and fd/buffer leaks in cert/script/socket/access-log
76+
reply paths and the controller config-store path (main process
77+
side); all reachable when nxt_port_msg_alloc fails inside the
78+
port machinery.
79+
80+

0 commit comments

Comments
 (0)