From: Scott Griepentrog Date: Mon, 16 Dec 2013 16:11:38 +0000 (+0000) Subject: pbx.c: put copy of ast_exten.data on stack to prevent memory corruption X-Git-Tag: 12.0.0~45 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=6663e142ef8193b72a234801a38f2fd2fb52074d;p=thirdparty%2Fasterisk.git pbx.c: put copy of ast_exten.data on stack to prevent memory corruption During dialplan execution in pbx_extension_helper(), the contexts global read lock prevents link list corruption, but was released with a pointer to the ast_exten and data later used in variable substitution. Instead, this patch removes pbx_substitute_variables() and locates a copy of the ast_exten data on the stack before releasing the lock, where ast_exten could get free'd by another thread performing a module reload. (issue AST-1179) Reported by: Thomas Arimont (issue AST-1246) Reported by: Alexander Hömig Review: https://reviewboard.asterisk.org/r/3055/ ........ Merged revisions 403862 from http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged revisions 403863 from http://svn.asterisk.org/svn/asterisk/branches/11 git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/12@403864 65c4cc65-6c06-0410-ace0-fbb531ad65f3 --- diff --git a/main/pbx.c b/main/pbx.c index 5c29a0c422..cb6aaf15d2 100644 --- a/main/pbx.c +++ b/main/pbx.c @@ -4614,25 +4614,6 @@ void pbx_substitute_variables_varshead(struct varshead *headp, const char *cp1, pbx_substitute_variables_helper_full(NULL, headp, cp1, cp2, count, &used); } -static void pbx_substitute_variables(char *passdata, int datalen, struct ast_channel *c, struct ast_exten *e) -{ - const char *tmp; - - /* Nothing more to do */ - if (!e->data) { - *passdata = '\0'; - return; - } - - /* No variables or expressions in e->data, so why scan it? */ - if ((!(tmp = strchr(e->data, '$'))) || (!strstr(tmp, "${") && !strstr(tmp, "$["))) { - ast_copy_string(passdata, e->data, datalen); - return; - } - - pbx_substitute_variables_helper(c, e->data, passdata, datalen - 1); -} - /*! * \brief The return value depends on the action: * @@ -4657,6 +4638,7 @@ static int pbx_extension_helper(struct ast_channel *c, struct ast_context *con, { struct ast_exten *e; struct ast_app *app; + char *substitute = NULL; int res; struct pbx_find_info q = { .stacklen = 0 }; /* the rest is reset in pbx_find_extension */ char passdata[EXT_DATA_SIZE]; @@ -4683,6 +4665,18 @@ static int pbx_extension_helper(struct ast_channel *c, struct ast_context *con, if (!e->cached_app) e->cached_app = pbx_findapp(e->app); app = e->cached_app; + if (ast_strlen_zero(e->data)) { + *passdata = '\0'; + } else { + const char *tmp; + if ((!(tmp = strchr(e->data, '$'))) || (!strstr(tmp, "${") && !strstr(tmp, "$["))) { + /* no variables to substitute, copy on through */ + ast_copy_string(passdata, e->data, sizeof(passdata)); + } else { + /* save e->data on stack for later processing after lock released */ + substitute = ast_strdupa(e->data); + } + } ast_unlock_contexts(); if (!app) { ast_log(LOG_WARNING, "No application '%s' for extension (%s, %s, %d)\n", e->app, context, exten, priority); @@ -4693,7 +4687,9 @@ static int pbx_extension_helper(struct ast_channel *c, struct ast_context *con, if (ast_channel_exten(c) != exten) ast_channel_exten_set(c, exten); ast_channel_priority_set(c, priority); - pbx_substitute_variables(passdata, sizeof(passdata), c, e); + if (substitute) { + pbx_substitute_variables_helper(c, substitute, passdata, sizeof(passdata)-1); + } ast_debug(1, "Launching '%s'\n", app->name); { ast_verb(3, "Executing [%s@%s:%d] " COLORIZE_FMT "(\"" COLORIZE_FMT "\", \"" COLORIZE_FMT "\") %s\n",