]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
BUG/MINOR: proxy: release watcher in various commands on CLI abort
authorAmaury Denoyelle <adenoyelle@haproxy.com>
Thu, 6 Aug 2026 14:11:53 +0000 (16:11 +0200)
committerAmaury Denoyelle <adenoyelle@haproxy.com>
Thu, 6 Aug 2026 14:45:28 +0000 (16:45 +0200)
Watcher has been added to protect several commands in src/proxy.c which
iterate over either the proxies or servers list against a runtime
deletion.

However, no io_release has been defined for such commands. This may
cause issue in case the command has yielded and is aborted before its
full completion, for example on client early disconnect. Related applet
context is freed while still subscribed into a proxy or server instance.
When this instance is deleted, a crash occurs on freed applet context
access.

To prevent this, define a dedicated io_release for the following
commands : "show servers state|conn", "show backend" and "show errors".
Any watcher is detached there.

Reported-by: Claude (ANT-2026-6Q55R82E)
This must be backported up to 3.4.

src/proxy.c

index 957c31ca81e8f9bc57ff3a137cf3faeddbdc73a6..1a83f7bd4464ea3c2cabbaead869d0b582ac0986 100644 (file)
@@ -4696,6 +4696,14 @@ static int cli_io_handler_servers_state(struct appctx *appctx)
        return 1;
 }
 
+/* release handler for "show servers conn|state" */
+static void cli_io_release_show_servers(struct appctx *appctx)
+{
+       struct show_srv_ctx *ctx = appctx->svcctx;
+       watcher_detach(&ctx->px_watch);
+       watcher_detach(&ctx->srv_watch);
+}
+
 /* Parses backend list and simply report backend names. It keeps the proxy
  * pointer in svcctx since there's nothing else to store there.
  */
@@ -4733,6 +4741,14 @@ static int cli_io_handler_show_backend(struct appctx *appctx)
        return 1;
 }
 
+/* release handler for "show backend" */
+static void cli_io_release_show_backend(struct appctx *appctx)
+{
+       struct show_be_ctx *ctx = appctx->svcctx;
+       if (ctx->px)
+               watcher_detach(&ctx->px_watch);
+}
+
 /* Parses the "enable dynamic-cookies backend" directive, it always returns 1.
  *
  * Grabs the proxy lock and each server's lock.
@@ -5542,6 +5558,13 @@ static int cli_io_handler_show_errors(struct appctx *appctx)
        return 0;
 }
 
+/* release handler for "show errors" */
+static void cli_io_release_show_errors(struct appctx *appctx)
+{
+       struct show_errors_ctx *ctx = appctx->svcctx;
+       watcher_detach(&ctx->px_watch);
+}
+
 /* register cli keywords */
 static struct cli_kw_list cli_kws = {{ },{
        { { "add", "backend", NULL },                       "add backend <backend>                   : add a new backend",                                              cli_parse_add_backend, NULL, NULL, NULL, 0 },
@@ -5552,15 +5575,15 @@ static struct cli_kw_list cli_kws = {{ },{
        { { "set", "maxconn", "frontend",  NULL },          "set maxconn frontend <frontend> <value> : change a frontend's maxconn setting",                            cli_parse_set_maxconn_frontend, NULL },
        { { "show", "default-server", NULL },               "show default-server [<backend>]         : list default-server instances in all or a single backend",       cli_parse_show_default_server, cli_io_handler_show_default_server, },
        { { "show", "defaults", NULL },                     "show defaults                           : list all proxies defaults sections",                             NULL, cli_io_handler_show_defaults },
-       { { "show","servers", "conn",  NULL },              "show servers conn [<backend>]           : dump server connections status (all or for a single backend)",   cli_parse_show_servers, cli_io_handler_servers_state },
-       { { "show","servers", "state",  NULL },             "show servers state [<backend>]          : dump volatile server information (all or for a single backend)", cli_parse_show_servers, cli_io_handler_servers_state },
-       { { "show", "backend", NULL },                      "show backend                            : list backends in the current running config", NULL,              cli_io_handler_show_backend },
+       { { "show","servers", "conn",  NULL },              "show servers conn [<backend>]           : dump server connections status (all or for a single backend)",   cli_parse_show_servers, cli_io_handler_servers_state, cli_io_release_show_servers, },
+       { { "show","servers", "state",  NULL },             "show servers state [<backend>]          : dump volatile server information (all or for a single backend)", cli_parse_show_servers, cli_io_handler_servers_state, cli_io_release_show_servers, },
+       { { "show", "backend", NULL },                      "show backend                            : list backends in the current running config",                    NULL, cli_io_handler_show_backend, cli_io_release_show_backend, },
        { { "shutdown", "frontend",  NULL },                "shutdown frontend <frontend>            : stop a specific frontend",                                       cli_parse_shutdown_frontend, NULL, NULL },
        { { "set", "dynamic-cookie-key", "backend", NULL }, "set dynamic-cookie-key backend <bk> <k> : change a backend secret key for dynamic cookies",                cli_parse_set_dyncookie_key_backend, NULL },
        { { "unpublish", "backend",  NULL },                "unpublish backend <backend>             : remove backend for traffic processing",                          cli_parse_unpublish_backend, NULL, NULL },
        { { "enable", "dynamic-cookie", "backend", NULL },  "enable dynamic-cookie backend <bk>      : enable dynamic cookies on a specific backend",                   cli_parse_enable_dyncookie_backend, NULL },
        { { "disable", "dynamic-cookie", "backend", NULL }, "disable dynamic-cookie backend <bk>     : disable dynamic cookies on a specific backend",                  cli_parse_disable_dyncookie_backend, NULL },
-       { { "show", "errors", NULL },                       "show errors [<px>] [request|response]   : report last request and/or response errors for each proxy",      cli_parse_show_errors, cli_io_handler_show_errors, NULL },
+       { { "show", "errors", NULL },                       "show errors [<px>] [request|response]   : report last request and/or response errors for each proxy",      cli_parse_show_errors, cli_io_handler_show_errors, cli_io_release_show_errors, },
        {{},}
 }};