]> git.ipfire.org Git - thirdparty/asterisk.git/commitdiff
app_dial.c: Moved channel lock to prevent deadlock
authorAlexey Khabulyak <khabalex@gmail.com>
Mon, 4 Aug 2025 14:48:57 +0000 (17:48 +0300)
committerAsterisk Development Team <asteriskteam@digium.com>
Wed, 10 Sep 2025 19:52:59 +0000 (19:52 +0000)
It's reproducible with pbx_lua, not regular dialplan.

deadlock description:
1. asterisk locks a channel
2. calls function onedigit_goto
3. calls ast_goto_if_exists funciton
4. checks ast_exists_extension -> pbx_extension_helper
5. pbx_extension_helper calls pbx_find_extension
6. Then asterisk starts autoservice in a new thread
7. autoservice run tries to lock the channel again

Because our channel is locked already, autoservice can't lock.
Autoservice can't lock -> autoservice stop is waiting forever.
onedigit_goto waits for autoservice stop.

Resolves: https://github.com/asterisk/asterisk/issues/1335
(cherry picked from commit 4b766d24d078dff701805f18cb41fb59bd6033ce)

apps/app_dial.c

index 8c2c8ecced68b754df286f02612f0911aaeb0bc5..4e742d28214975bd8e9cff7a5cd517c373b73128 100644 (file)
@@ -1869,7 +1869,10 @@ static struct ast_channel *wait_for_answer(struct ast_channel *in,
                                if (ast_test_flag64(peerflags, OPT_DTMF_EXIT)) {
                                        const char *context;
                                        ast_channel_lock(in);
-                                       context = pbx_builtin_getvar_helper(in, "EXITCONTEXT");
+                                       if ((context = pbx_builtin_getvar_helper(in, "EXITCONTEXT"))) {
+                                               context = ast_strdupa(context);
+                                       }
+                                       ast_channel_unlock(in);
                                        if (onedigit_goto(in, context, (char) f->subclass.integer, 1)) {
                                                ast_verb(3, "User hit %c to disconnect call.\n", f->subclass.integer);
                                                *to_answer = 0;
@@ -1878,14 +1881,12 @@ static struct ast_channel *wait_for_answer(struct ast_channel *in,
                                                pa->canceled = 1;
                                                publish_dial_end_event(in, out_chans, NULL, pa->status);
                                                ast_frfree(f);
-                                               ast_channel_unlock(in);
                                                if (is_cc_recall) {
                                                        ast_cc_completed(in, "CC completed, but the caller used DTMF to exit");
                                                }
                                                SCOPE_EXIT_RTN_VALUE(NULL, "%s: Caller pressed %c to end call\n",
                                                        ast_channel_name(in), f->subclass.integer);
                                        }
-                                       ast_channel_unlock(in);
                                }
 
                                if (ast_test_flag64(peerflags, OPT_CALLER_HANGUP) &&