From f9f36ca702ca812e142419df9ebca0d0a9b9fd1c Mon Sep 17 00:00:00 2001 From: Naveen Albert Date: Mon, 4 Dec 2023 12:58:17 -0500 Subject: [PATCH] pbx_variables.c: Prevent SEGV due to stack overflow. 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. --- main/pbx_variables.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/main/pbx_variables.c b/main/pbx_variables.c index b05a9d11ca..285ac765a4 100644 --- a/main/pbx_variables.c +++ b/main/pbx_variables.c @@ -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)