From eac9ad69a8826f18a46694a4b80e60d7e68733fb Mon Sep 17 00:00:00 2001 From: Matthew Fredrickson Date: Wed, 25 Oct 2023 21:14:48 -0500 Subject: [PATCH] app_followme.c: Grab reference on nativeformats before using it Fixes a crash due to a lack of proper reference on the nativeformats object before passing it into ast_request(). Also found potentially similar use case bugs in app_chanisavail.c, bridge.c, and bridge_basic.c Fixes: #388 (cherry picked from commit 275f7911b53fc9661524413126382ab9a5306fd0) --- apps/app_chanisavail.c | 15 ++++++++++++--- apps/app_followme.c | 12 ++++++++++-- main/bridge.c | 21 ++++++++++++++++++--- main/bridge_basic.c | 11 +++++++++-- 4 files changed, 49 insertions(+), 10 deletions(-) diff --git a/apps/app_chanisavail.c b/apps/app_chanisavail.c index c75bb79208..910e714624 100644 --- a/apps/app_chanisavail.c +++ b/apps/app_chanisavail.c @@ -117,6 +117,7 @@ static int chanavail_exec(struct ast_channel *chan, const char *data) struct ast_str *tmp_availcause = ast_str_alloca(2048); struct ast_channel *tempchan; struct ast_custom_function *cdr_prop_func = ast_custom_function_find("CDR_PROP"); + struct ast_format_cap *caps = NULL; AST_DECLARE_APP_ARGS(args, AST_APP_ARG(reqchans); AST_APP_ARG(options); @@ -126,6 +127,10 @@ static int chanavail_exec(struct ast_channel *chan, const char *data) AST_STANDARD_APP_ARGS(args, info); + ao2_lock(chan); + caps = ao2_bump(ast_channel_nativeformats(chan)); + ao2_unlock(chan); + if (args.options) { if (strchr(args.options, 'a')) { option_all_avail = 1; @@ -174,10 +179,11 @@ static int chanavail_exec(struct ast_channel *chan, const char *data) snprintf(trychan, sizeof(trychan), "%s/%s", tech, number); status = inuse = ast_device_state(trychan); } - ast_str_append(&tmp_availstat, 0, "%s%d", - ast_str_strlen(tmp_availstat) ? "&" : "", status); + ast_str_append(&tmp_availstat, 0, "%s%d", ast_str_strlen(tmp_availstat) ? "&" : "", status); + if ((inuse <= (int) AST_DEVICE_NOT_INUSE) - && (tempchan = ast_request(tech, ast_channel_nativeformats(chan), NULL, chan, number, &status))) { + && (tempchan = ast_request(tech, caps, NULL, chan, number, &status))) { + ast_str_append(&tmp_availchan, 0, "%s%s", ast_str_strlen(tmp_availchan) ? "&" : "", ast_channel_name(tempchan)); @@ -199,8 +205,11 @@ static int chanavail_exec(struct ast_channel *chan, const char *data) break; } } + } + ao2_cleanup(caps); + pbx_builtin_setvar_helper(chan, "AVAILCHAN", ast_str_buffer(tmp_availchan)); /* Store the originally used channel too */ pbx_builtin_setvar_helper(chan, "AVAILORIGCHAN", ast_str_buffer(tmp_availorig)); diff --git a/apps/app_followme.c b/apps/app_followme.c index 367452f3a7..d74c6b8034 100644 --- a/apps/app_followme.c +++ b/apps/app_followme.c @@ -1068,6 +1068,7 @@ static struct ast_channel *findmeexec(struct fm_args *tpargs, struct ast_channel ast_copy_string(num, nm->number, sizeof(num)); for (number = num; number; number = rest) { struct ast_channel *outbound; + struct ast_format_cap *caps; rest = strchr(number, '&'); if (rest) { @@ -1097,8 +1098,15 @@ static struct ast_channel *findmeexec(struct fm_args *tpargs, struct ast_channel ? "/n" : "/m"); } - outbound = ast_request("Local", ast_channel_nativeformats(caller), NULL, caller, - tmpuser->dialarg, &dg); + /* Capture nativeformats reference in case it gets changed */ + ast_channel_lock(caller); + caps = ao2_bump(ast_channel_nativeformats(caller)); + ast_channel_unlock(caller); + + outbound = ast_request("Local", caps, NULL, caller, tmpuser->dialarg, &dg); + + ao2_cleanup(caps); + if (!outbound) { ast_log(LOG_WARNING, "Unable to allocate a channel for Local/%s cause: %s\n", tmpuser->dialarg, ast_cause2str(dg)); diff --git a/main/bridge.c b/main/bridge.c index 112b621b43..8299a1967a 100644 --- a/main/bridge.c +++ b/main/bridge.c @@ -4118,10 +4118,18 @@ static enum ast_transfer_result blind_transfer_bridge(int is_external, struct ast_channel *local; char chan_name[AST_MAX_EXTENSION + AST_MAX_CONTEXT + 2]; int cause; + struct ast_format_cap *caps; + + ast_channel_lock(transferer); + caps = ao2_bump(ast_channel_nativeformats(transferer)); + ast_channel_unlock(transferer); snprintf(chan_name, sizeof(chan_name), "%s@%s", exten, context); - local = ast_request("Local", ast_channel_nativeformats(transferer), NULL, transferer, + local = ast_request("Local", caps, NULL, transferer, chan_name, &cause); + + ao2_cleanup(caps); + if (!local) { return AST_BRIDGE_TRANSFER_FAIL; } @@ -4228,9 +4236,16 @@ static enum ast_transfer_result attended_transfer_bridge(struct ast_channel *cha int cause; int res; const char *app = NULL; + struct ast_format_cap *caps; + + ast_channel_lock(chan1); + caps = ao2_bump(ast_channel_nativeformats(chan1)); + ast_channel_unlock(chan1); + + local_chan = ast_request("Local", caps, NULL, chan1, dest, &cause); + + ao2_cleanup(caps); - local_chan = ast_request("Local", ast_channel_nativeformats(chan1), NULL, chan1, - dest, &cause); if (!local_chan) { return AST_BRIDGE_TRANSFER_FAIL; } diff --git a/main/bridge_basic.c b/main/bridge_basic.c index 2d3872df64..38a9e6c17f 100644 --- a/main/bridge_basic.c +++ b/main/bridge_basic.c @@ -3293,10 +3293,17 @@ static struct ast_channel *dial_transfer(struct ast_channel *caller, const char { struct ast_channel *chan; int cause; + struct ast_format_cap *caps; + + ast_channel_lock(caller); + caps = ao2_bump(ast_channel_nativeformats(caller)); + ast_channel_unlock(caller); /* Now we request a local channel to prepare to call the destination */ - chan = ast_request("Local", ast_channel_nativeformats(caller), NULL, caller, destination, - &cause); + chan = ast_request("Local", caps, NULL, caller, destination, &cause); + + ao2_cleanup(caps); + if (!chan) { return NULL; }