]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
BUG/MINOR: map/cli: make sure patterns don't vanish under "show map"'s init
authorWilly Tarreau <w@1wt.eu>
Tue, 3 May 2022 13:26:27 +0000 (15:26 +0200)
committerWilly Tarreau <w@1wt.eu>
Fri, 6 May 2022 16:13:35 +0000 (18:13 +0200)
When "show map" initializes itself, it first takes the reference to the
starting point under a lock, then releases it before switching to state
STATE_LIST, and takes the lock again. The problem is that it is possible
for another thread to remove the first element during this unlock/lock
sequence, and make the list run anywhere. This is of course extremely
unlikely but not impossible.

Let's initialize the pointer in the STATE_LIST part under the same lock,
which is simpler and more reliable.

This should be backported to all versions.

src/map.c

index 4c0b45b73d06e49e67e37d0c732a1339fbc90b4d..6c35680a7a0b48dd31b7d04921742dac13da73ea 100644 (file)
--- a/src/map.c
+++ b/src/map.c
@@ -345,27 +345,17 @@ static int cli_io_handler_pat_list(struct appctx *appctx)
        switch (appctx->st2) {
 
        case STAT_ST_INIT:
-               /* the function had not been called yet, let's prepare the
-                * buffer for a response. We initialize the current stream
-                * pointer to the first in the global list. When a target
-                * stream is being destroyed, it is responsible for updating
-                * this pointer. We know we have reached the end when this
-                * pointer points back to the head of the streams list.
-                */
-               HA_SPIN_LOCK(PATREF_LOCK, &appctx->ctx.map.ref->lock);
-               LIST_INIT(&appctx->ctx.map.bref.users);
-               appctx->ctx.map.bref.ref = appctx->ctx.map.ref->head.n;
-               HA_SPIN_UNLOCK(PATREF_LOCK, &appctx->ctx.map.ref->lock);
                appctx->st2 = STAT_ST_LIST;
                /* fall through */
 
        case STAT_ST_LIST:
-
                HA_SPIN_LOCK(PATREF_LOCK, &appctx->ctx.map.ref->lock);
 
                if (!LIST_ISEMPTY(&appctx->ctx.map.bref.users)) {
                        LIST_DELETE(&appctx->ctx.map.bref.users);
                        LIST_INIT(&appctx->ctx.map.bref.users);
+               } else {
+                       appctx->ctx.map.bref.ref = appctx->ctx.map.ref->head.n;
                }
 
                while (appctx->ctx.map.bref.ref != &appctx->ctx.map.ref->head) {
@@ -718,6 +708,7 @@ static int cli_parse_show_map(char **args, char *payload, struct appctx *appctx,
                else
                        appctx->ctx.cli.i0 = appctx->ctx.map.ref->curr_gen;
 
+               LIST_INIT(&appctx->ctx.map.bref.users);
                appctx->io_handler = cli_io_handler_pat_list;
                appctx->io_release = cli_release_show_map;
                return 0;