diff options
author | Richard Mudgett <rmudgett@digium.com> | 2015-01-20 16:46:16 +0000 |
---|---|---|
committer | Richard Mudgett <rmudgett@digium.com> | 2015-01-20 16:46:16 +0000 |
commit | 6af6a216a1fcfb1dcefbfa6dc657d3781f3a24d9 (patch) | |
tree | 19b0d1bba2257ce3f7acf523dba76c14fa3c6a7c /funcs/func_channel.c | |
parent | 072db5e1b9201b3d7219a12ed559a9e856d535b6 (diff) |
CHANNEL(peer), chan_iax2, res_fax, SNMP agent: Fix deadlock from reaching across a bridge.
Calling ast_channel_bridge_peer() cannot be done while holding any channel
locks. The reported issue hit the deadlock in chan_iax2, but an audit of
the ast_channel_bridge_peer() calls found three more locations where the
same deadlock can occur.
* Made CHANNEL(peer), res_fax, and the SNMP agent not call
ast_channel_bridge_peer() with any channel locked. For CHANNEL(peer) I
had to rework the logic to not hold the channel lock.
* Made chan_iax2 no longer call ast_channel_bridge_peer(). It was done
for legacy reasons that no longer apply.
* Removed the iax.conf forcejitterbuffer option. It is now always enabled
when the jitterbuffer option is enabled. If you put a jitter buffer on a
channel it will be on the channel.
ASTERISK-24600 #close
Reported by: Jeff Collell
Review: https://reviewboard.asterisk.org/r/4342/
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/13@430817 65c4cc65-6c06-0410-ace0-fbb531ad65f3
Diffstat (limited to 'funcs/func_channel.c')
-rw-r--r-- | funcs/func_channel.c | 42 |
1 files changed, 27 insertions, 15 deletions
diff --git a/funcs/func_channel.c b/funcs/func_channel.c index 0ebab2a3e..4024cdf8b 100644 --- a/funcs/func_channel.c +++ b/funcs/func_channel.c @@ -508,22 +508,34 @@ static int func_channel_read(struct ast_channel *chan, const char *function, } ast_channel_unlock(chan); } else if (!strcasecmp(data, "peer")) { - RAII_VAR(struct ast_channel *, p, NULL, ast_channel_cleanup); - - ast_channel_lock(chan); - p = ast_channel_bridge_peer(chan); - if (p || ast_channel_tech(chan)) /* dummy channel? if so, we hid the peer name in the language */ - ast_copy_string(buf, (p ? ast_channel_name(p) : ""), len); - else { - /* a dummy channel can still pass along bridged peer info via - the BRIDGEPEER variable */ - const char *pname = pbx_builtin_getvar_helper(chan, "BRIDGEPEER"); - if (!ast_strlen_zero(pname)) - ast_copy_string(buf, pname, len); /* a horrible kludge, but... how else? */ - else - buf[0] = 0; + struct ast_channel *peer; + + peer = ast_channel_bridge_peer(chan); + if (peer) { + /* Only real channels could have a bridge peer this way. */ + ast_channel_lock(peer); + ast_copy_string(buf, ast_channel_name(peer), len); + ast_channel_unlock(peer); + ast_channel_unref(peer); + } else { + buf[0] = '\0'; + ast_channel_lock(chan); + if (!ast_channel_tech(chan)) { + const char *pname; + + /* + * A dummy channel can still pass along bridged peer info + * via the BRIDGEPEER variable. + * + * A horrible kludge, but... how else? + */ + pname = pbx_builtin_getvar_helper(chan, "BRIDGEPEER"); + if (!ast_strlen_zero(pname)) { + ast_copy_string(buf, pname, len); + } + } + ast_channel_unlock(chan); } - ast_channel_unlock(chan); } else if (!strcasecmp(data, "uniqueid")) { locked_copy_string(chan, buf, ast_channel_uniqueid(chan), len); } else if (!strcasecmp(data, "transfercapability")) { |