From: Richard Mudgett Date: Mon, 22 Apr 2013 16:30:53 +0000 (+0000) Subject: Fix crash when AMI redirect action redirects two channels out of a bridge. X-Git-Tag: 11.5.0-rc1~51 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=c1c2ae1e5fd4e7e327cbc17fa27b3df5a50701f0;p=thirdparty%2Fasterisk.git Fix crash when AMI redirect action redirects two channels out of a bridge. The two party bridging loops were changing the bridge peer pointers without the channel locks held. Thus when ast_channel_massquerade() tested and used the pointer there is a small window of opportunity for the pointers to become NULL even though the masquerade code has the channels locked. (closes issue ASTERISK-21356) Reported by: William luke Patches: jira_asterisk_21356_v11.patch (license #5621) patch uploaded by rmudgett Tested by: William luke ........ Merged revisions 386256 from http://svn.asterisk.org/svn/asterisk/branches/1.8 git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/11@386286 65c4cc65-6c06-0410-ace0-fbb531ad65f3 --- diff --git a/main/channel.c b/main/channel.c index 37d2066235..946c6033fd 100644 --- a/main/channel.c +++ b/main/channel.c @@ -7549,8 +7549,11 @@ static enum ast_bridge_result ast_generic_bridge(struct ast_channel *c0, struct if (ast_channel_softhangup_internal_flag(c1) & AST_SOFTHANGUP_UNBRIDGE) { ast_channel_clear_softhangup(c1, AST_SOFTHANGUP_UNBRIDGE); } + ast_channel_lock_both(c0, c1); ast_channel_internal_bridged_channel_set(c0, c1); ast_channel_internal_bridged_channel_set(c1, c0); + ast_channel_unlock(c0); + ast_channel_unlock(c1); } continue; } @@ -7831,8 +7834,11 @@ enum ast_bridge_result ast_channel_bridge(struct ast_channel *c0, struct ast_cha } /* Keep track of bridge */ + ast_channel_lock_both(c0, c1); ast_channel_internal_bridged_channel_set(c0, c1); ast_channel_internal_bridged_channel_set(c1, c0); + ast_channel_unlock(c0); + ast_channel_unlock(c1); ast_set_owners_and_peers(c0, c1); @@ -7926,8 +7932,11 @@ enum ast_bridge_result ast_channel_bridge(struct ast_channel *c0, struct ast_cha if (ast_channel_softhangup_internal_flag(c1) & AST_SOFTHANGUP_UNBRIDGE) { ast_channel_clear_softhangup(c1, AST_SOFTHANGUP_UNBRIDGE); } + ast_channel_lock_both(c0, c1); ast_channel_internal_bridged_channel_set(c0, c1); ast_channel_internal_bridged_channel_set(c1, c0); + ast_channel_unlock(c0); + ast_channel_unlock(c1); ast_debug(1, "Unbridge signal received. Ending native bridge.\n"); continue; } @@ -7973,8 +7982,11 @@ enum ast_bridge_result ast_channel_bridge(struct ast_channel *c0, struct ast_cha continue; } + ast_channel_lock_both(c0, c1); ast_channel_internal_bridged_channel_set(c0, NULL); ast_channel_internal_bridged_channel_set(c1, NULL); + ast_channel_unlock(c0); + ast_channel_unlock(c1); ast_format_cap_destroy(o0nativeformats); ast_format_cap_destroy(o1nativeformats); return res; @@ -8031,8 +8043,11 @@ enum ast_bridge_result ast_channel_bridge(struct ast_channel *c0, struct ast_cha ast_indicate(c0, AST_CONTROL_SRCUPDATE); ast_indicate(c1, AST_CONTROL_SRCUPDATE); + ast_channel_lock_both(c0, c1); ast_channel_internal_bridged_channel_set(c0, NULL); ast_channel_internal_bridged_channel_set(c1, NULL); + ast_channel_unlock(c0); + ast_channel_unlock(c1); manager_bridge_event(0, 1, c0, c1); ast_debug(1, "Bridge stops bridging channels %s and %s\n", ast_channel_name(c0), ast_channel_name(c1));