BUG/MINOR: stick-tables: properly index string-type keys

This is one of the rare pleasant surprises of fixing an almost 16-years
old bug that remained unnoticed since the feature was implemented. In
1.4-dev7, commit 3bd697e071 ("[MEDIUM] Add stick table (persistence)
management functions and types") introduced stick-tables with multiple
key types, including strings, IP addresses and integers. Entries are
coded in binary and their binary representation is indexed. A special
case was made for strings in order to index them as zero-terminated
strings. However, there's one subtlety. While strings indeed have a
zero appended, they're still indexed using ebmb_insert(), which means
that all the bytes till the configured size are indexed as well. And
while these bytes generally come from a temporary storage that often
contains zeroes, or that is longer than the configured string length
and will result in truncation, it's not always the case and certain
traffic patterns with certain configurations manage to occasionally
present unpadded strings resulting in apparent duplicate keys appearing
in the dump, as shown in GH issue #3161. It seems to be essentially
reproducible at boot, and not to be particularly affected by mixed
patterns. These keys are in fact not exact duplicates in memory, but
everywhere they're used (including during synchronization), they are
equal.

What's interesting is that when this happens, one key can be presented
to a peer with its own data and will be indexed as the only one, possibly
replacing contents from the previous key, which might replace them again
later once updated in turn. This is visible in the dump of the issue
above, where key "localhost:8001" was split into two entries, one with a
request count of one and the other with a request count of 499999, and
indeed, all peers see only that last value, which overwrote the first
one.

This fix must be backported to all stable branches. Special kudos to
Mark Wort for undelining that one.
This commit is contained in:
Willy Tarreau 2025-10-24 07:46:53 +02:00
parent d655ed5f14
commit 1824079fca

View File

@ -703,7 +703,10 @@ struct stksess *__stktable_store(struct stktable *t, struct stksess *ts, uint sh
{ {
struct ebmb_node *eb; struct ebmb_node *eb;
eb = ebmb_insert(&t->shards[shard].keys, &ts->key, t->key_size); if (t->type == SMP_T_STR)
eb = ebst_insert(&t->shards[shard].keys, &ts->key);
else
eb = ebmb_insert(&t->shards[shard].keys, &ts->key, t->key_size);
if (likely(eb == &ts->key)) { if (likely(eb == &ts->key)) {
ts->exp.key = ts->expire; ts->exp.key = ts->expire;
eb32_insert(&t->shards[shard].exps, &ts->exp); eb32_insert(&t->shards[shard].exps, &ts->exp);