Resolve deadlock between SIP registration and channel based functions

In r373424, several reentrancy problems in chan_sip were addressed. As a
result, the SIP channel driver is now properly locking the channel driver
private information in certain operations that it wasn't previously. This
exposed two latent problems either in register_verify or by functions called
by register_verify. This includes:
 * Holding the private lock while calling sip_send_mwi_to_peer. This can create
   a new sip_pvt via sip_alloc, which will obtain the channel container lock.
   This is a locking inversion, as any channel related lock must be obtained
   prior to obtaining the SIP channel technology private lock.

   Note that this issue was already fixed in Asterisk 11.

 * Holding the private lock while calling sip_poke_peer. In the same vein as
   sip_send_mwi_to_peer, sip_poke_peer can create a new SIP private, causing
   the same locking inversion.

Note that this locking inversion typically occured when CLI commands were run
while a SIP REGISTER request was being processed, as many CLI commands (such
as 'sip show channels', 'core show channels', etc.) have to obtain the channel
container lock.

(issue ASTERISK-21068)
Reported by: Nicolas Bouliane

(issue ASTERISK-20550)
Reported by: David Brillert

(issue ASTERISK-21314)
Reported by: Badalian Vyacheslav

(issue ASTERISK-21296)
Reported by: Gabriel Birke
........

Merged revisions 383863 from http://svn.asterisk.org/svn/asterisk/branches/1.8
........

Merged revisions 383878 from http://svn.asterisk.org/svn/asterisk/branches/11


git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@383879 65c4cc65-6c06-0410-ace0-fbb531ad65f3
This commit is contained in:
Matthew Jordan
2013-03-26 02:30:10 +00:00
parent ec7de8ed97
commit 58ee2b7d11

View File

@@ -16131,7 +16131,9 @@ static enum parse_register_result parse_register_contact(struct sip_pvt *pvt, st
ast_verb(3, "Registered SIP '%s' at %s\n", peer->name, ast_verb(3, "Registered SIP '%s' at %s\n", peer->name,
ast_sockaddr_stringify(&peer->addr)); ast_sockaddr_stringify(&peer->addr));
} }
sip_pvt_unlock(pvt);
sip_poke_peer(peer, 0); sip_poke_peer(peer, 0);
sip_pvt_lock(pvt);
register_peer_exten(peer, 1); register_peer_exten(peer, 1);
/* Save User agent */ /* Save User agent */
@@ -17163,9 +17165,9 @@ static enum check_auth_result register_verify(struct sip_pvt *p, struct ast_sock
} }
if (!res) { if (!res) {
if (send_mwi) { if (send_mwi) {
ao2_unlock(p); sip_pvt_unlock(p);
sip_send_mwi_to_peer(peer, 0); sip_send_mwi_to_peer(peer, 0);
ao2_lock(p); sip_pvt_lock(p);
} else { } else {
update_peer_lastmsgssent(peer, -1, 0); update_peer_lastmsgssent(peer, -1, 0);
} }
@@ -29611,6 +29613,9 @@ static int sip_poke_noanswer(const void *data)
\note This is done with 60 seconds between each ping, \note This is done with 60 seconds between each ping,
unless forced by cli or manager. If peer is unreachable, unless forced by cli or manager. If peer is unreachable,
we check every 10th second by default. we check every 10th second by default.
\note Do *not* hold a pvt lock while calling this function.
This function calls sip_alloc, which can cause a deadlock
if another sip_pvt is held.
*/ */
static int sip_poke_peer(struct sip_peer *peer, int force) static int sip_poke_peer(struct sip_peer *peer, int force)
{ {