]> 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)
committerGeorge Joseph <gjoseph@sangoma.com>
Wed, 17 Sep 2025 17:40:38 +0000 (11:40 -0600)
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 09a3c8df7024043bcf37843176933250f572dd8f)

apps/app_dial.c

index 93d269defb5dd70779731ef505d9e0f7020af570..4e583ab783b3636f783f8364c1090333820fa489 100644 (file)
@@ -1808,7 +1808,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;
@@ -1817,14 +1820,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) &&