ngx_mruby v2.7.4
ngx_mruby 2.7.4 is a maintenance release of the 2.x line.
It fixes a security issue of the stream module, with its advisory (GHSA-xjh6-6vgm-56wj, Moderate): entries 1 and 2 under “Behavior changes: read before upgrading”.
Behavior changes: read before upgrading
Section titled “Behavior changes: read before upgrading”1. Nginx::Stream::Connection.proxy_protocol_addr and proxy_protocol_ip return nil for a connection without a PROXY source address
Section titled “1. Nginx::Stream::Connection.proxy_protocol_addr and proxy_protocol_ip return nil for a connection without a PROXY source address”- Before: with nginx 1.17.6 and later,
Nginx::Stream::Connection.proxy_protocol_addrandNginx::Stream::Connection.proxy_protocol_ip, as class and as instance methods, did not return a value for a connection that had no source address from a PROXY protocol header: on a listen withoutproxy_protocol, and after the headerPROXY UNKNOWN(version 1) or a version 2 header with the commandLOCAL. - Now: the methods return
nilfor such a connection. After a header that carries addresses, they return its source address as before. - Why it changed:
- The defect: the methods returned no value for such a connection, as “Before” describes. The advisory GHSA-xjh6-6vgm-56wj describes the defect, the affected versions and the conditions.
- Why the old behavior could not be kept: such a connection has no address
to return, and
niltells it apart from a connection with one. In HTTP code,Nginx::Var#proxy_protocol_addrreturnsnilin the same case. - What the documentation promised: the methods were not documented.
docs/class_
and_ describes them now.method/README.md
- Affected:
mruby_streamandmruby_stream_codecode that calls these methods on a connection without a PROXY source address. - What to do: nothing for code that compares the result with a String. Code
that calls a String method on the result handles
nil, for example withto_s.
2. While the code of a TCP stream session sleeps, nginx reads nothing from the client, and worker_shutdown_timeout ends the session
Section titled “2. While the code of a TCP stream session sleeps, nginx reads nothing from the client, and worker_shutdown_timeout ends the session”- Before: while the code of a TCP session waited in
Nginx::Stream::Async.sleep, the read events of the connection were handled as before the code ran. On a listen withproxy_protocol, bytes that the client sent during the sleep could end the session (status 400 in the access log). Whenworker_shutdown_timeoutexpired during the sleep, the session did not end then. - Now: while the code sleeps, nginx reads nothing from the client. The bytes
that the client sends then stay for the phase after the code:
proxy_passsends them to the upstream. A client that closes the connection during the sleep is seen by the phase after the code, as on a listen withoutproxy_protocol. Whenworker_shutdown_timeoutexpires during the sleep, the session ends, and the code does not run again. - Why it changed:
- The defect: the read events during the sleep were handled as before the code ran, as “Before” describes. The advisory GHSA-xjh6-6vgm-56wj describes the defect, the affected versions and the conditions.
- Why the old behavior could not be kept: the bytes after the header
belong to the protocol that the later phases carry. A session that does
not end at
worker_shutdown_timeoutkeeps the old worker process after the time that the directive sets. - What the documentation promised:
docs/class_
and_ said nothing about reads during the sleep. nginx’s documentation ofmethod/README.md worker_shutdown_timeoutsays that nginx tries to close the open connections when the timeout expires.
- Affected: stream servers whose
mruby_streamormruby_stream_codecode callsNginx::Stream::Async.sleepon a TCP listen: the clients that send bytes or close the connection during the sleep on a listen withproxy_protocol, and a worker that shuts down (a reload, an upgrade, a stop) withworker_shutdown_timeoutwhile the code sleeps. - What to do: nothing. The phase after the code gets the bytes of the client, as on a session whose code does not sleep.
- Not changed by this release: a UDP session. Each datagram of its client
during the sleep runs the code again, as in 2.7.3, and
worker_shutdown_timeoutdoes not end a UDP session whose code sleeps.
New features
Section titled “New features”None.
None.
Build and test changes
Section titled “Build and test changes”- Tests:
test/t/cases/stream_proxy_protocol_wait.rbwithtest/conf/conf.d/stream/48-proxy-protocol-wait.conf(port 12384), and the modestream_masteroftest/t/cases/_second_instance.rb, a second nginx with a master process and one worker on ports 12385 to 12388.test/t/cases/_tcp_client.rbcan write a second payload 0.3 seconds after the first. - CI: a ready pull request that changes the code or the tests runs four cells of the
buildmatrix oftest.yml, not every cell (the 16 combinations of nginx version, link mode and--with-openssl-src, and the sanitizer cell). The four cells are nginx 1.31.8 with the static module and--with-openssl-src, nginx 1.30.6 with the dynamic module, the sanitizer cell (AddressSanitizer and UndefinedBehaviorSanitizer) and the cell under valgrind; the last two build nginx 1.31.8 with the static module. Every cell runs in the nightly run under valgrind, on the push of a tag, on a pull request with the new labelfull-matrix(the check pull request before a tag), and on “Run workflow” without the inputbaseor with the inputvalgrind. A push to av*.xbranch runs no build, as a push tomasterornextdoes not.test/ci/changes.sh, the same script as onnextagain, takes the run as options (--label,--draft,--push,--tag,--dispatch,--valgrind) and givesbuildstandard,fullornone(“Which jobs a run starts” in docs/test/README.md) (#704)
Upgrading
Section titled “Upgrading”- No directive was added, renamed or removed. Rebuild the module with this release the way you built 2.7.3, and replace the binary or the dynamic module as usual.
Check these before upgrading. Each line is the “What to do” of its entry above.
Nginx::Stream::Connection.proxy_protocol_addrandproxy_protocol_ip: nothing for code that compares the result with a String. Code that calls a String method on the result handlesnil, for example withto_s(entry 1).- The reads of a TCP stream session during
Nginx::Stream::Async.sleep: nothing (entry 2).