]> git.ipfire.org Git - thirdparty/asterisk.git/commitdiff
chan_pjsip: Fix deadlock when endpoint set_var uses PJSIP_HEADER master
authorCharles Langlois <charles.langlois@wazo.io>
Thu, 16 Apr 2026 20:02:54 +0000 (16:02 -0400)
committergithub-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Wed, 29 Apr 2026 19:29:26 +0000 (19:29 +0000)
When a PJSIP endpoint is configured with set_var invoking a dialplan
function (e.g. PJSIP_HEADER(add,...)), chan_pjsip_new() calls
pbx_builtin_setvar_helper() while holding the channel lock.
For function-style variables, this dispatches to ast_func_write()
which, in the case of PJSIP_HEADER, calls
ast_sip_push_task_wait_serializer() -- blocking synchronously while
the channel lock is held.

If a concurrent operation (ARI, AMI, rtp_check_timeout) traverses
the channels container via ast_channel_get_by_name(), it acquires
the container lock then tries to lock individual channels in the
iteration callback (by_uniqueid_cb/by_name_cb). When the serializer
thread also needs the container lock, a circular dependency forms:

  channel_lock -> serializer_wait -> container_lock -> channel_lock

This causes a complete Asterisk freeze. In the observed case, 36
threads were blocked on the container lock until res_freeze_check
triggered SIGABRT after its 30-second timeout.

Unlock the channel before iterating endpoint channel_vars so that
dialplan functions can block without holding the channel lock. Re-lock
the channel for ast_channel_stage_snapshot_done() so the batched
snapshot is published under lock and captures the full channel state
including the variables set during the loop.

Fixes: #1872
channels/chan_pjsip.c

index c2d44065fafecfa8fa17efe916a3bd4b16e7c2bf..008f41206b4ce0c51eab73d812db0a76e936f8be 100644 (file)
@@ -665,15 +665,15 @@ static struct ast_channel *chan_pjsip_new(struct ast_sip_session *session, int s
                ast_channel_zone_set(chan, zone);
        }
 
+       ast_channel_stage_snapshot_done(chan);
+       ast_channel_unlock(chan);
+
        for (var = session->endpoint->channel_vars; var; var = var->next) {
                char buf[512];
                pbx_builtin_setvar_helper(chan, var->name, ast_get_encoded_str(
                                        var->value, buf, sizeof(buf)));
        }
 
-       ast_channel_stage_snapshot_done(chan);
-       ast_channel_unlock(chan);
-
        set_channel_on_rtp_instance(session, ast_channel_uniqueid(chan));
 
        SCOPE_EXIT_RTN_VALUE(chan);