res_musiconhold: avoid moh state access on unlocked chan

Move channel unlock to after moh state access to avoid
potential unlocked access to state.

Resolves: #133
(cherry picked from commit 9c889911ad)
This commit is contained in:
Mike Bradeen
2023-05-31 10:37:53 -06:00
committed by Asterisk Development Team
parent 714950bd7c
commit 9dbd80ab73

View File

@@ -464,24 +464,22 @@ static void moh_files_write_format_change(struct ast_channel *chan, void *data)
static int moh_files_generator(struct ast_channel *chan, void *data, int len, int samples) static int moh_files_generator(struct ast_channel *chan, void *data, int len, int samples)
{ {
struct moh_files_state *state = ast_channel_music_state(chan); struct moh_files_state *state;
struct ast_frame *f = NULL; struct ast_frame *f = NULL;
int res = 0; int res = 0, sample_queue = 0;
ast_channel_lock(chan);
state = ast_channel_music_state(chan);
state->sample_queue += samples; state->sample_queue += samples;
/* save the sample queue value for un-locked access */
sample_queue = state->sample_queue;
ast_channel_unlock(chan);
while (state->sample_queue > 0) { while (sample_queue > 0) {
ast_channel_lock(chan); ast_channel_lock(chan);
f = moh_files_readframe(chan); f = moh_files_readframe(chan);
/* We need to be sure that we unlock
* the channel prior to calling
* ast_write. Otherwise, the recursive locking
* that occurs can cause deadlocks when using
* indirect channels, like local channels
*/
ast_channel_unlock(chan);
if (!f) { if (!f) {
ast_channel_unlock(chan);
return -1; return -1;
} }
@@ -495,6 +493,19 @@ static int moh_files_generator(struct ast_channel *chan, void *data, int len, in
if (ast_format_cmp(f->subclass.format, state->mohwfmt) == AST_FORMAT_CMP_NOT_EQUAL) { if (ast_format_cmp(f->subclass.format, state->mohwfmt) == AST_FORMAT_CMP_NOT_EQUAL) {
ao2_replace(state->mohwfmt, f->subclass.format); ao2_replace(state->mohwfmt, f->subclass.format);
} }
/* We need to be sure that we unlock
* the channel prior to calling
* ast_write, but after our references to state
* as it refers to chan->music_state. Update
* sample_queue for our loop
* Otherwise, the recursive locking that occurs
* can cause deadlocks when using indirect
* channels, like local channels
*/
sample_queue = state->sample_queue;
ast_channel_unlock(chan);
res = ast_write(chan, f); res = ast_write(chan, f);
ast_frfree(f); ast_frfree(f);
if (res < 0) { if (res < 0) {