]> git.kaiwu.me - haproxy.git/commit
BUG/MEDIUM: stick-tables: use the same bucket for string keys with a NUL
authorOlivier Houchard <ohouchard@haproxy.com>
Thu, 6 Aug 2026 07:30:13 +0000 (09:30 +0200)
committerWilly Tarreau <w@1wt.eu>
Fri, 7 Aug 2026 08:29:19 +0000 (10:29 +0200)
commit1014a43e02850682d2426fe5d3f781a4d788df18
tree392c3029e92f10ac19f8bbc92ab48fcac16ff85b
parent1af221457bae61ea898e5c672a4fd65c1aefcca5
BUG/MEDIUM: stick-tables: use the same bucket for string keys with a NUL

String stick-table keys are stored NUL-terminated and looked up in a string
ebtree, so an entry is identified by the bytes preceding the first NUL.
Accordingly stksess_kill(), __stksess_kill_if_expired(), stktable_lookup(),
stktable_requeue_exp() and stktable_set_entry() all derive the bucket from
strlen() of the stored key, but stktable_lookup_key() and
stktable_get_entry() derive it from the raw sample length. A key carrying an
embedded NUL is thus inserted in one bucket and later killed or requeued
while holding the lock of another one, so that bucket's tree ends up
modified without its lock while other threads look it up: corrupted tree,
hence a crash, a lost or duplicated entry, or a use-after-free on a stksess.

Embedded NULs are not exotic: url_decode() turns "%00" into one and keeps
going, while smp_to_stkey() passes the sample length as-is. Tracking
"url_param(q),url_dec" into a string table and sending "GET /?q=AB%00CD"
yields key_len 5 but strlen 2, hence two different buckets. The peers
protocol also transports raw key bytes.

Let's make the two remaining places stop at the first NUL as well, so that
a single canonical length is used everywhere.

The bucket split was introduced in 3.0 by commit 1a088da7c ("MAJOR:
stktable: split the keys across multiple shards to reduce contention").
This must be backported to 3.0.

Reported-by: Claude (ANT-2026-TNFHK5ZG)
src/stick_table.c