From 60bcd4e03c6927c4f7f518cc9cd717567d349453 Mon Sep 17 00:00:00 2001 From: Russell Bryant Date: Mon, 13 Aug 2007 19:27:39 +0000 Subject: [PATCH] I am fighting deadlocks in chan_iax2. I have tracked them down to a single core issue. You can not call find_callno() while holding a pvt lock as this function has to lock another (every) other pvt lock. Doing so can lead to a classic deadlock. So, I am tracking down all of the code paths where this can happen and fixing them. The fix I committed earlier today was along the same theme. This patch fixes some code down the path of authenticate_reply. git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/1.4@79272 65c4cc65-6c06-0410-ace0-fbb531ad65f3 --- channels/chan_iax2.c | 30 ++++++++++++++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) diff --git a/channels/chan_iax2.c b/channels/chan_iax2.c index e8f78cf06f..d6b55dd89e 100644 --- a/channels/chan_iax2.c +++ b/channels/chan_iax2.c @@ -1244,6 +1244,9 @@ static int make_trunk(unsigned short callno, int locked) return res; } +/*! + * \note Calling this function while holding another pvt lock can cause a deadlock. + */ static int find_callno(unsigned short callno, unsigned short dcallno, struct sockaddr_in *sin, int new, int lockpeer, int sockfd) { int res = 0; @@ -2502,6 +2505,10 @@ static int iax2_fixup(struct ast_channel *oldchannel, struct ast_channel *newcha return 0; } +/*! + * \note This function calls reg_source_db -> iax2_poke_peer -> find_callno, + * so do not call this with a pvt lock held. + */ static struct iax2_peer *realtime_peer(const char *peername, struct sockaddr_in *sin) { struct ast_variable *var; @@ -5219,6 +5226,10 @@ static int authenticate(const char *challenge, const char *secret, const char *k return res; } +/*! + * \note This function calls realtime_peer -> reg_source_db -> iax2_poke_peer -> find_callno, + * so do not call this function with a pvt lock held. + */ static int authenticate_reply(struct chan_iax2_pvt *p, struct sockaddr_in *sin, struct iax_ies *ies, const char *override, const char *okey) { struct iax2_peer *peer = NULL; @@ -5226,7 +5237,8 @@ static int authenticate_reply(struct chan_iax2_pvt *p, struct sockaddr_in *sin, int res = -1; int authmethods = 0; struct iax_ie_data ied; - + uint16_t callno = p->callno; + memset(&ied, 0, sizeof(ied)); if (ies->username) @@ -5263,11 +5275,21 @@ static int authenticate_reply(struct chan_iax2_pvt *p, struct sockaddr_in *sin, if (!peer) { /* We checked our list and didn't find one. It's unlikely, but possible, that we're trying to authenticate *to* a realtime peer */ - if ((peer = realtime_peer(p->peer, NULL))) { + const char *peer_name = ast_strdupa(p->peer); + ast_mutex_unlock(&iaxsl[callno]); + if ((peer = realtime_peer(peer_name, NULL))) { + ast_mutex_lock(&iaxsl[callno]); + if (!(p = iaxs[callno])) + return -1; res = authenticate(p->challenge, peer->secret,peer->outkey, authmethods, &ied, sin, &p->ecx, &p->dcx); if (ast_test_flag(peer, IAX_TEMPONLY)) destroy_peer(peer); } + if (!peer) { + ast_mutex_lock(&iaxsl[callno]); + if (!(p = iaxs[callno])) + return -1; + } } } if (ies->encmethods) @@ -7384,6 +7406,10 @@ retryowner2: "I don't know how to authenticate %s to %s\n", ies.username ? ies.username : "", ast_inet_ntoa(iaxs[fr->callno]->addr.sin_addr)); } + if (!iaxs[fr->callno]) { + ast_mutex_unlock(&iaxsl[fr->callno]); + return 1; + } break; case IAX_COMMAND_AUTHREP: /* For security, always ack immediately */