]> git.ipfire.org Git - thirdparty/asterisk.git/commitdiff
channel: Prevent crash during DTMF emulation when no timing module is loaded
authorAlexis Hadjisotiriou <ah@gilawa.com>
Thu, 26 Feb 2026 15:37:56 +0000 (15:37 +0000)
committergithub-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Mon, 9 Mar 2026 13:08:35 +0000 (13:08 +0000)
Description:
When Asterisk is running without a timing module, attempting to process DTMF
triggers a segmentation fault. This occurs because the system
attempts to access a null timing file descriptor when setting up the
DTMF emulation timer.

This fix ensures that the system checks for a valid timing source before
attempting to start the DTMF emulation timer. If no timing module is
present, it logs a warning and skips the emulation instead of crashing
the process.

Changes:
- Modified main/channel.c to add a safety check within the __ast_read function.
- Implemented a graceful return path when no timing source is available
- Added a LOG_WARNING to inform the administrator that DTMF emulation
  was skipped due to missing timing modules.

Testing:
- Disabled all timing_ modules in modules.conf and confirmed with
  'timing test'.
- Reproduced the crash by modifying the dialplan with:
 exten => 707,1,NoOp(Starting DTMF - No Timing Mode)
 same => n,Answer()
 same => n,Background(demo-congrats)
 same => n,WaitExten(10)
 same => n,Hangup()
  And calling 707 followed by 1
- Verified that with the fix applied, the system logs "No timing module
  loaded; skipping DTMF timer" and continues dialplan
  execution without crashing.
- Confirmed stability during concurrent media sessions and DTMF input.

Fixes: #566
main/channel.c

index 8121b5c3d78bb19b59e3de2488e272fce969a0da..76e7c3c78796e93553c100b47e7d98362515358d 100644 (file)
@@ -2893,7 +2893,12 @@ void ast_deactivate_generator(struct ast_channel *chan)
        deactivate_generator_nolock(chan);
        if (should_trigger_dtmf_emulating(chan)) {
                /* if in the middle of dtmf emulation keep 50 tick per sec timer on rolling */
-               ast_timer_set_rate(ast_channel_timer(chan), 50);
+               struct ast_timer *timer = ast_channel_timer(chan);
+               if (timer) {
+                       ast_timer_set_rate(timer, 50);
+               } else {
+                       ast_log(LOG_WARNING, "No timing module loaded, DTMF length may be inaccurate\n");
+               }
        }
        ast_channel_unlock(chan);
 }
@@ -3183,6 +3188,7 @@ int ast_settimeout_full(struct ast_channel *c, unsigned int rate, int (*func)(co
 {
        int res;
        unsigned int real_rate = rate, max_rate;
+       struct ast_timer *timer = ast_channel_timer(c);
 
        ast_channel_lock(c);
 
@@ -3196,13 +3202,13 @@ int ast_settimeout_full(struct ast_channel *c, unsigned int rate, int (*func)(co
                data = NULL;
        }
 
-       if (rate && rate > (max_rate = ast_timer_get_max_rate(ast_channel_timer(c)))) {
+       if (rate && rate > (max_rate = ast_timer_get_max_rate(timer))) {
                real_rate = max_rate;
        }
 
        ast_debug(3, "Scheduling timer at (%u requested / %u actual) timer ticks per second\n", rate, real_rate);
 
-       res = ast_timer_set_rate(ast_channel_timer(c), real_rate);
+       res = ast_timer_set_rate(timer, real_rate);
 
        if (ast_channel_timingdata(c) && ast_test_flag(ast_channel_flags(c), AST_FLAG_TIMINGDATA_IS_AO2_OBJ)) {
                ao2_ref(ast_channel_timingdata(c), -1);
@@ -3912,7 +3918,12 @@ static struct ast_frame *__ast_read(struct ast_channel *chan, int dropaudio, int
                                         * timer events to generate null frames.
                                         */
                                        if (!ast_channel_generator(chan)) {
-                                               ast_timer_set_rate(ast_channel_timer(chan), 50);
+                                               struct ast_timer *timer = ast_channel_timer(chan);
+                                               if (timer) {
+                                                       ast_timer_set_rate(timer, 50);
+                                           } else {
+                                                       ast_log(LOG_WARNING, "No timing module loaded, DTMF length may be inaccurate\n");
+                                               }
                                        }
                                }
                                if (ast_channel_audiohooks(chan)) {
@@ -3962,7 +3973,12 @@ static struct ast_frame *__ast_read(struct ast_channel *chan, int dropaudio, int
                                         * timer events to generate null frames.
                                         */
                                        if (!ast_channel_generator(chan)) {
-                                               ast_timer_set_rate(ast_channel_timer(chan), 50);
+                                               struct ast_timer *timer = ast_channel_timer(chan);
+                                               if (timer) {
+                                                       ast_timer_set_rate(timer, 50);
+                                               } else {
+                                                       ast_log(LOG_WARNING, "No timing module loaded, DTMF length may be inaccurate\n");
+                                               }
                                        }
                                } else {
                                        ast_log(LOG_DTMF, "DTMF end passthrough '%c' on %s\n", f->subclass.integer, ast_channel_name(chan));
@@ -3977,7 +3993,12 @@ static struct ast_frame *__ast_read(struct ast_channel *chan, int dropaudio, int
                                         * timer events to generate null frames.
                                         */
                                        if (!ast_channel_generator(chan)) {
-                                               ast_timer_set_rate(ast_channel_timer(chan), 50);
+                                               struct ast_timer *timer = ast_channel_timer(chan);
+                                               if (timer) {
+                                                       ast_timer_set_rate(timer, 50);
+                                               } else {
+                                                       ast_log(LOG_WARNING, "No timing module loaded, DTMF length may be inaccurate\n");
+                                               }
                                        }
                                }
                                if (ast_channel_audiohooks(chan)) {
@@ -4039,7 +4060,12 @@ static struct ast_frame *__ast_read(struct ast_channel *chan, int dropaudio, int
                                         * timer events to generate null frames.
                                         */
                                        if (!ast_channel_generator(chan)) {
-                                               ast_timer_set_rate(ast_channel_timer(chan), 50);
+                                               struct ast_timer *timer = ast_channel_timer(chan);
+                                               if (timer) {
+                                                       ast_timer_set_rate(timer, 50);
+                                               } else {
+                                                       ast_log(LOG_WARNING, "No timing module loaded, DTMF length may be inaccurate\n");
+                                               }
                                        }
                                }
                        }