From: Tinet-mucw Date: Fri, 20 Mar 2026 10:17:31 +0000 (-0700) Subject: pbx: Hold channel lock for exception datastore access X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=2f85c76fb9a944a703aa537f604c4e720d8756fe;p=thirdparty%2Fasterisk.git pbx: Hold channel lock for exception datastore access ast_channel_datastore_find() and ast_channel_datastore_add() must only be called while the channel is locked (see channel.h). raise_exception() and the EXCEPTION dialplan function read path accessed the exception datastore without holding ast_channel_lock, which could corrupt the per-channel datastore list under concurrency and lead to crashes during teardown (e.g. double free in ast_datastore_free). Resolves: #1831 --- diff --git a/main/pbx.c b/main/pbx.c index 7f97e1821a..f7a5ceb024 100644 --- a/main/pbx.c +++ b/main/pbx.c @@ -2820,15 +2820,20 @@ static const struct ast_datastore_info exception_store_info = { */ int raise_exception(struct ast_channel *chan, const char *reason, int priority) { - struct ast_datastore *ds = ast_channel_datastore_find(chan, &exception_store_info, NULL); - struct pbx_exception *exception = NULL; + struct ast_datastore *ds; + struct pbx_exception *exception; + ast_channel_lock(chan); + ds = ast_channel_datastore_find(chan, &exception_store_info, NULL); if (!ds) { ds = ast_datastore_alloc(&exception_store_info, NULL); - if (!ds) + if (!ds) { + ast_channel_unlock(chan); return -1; + } if (!(exception = ast_calloc_with_stringfields(1, struct pbx_exception, 128))) { ast_datastore_free(ds); + ast_channel_unlock(chan); return -1; } ds->data = exception; @@ -2840,16 +2845,24 @@ int raise_exception(struct ast_channel *chan, const char *reason, int priority) ast_string_field_set(exception, context, ast_channel_context(chan)); ast_string_field_set(exception, exten, ast_channel_exten(chan)); exception->priority = ast_channel_priority(chan); + ast_channel_unlock(chan); + set_ext_pri(chan, "e", priority); return 0; } static int acf_exception_read(struct ast_channel *chan, const char *name, char *data, char *buf, size_t buflen) { - struct ast_datastore *ds = ast_channel_datastore_find(chan, &exception_store_info, NULL); - struct pbx_exception *exception = NULL; - if (!ds || !ds->data) + struct ast_datastore *ds; + struct pbx_exception *exception; + int res = 0; + + ast_channel_lock(chan); + ds = ast_channel_datastore_find(chan, &exception_store_info, NULL); + if (!ds || !ds->data) { + ast_channel_unlock(chan); return -1; + } exception = ds->data; if (!strcasecmp(data, "REASON")) ast_copy_string(buf, exception->reason, buflen); @@ -2860,8 +2873,10 @@ static int acf_exception_read(struct ast_channel *chan, const char *name, char * else if (!strcasecmp(data, "PRIORITY")) snprintf(buf, buflen, "%d", exception->priority); else - return -1; - return 0; + res = -1; + + ast_channel_unlock(chan); + return res; } static struct ast_custom_function exception_function = {