Mia Kanashi [Wed, 6 May 2026 21:17:39 +0000 (00:17 +0300)]
MEDIUM: tools: read_line_to_trash() handle empty files without \n
fgets() returns NULL when EOF is reached before newline, handle
that as a success for consistency, current behaviour is arguably a bug,
the API of fgets() is pretty weird after all so someone probably forgot.
BUG/MEDIUM: mux-h2: Properly consume padding for DATA frames
Since the commit 617592c9e ("MEDIUM: mux-h2: try to coalesce outgoing
WINDOW_UPDATE frames"), padding of DATA frames is no longer
consumed. Instead, this padidng is left in the demux buffer and used as the
header of the next frame. Because all bytes of the padding must be zero,
this lead to trigger a PROTOCOL_ERROR because haproxy erroneously thinks the
peer sent a DATA frame for the stream-id 0. It is true for a padding of 9
bytes or more, but similar issues may be exprienced with smaller padding.
Before the commit above, the padding was consumed in h2_process_demux to
restore the H2_CS_FRAME_H state at the end of the while loop processing
received frames.
However, it seems a bit strange to deal with the padding at this stage,
espcially because it is not obvious at all. So to fix the issue, the padding
is now consumed at the end of h2_frt_transfer_data(), inside "end_tranfer"
label. At the stage, we know all payload of the current DATA frame were
consumed and only the padding is still there, if any. We must only take care
to not consume more than available in the demux buffer. The padding may have
been partially received.
This patch should fix the issue #3354. It must be backported as far as 2.8.
MEDIUM: mux-h1: Return an error on h2 upgrade attempts if not allowed
If h1 to h2 upgrades are not allowed, a 405-method-not-allowed error is now
returned from the H1 multiplexer itself instead of dealing with "PRI *
HTTP/2.0\r\n\r\n" request as a normal request.
Before this kind of request was caught by the HTTP analyzers and a
400-bad-request was returned. This was added before the multiplexers era to
protect backend apps against unexpected H1 to H2 uprade on server side.
Now, it is possible to handle the error in the H1 multiplexer. One benefit
is to be able to increment the glichtes counters. However, the error is
still handled in HTTP analyzers to be sure to detect unwanted upgrades that
can be hidden in H2 or H3 requests.
There is a special case. TCP > H1 > H2 upgrades. In that case, a H1 stream
exist. So we must report an error to the upper layer too.
A reg-test script was added to validate the feature. In addition,
tcp_to_http_upgrade.vtc was updated accordingly.
BUG/MINOR: mux_quic: refresh timeout only if I/O performed
Previously, QUIC MUX timeout was refreshed on every qcc_io_cb()
execution. This is not desired if no send/receive were performed, as in
this case the connection may be stuck.
This patch fixes this by refreshing timeout only if some progress is
performed during qcc_io_cb(). To implement this, return value of
qcc_io_recv() has been adjusted to return the number of newly decoded
bytes.
This patch is considered as a bug fix as without it there is a risk of
QUIC MUX inactivity timeout to be less efficient and to maintain a
connection too long.
This should be backported up to 2.8, after a period of observation.
MINOR: mux_quic: release BE conns if reuse definitely blocked
avail_streams callback serves to indicates how many streams can be
attached for a backend connection. On QUIC mux, this relies on several
parameters, first based on static limitation which only decreases over
time, but also on flow control which is dynamically adjusted by the peer
and can be increased or decreased at will.
qcc_is_dead() on the other hand serves to determine if a connection can
be removed. First, it must be inactive (no request in progress). Then,
if a backend connection cannot be reused due to some of the above
limitation reached, it is definitely useless and should be removed as
soon as possible. However, prior to this patch, qcc_is_dead() did not
take into account the same set of parameters than avail_streams : only
if graceful shutdown was initiated by the peer was considered.
The purpose of this patch is to linked these two functions together.
Reuse calcul based on static limits is extracted from avail_streams()
into new qcc_be_is_reusable(). This function is used directly in
qcc_is_dead(), which now for example takes into account the server
max-reuse parameter.
This patch should ensure that a backend connection which can not be
reuse anymore is release as soon as possible. This could improve
slightly reuse rate in some specific scenarii as non-reusable
connections should not pollute the idle cache.
Return value of QUIC avail_streams() is changed by this patch as server
max-reuse and max stream ID limits are now only taken into account when
already exceeded or if a single stream remains. However, this has no
consequence as callers of avail_streams() do not differentiates return
value of 2 or more.
However, the calcul is incorrect, as <next_bidi_l> member value is set
to the next ID available, not the last one in use. Also, when the last
stream is closed, it will be greater than QCS_ID_MAX_STRM_CL_BIDI,
resulting in a substraction wrapping.
Fix this by using the simplest approach. Return value of avail_streams()
is only reduced if either the maximum stream ID limit is already
exceeded, or there is only a single stream still usable. In other cases,
return value is left as is.
Note that this bug is unlikely to have any impact as the maximum stream
ID is a very large value.
BUG/MINOR: ssl: Use the sequence number with kTLS and TLS 1.2
When using TLS 1.2 and kTLS, use the sequence number as the explicit
nonce (what the linux kTLS API calls "iv"), as is strongly recommanded,
and done by most TLS implementations, instead of trying to generate a
pseudo random-number.
In practice, it changes nothing, because the kernel would override that
with the sequence number anyway, but there is no need to have confusing
code that uses statistical_prng_range() anyway.
In order for the code behind the "commit ssl cert" logic to be usable
outside of the CLI context, some new "ckch_store_update_" functions are
created. They allow to perform all the operations on ckch_stores to be
performed without needing an appctx.
The first function being called is ckch_store_update_init which mainly
takes the ckch_store lock and checks that there is an ongoing
transaction with the proper path (which was already done in
cli_parse_commit_cert).
The main one is ckch_store_update_process which replicates the logic
that could be found in the cli_io_handler_commit_cert function. We
iterate over the ckch instances of an existing ckch store and duplicate
them in the new ckch store which is still detached from the tree, before
replacing the old store with the new one. This whole operation could
take some time so we were yielding every 10 instances or when
applet_putstr calls would fail. The actual ckch_store operations and the
applet related calls are now decorrelated in order to stop having to
have an appctx during the ckch store/instances processing.
The ckch_store_update_process will now update a "msg" buffer and a
"state" that allow to send processing messages to the caller as well as
keep the state of the processing "state machine".
When the ckch_store_update_process loop is over,
ckch_store_update_cleanup can be called to release the lock and free
some now useless structures.
MINOR: ssl: Factorize ckch instance rebuild process
The ckch instances for a given ckch_store have to be rebuilt when a
certificate is updated during runtime (via cli or lua). The code was
duplicated in lua so factorizing the actual loop avoids future errors
if the code changes. The new 'ckch_store_rebuild_instances' will have a
dedicated 0 return code if it needs to be called again (because of the
yielding logic since ckch instance rebuild might take some time).
Since the previous patch, accounting of HTTP requests in progress on MUX
QUIC as been simplified. Now QCC <nb_hreq> identifies them until the QCS
free.
Thus, MUX_CTL_GET_NBSTRM can be simplified. Instead of relying on
<nb_sc> plus the <opening_list>, simply return <nb_hreq> value which
should be slighly identical.
BUG/MEDIUM: mux_quic: adjust qcc_is_dead() to account detached streams
Muxes are responsible to release connections once they are inactive and
won't be reusable. In QUIC mux, such connections are detected via
qcc_is_dead(). The first precondition is that there is no more upper
streams attached. This was accounted via QCC <nb_sc> counter.
A special characteristic of QCS instances is that they can be in
detached state : upper stream has been removed but there is still data
to emit. Such QCS were not taken into account in qcc_is_dead(), so a
connection could be freed with some remaining data not yet emitted.
It is also not possible for QUIC MUX to simply look at the QCS tree to
determine if the connection is inactive. Indeed, some streams are opened
for protocol internal usage. This is the case for example with HTTP/3
unidirectional control stream or QPACK encoder/decoder streams. These
streams are never closed. In the end, only requests streams should be
taken into account for the connection activity.
This patch improves the situation by reworking <nb_hreq> QCC counter.
Previously, it served for http-request timeout implementation. However,
this timeout only relies on <opening_list> now. Thus, <nb_hreq> scope is
changed : it is now incremented via qcs_wait_http_req(), used by app
protocol layer once a request stream is identified. Decrement is
performed on qcs_free(), so this guarantees that a connection cannot be
freed anymore if request streams still exists, unless if inactivity
timeout fires. As such, <nb_hreq> now supersedes <nb_sc> entirely, so
the qcc_is_dead() can now relies on the former.
Along with this change, qcc_timeout_task() must be updated. Call to
qcc_is_dead() was unnecessary prior to this patch as timeout handling
was only active when no upper streams were attached. When tested, both
<nb_sc> and QCC <task> were already null, so a connection was always
released on timeout, as expected. With qcc_is_dead() now checking
<nb_hreq> instead, this is not always the case anymore. In fact, this
check is unnecessary as inactivity timeout serves precisely to free a
stucked connection with remaining data to emit.
This patch also has some impact on http-keep-alive timeout. Previously,
this timeout could be armed if only detached streams remained. Now, it
is only applicable if all QCS request instances are closed and freed.
Thus, qcc_reset_idle_start() is now closed directly on qcs_free().
Ideally this should be backported up to 2.6, or at least 2.8 as QUIC
experimental status was removed there.
MINOR: mux_quic: do not perform unnecessary timeout handling on BE side
MUX implements a timeout for HTTP keep-alive which monitors the delay
between two HTTP requests. This is only applicable for frontend
connections, as on the backend side idle connections can be kept in the
server pool. In QUIC mux, this timeout relies on QCC <idle_start> which
is refresh when the last request is terminated.
This patch modifies the refresh operation so that it is only performed
for frontend connections. This is not strictly necessary but the timeout
timeout management is now clearer and it eliminates an unnecessary
operation for backend connections.
Similarly, http-request timeout is also only applicable for frontend
connections. This relies on qcs_wait_http_req() function. A request QCS
is inserted in <opening_list> until the headers are received. This is
unnecessary on the backend side so this is excluded as well.
MINOR: mux_quic: reset stream after app shutdown for HTTP/0.9
HTTP/3 implements a GOAWAY frame for graceful shutdown. This allows to
reject any new stream opening with a larger ID. This is implemented via
HTTP/3 attach() callback called by qcs_new().
When HTTP/0.9 is used, there is no similar mechanism. This renders some
feature such as server max-reuse difficult to implement. This patch now
provides a method for such protocols with no graceful shutdown support.
Instead of invoking attach() callback, a stream is now immediately
resetted if the application protocol layer is already closed.
This patch does not change the behavior for HTTP/3. Only limited
protocols (currently only HTTP/0.9) without graceful shutdown are
impacted. These protocols are identified as their shutdown() callback is
nul.
This change is only necessary for HTTP/0.9 as there is no equivalent of
HTTP/3 GOAWAY in this case.
MINOR: haterm: Remove now useless req_body field from hstream
req_body field is no longer used, except in trace messages. And in fact, it
is not necessarily true if some data are received with the request headers.
So no reason to still use it.
BUG/MINOR: haterm: Report a 400-bad-request error on receive error
When an error is reported when reading request data, the hstream now try to
send a 400-bad-request to the client. Before, the connection was just closed
with no error message.
BUG/MINOR: haterm: Fix condition to use direct data forwarding
The direct fowarding support was only relying on "hs->to_write" value. But
we must be sure to retry if fast-forward data are still there in the I/O
buffer.
No client timeout was set with haterm. It could be an issue with
unresponsive clients. So the I/O timeout of the SC is initialized to the
frontend client timeout when the hstream is created. Then a read activity is
reported when data are received. This read activity is used to set an
expiration date on the hstream task and test it when the hstream is woken up
with TASK_WOKEN_TIMER reason.
When a client timeout is detected, the hstream try to send a 408 and report
an error.
BUG/MEDIUM: haterm: Properly handle end of request and end of response
There were several issues with the handling of end of the request or end of
response. The main problem was about the request draining.
To help to fix these issues, two flags were introduced:
* HS_ST_HTTP_EOM_RCVD: to know the request was fully received
* HS_ST_HTTP_EOM_SENT: to know the response was fully sent
Thanks to these flags some parts were reviewed and simplified.
In the I/O callback function, outside of any error, the hstream task is now
woken when one of the direction is not finished or when there are still some
data in a buffer.
The function hstream_must_drain() was reworked to properly drain request
with no content-length before replying.
The condition to wake hstream up to drain the request after replying was
also reworked, and moved ouside of the else block. Indeed, it must also be
evaluated when the response was fully sent in one call, when request headers
were processed.
Finally, the condition to shut the hstream was slighly adapted to use the
new flags. In addition, we now rely on se_shutdown().
BUG/MEDIUM: haterm: Subscribe for receives until request was fully drained
When draining the request, if some data were received, no subscribe for
receives was performed to get the remaining. However, because request data
are just ignored, we must always subscribe until it was fully
drained. Otherwise, haterm will never be woken up to drain more data.
BUG/MINOR: haterm: Fix a possible integer overflow on the request body length
When request data were received, the request body length was decremented
accordingly with no check on it to be sure it was set. However, it remains
equal to 0 for chunked requests or H2/H3 requests with no content-length.
So now, it is only decremented when it is greater than 0.
BUG/MINOR: haterm: Immediately report error when draining the request
When draining the request data, if an error was reported while some data
were received, the error was not processed immediately. This part was copied
from tcpchecks where the response should be processed first. For haterm, the
request data are ignored. So no reason to wait to handle the error. It may
be an issue because the response may be sent in the meanwhile.
CLEANUP: haterm: Remove duplicated bloc to know if haterm must drain
When haterm was waiting for request headers, there was two test to know if
it had to drain the request data before replying. One of them was useless
and was thus removed.
BUG/MEDIUM: h1_htx: Remove reverved block on error during contig chunks parsing
In h1_parse_full_contig_chunks(), we first try to reserve the bigger HTX
DATA block as possible. It is ajusted at the end of chunks parsing or
removed if no data was copied. However, it should also be removed when a
parsing error is triggered. It could be an issue for http health checks and
haterm to properly handle errors.
BUG/MINOR: http-fetch: Fix http_auth_bearer() when custom header is used
When http_auth_bearer() sample fetch function is called with a custom header
and the header is not found or type didn't match 'Bearer', a mismatch must
be reported instead of an empty string.
Mia Kanashi [Fri, 1 May 2026 18:06:17 +0000 (21:06 +0300)]
BUG/MINOR: acme: contact mail should be optional, don't pass ToS bool
According to ACME RFC contact email is optional.
Letsencrypt used it some long time ago, but not today.
Currently HAProxy always sets the value of the contact mail to a string
that is read from the config, but if that string is not specified,
it sets %s in mailto:%s to null, which cases new account request
to fail in pebble.
Also HAProxy currently passes termsOfServiceAgreed bool to requests
that contain onlyReturnExisting, that isn't needed according to the RFC
and other ACME impls.
This patch dynamically builds the account request JSON to address that.
Willy Tarreau [Tue, 5 May 2026 11:33:05 +0000 (13:33 +0200)]
BUG/MINOR: h2: only accept :protocol with extended CONNECT
As reported by Huangbin Zhan in github issue #3355, we're too lax on
the :protocol pseudo header. It is currently accepted with regular
CONNECT as well as non-CONNECT methods while it only ought to be
accepted with extended CONNECT (i.e. CONNECT after the connection
negotiated the RFC8441 extension). Let's refine the check in H2 by
leveraging the new flag H2_MSGF_EXT_CONN_OK that is passed by the
caller when the connection supports the extension. This is sufficient
to sort the various cases.
The proto upgrade regtest was updated to verify that CONNECT with
:protocol without nego and another method with nego and :protocol
both fail.
Thanks to Huangbin Zhan (@zhanhb) for the report and helpful reproducer.
This needs to be backported to all versions. It relies on these patches
first:
REGTESTS: http-messaging: always send RFC8441 client settings to use ext connect
BUG/MINOR: mux-h2: condition the processing of 8441 extension to global setting
MINOR: mux-h2: add a new message flag to indicate ext connect support
Willy Tarreau [Tue, 5 May 2026 09:40:29 +0000 (11:40 +0200)]
BUG/MINOR: mux-h2: condition the processing of 8441 extension to global setting
When rfc8441 (extended connect) is disabled via
h2-workaround-bogus-websocket-clients, we properly refrain from
advertising support for extended connect, but we should also ignore
the incoming setting, otherwise it can remain enabled if the client
advertises it.
Willy Tarreau [Tue, 5 May 2026 09:15:26 +0000 (11:15 +0200)]
BUG/MINOR: h2: add decoding for :protocol in traces
Function h2_phdr_to_list() was missing the decoding for the :protocol
header and would emit :UNKNOWN in this case. It's only used in traces
so it's not important. The fix can be backported in all versions.
Willy Tarreau [Tue, 5 May 2026 11:24:50 +0000 (13:24 +0200)]
REGTESTS: http-messaging: always send RFC8441 client settings to use ext connect
The tests were validating extended connect without sending the setting
in the client settings frame. It currently works due to a bug, so let's
fix the vtc first.
BUG/MINOR: mworker/cli: check ci_insert() return value in pcli_parse_request()
All ci_insert() calls in pcli_parse_request() were ignoring the return
value, silently miscounting the bytes to forward if an insertion failed.
Add a check on each call and return -1 on failure. In practice this has
no impact: the channel receive machinery enforces a maxrewrite reserve,
so there is always sufficient room in the buffer for these small
prefixes by the time pcli_parse_request() is called.
Must be backported in every maintained versions, the list of available
commands might change.
Willy Tarreau [Mon, 4 May 2026 16:53:33 +0000 (18:53 +0200)]
REGTESTS: add a regtest to validate various NTLM transitions
This test first performs two successive requests over the same
connection where reuse is expected, then perform two 401 which must
both work, testing both the transition from null->sess, and sess->sess.
This test could be backported to detect changes related to private
sessions.
Willy Tarreau [Mon, 4 May 2026 15:42:45 +0000 (17:42 +0200)]
BUG/MAJOR: http-ana: fix private session retrieval on NTLM
During the architectural review leading to commit 90b2154d93 ("MEDIUM:
muxes: always set conn->owner to the session that owns the connection"),
we wondered whether srv_conn->owner could ever be NULL or even invalid,
or if it ought to be changed to sess, and the projections of various use
cases, as well as a number of attempts to fool it led us to conclude
that it was always valid since the connection is private. So it was
considered safer not to start fiddling with the pointer in case it
could still match a previous session after a reuse, which would match
the scenario described in the session_add_conn() comment.
Actually there was exactly one case where a NULL could be met, and that
was covered by the preliminary call to conn_set_owner() that was removed
in that patch, precisely related to the one that the next patch tried to
address: in http-reuse always, after the second request on a connection
releases the connection, the owner can now become NULL, so if an NTLM
header is seen at this point, it will crash.
Interestingly, after the immediately following commit was merged, d93c53b0df ("MEDIUM: session: always reset the conn->owner on backend
when installing mux"), the problem became immediate as the conn's
owner is now null during operation if the connection is not private, and
now the first response in NTLM is sufficient to crash the process. On
the other hand, thanks to the two patches above, we're now certain never
to meet a different session, which was the sought goal: either the session
is normal and it has no owner, or it's private and it has <sess> as owner.
Also with HTTP/1 (since the code explicitly checks for H1), there may be
a single request at a time on a connection so the owner should either be
the session or NULL.
So this patch finally implements the original plan, to pass <sess> to
session_add_conn(). The call is idempotent if the owner is already set,
but at least the function performs some preliminary sanity checks which
are quite welcome, so better continue to always call it.
Note that this is only for 3.4 or any branch that has exactly the two
patches above. And if the patches above were to ever be backported
(together), this one would be needed as well.
Thanks to Omkhar Arasaratnam for reporting this regression.
BUG/MEDIUM: ssl/sample: check output buffer size in aes_cbc_enc converter
AES-CBC uses a 16-byte block size, and PKCS padding always adds at least
one byte (up to a full 16 bytes when input is already block-aligned), so
the encrypted output is always larger than the input. Without checking
that the output buffer can hold the padded result, encryption could
overflow it. Add a pre-encryption guard for block cipher (blksize > 1)
that rejects the operation when the output buffer is too small.
Willy Tarreau [Mon, 4 May 2026 15:08:22 +0000 (17:08 +0200)]
BUG/MAJOR: net_helper: also fix tcp_options_list for OOB write loop
The exact same issue that was fixed for ip.fp with commit dbf471f99a
("BUG/MAJOR: net_helper: ip.fp infinite loop on malformed tcp options")
also exists for tcp_options_list: an option with a zero size will prevent
the offset from making any progress and will loop forever. In this case,
since we produce output, trash->data gets incremented on each loop and
the byte at ofs is used to fill the memory there, quickly overflowing the
area.
The exact same fix as above was applied here again, including the uchar
cast to make sure we don't go back-and-forth between two positions.
Such TCP options are not valid and will not be reported by the TCP stack,
however they can happen in case options are passed in headers by a first
proxy, or are offered in a return directive fed from a query string as a
means of providing a debugging tool for admins.
Thanks to Omkhar Arasaratnam for reporting this issue.
This fix must be backported to 3.2 where the commits above were
backported.
BUG/MINOR: resolvers: Free opts on parse error in resolv_parse_do_resolve()
The error handler at do_resolve_parse_error freed varname and resolvers_id
but missed freeing rule->arg.resolv.opts (allocated via calloc). Added
ha_free(&rule->arg.resolv.opts) to the cleanup path.
This patch could be backported to all stable branches.
BUG/MINOR: resolvers: Fix lookup for a hostname in the state-file tree
In resolv_check_response(), the condition 'if (!srvrq->named_servers)' was
inverted - it ran the named server lookup when the tree was empty/NULL
instead of when it was populated. This prevented proper hostname-based
matching of SRV records to servers from the state file.
The issue was introduced when tree of servers was replaced by a cebis tree
(fdf6fd5b45).
BUG/MINOR: resolvers: Free new requester on error when linking a resolution
If an error is triggered while the requester was allocated, it is not
immediately released. It is not really a memory leak because the requester
will be reused laster, on a next attempt, or released on deinit. For a
do-resolv action, the requester is released with the stream. So no leak
here. But it is probably not expected to keep a newly allocated requester in
case of error.
BUG/MINOR: tcpcheck: Properly report error for http health-checks
When an error is reported on an expect rule for tcp and http health-checks,
a dedicated message is reported with details about the wrong match. However,
this was never performed for HTTP health-check because of the wrong test on
the check type.
In addition, when an error was reported on an "expect hdr" rule, a break
statement was missing. So the error message could be truncated (but never
emitted because of the issue above).
This patch should be backported to all stable versions.
Willy Tarreau [Mon, 4 May 2026 14:10:20 +0000 (16:10 +0200)]
BUG/MINOR: dns: always validate the source address in responses
When we removed the use of connect() to reach DNS servers in 3.3 with
commit 2c7e05f80e ("MEDIUM: dns: don't call connect to dest socket for
AF_INET*"), we accidentally lost a check on the server's address in
responses, opening the possibility of spoofed DNS responses for someone
who knows both haproxy's IP:port and the transaction ID.
In practice, the impact is very low, because:
- DNS servers IP addresses are almost always known, and often even among
the widely used ones (1.1.1.1, 8.8.8.8 etc), and their port is 53.
- all DNS "security" relies on the ignorance of the transaction ID and
is possible source port, so if either the attacker is on-path and sees
them, or it's off-path and has to guess them, but in any case it's
trivial to spoof the known server in responses, with or without the
check.
Regardless, let's not further weaken the protocol and do the check.
Thanks to Omkhar Arasaratnam for reporting this issue.
An interesting observation while testing this fix was that the code does
support UNIX dgram sockets (via connect()) but that since we don't bind
to a local UNIX socket to send requests, the server's recvfrom() doesn't
get any address and has nowhere to respond to. So in practice while the
code is designed to deal with UNIX sockets, these cannot work by design.
This fix must be backported to 3.2 where the commit above was backported.
DOC: acme: document missing acme-vars and provider-name keywords
Both keywords are used with dns-01 and dns-persist-01 challenges to pass
information to an external DNS provisioning tool (e.g. the dataplaneAPI)
via the "dpapi" sink. provider-name sets the DNS provider identifier and
acme-vars passes arbitrary tool-specific variables.
Thanks to @oliwer for reporting the issue.
Must be backported to 3.2, however previous version don't have
"dns-persist-01".
Willy Tarreau [Mon, 4 May 2026 12:37:02 +0000 (14:37 +0200)]
DOC: otel: update the filter's status and URL in the docs
The docs (readme and configuration.txt) still used to mention that OTEL
was under development. Now that it's released, let's indicate that it's
ready with the download URL.
Willy Tarreau [Mon, 4 May 2026 11:51:36 +0000 (13:51 +0200)]
BUG/MAJOR: mux-h2: preset MSGF_BODY_CL on H2_SF_DATA_CLEN in h2c_dec_hdrs()
Commit d12edebe4a ("BUG/MAJOR: mux-h2: detect incomplete transfers on
HEADERS frames as well") tried to enforce strict matching between
advertised content-length and transferred data when dealing with ES on
a headers frame. It purposely arranged the code so that it would cover
both headers and trailers. The problem is, in h2c_dec_hdrs() we preset
message flags (msgf) based on the current state and knowledge related
to the stream being processed, then we pass these flags to the headers
parser and use their final state to perform some extra checks.
MSGF_BODY_CL was set by the parsers themselves when processing a
content-length header, but when parsing a trailers frame, it will not
be set, and due to this the matching between the remaining expected
content-length and the transferred data is not verified, so the fix
above doesn't work for trailers.
This patch sets MSGF_BODY_CL to the same value as H2_SF_DATA_CLEN so
that during headers it remains zero, but it matches what was learned
during headers when processing trailers. It is sufficient to re-enable
the check that was attempted in the commit above.
The impact remains the same as the one indicated in the commit above: in
practice this can be used to force subsequent requests to fail, or when
running with "http-reuse never" or when running with a totally idle server,
to perform a request smuggling by constructing specially crafted request
pairs where the first one is used to trigger an early response and hide
parts of or all headers of the second one, to instead use a second
embedded one that was not subject to analysis. As such, the risk remains
moderate given the low prevalence of "http-reuse never" in production
environments, and of idle servers. Again, a temporary alternative to the
fix is to disable HTTP/2 by specifying "alpn http/1.1" on "bind" lines,
and adding "option disable-h2-upgrade" in HTTP frontends.
Many thanks to Pratham Gupta / alchemy1729 for spotting and analyzing
this problem, and for providing a lightweight reproducer to illustrate
the problem!
This fix must be backported to all versions where the fix above was
backported (i.e. all). Note that it depends on this previous commit
otherwise trailers will always break:
BUG/MEDIUM: mux-h2: fix the body_len to check when parsing request trailers
As a side note, it's worth noting that these temporary message flags have
reached a level of pain and fragility that really warrants a complete
rework. Ideally we should have a pair of such flags in the h2s (one per
direction) and the callers of the parsers should point to them so that
they are always up to date. And by having generic HTTP flags instead of
H2, we could better unify the h1/h2/h3/fcgi processors (and maybe avoid
some HTX conversion). One flag could even indicate that trailers are
being parsed (since they're last) so as to ease this detection down the
chain.
Willy Tarreau [Mon, 4 May 2026 11:42:52 +0000 (13:42 +0200)]
BUG/MEDIUM: mux-h2: fix the body_len to check when parsing request trailers
The h2 content-length validation in commit d12edebe4a ("BUG/MAJOR:
mux-h2: detect incomplete transfers on HEADERS frames as well") was
insufficient. The content-length check is still ineffective on request
trailers and it could not work by default due to the fact that the
default body_len is used in h2c_frt_handle_headers() when processing
trailers, instead of passing h2s->body_len, which was necessarily parsed
before reaching trailers. Let's fix this point first, otherwise fixing
the second issue would break trailers.
Many thanks to Pratham Gupta / alchemy1729 for spotting and analyzing
this problem, and for providing a lightweight reproducer to illustrate
the problem!
This fix must be backported to all versions where the fix above was
backported (i.e. all).
BUILD: otel: removed USE_OTEL, addon is now built via EXTRA_MAKE
The OpenTelemetry filter has been moved out of the haproxy source tree and
now lives and is developed in the haproxy-opentelemetry repository as an
external addon. Removed all hard-coded references to USE_OTEL and to the
addons/otel directory from the main Makefile, as the addon is now plugged
in through the generic EXTRA_MAKE hook added in the previous commit.
Willy Tarreau [Mon, 4 May 2026 09:57:12 +0000 (11:57 +0200)]
CLEANUP: mux-h2: remove the outdated condition to release h2c on timeout
The historical code dealing with timeout was left with a confusing
condition that is always true but always requires some analysis. It
would check if some streams were left pending before deciding to
release the connection. It could indeed be problematic to leave with
no timeout and an active connection!
As Christopher figured, the situation cannot exist because a first
check ensures there's no more h2c via h2c_may_expire(), then a call
to h2_wake_some_streams() will call h2s_wake_one_stream() for each
of the h2s, and all those with no h2c are purged. Thus on return
from h2_wake_some_streams() we're guaranteed to have an empty tree.
Let's just remove the condition and clean up the code.
BUG/MINOR: quic: fix trace crash on datagram receive
Recently, datagram reception architecture has been completely reworked
to improve performance. A regression has been introduced when using
traces in qc_rcv_buf() : datagram argument is uninitialized after recv
syscall. This may cause a crash as CIDs buffer is dereferenced.
Fix this by removing dgram argument from the affected trace. A new trace
is added after quic_dgram_init() to keep the ability to display the
received content.
This issue has caused failure of all QUIC interop testing.
BUG/MEDIUM: acme: fix stalled renewal when opportunistic DNS check fails
In ACME_INITIAL_RSLV_READY, when the opportunistic DNS propagation check
fails and the code falls back to ACME_CLI_WAIT, ACME_RDY_INITIAL_DNS was
left set in cond_ready. Since the CLI-wait path only ever sets ACME_RDY_CLI
on auth->ready, the readiness check in ACME_CLI_WAIT could never be
satisfied, permanently stalling certificate renewal.
Fix this by stripping ACME_RDY_INITIAL_DNS from cond_ready before falling
back to the regular CLI-wait flow. Also replace the &= with a plain
assignment in the success path to make the intent explicit.
BUG/MINOR: quic: fix buffer overflow with sockaddr_in46
New type sockaddr_in46 has been recently introduced. It serves as a
union which can store either an IPv4 or IPv6 address. The objective is
to reduce the storage size for QUIC datagrams which previously uses a
sockaddr_storage field.
On qc_new_conn(), source and destination addresses from the datagram are
passed to the function as sockaddr_storage so that they are copied into
the newly built quic_conn instance. However, the involved memcpy() is
producing a buffer overflow as sockaddr_in46 is smaller than
sockaddr_storage type.
This patch fixes this by defining a new helper function
in46un_to_addr(). This allows to convert safely sockaddr_in46 to a plain
sockaddr type. The function is now used before invoking qc_new_conn().
Note that there is still other several places where union sockaddr_in46
is casted as sockaddr_storage type. However, these should be safe as in
these cases sockaddr fields are accessed individually after checking
ss_family. The memory issue only exists when plain memcpy is used.
This bug was detected using ASAN. It generates the following traces when
a QUIC connection is instantiated.
==37474==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x7c3bb9a61100 at pc 0x5631f52c3946 bp 0x7ffc83e45b50 sp 0x7ffc83e45310
READ of size 128 at 0x7c3bb9a61100 thread T0
#0 0x5631f52c3945 in __asan_memcpy (/home/amaury/work/haproxy-quic-dev/haproxy+0x3ae945) (BuildId: a7ccfd74b7a71a869b8ff8d13f6dcde8c82c1487)
#1 0x5631f55f9e34 in qc_new_conn /home/amaury/work/haproxy-quic-dev/src/quic_conn.c:1311:2
#2 0x5631f558d5c3 in quic_rx_pkt_retrieve_conn /home/amaury/work/haproxy-quic-dev/src/quic_rx.c:1875:10
#3 0x5631f558330b in quic_dgram_parse /home/amaury/work/haproxy-quic-dev/src/quic_rx.c:2463:29
#4 0x5631f5625da6 in quic_lstnr_dghdlr /home/amaury/work/haproxy-quic-dev/src/quic_sock.c:206:3
#5 0x5631f6a64173 in run_tasks_from_lists /home/amaury/work/haproxy-quic-dev/src/task.c:660:26
#6 0x5631f6a6ba1e in process_runnable_tasks /home/amaury/work/haproxy-quic-dev/src/task.c:913:9
#7 0x5631f5e984c3 in run_poll_loop /home/amaury/work/haproxy-quic-dev/src/haproxy.c:2982:3
#8 0x5631f5e9a715 in run_thread_poll_loop /home/amaury/work/haproxy-quic-dev/src/haproxy.c:3212:2
#9 0x5631f5e9f732 in main /home/amaury/work/haproxy-quic-dev/src/haproxy.c:3853:2
#10 0x7f2bba8276c0 (/usr/lib/libc.so.6+0x276c0) (BuildId: ca0db5ab57a36507d61bbcf4988d344974331f19)
#11 0x7f2bba8277f8 in __libc_start_main (/usr/lib/libc.so.6+0x277f8) (BuildId: ca0db5ab57a36507d61bbcf4988d344974331f19)
#12 0x5631f51be594 in _start (/home/amaury/work/haproxy-quic-dev/haproxy+0x2a9594) (BuildId: a7ccfd74b7a71a869b8ff8d13f6dcde8c82c1487)
CLEANUP: acl: remove duplicate test in parse_acl_expr() and unused variable
aclkw->match_type was compared twice to PAT_MATCH_DOM in parse_acl_expr().
After auditing the involved types, it's only a copy-paste mistake, as no
other matching method is missing, so let's drop it to avoid the confusion.
Also drop variable ckw which is assigned NULL and passed to free(), and is
clearly a leftover from a previous version.
BUG/MINOR: pattern: release the reference on failure to load from file
In pattern_read_from_file(), in case of failure to load from the file,
the newly allocated reference remains attached to the list and is never
freed. Let's just do it.
This can be backported to all versions since it arrived in 1.5 with
commit 1e00d3853b ("MAJOR: pattern/map: Extends the map edition system
in the patterns").
BUG/MINOR: map: do not leak a map descriptor on load error
Maps can leak a map descriptor in sample_load_map() on error. This is
harmless since the process won't start after this, and this cannot be
used at run time. but it's cleaner to fix it. This can be backported.
BUG/MINOR: acl: fix a possible arg corruption in smp_fetch_acl_parse()
smp_fetch_acl_parse() first places the newly allocated ACL sample into
the first argument to be parsed, *before* parsing it. The type is not
changed so the first argument remains of type string. In case of error,
the allocated sample is released and release_sample_expr() will call
release_sample_arg() to release the argument, possibly freeing the
string present there. And here's the catch: by overwriting the first
arguments's ->ptr entry, it happens to be located over the ->str.size
location, to not be null and to still be freed, but by pure chance
thanks to aliasing. A slight reorder of the args or buffer fields
could place it in the ->area and provoke a double-free, or even always
make the first argument's parsing fail.
Let's move the assignment after the loop has succeeded instead, and
properly set type=ARGT_PTR so that we never try to free it. The bug
appeared with the "acl()" sample fetch in 2.9 with commit 7fccccccea
("MINOR: acl: add acl() sample fetch") so it can be backported to 3.0.
MINOR: h3/hq_interop: implement stream reset on shut abort/kill-conn
Adjust QUIC mux stream shut procedure when abort or kill-conn is
performed. Changes are implemented directly into lclose callback for
h3/h09 protocols.
On abort, the stream is resetted as previously. The only change is that
now a proper error code can be used, with REQUEST_CANCELLED specified
for HTTP/3 protocol.
Kill-conn is requested when a tcp-requect connection reject rule has
been executed. In this case the stream is resetted, and the connection
is also closed. This is identical to the H2 multiplexer. HTTP/3 protocol
uses EXCESSIVE_LOAD as error code in this case.
Previously, shut callback was entirely implemented in QUIC mux layer.
However, this operation depends on the above application protocol, as it
may define its own closure procedure and error codes. This is the case
notably with HTTP/3 specification.
This patch defines a stream shut API between QUIC mux and application
protocol layers via the new qcc_app_ops callback lclose(). The closure
reason is specified via an enum argument. Application protcol can then
perform the stream closure as intended.
This patch is only an architecture adjustment but should not have any
functional impact. Stream closure logic was moved identically from QUIC
mux into h3 and h09 lclose callback.
In master-worker mode the master CLI proxy (mworker_proxy) has a
hardcoded maxconn of 10. When a client connects to the master CLI
socket and issues a command that gets forwarded to an unresponsive
worker (e.g. one that is stuck or very slow), the connection hangs
waiting for the worker's response. If the client then disconnects
(timeout, Ctrl-C, etc.), the connection slot is never released because
the client-side FIN is never acknowledged by the unresponsive worker.
After 10 such leaked slots the master CLI socket becomes completely
unreachable, returning "Resource temporarily unavailable" to any new
connection attempt. In containerized deployments this means readiness
probes start failing and the pod gets restarted.
The fix adds a timeout server-fin of 1s to the mworker_proxy. When
the client disconnects while waiting for a worker response, this
timeout ensures the dangling backend connection is cleaned up after
1s, freeing the connection slot. This does not affect normal CLI
operations since the timeout only starts after the client has already
closed its side of the connection.
A regression test is included that blocks the worker CLI thread using
"debug dev delay" with nbthread 1, fills all 10 master CLI slots,
waits for client-side timeouts, then verifies a new connection still
succeeds.
This fixes GH issue #3351.
This should be backported to all stable branches.
Co-authored-by: Martin Strenge <github@trixer.net> Co-authored-by: William Lallemand <wlallemand@haproxy.com>
Maxime Henrion [Tue, 21 Apr 2026 19:25:58 +0000 (15:25 -0400)]
OPTIM: quic: reduce the size of struct quic_dgram
The QUIC code can only handle IPv4 or IPv6 addresses, so using two
sockaddr_storage structs wastes a lot of space in the quic_dgram struct.
This is a very large overhead since this structure is written in the MPSC
ring buffers before every datagram, while many of those datagrams are only
50 bytes or less. Using an union instead saves 200 bytes per datagram,
increasing the capacity of the buffers significantly.
Maxime Henrion [Mon, 23 Mar 2026 14:31:53 +0000 (10:31 -0400)]
MINOR: quic: store the DCID as an offset
Using an offset instead of a pointer into the datagram buffer is less
error-prone as we do not have to manually fixup that pointer when the
datagram is moved somewhere else in memory.
Maxime Henrion [Fri, 30 Jan 2026 16:39:04 +0000 (11:39 -0500)]
OPTIM: quic: rework the QUIC RX code
Use an MPSC ring buffer to hold data for each datagram handler. Holding
this data in a per-handler buffer avoids the HoL blocking we experienced
when we had per-listener buffers with data from all threads mixed up
in them.
This also gets rid of the mt_list contention we were suffering before,
that was causing some threads to be stuck for a significant amount of
time, causing warnings and even crashes in some cases.
Maxime Henrion [Mon, 23 Feb 2026 22:19:15 +0000 (17:19 -0500)]
MINOR: add an MPSC ring buffer implementation
This is to be used in the QUIC code, where the multiple producers are
the listener threads, and the single consumer is the datagram handler
thread. Entries are variable-length with a size header, and are kept
contiguous in the buffer, so padding is inserted at the end when an
entry would otherwise wrap around. The size field is overloaded to also
mark padding (-1) and entries that are still free or not yet ready for
reads (0).
Headers and payloads are aligned on 8 bytes. Aligning on 16 bytes might
be beneficial on some architectures to let memcpy() use 128-bit SIMD
instructions.
The head and tail offsets are 64-bit unsigned integers, making ABA
issues from integer overflow impossible on current or near-future
hardware. Reservation uses a CAS rather than FAA because of the need to
insert padding to keep entries contiguous.
BUG/MINOR: hpack: validate idx > 0 in hpack_valid_idx()
HPACK indices start at 1, so idx=0 is invalid. The function only checked
the upper bound before, allowing idx=0 to pass as valid. This is harmless
as the code properly checks for existing name and values everywhere, but
then due to the call to hpack_idx_to_phdr(), index 0 will be taken for
:authority. Let's just make sure it's never zero.
BUG/MINOR: vars: only print first invalid char in fill_desc()
The variable name is passed as (ptr,len) suggesting that certain callers
might not always have 0-terminated strings (e.g. when used in arguments
where closing parenthesis or commas might follow), the error message
carefully tries to designate the first invalid character, yet by mistake
it prints the whole string. This mistake has been there since commit 4834bc773c ("MEDIUM: vars: adds support of variables") in 1.6. Let's
properly report the char as promised instead. This could be backported
but is totally unimportant.
BUG/MINOR: vars: don't store the variable twice with set-var-fmt
In 2.5, commit 9a621ae76d ("MEDIUM: vars: add a new "set-var-fmt" action")
introduced the set-var-fmt action. However the storage (by then
sample_store_stream() now var_set()) was added for this specific
branch without any return, leaving the sample copied again over the
variable via the final call, meaning that the variable name is looked
up twice and for proc scope, the lock is taken twice for each call to
set-var-fmt.
This patch removes the first call. Tests show that proc operations
now jump from 1.1M to 1.67M/s on a 64-core CPU (lower lock contention),
while other scopes only observe a modest improvement with few vars
(10 goes from 43.3M to 44M/s). This could be backported.
BUG/MINOR: vars: make parse_store() return error on var_set() failure
In 2.5, variables in the scope "proc" were pre-created with commit df8eeb1619 ("MEDIUM: vars: pre-create parsed SCOPE_PROC variables as
permanent ones"). However one test on var_set() was copy-pasted from
vars_check_args() into parse_store(), and the former returns 0 on
error while for the latter it's a success. This means that some errors
on variables of scope "proc" (typically alloc failure) can be missed
at boot time, probably either making that variable invisible or causing
a crash during boot.
Let's return ACT_RET_PRS_ERR instead. This can be backported.
CLEANUP: net_helper: fix incorrect const pointers in writev_n16()
It's interesting to see that output pointers p1 and p2 were declared
as const, and that thisremained unnoticed due to the explicit casts
to u8 when writing to them. The function is currently not used, but
better clean it up to avoid surprises.
BUG/MINOR: sink: do not free existing sinks on allocation error
In 3.1 with commit 1bdf6e884a ("MEDIUM: sink: implement sink_find_early()")
sink creation started to support plugging to an existing sink and only
updating the description. However if the strdup() for the new description
failed, it would go down the error path releasing everything, while leaving
the released entry in the sink list and leaving other users still attached
to it.
Here we take a different approach, we first allocate the new description,
and release the old one on success, otherwise we leave the entry unchanged.
And we only release new sinks, not old ones. This way allocation errors
just do not change what is already referenced elsewhere, so that error
unrolling remains clean.
This remains of low importance anyway since it's only a case of boot
error aggravation. Not really needed to be backported.
BUG/MINOR: acme: skip auth/challenge steps when newOrder returns a certificate
When an ACME server returns a certificate URL directly in the newOrder
response (order already validated), parse it and transition straight to
ACME_CERTIFICATE, bypassing the auth/challenge steps.
BUG/MEDIUM: acme: fix segfault on newOrder with empty authorizations
When an ACME server returns a newOrder response with an empty
authorizations array (certificate already validated), ctx->auths
remains NULL. The state machine then transitions to ACME_AUTH which
immediately dereferences ctx->next_auth, causing a segfault.
Return an error from acme_res_neworder() so the caller retries.
Released version 3.4-dev10 with the following main changes :
- DOC: config: fix spelling of "max-threads-per-group" in the index
- MEDIUM: threads: change the default max-threads-per-group value to 16
- BUG/MEDIUM: mux-h2: ignore conn->owner when deciding if a connection is dead
- BUG/MINOR: task: fix uninitialised read in run_tasks_from_lists()
- MINOR: compression: prefix compression oriented functions with "comp_"
- BUG/MINOR: mux_quic: limit avail_streams() to 2^62
- MINOR: h3: simplify GOAWAY local emission
- MEDIUM: h3: prevent new streams on GOAWAY reception
- MINOR: mux-quic: release BE idle conn after GOAWAY reception
- MINOR: otel: added debug thread ID support for the OTel C wrapper library
- MINOR: otel: test: added option parsing to the speed test script
- MINOR: otel: test: replaced argument variables with positional parameters in run scripts
- CLEANUP: otel: removed insecure-fork-wanted requirement
- MINOR: otel: test: unified run scripts into a single symlinked script
- BUILD: haterm: don't pass size_t to %lu in error messages
- CI: github: merge Test and Test-musl in VTest.yml
- CI: Build halog as part of contrib.yml
- BUG/MINOR: xprt_qstrm: read record length in 64bits
- BUG/MINOR: mux_quic: convert QCC rx.rlen to 64bits
- CI: github: revert quictls version on cross-zoo.yml
- BUG/MINOR: xprt_qstrm: reduce max record length check
- CI: github: use quictls-3.1.7 for cross-zoo.yml
- BUILD: ssl/sample: potential null pointer dereference in sample_conv_aes
- CI: github: add an i686 job in cross-zoo.yml
- CI: github: run cross-zoo.yml weekly
- CI: github: add cross-zoo.yml in README.md
- BUG/MEDIUM: checks: Don't forget to set the "alt_proto" field
- CI: github: do not install pcre-devel on Fedora Rawhide build
- CI: github: fix sysctl in fedora-rawhide
- CI: github: switch to USE_PCRE2 in Fedora Rawhide build
- MINOR: acme: implement draft-ietf-acme-profiles
- MINOR: acme: allow IP SAN in certificate request
- BUG/MINOR: log: consider format expression dependencies to decide when to log
- MINOR: sample: make RQ/RS stats available everywhere
- BUG/MINOR: sample: adjust dependencies for channel output bytes counters
- MEDIUM: muxes: always set conn->owner to the session that owns the connection
- MEDIUM: session: always reset the conn->owner on backend when installing mux
- CLEANUP: mux-h1: avoid using conn->owner in uncertain areas
- CLEANUP: mux-h1: remove the unneeded test on conn->owner in h1s_finish_detach()
- BUG/MAJOR: sched: protect task->expire on 32-bit platforms
- CI: github: add an i686 job to the push job
- BUILD: config: also set DEF_MAX_THREADS_PER_GROUP when not using threads
- reg-tests/ssl/ssl_dh.vtc: fix syntax error
- ci: modernize actions/upload-artifact@v4
- BUG/MINOR: reg-tests: make shell syntax errors fatal
- MINOR: cli: Handle the paylod pattern as a pointer in the cmdline buffer
- MEDIUM: cli: Make a buffer for the command payload
- MEDIUM: cli: Add support for dynamically allocated payloads
- MEDIUM: cli: increase the payload pattern up to 64 bytes
- MINOR: stream: Move the HTTP txn in an union
- MINOR: stream: Add flags to identify the stream tansaction when allocated
- MINOR: stream: Use a pcli transaction to replace pcli_* members
- CLEANUP: applet: Remove useless shadow pointer from appctx
- REGTESTS: ssl: mark ssl_dh.vtc as broken
- BUG/MINOR: mux-h2: count a protocol error when failing to parse a trailer
- BUG/MINOR: mux-h2: count a proto error when rejecting a stream on parsing error
- BUG/MEDIUM: tasks: Make sure we don't schedule a task already running
- BUG/MAJOR: net_helper: ip.fp infinite loop on malformed tcp options
- BUG/MINOR: h2: make tune.h2.log-errors actually work
- BUG/MINOR: h2: Don't look at the exclusive bit for PRIORITY frame
- BUG/MINOR: H2: Don't forget to free shared_rx_bufs on failure
- BUG/MINOR: log: also wait for the response when logging response headers
- BUG/MINOR: mux-h1: Fix condition to send null-chunk for bodyless message
- BUG/MINOR: mux-h1: Fix test to skip trailers from chunked messages
- BUG/MINOR: http-act: fix a typo in a "del-heeaders-bin" error message
- CLEANUP: tcpcheck: Fix some typos in comments
- MINOR: tcpcheck: Rely on free_tcpcheck_ruleset() to deinit tcpchecks
- BUG/MINOR: tcpcheck: Don't release ruleset when parsing 'spop-check' ruleset
- BUG/MINOR: tcpcheck: Fix a leak on deinit by releasing ruleset's conf.file
- CLEANUP: haterm: Fix typos in comments
- CLEANUP: config: Fix warning about invalid small buffer size
- CLEANUP: htx: Fix typos in comments
- CLEANUP: chunk: Fix a typo in a comment
- CLEANUP: http-client: Fix typos in comments
- BUG/MEDIUM: tcpcheck: Release temporary small chunk when retrying on http-check
- CLEANUP: proxy: Fix typos in comments
- DOC: config: Fix a typo for "external-check" directive
- CLEANUP: cli: Fix typos in comments
- BUG/MINOR: stream: Add SF_TXN_HTTP/SF_TXN_PCLI flags in strm_show_flags()
- REGTESTS: Never reuse server connection in jwt/jws_verify.vtc
- REGTESTS: Never reuse server connection in server/cli_delete_dynamic_server.vtc
- BUG/MINOR: compression: properly disable request when setting response
- BUG/MINOR: servers: fix last_sess date calculation
- DOC: config: fix typo introduce in max-threads-per-group documentation
- BUG/MINOR: stream: add the newly added SF_TXN_* flags to strm_show_flags()
- BUG/MINOR: debug: properly mark the entire libs archive read-only
- Revert "BUG/MINOR: stream: add the newly added SF_TXN_* flags to strm_show_flags()"
- BUG/MINOR: server: fix a possible leak of an error message in dynamic servers
- BUG/MAJOR: mux-h2: detect incomplete transfers on HEADERS frames as well
- BUG/MEDIUM: mux-h1: Force close mode for bodyless message announcing a C-L
- BUG/MINOR: mux_quic: prevent crash on qc_frm_free() with QMux
- BUG/MINOR: xprt_qstrm: ensure all local TPs are allocated
- BUG/MINOR: xprt_qstrm: prevent crash if conn release on MUX wake
- BUG/MINOR: mux_quic: do not release conn on qcc_recv() for QMux
- MINOR: xprt_qstrm: remove unused subs
- MINOR: connection: document conn_create_mux()
- MINOR: xprt_qstrm: implement close callback
- MINOR: mux_quic: refactor QMux send frames function
- MINOR: mux_quic: use dynamic Tx streams buffers for QMux
- MINOR: mux_quic: use dynamic conn buffers for QMux
- MINOR: mux_quic/xprt_qstrm: simplify Rx buffer transfer
- MINOR: mux_quic: receive MAX_STREAMS_BIDI frames in QMux
- MINOR: mux_quic: handle conn errors on QMux without crash
- MINOR: mux_quic: handle incomplete QMux record read
- BUG/MINOR: tcpcheck: Allow connection reuse without prior traffic
- MINOR: sample: converter for frontend existence check
- BUG/MEDIUM: stats: fix crash on 'dump stats-file'
- BUG/MINOR: ssl: fix memory leaks on realloc failure in ssl_ckch.c
- BUG/MINOR: ssl: fix memory leaks on realloc failure in ssl_sock.c
- BUG/MINOR: ssl: fix memory leak on realloc failure in acme.ips
- DOC: config: Fix log-format example with last rule expressions
- DOC: config: Fix typo in tune.bufsize.large description
- MEDIUM: ot: emitted deprecation warning at filter init
- BUILD: ot: emitted deprecation warning at build time
- BUG/MINOR: ssl: fix double-free on failed realloc in ssl_sock.c
- BUG/MINOR: tree-wide: fix a few user-visible spelling mistakes from dev7
- CLEANUP: tree-wide: address various spelling mistakes in comments from -dev7
- BUG/MINOR: tools: my_memspn/my_memcspn wrong cast causing incorrect byte reading
- BUG/MINOR: tools: fix memory leak in indent_msg() on out of memory
- BUG/MINOR: tools: free previously allocated strings on strdup failure in backup_env()
- BUG/MINOR: sample: fix memory leak in check_when_cond() when ACL is not found
- BUG/MINOR: sample: fix memory leak in smp_resolve_args error paths
- BUG/MINOR: sample: fix NULL strm dereference in sample_conv_when
- BUG/MINOR: peers: fix logical "and" when checking for local in PEER_APP_ST_STARTING
- BUG/MINOR: peers: fix wrong flag reported twice for dump_flags
- CLEANUP: peers: fix a few user-visible spelling mistakes
- CLEANUP: tools: drop upper case check after tolower()
- CLEANUP: mux-h2: remove duplicate forward declaration of h2s_rxbuf_{head,tail}()
- CLEANUP: tree-wide: fix around 20 mistakes in comments in h2,tools,peers
- MINOR: mux_quic: return conn error code in debug string
- MINOR: mux_quic: display QCS sd on traces
- MINOR: mux_quic/h3: report termination events at connection level
- MINOR: mux_quic/h3: report termination events at stream layer
- BUG/MEDIUM: mux_h1: fix stack buffer overflow in h1_append_chunk_size()
- BUG/MINOR: http_ana: use scf to report term_evts in http_wait_for_request()
- MINOR: lb: infrastructure for declarative initialization
- MEDIUM: lb: use the LB ops tables
- MINOR: lb: cleanups
- MINOR: mux_quic: remove superfluous b_size() before b_alloc()
- BUG/MINOR: mux_quic: free frames emitted with QMux
- BUILD: 51d: fix bool definition on dummy lib v4
- CLEANUP: Reapply ist.cocci (4)
- CLEANUP: Reapply strcmp.cocci (3)
- CLEANUP: Reapply ha_free.cocci (2)
- BUG/MAJOR: http-htx: Store new host in a chunk for scheme-based normalization
- BUG/MEDIUM: http-htx: Don't use data from HTX message to update authority
- BUG/MEDIUM: http-htx: Loop on full host value during scheme based normalization
- MEDIUM: http-htx: Make authority update optional when replacing a header value
- MEDIUM: http-htx: Make authority update optional when adding a header
- BUG/MAJOR: http: forbid comma character in authority value
- BUG/MEDIUM: h1: Enforce the authority validation during H1 request parsing
- BUG/MAJOR: mux-h1: Deal with true 64-bits integer to emit chunks size
- BUG/MEDIUM: tasks: Do not loop in task_schedule() if a task is running
- BUG/MINOR: fix various typos and spelling mistakes in user-visible messages
- CLEANUP: tree-wide: fix comment typos all over the tree (~68)
- BUG/MINOR: payload: validate minimum keyshare_len in smp_fetch_ssl_keyshare_groups
- BUG/MINOR: payload: prevent integer overflow in distcc token parsing
- BUG/MINOR: net_helper: fix out-of-bounds read in tcp_fullhdr_find_opt
- BUG/MINOR: net_helper: fix out-of-bounds read in sample_conv_tcp_options_list
- BUG/MINOR: net_helper: fix incomplete decoding in sample_conv_eth_vlan
- BUG/MEDIUM: mux-fcgi: Properly handle full buffer for FCGI_PARAM record
- BUG/MINOR: http-htx: Don't normalize emtpy path for OPTIONS requests
BUG/MINOR: http-htx: Don't normalize emtpy path for OPTIONS requests
When the scheme-based normalization is performed, an empty path is
normalized to "/". But as stated in RFC9110#4.2.3, this must not be applied
on OPTIONS requests.
So let's fix the issue by adding a test on the method.
Thanks to @zhanhb for the bug report and the analysis.
This patch should fix the issue #3352. It must be backported as far as 3.0.
BUG/MEDIUM: mux-fcgi: Properly handle full buffer for FCGI_PARAM record
The function encoding and sending FCGI_PARAM records was reworked to
properly deal with full buffer. An error must be triggered only when the
parameters cannot be encoded while the mbuf is empty (or the free space is
greater than the max record size). Otherwise we must wait and retry later.
Before, an error was triggered on encoding error if any HTX block was
consumed, regarless the mbuf state. Now, blocks are removed on success
only. So we can wait for more space.
This patch should fix the issue #3346. It should be backported to all stable
versions.
BUG/MINOR: net_helper: fix incomplete decoding in sample_conv_eth_vlan
sample_conv_eth_vlan() reads the VLAN TCI at area[idx + 2] without
ensuring there are enough bytes. The original condition 'idx + 4 < data'
breaks when there IS room for more data, leading to an incomplete read
when trying to decode a VLAN ID.
This can be backported where this converter was backported.
BUG/MINOR: net_helper: fix out-of-bounds read in sample_conv_tcp_options_list
sample_conv_tcp_options_list() uses 'ofs + 1 <= len' to check bounds
before reading the option length field at area[ofs + 1]. When ofs + 1
equals len, this reads one byte past the valid buffer (valid indices are
0 to len-1).
This is the same bug pattern as tcp_fullhdr_find_opt() fixed previously,
and the impact is also almost inexistent.
BUG/MINOR: net_helper: fix out-of-bounds read in tcp_fullhdr_find_opt
tcp_fullhdr_find_opt() reads smp->data.u.str.area[next + 1] without
checking that next + 1 < len. When the last byte of a TCP header's
options section (at index len - 1) contains an option type that is not
0 (EOL) and not 1 (NOP), the code reads one byte past the valid buffer,
which is an out-of-bounds read, which in practice is totally harmless
but should be fixed.
This can be backported where tcp_fullhdr_find_opt() was backported.
BUG/MINOR: payload: prevent integer overflow in distcc token parsing
In both smp_fetch_distcc_param() and smp_fetch_distcc_body(), the code
does "ofs += body" without checking if body is larger than the remaining
data. If a malicious distcc packet contains a token with a very large
body length (param value up to 0xFFFFFFFF), ofs could overflow and wrap
around to a small value, causing the next iteration's bounds check
"ofs + 12 > ci_data(chn)" to pass incorrectly.
This could lead to out-of-bounds reads or an infinite loop.
Given that this is only used in trusted environments, this is mostly
harmless. It can be backported to all stable versions.
BUG/MINOR: payload: validate minimum keyshare_len in smp_fetch_ssl_keyshare_groups
The keyshare extension parsing loop reads dataPointer[readPosition+2]
and dataPointer[readPosition+3] inside the loop body, requiring at least
4 bytes to be safe. However, keyshare_len was only validated as >= 2.
With keyshare_len == 2 or 3, the first loop iteration would read past
the end of the extension data, causing an out-of-bounds read which is
harmless in practice. We also need to make sure that the read position
stops 4 bytes before the end in order to read the 4 next bytes.
BUG/MINOR: fix various typos and spelling mistakes in user-visible messages
A few typos like "not unhandled" in error messages, and some spelling
mistakes mostly in cfgparse error messages were fixed. One spelling
mistake in a function name was fixed as well (ssl_sock_chose_sni_ctx
renamed to ssl_sock_choose_sni_ctx). Those which apply may be worth
being backported.
BUG/MEDIUM: tasks: Do not loop in task_schedule() if a task is running
Commit 7e1cc0fcdbcace75a957a69fc8a4d991f7b30fdb made it so we'd loop in
task_schedule() if the task is currently running, so that we'd be sure
that the task would not overwrite the expire field. However,
task_schedule() may be called while a lock is held, and if the running
task attempts to acquire that lock, it will lead to a deadlock.
So instead, if the task is running, just wake it up, so that we're sure
that it will reschedule itself correctly, as it should do anyway. We
already do nothing if the task is in a run queue, so it is expected that
tasks do that, and if they do not, then it is a bug.
BUG/MAJOR: mux-h1: Deal with true 64-bits integer to emit chunks size
Functions emitting chunks size are using size_t integer to do so. Depending
on the code path, these functions can be called using an unsigned long long
integer (h1m->curr_len for instance). On 64-bits architectures, there is no
issue. But on the 32-bits architecture, it is a problem. size_t are 32-bits
integer so the 64-bits parameter will be casted to a 32-bits integer. For
chunk size exceeding 4GB, the wrong size will be emitted.
To fix the issue, these functions are now using true 64-bits
integer. h1s_consume_kop() was also modified accordingly.
In addition, when a size_t is compared to a 64-bits integer, an explicit
cast is used to be sure the right type is used.
This patch must be backported as far as 3.0. It must be backported after 1ef74fc7c ("BUG/MEDIUM: mux_h1: fix stack buffer overflow in
h1_append_chunk_size()").
BUG/MEDIUM: h1: Enforce the authority validation during H1 request parsing
When a H1 request was parsed, only a light validation was performed on the
URI, mainly because there was no distinction between the different parts of
the URI. So only characters in the range [0x21, 0x7e], excluding the "#" was
allowed.
To be consistant with the H2 and H3 parser, the authority is now validated,
using http_authority_has_forbidden_char() function.
This patch should be backported as far as 2.8. For previous verions,
http_authority_has_forbidden_char() function does not exist.
BUG/MAJOR: http: forbid comma character in authority value
Strictly speaking, the comma character in authority is allowed by RFC3986.
However, it is pretty ambiguous for Host header value because comma is also
the value separator for headers supporting multiple value. It is also very
unlikely to have comma in host header value or authority. So instead of
dealing with this case with all the risks of bugs that this entails, we've
decided to forbid the comma in authority and host header value during the
parsing. Concretely, only http_authority_has_forbidden_char() was updated.
The internal API was not updated to prevent comma to be inserted when the
host header value is updated for instance. But this should be so uncommon
that it is not really a concern.
This patch should be backported as far as 2.8. For previous verions,
http_authority_has_forbidden_char() function does not exist.
MEDIUM: http-htx: Make authority update optional when adding a header
This patch is similar to the previous one but for header addtion. It is now
possible to skip the authority updated. An extra argument was added to
http_add_header() function for this purpose.