]> git.ipfire.org Git - thirdparty/asterisk.git/commitdiff
app_macro: Prevent infinite loop in find_matching_priority.
authorCorey Farrell <git@cfware.com>
Fri, 4 May 2018 18:47:25 +0000 (14:47 -0400)
committerCorey Farrell <git@cfware.com>
Mon, 7 May 2018 13:59:00 +0000 (07:59 -0600)
Use AST_PBX_MAX_STACK to escape if we recurse 128 times.  This will
prevent crash if dialplan contains an include loop.  Log an error when
this occurs, at most one message per call to Macro() so we avoid logger
spam.

ASTERISK-26570 #close

Change-Id: I6c71b76998c31434391b150de055ae9a531e31da

apps/app_macro.c

index 5c50a9f4020ff2f71815fc0fb2a913f7fa8646d3..16d9ce2994dad9d00580cda3d391264e64c9e029 100644 (file)
@@ -38,6 +38,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 #include "asterisk/channel.h"
 #include "asterisk/pbx.h"
 #include "asterisk/module.h"
+#include "asterisk/extconf.h"
 #include "asterisk/config.h"
 #include "asterisk/utils.h"
 #include "asterisk/lock.h"
@@ -187,12 +188,21 @@ static void macro_fixup(void *data, struct ast_channel *old_chan, struct ast_cha
        }
 }
 
-static struct ast_exten *find_matching_priority(struct ast_context *c, const char *exten, int priority, const char *callerid)
+static struct ast_exten *find_matching_priority(struct ast_context *c, const char *exten,
+       int priority, const char *callerid, int iter, int *had_error)
 {
        struct ast_exten *e;
        struct ast_include *i;
        struct ast_context *c2;
 
+       if (iter >= AST_PBX_MAX_STACK) {
+               if (!(*had_error)) {
+                       *had_error = 1;
+                       ast_log(LOG_ERROR, "Potential infinite loop detected, will not recurse further.\n");
+               }
+               return NULL;
+       }
+
        for (e=ast_walk_context_extensions(c, NULL); e; e=ast_walk_context_extensions(c, e)) {
                if (ast_extension_match(ast_get_extension_name(e), exten)) {
                        int needmatch = ast_get_extension_matchcid(e);
@@ -213,7 +223,7 @@ static struct ast_exten *find_matching_priority(struct ast_context *c, const cha
        for (i=ast_walk_context_includes(c, NULL); i; i=ast_walk_context_includes(c, i)) {
                for (c2=ast_walk_contexts(NULL); c2; c2=ast_walk_contexts(c2)) {
                        if (!strcmp(ast_get_context_name(c2), ast_get_include_name(i))) {
-                               e = find_matching_priority(c2, exten, priority, callerid);
+                               e = find_matching_priority(c2, exten, priority, callerid, iter + 1, had_error);
                                if (e)
                                        return e;
                        }
@@ -250,6 +260,7 @@ static int _macro_exec(struct ast_channel *chan, const char *data, int exclusive
        char *save_macro_offset;
        int save_in_subroutine;
        struct ast_datastore *macro_store = ast_channel_datastore_find(chan, &macro_ds_info, NULL);
+       int had_infinite_include_error = 0;
 
        if (ast_strlen_zero(data)) {
                ast_log(LOG_WARNING, "Macro() requires arguments. See \"core show application macro\" for help.\n");
@@ -418,7 +429,9 @@ static int _macro_exec(struct ast_channel *chan, const char *data, int exclusive
                                                ast_log(LOG_WARNING, "Unable to lock context?\n");
                                        } else {
                                                e = find_matching_priority(c, ast_channel_exten(chan), ast_channel_priority(chan),
-                                                       S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, NULL));
+                                                       S_COR(ast_channel_caller(chan)->id.number.valid,
+                                                       ast_channel_caller(chan)->id.number.str, NULL),
+                                                       0, &had_infinite_include_error);
                                                if (e) { /* This will only be undefined for pbx_realtime, which is majorly broken. */
                                                        ast_copy_string(runningapp, ast_get_extension_app(e), sizeof(runningapp));
                                                        ast_copy_string(runningdata, ast_get_extension_app_data(e), sizeof(runningdata));