From 169e5533204c54ad5dd09bfb0e92b8783c35979c Mon Sep 17 00:00:00 2001 From: Naveen Albert <asterisk@phreaknet.org> Date: Mon, 16 May 2022 13:01:48 +0000 Subject: [PATCH] chan_iax2: Prevent deadlock due to duplicate autoservice. If a switch is invoked using chan_iax2, deadlock can result because the PBX core is autoservicing the channel while chan_iax2 also then attempts to service it while waiting for the result of the switch. This removes servicing of the channel to prevent any conflicts. ASTERISK-30064 #close Change-Id: Ie92f206d32f9a36924af734ddde652b21106af22 --- channels/chan_iax2.c | 48 ++++++++++++++++++-------------------------- 1 file changed, 20 insertions(+), 28 deletions(-) diff --git a/channels/chan_iax2.c b/channels/chan_iax2.c index 6d76dc5755..210c34417a 100644 --- a/channels/chan_iax2.c +++ b/channels/chan_iax2.c @@ -14214,9 +14214,7 @@ static struct iax2_dpcache *find_cache(struct ast_channel *chan, const char *dat { struct iax2_dpcache *dp = NULL; struct timeval now = ast_tvnow(); - int x, com[2], timeout, old = 0, outfd, doabort, callno; - struct ast_channel *c = NULL; - struct ast_frame *f = NULL; + int x, com[2], timeout, doabort, callno; AST_LIST_TRAVERSE_SAFE_BEGIN(&dpcache, dp, cache_list) { if (ast_tvcmp(now, dp->expiry) > 0) { @@ -14263,8 +14261,8 @@ static struct iax2_dpcache *find_cache(struct ast_channel *chan, const char *dat /* By here we must have a dp */ if (dp->flags & CACHE_FLAG_PENDING) { - struct timeval start; - int ms; + int res; + struct pollfd pfd; /* Okay, here it starts to get nasty. We need a pipe now to wait for a reply to come back so long as it's pending */ for (x = 0; x < ARRAY_LEN(dp->waiters); x++) { @@ -14285,35 +14283,31 @@ static struct iax2_dpcache *find_cache(struct ast_channel *chan, const char *dat timeout = iaxdefaulttimeout * 1000; /* Temporarily unlock */ AST_LIST_UNLOCK(&dpcache); - /* Defer any dtmf */ - if (chan) - old = ast_channel_defer_dtmf(chan); doabort = 0; - start = ast_tvnow(); - while ((ms = ast_remaining_ms(start, timeout))) { - c = ast_waitfor_nandfds(&chan, chan ? 1 : 0, &com[0], 1, NULL, &outfd, &ms); - if (outfd > -1) - break; - if (!c) - continue; - if (!(f = ast_read(c))) { - doabort = 1; - break; - } - ast_frfree(f); - } - if (!ms) { + + /* chan is in autoservice here, so do NOT service it here! */ + pfd.fd = com[0]; + pfd.events = POLLIN; + pfd.revents = 0; + /* Wait for pipe activity... if the channel hangs up, we'll catch it on the way out. */ + res = ast_poll(&pfd, 1, timeout); + if (res < 0) { + ast_log(LOG_WARNING, "poll returned < 0: %s\n", strerror(errno)); + return NULL; + } else if (!pfd.revents) { ast_log(LOG_WARNING, "Timeout waiting for %s exten %s\n", data, exten); } + + if (ast_check_hangup(chan)) { + doabort = 1; + } + AST_LIST_LOCK(&dpcache); dp->waiters[x] = -1; close(com[1]); close(com[0]); if (doabort) { - /* Don't interpret anything, just abort. Not sure what th epoint - of undeferring dtmf on a hung up channel is but hey whatever */ - if (!old && chan) - ast_channel_undefer_dtmf(chan); + /* Don't interpret anything, just abort. */ return NULL; } if (!(dp->flags & CACHE_FLAG_TIMEOUT)) { @@ -14336,8 +14330,6 @@ static struct iax2_dpcache *find_cache(struct ast_channel *chan, const char *dat } } /* Our caller will obtain the rest */ - if (!old && chan) - ast_channel_undefer_dtmf(chan); } return dp; } -- GitLab