]> git.ipfire.org Git - thirdparty/asterisk.git/commitdiff
pbx_variables.c: Create real channel for "dialplan eval function".
authorNaveen Albert <asterisk@phreaknet.org>
Tue, 9 Sep 2025 20:10:14 +0000 (16:10 -0400)
committergithub-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Thu, 11 Sep 2025 12:31:43 +0000 (12:31 +0000)
"dialplan eval function" has been using a dummy channel for function
evaluation, much like many of the unit tests. However, sometimes, this
can cause issues for functions that are not expecting dummy channels.
As an example, ast_channel_tech(chan) is NULL on such channels, and
ast_channel_tech(chan)->type consequently results in a NULL dereference.
Normally, functions do not worry about this since channels executing
dialplan aren't dummy channels.

While some functions are better about checking for these sorts of edge
cases, use a real channel with a dummy technology to make this CLI
command inherently safe for any dialplan function that could be evaluated
from the CLI.

Resolves: #1434

main/pbx_variables.c

index f9c3fd1ef2b80ee4c7061a6b4d23484500205515..9c9ed92cedb1186d3ee026f59a58397de30db22e 100644 (file)
@@ -39,6 +39,7 @@
 #include "asterisk/module.h"
 #include "asterisk/paths.h"
 #include "asterisk/pbx.h"
+#include "asterisk/format_cache.h"
 #include "asterisk/stasis_channels.h"
 #include "asterisk/test.h"
 #include "pbx_private.h"
@@ -984,13 +985,19 @@ static char *handle_show_chanvar(struct ast_cli_entry *e, int cmd, struct ast_cl
        return CLI_SUCCESS;
 }
 
+static const struct ast_channel_tech mock_channel_tech = {
+};
+
+static int cli_chan = 0;
+
 /*! \brief CLI support for executing function */
 static char *handle_eval_function(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 {
        struct ast_channel *c = NULL;
-       char *fn, *substituted;
+       const char *fn, *substituted;
        int ret;
        char workspace[1024];
+       RAII_VAR(struct ast_format_cap *, caps, NULL, ao2_cleanup);
 
        switch (cmd) {
        case CLI_INIT:
@@ -1010,19 +1017,51 @@ static char *handle_eval_function(struct ast_cli_entry *e, int cmd, struct ast_c
                return CLI_SHOWUSAGE;
        }
 
-       c = ast_dummy_channel_alloc();
-       if (!c) {
-               ast_cli(a->fd, "Unable to allocate bogus channel for function evaluation.\n");
+       if (a->argc != e->args + 1 && a->argc != e->args + 2) {
+               return CLI_SHOWUSAGE;
+       }
+
+       caps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);
+       if (!caps) {
+               ast_log(LOG_WARNING, "Could not allocate an empty format capabilities structure\n");
+               return CLI_FAILURE;
+       }
+
+       if (ast_format_cap_append(caps, ast_format_ulaw, 0)) {
+               ast_log(LOG_WARNING, "Failed to append a ulaw format to capabilities for channel nativeformats\n");
                return CLI_FAILURE;
        }
 
-       fn = (char *) a->argv[3];
+       if (ast_format_cap_append(caps, ast_format_alaw, 0)) {
+               ast_log(LOG_WARNING, "Failed to append an alaw format to capabilities for channel nativeformats\n");
+               return CLI_FAILURE;
+       }
+
+       if (ast_format_cap_append(caps, ast_format_h264, 0)) {
+               ast_log(LOG_WARNING, "Failed to append an h264 format to capabilities for channel nativeformats\n");
+               return CLI_FAILURE;
+       }
+
+       c = ast_channel_alloc(0, AST_STATE_DOWN, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0, "CLIEval/%d", ++cli_chan);
+       if (!c) {
+               ast_cli(a->fd, "Unable to allocate mock channel for application execution.\n");
+               return CLI_FAILURE;
+       }
+       ast_channel_tech_set(c, &mock_channel_tech);
+       ast_channel_nativeformats_set(c, caps);
+       ast_channel_set_writeformat(c, ast_format_slin);
+       ast_channel_set_rawwriteformat(c, ast_format_slin);
+       ast_channel_set_readformat(c, ast_format_slin);
+       ast_channel_set_rawreadformat(c, ast_format_slin);
+       ast_channel_unlock(c);
+
+       fn = a->argv[3];
        pbx_substitute_variables_helper(c, fn, workspace, sizeof(workspace));
        substituted = ast_strdupa(workspace);
        workspace[0] = '\0';
        ret = ast_func_read(c, substituted, workspace, sizeof(workspace));
 
-       c = ast_channel_unref(c);
+       ast_hangup(c); /* no need to unref separately */
 
        ast_cli(a->fd, "Return Value: %s (%d)\n", ret ? "Failure" : "Success", ret);
        ast_cli(a->fd, "Result: %s\n", workspace);