]> git.ipfire.org Git - thirdparty/asterisk.git/commitdiff
Make code that updates BRIDGEPEER variable thread-safe.
authorRussell Bryant <russell@russellbryant.com>
Wed, 11 Mar 2009 21:42:58 +0000 (21:42 +0000)
committerRussell Bryant <russell@russellbryant.com>
Wed, 11 Mar 2009 21:42:58 +0000 (21:42 +0000)
It is not safe to read the name field of an ast_channel without the channel
locked.  This patch fixes some places in channel.c where this was being done,
and lead to crashes related to masquerades.

(closes issue #14623)
Reported by: guillecabeza

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

main/channel.c

index 07bc5d474f6eae3ecc42eae2369ccf5d8158c7e9..4759421637f3785f342822f1bcb0151a69fae733 100644 (file)
@@ -4060,6 +4060,29 @@ static enum ast_bridge_result ast_generic_bridge(struct ast_channel *c0, struct
        return res;
 }
 
+static void update_bridgepeer(struct ast_channel *c0, struct ast_channel *c1)
+{
+       const char *c0_name;
+       const char *c1_name;
+
+       ast_channel_lock(c1);
+       c1_name = ast_strdupa(c1->name);
+       ast_channel_unlock(c1);
+
+       ast_channel_lock(c0);
+       if (!ast_strlen_zero(pbx_builtin_getvar_helper(c0, "BRIDGEPEER"))) {
+               pbx_builtin_setvar_helper(c0, "BRIDGEPEER", c1_name);
+       }
+       c0_name = ast_strdupa(c0->name);
+       ast_channel_unlock(c0);
+
+       ast_channel_lock(c1);
+       if (!ast_strlen_zero(pbx_builtin_getvar_helper(c1, "BRIDGEPEER"))) {
+               pbx_builtin_setvar_helper(c1, "BRIDGEPEER", c0_name);
+       }
+       ast_channel_unlock(c1);
+}
+
 /*! \brief Bridge two channels together */
 enum ast_bridge_result ast_channel_bridge(struct ast_channel *c0, struct ast_channel *c1,
                                          struct ast_bridge_config *config, struct ast_frame **fo, struct ast_channel **rc)
@@ -4176,7 +4199,7 @@ enum ast_bridge_result ast_channel_bridge(struct ast_channel *c0, struct ast_cha
                                res = 0;
                                break;
                        }
-                       
+
                        if (!to) {
                                if (time_left_ms >= 5000 && config->warning_sound && config->play_warning && ast_test_flag(config, AST_FEATURE_WARNING_ACTIVE)) {
                                        int t = (time_left_ms + 500) / 1000; /* round to nearest second */
@@ -4204,7 +4227,7 @@ enum ast_bridge_result ast_channel_bridge(struct ast_channel *c0, struct ast_cha
                                ast_log(LOG_DEBUG, "Unbridge signal received. Ending native bridge.\n");
                        continue;
                }
-               
+
                /* Stop if we're a zombie or need a soft hangup */
                if (ast_test_flag(c0, AST_FLAG_ZOMBIE) || ast_check_hangup_locked(c0) ||
                    ast_test_flag(c1, AST_FLAG_ZOMBIE) || ast_check_hangup_locked(c1)) {
@@ -4221,13 +4244,9 @@ enum ast_bridge_result ast_channel_bridge(struct ast_channel *c0, struct ast_cha
                                        ast_check_hangup(c1) ? "Yes" : "No");
                        break;
                }
-               
-               /* See if the BRIDGEPEER variable needs to be updated */
-               if (!ast_strlen_zero(pbx_builtin_getvar_helper(c0, "BRIDGEPEER")))
-                       pbx_builtin_setvar_helper(c0, "BRIDGEPEER", c1->name);
-               if (!ast_strlen_zero(pbx_builtin_getvar_helper(c1, "BRIDGEPEER")))
-                       pbx_builtin_setvar_helper(c1, "BRIDGEPEER", c0->name);
-               
+
+               update_bridgepeer(c0, c1);
+
                if (c0->tech->bridge &&
                    (config->timelimit == 0) &&
                    (c0->tech->bridge == c1->tech->bridge) &&
@@ -4278,7 +4297,7 @@ enum ast_bridge_result ast_channel_bridge(struct ast_channel *c0, struct ast_cha
                                break;
                        }
                }
-       
+
                if (((c0->writeformat != c1->readformat) || (c0->readformat != c1->writeformat) ||
                    (c0->nativeformats != o0nativeformats) || (c1->nativeformats != o1nativeformats)) &&
                    !(c0->generator || c1->generator)) {
@@ -4299,10 +4318,7 @@ enum ast_bridge_result ast_channel_bridge(struct ast_channel *c0, struct ast_cha
                        o1nativeformats = c1->nativeformats;
                }
 
-               if (!ast_strlen_zero(pbx_builtin_getvar_helper(c0, "BRIDGEPEER")))
-                       pbx_builtin_setvar_helper(c0, "BRIDGEPEER", c1->name);
-               if (!ast_strlen_zero(pbx_builtin_getvar_helper(c1, "BRIDGEPEER")))
-                       pbx_builtin_setvar_helper(c1, "BRIDGEPEER", c0->name);
+               update_bridgepeer(c0, c1);
 
                res = ast_generic_bridge(c0, c1, config, fo, rc, config->nexteventts);
                if (res != AST_BRIDGE_RETRY) {