]> git.ipfire.org Git - thirdparty/asterisk.git/commitdiff
pbx_variables.c: Prevent SEGV due to stack overflow.
authorNaveen Albert <asterisk@phreaknet.org>
Mon, 4 Dec 2023 17:58:17 +0000 (12:58 -0500)
committerAsterisk Development Team <asteriskteam@digium.com>
Thu, 9 May 2024 13:48:09 +0000 (13:48 +0000)
It is possible for dialplan to result in an infinite
recursion of variable substitution, which eventually
leads to stack overflow. If we detect this, abort
substitution and log an error for the user to fix
the broken dialplan.

Resolves: #480

UpgradeNote: The maximum amount of dialplan recursion
using variable substitution (such as by using EVAL_EXTEN)
is capped at 15.

(cherry picked from commit 310c8a7c68cbbe0e16165116ebe55ea82db2675b)

main/pbx_variables.c

index b05a9d11ca86da65d91272d9b71c7656d5ba51b5..285ac765a477a14adbac713d6a118761d88065d5 100644 (file)
@@ -662,6 +662,11 @@ void pbx_substitute_variables_helper_full(struct ast_channel *c, struct varshead
        pbx_substitute_variables_helper_full_location(c, headp, cp1, cp2, count, used, NULL, NULL, 0);
 }
 
+/*! \brief Thread local keeping track of recursion depth */
+AST_THREADSTORAGE(varsub_recurse_level);
+
+#define MAX_VARIABLE_SUB_RECURSE_DEPTH 15
+
 void pbx_substitute_variables_helper_full_location(struct ast_channel *c, struct varshead *headp, const char *cp1, char *cp2, int count, size_t *used, const char *context, const char *exten, int pri)
 {
        /* Substitutes variables into cp2, based on string cp1, cp2 NO LONGER NEEDS TO BE ZEROED OUT!!!!  */
@@ -669,8 +674,22 @@ void pbx_substitute_variables_helper_full_location(struct ast_channel *c, struct
        const char *orig_cp2 = cp2;
        char ltmp[VAR_BUF_SIZE];
        char var[VAR_BUF_SIZE];
+       int *recurse_depth;
 
        *cp2 = 0; /* just in case nothing ends up there */
+
+       /* It is possible to craft dialplan that will recurse indefinitely and cause a stack overflow.
+        * This is symptomatic of a dialplan bug, so abort substitution rather than crash. */
+       recurse_depth = ast_threadstorage_get(&varsub_recurse_level, sizeof(*recurse_depth));
+       if (!recurse_depth) {
+               return;
+       }
+       if ((*recurse_depth)++ >= MAX_VARIABLE_SUB_RECURSE_DEPTH) {
+               ast_log(LOG_ERROR, "Exceeded maximum variable substitution recursion depth (%d) - possible infinite recursion in dialplan?\n", MAX_VARIABLE_SUB_RECURSE_DEPTH);
+               (*recurse_depth)--;
+               return;
+       }
+
        whereweare = cp1;
        while (!ast_strlen_zero(whereweare) && count) {
                char *nextvar = NULL;
@@ -881,6 +900,7 @@ void pbx_substitute_variables_helper_full_location(struct ast_channel *c, struct
        if (used) {
                *used = cp2 - orig_cp2;
        }
+       (*recurse_depth)--;
 }
 
 void pbx_substitute_variables_helper(struct ast_channel *c, const char *cp1, char *cp2, int count)