From: Willy Tarreau Date: Thu, 8 May 2025 21:21:25 +0000 (+0200) Subject: BUG/MEDIUM: stick-table: always remove update before adding a new one X-Git-Tag: v3.2-dev15~4 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=576e47fb9a93b408a613be580cdcdea0ce22fc8b;p=thirdparty%2Fhaproxy.git BUG/MEDIUM: stick-table: always remove update before adding a new one Since commit 388539faa ("MEDIUM: stick-tables: defer adding updates to a tasklet"), between the entry creation and its arrival in the updates tree, there is time for scheduling, and it now becomes possible for an stksess entry to be requeued into the list while it's still in the tree as a remote one. Only local updates were removed prior to being inserted. In this case we would re-insert the entry, causing it to appear as the parent of two distinct nodes or leaves, and to be visited from the first leaf during a delete() after having already been removed and freed, causing a crash, as Christian reported in issue #2959. There's no reason to backport this as this appeared with the commit above in 3.2-dev13. --- diff --git a/src/stick_table.c b/src/stick_table.c index 26747eac3..a1900f66f 100644 --- a/src/stick_table.c +++ b/src/stick_table.c @@ -796,7 +796,7 @@ static struct task *stktable_add_pend_updates(struct task *t, void *ctx, unsigne empty_tgid++; cur_tgid++; if (cur_tgid == global.nbtgroups) - cur_tgid = 0; + cur_tgid = 0; if (empty_tgid == global.nbtgroups) break; @@ -815,9 +815,15 @@ static struct task *stktable_add_pend_updates(struct task *t, void *ctx, unsigne } else { stksess->upd.key = (++table->update) + (2147483648U); } + + /* even though very unlikely, it seldom happens that the entry + * is already in the tree (both for local and remote ones). We + * must dequeue it and requeue it at its new position (e.g. it + * might already have been seen by some peers). + */ + eb32_delete(&stksess->upd); eb = eb32_insert(&table->updates, &stksess->upd); if (eb != &stksess->upd) { - BUG_ON(1); eb32_delete(eb); eb32_insert(&table->updates, &stksess->upd); }