]> git.kaiwu.me - haproxy.git/commitdiff
BUG/MEDIUM: proxy: protect show backend against be deletion
authorAmaury Denoyelle <adenoyelle@haproxy.com>
Tue, 21 Jul 2026 09:35:25 +0000 (11:35 +0200)
committerAmaury Denoyelle <adenoyelle@haproxy.com>
Tue, 21 Jul 2026 14:58:20 +0000 (16:58 +0200)
Command "show backend" loops over the list of visible proxies to display
information about all the backend instances. This command may yield in
case of a long output, but this is not safe with introduction of dynamic
backend deletion at runtime.

Fixes this by using the watcher mechanism, similarly to what is
implemented for stats dump. To support this, a new context dedicated to
"show backend" has been defined.

This must be backported up to 3.4.

src/proxy.c

index 61457b49cfc7b63d4327190ba96a2e04796b4f23..62b45b8c176a5110588b3cdf6883302050fbf59c 100644 (file)
@@ -82,6 +82,12 @@ unsigned int error_snapshot_id = 0;     /* global ID assigned to each error then
 
 unsigned int dynpx_next_id = 0; /* lowest ID assigned to dynamic proxies */
 
+/* CLI context used during "show backend" */
+struct show_be_ctx {
+       struct proxy *px;
+       struct watcher px_watch; /* watcher to automatically update px pointer on backend deletion */
+};
+
 /* CLI context used during "show servers {state|conn}" */
 struct show_srv_ctx {
        struct proxy *px;       /* current proxy to dump or NULL */
@@ -4609,20 +4615,23 @@ static int cli_io_handler_servers_state(struct appctx *appctx)
  */
 static int cli_io_handler_show_backend(struct appctx *appctx)
 {
+       struct show_be_ctx *ctx = applet_reserve_svcctx(appctx, sizeof(*ctx));
        struct proxy *curproxy;
 
        chunk_reset(&trash);
 
-       if (!appctx->svcctx) {
+       if (!ctx->px) {
                chunk_printf(&trash, "# name\n");
                if (applet_putchk(appctx, &trash) == -1)
                        return 0;
 
-               appctx->svcctx = proxies_list;
+               watcher_init(&ctx->px_watch, &ctx->px, offsetof(struct proxy, watcher_list));
+               /* This will automatically update ctx->px pointer. */
+               watcher_attach(&ctx->px_watch, proxies_list);
        }
 
-       for (; appctx->svcctx != NULL; appctx->svcctx = curproxy->next) {
-               curproxy = appctx->svcctx;
+       for (; ctx->px; watcher_next(&ctx->px_watch, ctx->px->next)) {
+               curproxy = ctx->px;
 
                /* looking for non-internal backends only */
                if ((curproxy->cap & (PR_CAP_BE|PR_CAP_INT)) != PR_CAP_BE)