From: Amaury Denoyelle Date: Thu, 22 Feb 2024 13:16:37 +0000 (+0100) Subject: BUG/MAJOR: promex: fix crash on deleted server X-Git-Tag: v3.0-dev4~9 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=f81c00cd447e21b07ee355fd5c2fb2a4787ea4a0;p=thirdparty%2Fhaproxy.git BUG/MAJOR: promex: fix crash on deleted server Promex applet is used to dump many metrics. Some of them are related to a server instance. The applet can be interrupted in the middle of a dump, for example waiting for output buffer space. In this case, its context is save to resume dump on the correct instance. A crash can occur if dump is interrupted during servers loop. If the server instance is deleted during two scheduling of the promex applet, its context will still referenced the deleted server on resume. To fix this, use server refcount to prevent its deletion during parsing. No backport is needed, despite all stable releases being affected. This is because promex applet context has been recently rewritten to use generic pointers. As such, a specific commit will be applied for earlier releases. --- diff --git a/addons/promex/service-prometheus.c b/addons/promex/service-prometheus.c index 4fc418ab29..1d587711c6 100644 --- a/addons/promex/service-prometheus.c +++ b/addons/promex/service-prometheus.c @@ -1518,6 +1518,12 @@ static int promex_dump_srv_metrics(struct appctx *appctx, struct htx *htx) return -1; /* Unexpected and unrecoverable error */ channel_add_input(chn, out.len); } + + /* Decrement server refcount if it was saved through ctx.p[1]. */ + srv_drop(ctx->p[1]); + if (sv) + srv_take(sv); + /* Save pointers (0=current proxy, 1=current server, 2=current stats module) of the current context */ ctx->p[0] = px; ctx->p[1] = sv; @@ -2061,6 +2067,11 @@ static void promex_appctx_release(struct appctx *appctx) struct promex_metric_filter *flt; struct eb32_node *node, *next; + if (appctx->st1 == PROMEX_DUMPER_SRV) { + struct server *srv = objt_server(ctx->p[1]); + srv_drop(srv); + } + list_for_each_entry_safe(ref, back, &ctx->modules, list) { LIST_DELETE(&ref->list); pool_free(pool_head_promex_mod_ref, ref);