]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
BUG/MEDIUM: stick-tables: Always return the good stksess from stktable_set_entry
authorChristopher Faulet <cfaulet@haproxy.com>
Fri, 14 Nov 2025 10:31:45 +0000 (11:31 +0100)
committerChristopher Faulet <cfaulet@haproxy.com>
Fri, 14 Nov 2025 10:56:12 +0000 (11:56 +0100)
In stktable_set_entry(), the return value of __stktable_store() is not
tested while it is possible to get an existing session with the same key
instead of the one we want to insert. It happens when we fails to upgrade
the read lock on the bucket to an write lock. In that case, we release the
lock for a short time to get a write lock.

So, to fix the bug, we must check the session returned by __stktable_store()
and take care to return this one.

The bug was introduced by the commit e62885237c ("MEDIUM: stick-table: make
stktable_set_entry() look up under a read lock"). It must be backported as
far as 2.8.

src/stick_table.c

index c9faa56a8f344b0fbc00fb7d865bb1065b42480a..240f10c75bee95cbd57626bb41480ff0973ad8a6 100644 (file)
@@ -927,10 +927,9 @@ struct stksess *stktable_set_entry(struct stktable *table, struct stksess *nts)
                HA_RWLOCK_RDUNLOCK(STK_TABLE_LOCK, &table->shards[shard].sh_lock);
                return ts;
        }
-       ts = nts;
 
        /* let's increment it before switching to exclusive */
-       HA_ATOMIC_INC(&ts->ref_cnt);
+       HA_ATOMIC_INC(&nts->ref_cnt);
 
        if (HA_RWLOCK_TRYRDTOSK(STK_TABLE_LOCK, &table->shards[shard].sh_lock) != 0) {
                /* upgrade to seek lock failed, let's drop and take */
@@ -942,10 +941,15 @@ struct stksess *stktable_set_entry(struct stktable *table, struct stksess *nts)
 
        /* now we're write-locked */
 
-       __stktable_store(table, ts, shard);
+       ts = __stktable_store(table, nts, shard);
+       if (ts != nts) {
+               HA_ATOMIC_DEC(&nts->ref_cnt);
+               HA_ATOMIC_INC(&ts->ref_cnt);
+       }
        HA_RWLOCK_WRUNLOCK(STK_TABLE_LOCK, &table->shards[shard].sh_lock);
 
-       stktable_requeue_exp(table, ts);
+       if (ts == nts)
+               stktable_requeue_exp(table, ts);
        return ts;
 }