]> git.ipfire.org Git - thirdparty/asterisk.git/commitdiff
pbx: Fix off-nominal case where a freed extension may still be used.
authorJoshua Colp <jcolp@digium.com>
Wed, 12 Nov 2014 16:10:46 +0000 (16:10 +0000)
committerJoshua Colp <jcolp@digium.com>
Wed, 12 Nov 2014 16:10:46 +0000 (16:10 +0000)
If during the operation of adding an extension a priority is added but
fails it is possible for the extension to be freed but still exist in
the PBX core. If this occurs subsequent lookups may try to access the
extension and end up in freed memory.

This change removes the extension from the PBX core when the priority
addition fails and then frees the extension.

ASTERISK-24444 #close
Reported by: Leandro Dardini

Review: https://reviewboard.asterisk.org/r/4162/

git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/11@427709 65c4cc65-6c06-0410-ace0-fbb531ad65f3

main/pbx.c

index 3903cd03885c3e8e79b3257e1d0e998e24757be0..71ae6dad312643c477826a7b06978b26dd50a272 100644 (file)
@@ -9903,13 +9903,7 @@ static int add_priority(struct ast_context *con, struct ast_exten *tmp,
                                        "Unable to register extension '%s' priority %d in '%s', already in use\n",
                                        tmp->exten, tmp->priority, con->name);
                        }
-                       if (tmp->datad) {
-                               tmp->datad(tmp->data);
-                               /* if you free this, null it out */
-                               tmp->data = NULL;
-                       }
 
-                       ast_free(tmp);
                        return -1;
                }
                /* we are replacing e, so copy the link fields and then update
@@ -10183,6 +10177,26 @@ static int ast_add_extension2_lockopt(struct ast_context *con,
        }
        if (e && res == 0) { /* exact match, insert in the priority chain */
                res = add_priority(con, tmp, el, e, replace);
+               if (res < 0) {
+                       if (con->pattern_tree) {
+                               struct match_char *x = add_exten_to_pattern_tree(con, tmp, 1);
+
+                               if (x->exten) {
+                                       x->deleted = 1;
+                                       x->exten = 0;
+                               }
+
+                               ast_hashtab_remove_this_object(con->root_table, tmp);
+                       }
+
+                       if (tmp->datad) {
+                               tmp->datad(tmp->data);
+                               /* if you free this, null it out */
+                               tmp->data = NULL;
+                       }
+
+                       ast_free(tmp);
+               }
                if (lock_context) {
                        ast_unlock_context(con);
                }