From: Willy Tarreau Date: Tue, 3 May 2022 13:26:27 +0000 (+0200) Subject: BUG/MINOR: map/cli: make sure patterns don't vanish under "show map"'s init X-Git-Tag: v2.6-dev9~80 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=1ae0c43244254a3cf652300413625191d6a9dd4f;p=thirdparty%2Fhaproxy.git BUG/MINOR: map/cli: make sure patterns don't vanish under "show map"'s init 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. --- diff --git a/src/map.c b/src/map.c index 4c0b45b73d..6c35680a7a 100644 --- 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;