summaryrefslogtreecommitdiff
path: root/main/channel.c
diff options
context:
space:
mode:
authorRussell Bryant <russell@russellbryant.com>2014-01-27 01:25:23 +0000
committerRussell Bryant <russell@russellbryant.com>2014-01-27 01:25:23 +0000
commit33071d636cff3085be3bcc01bbba9d38ca9acb46 (patch)
tree14f4ac34e6aa413ffacd8b583a993b4911d752fe /main/channel.c
parent45261449ecfe621e2ba5e371a7c24addfa8a9c72 (diff)
Protect ast_filestream object when on a channel
The ast_filestream object gets tacked on to a channel via chan->timingdata. It's a reference counted object, but the reference count isn't used when putting it on a channel. It's theoretically possible for another thread to interfere with the channel while it's unlocked and cause the filestream to get destroyed. Use the astobj2 reference count to make sure that as long as this code path is holding on the ast_filestream and passing it into the file.c playback code, that it knows it's valid. Bug reported by Leif Madsen. Review: https://reviewboard.asterisk.org/r/3135/ ........ Merged revisions 406566 from http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged revisions 406567 from http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged revisions 406574 from http://svn.asterisk.org/svn/asterisk/branches/12 git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@406595 65c4cc65-6c06-0410-ace0-fbb531ad65f3
Diffstat (limited to 'main/channel.c')
-rw-r--r--main/channel.c24
1 files changed, 24 insertions, 0 deletions
diff --git a/main/channel.c b/main/channel.c
index 567d8c621..a9f0fbb34 100644
--- a/main/channel.c
+++ b/main/channel.c
@@ -3421,6 +3421,11 @@ int ast_waitfordigit(struct ast_channel *c, int ms)
int ast_settimeout(struct ast_channel *c, unsigned int rate, int (*func)(const void *data), void *data)
{
+ return ast_settimeout_full(c, rate, func, data, 0);
+}
+
+int ast_settimeout_full(struct ast_channel *c, unsigned int rate, int (*func)(const void *data), void *data, unsigned int is_ao2_obj)
+{
int res;
unsigned int real_rate = rate, max_rate;
@@ -3444,9 +3449,20 @@ int ast_settimeout(struct ast_channel *c, unsigned int rate, int (*func)(const v
res = ast_timer_set_rate(ast_channel_timer(c), 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);
+ }
+
ast_channel_timingfunc_set(c, func);
ast_channel_timingdata_set(c, data);
+ if (data && is_ao2_obj) {
+ ao2_ref(data, 1);
+ ast_set_flag(ast_channel_flags(c), AST_FLAG_TIMINGDATA_IS_AO2_OBJ);
+ } else {
+ ast_clear_flag(ast_channel_flags(c), AST_FLAG_TIMINGDATA_IS_AO2_OBJ);
+ }
+
if (func == NULL && rate == 0 && ast_channel_fdno(c) == AST_TIMING_FD) {
/* Clearing the timing func and setting the rate to 0
* means that we don't want to be reading from the timingfd
@@ -3795,9 +3811,17 @@ static struct ast_frame *__ast_read(struct ast_channel *chan, int dropaudio)
/* save a copy of func/data before unlocking the channel */
ast_timing_func_t func = ast_channel_timingfunc(chan);
void *data = ast_channel_timingdata(chan);
+ int got_ref = 0;
+ if (data && ast_test_flag(ast_channel_flags(chan), AST_FLAG_TIMINGDATA_IS_AO2_OBJ)) {
+ ao2_ref(data, 1);
+ got_ref = 1;
+ }
ast_channel_fdno_set(chan, -1);
ast_channel_unlock(chan);
func(data);
+ if (got_ref) {
+ ao2_ref(data, -1);
+ }
} else {
ast_timer_set_rate(ast_channel_timer(chan), 0);
ast_channel_fdno_set(chan, -1);