]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
BUG/MAJOR: stick-tables: do not try to index a server name for applets
authorWilly Tarreau <w@1wt.eu>
Wed, 12 Oct 2022 08:35:41 +0000 (10:35 +0200)
committerWilly Tarreau <w@1wt.eu>
Wed, 12 Oct 2022 12:19:05 +0000 (14:19 +0200)
Since commit 03cdf55e6 ("MINOR: stream: Stickiness server lookup by name.")
in 2.0-dev6, server names may be used instead of their IDs, in order to
perform stickiness. However the commit above may end up trying to insert
an empty server name in the dictionary when the server is an applet
instead, resulting in an immediate segfault. This is typically what
happens when a "stick-store" rule is present in a backend featuring a
"stats" directive. As there doesn't seem to be an easy way around it,
it seems to imply that "stick-store" is not much used anymore.

The solution here is to only try to insert non-null keys into the
dictionary. The patch moves the check of the key type before the
first lock so that the test on the key can be performed under the lock
instead of locking twice (the patch is more readable with diff -b).

Note that before 2.4, there's no <key> variable there as it was
introduced by commit 92149f9a8 ("MEDIUM: stick-tables: Add srvkey
option to stick-table"), but the __objt_server(s->target)->id still
needs to be tested.

This needs to be backported as far as 2.0.

src/stream.c

index a3c4a1ab700d1dd9bc492d3eda52b4de3e80d537..b19519f84adee35cfa509039f54d6ef806b3307e 100644 (file)
@@ -1424,24 +1424,25 @@ static int process_store_rules(struct stream *s, struct channel *rep, int an_bit
                }
                s->store[i].ts = NULL;
 
-               HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
-               ptr = __stktable_data_ptr(t, ts, STKTABLE_DT_SERVER_ID);
-               stktable_data_cast(ptr, std_t_sint) = __objt_server(s->target)->puid;
-               HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
-
                if (t->server_key_type == STKTABLE_SRV_NAME)
                        key = __objt_server(s->target)->id;
                else if (t->server_key_type == STKTABLE_SRV_ADDR)
                        key = __objt_server(s->target)->addr_node.key;
                else
-                       continue;
+                       key = NULL;
 
                HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
-               de = dict_insert(&server_key_dict, key);
-               if (de) {
-                       ptr = __stktable_data_ptr(t, ts, STKTABLE_DT_SERVER_KEY);
-                       stktable_data_cast(ptr, std_t_dict) = de;
+               ptr = __stktable_data_ptr(t, ts, STKTABLE_DT_SERVER_ID);
+               stktable_data_cast(ptr, std_t_sint) = __objt_server(s->target)->puid;
+
+               if (key) {
+                       de = dict_insert(&server_key_dict, key);
+                       if (de) {
+                               ptr = __stktable_data_ptr(t, ts, STKTABLE_DT_SERVER_KEY);
+                               stktable_data_cast(ptr, std_t_dict) = de;
+                       }
                }
+
                HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
 
                stktable_touch_local(t, ts, 1);