Commit graph

26221 commits

Author SHA1 Message Date
Christopher Faulet
e62e8de5a7 MEDIUM: stream: Offer buffers of default size only
Check the channels buffers size on release before trying to offer it to
waiting entities. Only normal buffers must be considered. This will be
mandatory when the large buffers support on channels will be added.
2026-02-18 13:26:21 +01:00
Christopher Faulet
bc586b4138 MINOR: h1-htx: Disable 0-copy for buffers of different size
When a message payload is parsed, it is possible to swap buffers. We must
only take care both buffers have same size. It will be mandatory when the
large buffers support on channels will be added.
2026-02-18 13:26:21 +01:00
Christopher Faulet
8b27dfdfb0 MEDIUM: applet: Disable 0-copy for buffers of different size
Just like the previous commit, we must take care to never swap buffers of
different size when data are exchanged between an applet and a SC. it will
be mandatory when the large buffers support on channels will be added.
2026-02-18 13:26:21 +01:00
Christopher Faulet
36282ae348 MEDIUM: mux-h1/mux-h2/mux-fcgi/h3: Disable 0-copy for buffers of different size
Today, it is useless to check the buffers size before performing a 0-copy in
muxes when data are sent, but it will be mandatory when the large buffers
support on channels will be added. Indeed, muxes will still rely on normal
buffers, so we must take care to never swap buffers of different size.
2026-02-18 13:26:21 +01:00
Christopher Faulet
f82ace414b MEDIUM: compression: Be sure to never compress more than a chunk at once
When the compression is performed, a trash chunk is used. So be sure to
never compression more data than the trash size. Otherwise the commression
could fail. Today, this cannot happen. But with the large buffers support on
channels, it could be an issue.

Note that this part should be reviewed to evaluate if we should use a larger
chunk too to perform the compression, maybe via an option.
2026-02-18 13:26:21 +01:00
Christopher Faulet
53b7150357 MEDIUM: stream: Limit number of synchronous send per stream wakeup
It is not a bug fix, because there is no way to hit the issue for now. But
there is nothing preventing a loop of synchronous sends in process_stream().
Indead, when a synchronous send is successfully performed, we restart the
SCs evaluation and at the end another synchronous send is attempted. So with
an endpoint consuming data bit by bit or with a filter fowarding few bytes
at each call, it is possible to loop for a while in process_stream().

Because it is not expected, we now limit the number of synchronous send per
wakeup to two calls. In a nominal case, it should never be more. This commit
is mandatory to be able to handle large buffers on channels

There is no reason to backport this commit except if the large buffers
support on channels are backported.
2026-02-18 13:26:21 +01:00
Christopher Faulet
5965a6e1d2 MEDIUM: cache: Don't rely on a chunk to store messages payload
When the response payload is stored in the cache, we can avoid to use a
trash chunk as temporary space area before copying everything in the cache
in one call. Instead we can directly write each HTX block in the cache, one
by one. It should not be an issue because, most of time, there is only one
DATA block.

This commit depends on "BUG/MEDIUM: shctx: Use the next block when data
exactly filled a block".
2026-02-18 13:26:20 +01:00
Christopher Faulet
9ad9def126 BUG/MINOR: config: Check buffer pool creation for failures
The call to init_buffer() during the worker startup may fail. In that case,
an error message is displayed but the error was not properly handled. So
let's add the proper check and exit on error.
2026-02-18 13:26:20 +01:00
Christopher Faulet
fae478dae5 MINOR: buffers: Swap buffers of same size only
In b_xfer(), we now take care to swap buffers of the same size only. For
now, it is always the case. But that will change.
2026-02-18 13:26:20 +01:00
Christopher Faulet
6bf450b7fe MINOR: tree-wide: Use the buffer size instead of global setting when possible
At many places, we rely on global.tune.bufsize value instead of using the buffer
size. For now, it is not a problem. But if we want to be able to deal with
buffers of different sizes, it is good to reduce as far as possible dependencies
on the global value. most of time, we can use b_size() or c_size()
functions. The main change is performed on the error snapshot where the buffer
size was added into the error_snapshot structure.
2026-02-18 13:26:20 +01:00
David Carlier
fc89ff76c7 BUG/MEDIUM: jwe: fix timing side-channel and dead code in JWE decryption
Fix two issues in JWE token processing:

- Replace memcmp() with CRYPTO_memcmp() for authentication tag
  verification in build_and_check_tag() to prevent timing
  side-channel attacks. Also add a tag length validation check
  before the comparison to avoid potential buffer over-read when
  the decoded tag length doesn't match the expected HMAC half.

- Remove unreachable break statement after JWE_ALG_A256GCMKW case
  in decrypt_cek_aesgcmkw().
2026-02-18 10:46:32 +01:00
Christopher Faulet
806c8c830d REORG: stconn: Move functions related to channel buffers to sc_strm.h
sc_have_buff(), sc_need_buff(), sc_have_room() and sc_need_room() are
related to the buffer's channel. So we can move them in sc_strm.h header
file. In addition, this will be mandatory for the next commit.
2026-02-18 09:44:16 +01:00
Christopher Faulet
1b1a0b3bae MINOR: stconn: Add missing SC_FL_NO_FASTFWD flag in sc_show_flags
SC_FL_NO_FASTFWD flag was not listed in sc_show_flags() function. Let's do
so.

This patch could be backported as far as 3.0.
2026-02-18 09:44:16 +01:00
Christopher Faulet
0aca25f725 BUG/MINOR: http-ana: Stop to wait for body on client error/abort
During the message analysis, we must take care to stop wait for the message
body if an error was reported on client side or an abort was detected with
abort-on-close configured (by default now).

The bug was introduced when the "wait-for-body" action was added. Only the
producer state was tested. So, when we were waiting for the request payload,
there was no issue. But when we were waiting for the response payload, error
or abort on client side was not considered.

This patch should be backported to all stable versions.
2026-02-18 09:44:16 +01:00
Christopher Faulet
9e17087aeb BUG/MEDIUM: shctx: Use the next block when data exactly filled a block
When the hot list was removed in 3.0, a regression was introduced.
Theorically, it is possible to override data in a block when new data are
appended. It happens when data are copied. If the data size is a multiple of
the block size, all data are copied and the last used block is full. But
instead of saving a reference on the next block as the restart point for the
next copies, we keep a reference on the last full one. On the next read, we
reuse this block and old data are crushed. To hit the bug, no new blocks
should be reserved between the two data copy attempts.

Concretely, for now, it seems not possible to hit the bug. But with a block
size set to 1024, if more than 1024 bytes are reseved, with a first copy of
1024 bytes and a second one with remaining data, data in the first block
will be crushed.

So to fix the bug, the reference of the last block used to write data (which
is in fact the next one to use to perform the next copy) is only updated
when a block is full. In that case the next block is used.

This patch should be backported as far as 3.0 after a period of observation.
2026-02-18 09:44:15 +01:00
Christopher Faulet
b248b1c021 CLEANUP: compression: Remove unused static buffers
Since the legacy HTTP code was removed, the global and thread-local buffers,
tmpbuf and zbuf, are no longer used. So let's removed them.

This could be backported, theorically to all supported versions. But at
least it could be good to do so as far as 3.2 as it saves 2 buffers
per-thread.
2026-02-18 09:44:15 +01:00
Christopher Faulet
829002d459 MINOR: flt-trace: Add an option to limit the amount of data forwarded
"max-fwd <max>" option can now be used to limit the maximum amount of data
forwarded at a time by the filter. It could be handy to make tests.
2026-02-18 09:44:15 +01:00
Christopher Faulet
92307b5fec BUG/MINOR: flt-trace: Properly compute length of the first DATA block
This bug is quite old. When the length of the first DATA block is computed,
the offset is used instead of the block length minus the offset. It is only
used with random forwarding and there is a test just after to prevent any
issue, so there is no effect.

It could be backported to all stable versions.
2026-02-18 09:44:15 +01:00
Christopher Faulet
ccb075fa1b DEV: term-events: Fix hanshake events decoding
Handshakes events were not properly decoded. Only send errors were decoded
as expected, other events were reported with a '-'. It is now fixes.

This patch could be backported as far as 3.2.
2026-02-18 09:44:15 +01:00
Christopher Faulet
1b7843f1c1 BUG/MEDIUM: applet: Fix test on shut flags for legacy applets (v2)
The previous fix was wrong. When shut flags are tested for legacy applets,
to know if the I/O handler can be called or not, we must be sure shut for
reads and for writes are both set to skip the applet I/O handler.

This bug introduced regression, at least for the peer applet and for the DNS
applet.

This patch must be backported with abc1947e1 ("BUG/MEDIUM: applet: Fix test
on shut flags for legacy applets"), so as far as 3.0.
2026-02-18 09:44:15 +01:00
Christopher Faulet
8e0c2599b6 BUG/MEDIUM: mux-h1: Stop sending vi fast-forward for unexpected states
If a producer tries to send data via the fast-forward mechanism while the
message is in an unexpected state from the consumer point of view, the
fast-forward is now disabled. Concretely, we now take care that the message
is in its data/tunnel stage to proceed in h1_nego_ff().

By disabling fast-forward in that case, we will automatically fall back on
the regular sending path and be able to handle the error in h1_snd_buf().

This patch should be backported as far as 3.0
2026-02-18 09:44:15 +01:00
Christopher Faulet
cda056b9f4 BUG/MEDIUM: mux-h2/quic: Stop sending via fast-forward if stream is closed
If is illegal to send data if the stream is already closed. The case is
properly handled when data are sent via snd_buf(), by draining the data. But
it was still possible to process these data via nego_ff().

So, in this patch, both for the H2 and QUIC multiplexers, the fast-forward
is disabled if the stream is closed and nothing is performed. Doing so, we
will automatically fall back on the regular sending path and be able to
drain data in snd_buf().

Thanks to Mike Walker for his investigation on the subject.

This patch should be backported as far as 3.0.
2026-02-18 09:44:09 +01:00
Amaury Denoyelle
2f94f61c31 REGTESTS: fix quoting in feature cmd which prevents test execution
Some checks are pending
Contrib / build (push) Waiting to run
alpine/musl / gcc (push) Waiting to run
VTest / Generate Build Matrix (push) Waiting to run
VTest / (push) Blocked by required conditions
Windows / Windows, gcc, all features (push) Waiting to run
Remove extra quote in feature cmd used to test SSL compatibility with
set_ssl_cafile QUIC regtest. Due to this syntax error, the test was
never executed.

No need to backport.
2026-02-17 18:31:29 +01:00
Amaury Denoyelle
18a78956cb MINOR: mux-quic: add BUG_ON_STRESS() when draining data on closed stream
Add a BUG_ON_STRESS() to be able to detect if data draining is performed
due to early stream closure.
2026-02-17 18:18:44 +01:00
Amaury Denoyelle
4c275c7d17 BUG/MEDIUM: h3: reject frontend CONNECT as currently not implemented
HTTP/3 CONNECT transcoding is not properly implemented on the frontend
side. Neither tunnel mode of application nor extended connect are
currently functional.

Clarify this situation by rejecting any CONNETC attempts on the frontend
side. The stream is thus now closed via a RESET_STREAM with error code
REQUEST_REJECTED.

This should be backported to every stable versions.
2026-02-17 18:18:44 +01:00
Amaury Denoyelle
f3003d1508 BUG/MAJOR: Revert "MEDIUM: mux-quic: add BUG_ON if sending on locally closed QCS"
This reverts commit 235e8f1afd.

Prior to the above commit, snd_buf callback for QUIC MUX was able to
deal with data even after stream closure. The excess was simply
discarded, as no STREAM frame can be emitted after FIN/RESET_STREAM.
This code was later removed and replaced by a BUG_ON() to ensure snd_buf
is never called after stream closure.

However, this approach is too strict. Indeed, there is nothing in the
haproxy stream architecture which forbids this scheduling, in part
because QUIC MUX is the sole responsible of the stream closure. As such,
it is preferable to revert to the old code to prevent any triggering of
a BUG_ON() failure.

Note that nego_ff does not implement data draining if called after
stream closure. This will be done in a future patch.

Thanks to Mike Walker for his investigation on the subject.

This must be backported up to 2.8.
2026-02-17 18:18:44 +01:00
Aurelien DARRAGON
747ff09818 MEDIUM: backend: make "balance random" consider tg local req rate when loads are equal
Some checks are pending
Contrib / build (push) Waiting to run
alpine/musl / gcc (push) Waiting to run
VTest / Generate Build Matrix (push) Waiting to run
VTest / (push) Blocked by required conditions
Windows / Windows, gcc, all features (push) Waiting to run
This is a follow up to b6bdb2553 ("MEDIUM: backend: make "balance random"
consider req rate when loads are equal")

In the above patch, we used the global sess_per_sec metric to choose which
server we should be using. But the original intent was to use the per
thread group statistic.

No backport needed, the previous patch already improved the situation in
3.3, so let's not take the risk of breaking that.
2026-02-17 09:51:46 +01:00
William Lallemand
1274c21a42 BUG/MINOR: ssl: error with ssl-f-use when no "crt"
Some checks are pending
Contrib / build (push) Waiting to run
alpine/musl / gcc (push) Waiting to run
VTest / Generate Build Matrix (push) Waiting to run
VTest / (push) Blocked by required conditions
Windows / Windows, gcc, all features (push) Waiting to run
ssl-f-use lines tries to load a crt file, but the "crt" keyword is not
mandatory. That could lead to crtlist_load_crt() being called with a
NULL path, and trying to do a stat.

In this particular case we don't need to try anything and it's better to
leave with an actual error.

Must be backported as far as 3.2.
2026-02-16 18:41:40 +01:00
William Lallemand
0016d45a9c BUG/MINOR: ssl: clarify ssl-f-use errors in post-section parsing
crtlist_load_crt() in post_section_frontend_crt_init() won't give
details about the line being parsed, this should be done by the caller.

Modify post_section_frontend_crt_init() to ouput the right error format.

Must be backported to 3.2.
2026-02-16 18:41:08 +01:00
William Lallemand
e0d1cdff6a BUG/MINOR: ssl: fix leak in ssl-f-use parser upon error
cfg_crt_node->filename is leaked on the error path in the ssl-f-use
configuration parser.

Could be backported as far as 3.2
2026-02-16 16:04:35 +01:00
William Lallemand
86df0e206e BUG/MINOR: ssl: double-free on error path w/ ssl-f-use parser
In post_section_frontend_crt_init(), the crt_entry is populated by the
ssl_conf fromt the cfg_crt_node. On error path, the crt_list is
completely freed, including the ssl_conf structure. But the ssl_conf
structure was already freed when freeing the cfg_crt_node.

Fix the issue by doing a crtlist_dup_ssl_conf(n->ssl_conf) in the
crtlist_entry instead of an assignation.

Fix issue #3268.

Need to be backported as far as 3.2. The previous patch which adds the
crtlist_dup_ssl_conf() declaration is needed.
2026-02-16 16:04:35 +01:00
William Lallemand
df8e05815c BUG/MINOR: ssl: lack crtlist_dup_ssl_conf() declaration
Add lacking crtlist_dup_ssl_conf() declaration in ssl_crt-list.h.

Could be backported if needed.
2026-02-16 16:04:35 +01:00
Willy Tarreau
1d2490c5ae DEV: gdb: use unsigned longs to display pools memory usage
Some checks are pending
Contrib / build (push) Waiting to run
alpine/musl / gcc (push) Waiting to run
VTest / Generate Build Matrix (push) Waiting to run
VTest / (push) Blocked by required conditions
Windows / Windows, gcc, all features (push) Waiting to run
The pools memory usage calculation was done using ints by default, making
it harder to identify large ones. Let's switch to unsigned long for the
size calculations.
2026-02-16 11:07:23 +01:00
David Carlier
cb63e899d9 CLEANUP: deviceatlas: add unlikely hints and minor code tidying
Some checks failed
Contrib / build (push) Has been cancelled
alpine/musl / gcc (push) Has been cancelled
VTest / Generate Build Matrix (push) Has been cancelled
Windows / Windows, gcc, all features (push) Has been cancelled
VTest / (push) Has been cancelled
Add unlikely() hints on error paths in init, conv and fetch functions.
Remove unnecessary zero-initialization of local buffers that are
always written before use. Fix indentation in da_haproxy_checkinst()
and remove unused loop variable initialization.
2026-02-14 15:49:00 +01:00
David Carlier
076ec9443c MINOR: deviceatlas: precompute maxhdrlen to skip oversized headers early
Precompute the maximum header name length from the atlas evidence
headers at init and hot-reload time. Use it in da_haproxy_fetch() to
skip headers early that cannot match any known DeviceAtlas evidence
header, avoiding unnecessary string copies and comparisons.
2026-02-14 15:49:00 +01:00
David Carlier
f5d03bbe13 MINOR: deviceatlas: define header_evidence_entry in dummy library header
Add the struct header_evidence_entry definition to the dummy dac.h
to accommodate the ongoing deviceatlas module update which now
iterates over atlas header_priorities to precompute maxhdrlen.
The struct was already referenced by struct da_atlas but lacked
a definition in the dummy header.
2026-02-14 15:49:00 +01:00
David Carlier
23aeb72798 MINOR: deviceatlas: increase DA_MAX_HEADERS and header buffer sizes
Increase DA_MAX_HEADERS from 24 to 32 and hbuf from 24 to 64 to
accommodate current DeviceAtlas data files which may use more headers
and longer header names.
2026-02-14 14:47:22 +01:00
David Carlier
8031bf6e03 MINOR: deviceatlas: check getproptype return and remove pprop indirection
Check the return value of da_atlas_getproptype() and skip the property
on failure instead of using an uninitialized proptype. Also remove the
unnecessary pprop pointer indirection, using prop directly.
2026-02-14 14:47:22 +01:00
David Carlier
0fad24b5da BUG/MINOR: deviceatlas: set cache_size on hot-reloaded atlas instance
When hot-reloading the atlas in da_haproxy_checkinst(), the configured
cache_size was not applied to the new instance, causing it to use the
default value.

This should be backported to lower branches.
2026-02-14 14:47:22 +01:00
David Carlier
1d1daff7c4 BUG/MINOR: deviceatlas: fix deinit to only finalize when initialized
da_fini() was called unconditionally in deinit_deviceatlas() even when
da_init() was never called. Move it inside the daset check. Also remove
the erroneous shm_unlink() call which could affect the dadwsch shared
memory used by the scheduling process.

This should be backported to lower branches.
2026-02-14 14:47:22 +01:00
David Carlier
d8ff676592 BUG/MINOR: deviceatlas: fix resource leak on hot-reload compile failure
In da_haproxy_checkinst(), when da_atlas_compile() failed, the cnew
buffer was leaked. Add a free(cnew) in the else branch.

This should be backported to lower branches.
2026-02-14 14:47:22 +01:00
David Carlier
ea3b1bb866 BUG/MINOR: deviceatlas: fix double-checked locking race in checkinst
In da_haproxy_checkinst(), base[0] was checked before acquiring the
lock but not re-checked after. Another thread could have already
processed the reload between the initial check and the lock
acquisition, leading to a race condition.

This should be backported to lower branches.
2026-02-14 14:47:22 +01:00
David Carlier
734a139c52 BUG/MINOR: deviceatlas: fix cookie vlen using wrong length after extraction
In da_haproxy_fetch(), vlen was set from v.len (the raw header value
length) instead of the truncated copy length. Also the cookie-specific
vlen calculation used an incorrect subtraction instead of the actual
extracted cookie value length (pl) returned by
http_extract_cookie_value().

This should be backported to lower branches.
2026-02-14 14:47:22 +01:00
David Carlier
7098b4f93a BUG/MINOR: deviceatlas: fix off-by-one in da_haproxy_conv()
The user-agent string copy had an off-by-one error: the buffer size
limit did not account for the null terminator, and the memcpy length
used i-1 which truncated the last character of the user-agent string.

This should be backported to lower branches.
2026-02-14 14:47:22 +01:00
David Carlier
d8f219b380 BUG/MEDIUM: deviceatlas: fix resource leaks on init error paths
When da_atlas_compile() or da_atlas_open() failed in init_deviceatlas(),
atlasimgptr was leaked and da_fini() was never called. Also add a NULL
check on strdup() for the default cookie name with proper cleanup of
the atlas and image pointer on failure.

This should be backported to lower branches.
2026-02-14 14:47:22 +01:00
David Carlier
6342705cee BUG/MINOR: deviceatlas: add NULL checks on strdup() results in config parsers
Add missing NULL checks after strdup() for the json file path in
da_json_file() and the cookie name in da_properties_cookie().

This should be backported to lower branches.
2026-02-14 14:47:22 +01:00
David Carlier
2d6e9e15cd BUG/MINOR: deviceatlas: add missing return on error in config parsers
da_log_level() and da_cache_size() were missing a return -1 on error,
causing fall-through to the normal return 0 path when invalid values
were provided.

This should be backported to lower branches.
2026-02-14 14:47:22 +01:00
Willy Tarreau
5689605c8e DEV: gdb: add a utility to find the post-mortem address from a core
More and more often, core dumps retrieved on systems that build with
-fPIE by default are becoming unexploitable. Even functions and global
symbols get relocated and gdb cannot figure their final position.
Ironically the post_mortem struct lying in its own section that was
meant to ease its finding is not exempt from this problem.

The only remaining way is to inspect the core to search for the
post-mortem magic, figure its offset from the file and look up the
corresponding virtual address with objdump. This is quite a hassle.

This patch implements a simple utility that opens a 64-bit core dump,
scans the program headers looking for a data segment which contains
the post-mortem magic, and prints it on stdout. It also places the
"pm_init" command alone on its own line to ease copy-pasting into the
gdb console. With this, at least the other commands in this directory
work again and allow to inspect the program's state. E.g:

  $ ./getpm core.57612
  Found post-mortem magic in segment 5:
    Core File Offset: 0xfc600 (0xd5000 + 0x27600)
    Runtime VAddr:    0x5613e52b6600 (0x5613e528f000 + 0x27600)
    Segment Size:     0x28000

  In gdb, copy-paste this line:

     pm_init 0x5613e52b6600

It's worth noting that the program has so few dependencies that it even
builds with nolibc, allowing to upload a static executable into containers
being debugged and lacking development tools and compilers. The build
procedure is indicated inthe source code.
2026-02-14 14:46:33 +01:00
Aurelien DARRAGON
d71e2e73ea MEDIUM: filters: use per-channel filter list when relevant
Some checks failed
Contrib / build (push) Has been cancelled
alpine/musl / gcc (push) Has been cancelled
VTest / Generate Build Matrix (push) Has been cancelled
Windows / Windows, gcc, all features (push) Has been cancelled
VTest / (push) Has been cancelled
In the historical implementation, all filter related information where
stored at the stream level (using struct strm_flt * context), and filters
iteration was performed at the stream level also.

We identified that this was not ideal and would make the implementation of
future filters more complex since filters ordering should be handled in
a different order during request and response handling for decompression
for instance.

To make such thing possible, in this commit we migrate some channel
specific filter contexts in the channel directly (request or response),
and we implement 2 additional filter lists, one on the request channel
and another on the response channel. The historical stream filter list
is kept as-is because in some contexts only the stream is available and
we have to iterate on all filters. But for functions where we only are
interested in request side or response side filters, we now use dedicated
channel filters list instead.

The only overhead is that the "struct filter" was expanded by two "struct
list".

For now, no change of behavior is expected.
2026-02-13 12:24:13 +01:00
Aurelien DARRAGON
bb6cfbe754 MINOR: filters: rework filter iteration for channel related callback functions
Multiple channel related functions have the same construction: they use
list_for_each_entry() to work on a given filter from the stream+channel
combination. In future commits we will try to use filter list from
dedicated channel list instead of the stream one, thus in this patch we
need as a prerequisite to implement and use the flt_list_{start,next} API
to iterate over filter list, giving the API the responsibility to iterate
over the correct list depending on the context, while the calling function
remains free to use the iteration construction it needs. This way we will
be able to easily change the way we iterate over filter list without
duplicating the code for requests and responses.
2026-02-13 12:24:07 +01:00