From 385e26efe24070bfdb654ef5aa44797a290a45d3 Mon Sep 17 00:00:00 2001
From: Matt Jordan <mjordan@digium.com>
Date: Wed, 4 Nov 2015 14:31:28 -0600
Subject: [PATCH] main/dial: Protect access to the format_cap structure of the
 requesting channel

When a dial attempt is made that involves a requesting channel, we previously
were not:
a) Protecting access to the native format capabilities structure on the
   requesting channel. That is inherently unsafe.
b) Reference bumping the lifetime of the format capabilities structure.

In both cases, something else could sneak in, blow away the format
capabilities, and we'd be holding onto an invalid format_cap structure. When
the newly created channel attempts to construct its format capabilities, things
go poorly.

This patch:
a) Ensures that we get a reference to the native format capabilities while
   the requesting channel is locked
b) Holds a reference to the native format capabilities during the creation
   of the new channel.

ASTERISK-25522 #close

Change-Id: I0bfb7ba8b9711f4158cbeaae96edf9626e88a54f
---
 main/dial.c | 7 +++++--
 1 file changed, 5 insertions(+), 2 deletions(-)

diff --git a/main/dial.c b/main/dial.c
index c8c1a7870e..74430c3e42 100644
--- a/main/dial.c
+++ b/main/dial.c
@@ -294,6 +294,7 @@ static int begin_dial_prerun(struct ast_dial_channel *channel, struct ast_channe
 	char numsubst[AST_MAX_EXTENSION];
 	struct ast_format_cap *cap_all_audio = NULL;
 	struct ast_format_cap *cap_request;
+	struct ast_format_cap *requester_cap = NULL;
 	struct ast_assigned_ids assignedids = {
 		.uniqueid = channel->assignedid1,
 		.uniqueid2 = channel->assignedid2,
@@ -304,6 +305,7 @@ static int begin_dial_prerun(struct ast_dial_channel *channel, struct ast_channe
 
 		ast_channel_lock(chan);
 		max_forwards = ast_max_forwards_get(chan);
+		requester_cap = ao2_bump(ast_channel_nativeformats(chan));
 		ast_channel_unlock(chan);
 
 		if (max_forwards <= 0) {
@@ -317,8 +319,8 @@ static int begin_dial_prerun(struct ast_dial_channel *channel, struct ast_channe
 
 	if (cap && ast_format_cap_count(cap)) {
 		cap_request = cap;
-	} else if (chan) {
-		cap_request = ast_channel_nativeformats(chan);
+	} else if (requester_cap) {
+		cap_request = requester_cap;
 	} else {
 		cap_all_audio = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);
 		ast_format_cap_append_by_type(cap_all_audio, AST_MEDIA_TYPE_AUDIO);
@@ -331,6 +333,7 @@ static int begin_dial_prerun(struct ast_dial_channel *channel, struct ast_channe
 		return -1;
 	}
 	cap_request = NULL;
+	ao2_cleanup(requester_cap);
 	ao2_cleanup(cap_all_audio);
 
 	if (chan) {
-- 
GitLab