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/
........

Merged revisions 430817 from http://svn.asterisk.org/svn/asterisk/branches/13


git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@430819 65c4cc65-6c06-0410-ace0-fbb531ad65f3
This commit is contained in:
Richard Mudgett
2015-01-20 16:59:30 +00:00
parent 14b8e03dad
commit e4738a59eb
6 changed files with 53 additions and 80 deletions

View File

@@ -514,22 +514,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);
struct ast_channel *peer;
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;
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")) {