From 35865bd90cbbf1d11019ea5f2cf344977338c663 Mon Sep 17 00:00:00 2001 From: Anthony Minessale <anthm@freeswitch.org> Date: Thu, 9 Mar 2017 13:22:11 -0600 Subject: [PATCH] FS-10118: [freeswitch-core] Race conditions from lack of error checking in switch_core_session_read_lock #resolve --- .../applications/mod_dptools/mod_dptools.c | 14 +++-- src/switch_core_media.c | 55 +++++++++++++++---- src/switch_cpp.cpp | 3 +- src/switch_ivr_async.c | 7 ++- src/switch_ivr_bridge.c | 12 +++- src/switch_ivr_originate.c | 8 ++- 6 files changed, 76 insertions(+), 23 deletions(-) diff --git a/src/mod/applications/mod_dptools/mod_dptools.c b/src/mod/applications/mod_dptools/mod_dptools.c index 04f35b538f..6daddfcdc5 100644 --- a/src/mod/applications/mod_dptools/mod_dptools.c +++ b/src/mod/applications/mod_dptools/mod_dptools.c @@ -3271,14 +3271,22 @@ struct camping_stake { static void *SWITCH_THREAD_FUNC camp_music_thread(switch_thread_t *thread, void *obj) { struct camping_stake *stake = (struct camping_stake *) obj; - switch_core_session_t *session = stake->session; - switch_channel_t *channel = switch_core_session_get_channel(stake->session); + switch_core_session_t *session; + switch_channel_t *channel; const char *moh = stake->moh, *greet = NULL; switch_input_args_t args = { 0 }; char dbuf[2] = ""; switch_status_t status = SWITCH_STATUS_FALSE; const char *stop; + session = stake->session; + + if (switch_core_session_read_lock(session) != SWITCH_STATUS_SUCCESS) { + return NULL; + } + + channel = switch_core_session_get_channel(stake->session); + if ((stop = switch_channel_get_variable(channel, "campon_stop_key"))) { *dbuf = *stop; } @@ -3287,8 +3295,6 @@ static void *SWITCH_THREAD_FUNC camp_music_thread(switch_thread_t *thread, void args.buf = dbuf; args.buflen = sizeof(dbuf); - switch_core_session_read_lock(session); - /* don't set this to a local_stream:// or you will not be happy */ if ((greet = switch_channel_get_variable(channel, "campon_announce_sound"))) { status = switch_ivr_play_file(session, NULL, greet, &args); diff --git a/src/switch_core_media.c b/src/switch_core_media.c index 4a6f14ab21..2205fe2534 100644 --- a/src/switch_core_media.c +++ b/src/switch_core_media.c @@ -91,6 +91,7 @@ struct media_helper { switch_mutex_t *file_read_mutex; switch_mutex_t *file_write_mutex; int up; + int ready; }; typedef enum { @@ -6720,8 +6721,8 @@ SWITCH_DECLARE(switch_status_t) switch_core_session_start_audio_write_thread(swi static void *SWITCH_THREAD_FUNC text_helper_thread(switch_thread_t *thread, void *obj) { struct media_helper *mh = obj; - switch_core_session_t *session = mh->session; - switch_channel_t *channel = switch_core_session_get_channel(session); + switch_core_session_t *session; + switch_channel_t *channel; switch_status_t status; switch_frame_t *read_frame = NULL; switch_media_handle_t *smh; @@ -6729,10 +6730,22 @@ static void *SWITCH_THREAD_FUNC text_helper_thread(switch_thread_t *thread, void unsigned char CR[] = TEXT_UNICODE_LINEFEED; switch_frame_t cr_frame = { 0 }; + + session = mh->session; + + if (switch_core_session_read_lock(session) != SWITCH_STATUS_SUCCESS) { + mh->ready = -1; + return NULL; + } + + mh->ready = 1; + if (!(smh = session->media_handle)) { return NULL; } + channel = switch_core_session_get_channel(session); + if (switch_channel_var_true(session->channel, "fire_text_events")) { switch_channel_set_flag(session->channel, CF_FIRE_TEXT_EVENTS); } @@ -6743,8 +6756,6 @@ static void *SWITCH_THREAD_FUNC text_helper_thread(switch_thread_t *thread, void t_engine = &smh->engines[SWITCH_MEDIA_TYPE_TEXT]; t_engine->thread_id = switch_thread_self(); - switch_core_session_read_lock(session); - mh->up = 1; switch_core_media_check_dtls(session, SWITCH_MEDIA_TYPE_TEXT); @@ -6845,7 +6856,15 @@ SWITCH_DECLARE(switch_status_t) switch_core_session_start_text_thread(switch_cor //switch_mutex_init(&t_engine->mh.file_write_mutex, SWITCH_MUTEX_NESTED, pool); //switch_mutex_init(&smh->read_mutex[SWITCH_MEDIA_TYPE_TEXT], SWITCH_MUTEX_NESTED, pool); //switch_mutex_init(&smh->write_mutex[SWITCH_MEDIA_TYPE_TEXT], SWITCH_MUTEX_NESTED, pool); - switch_thread_create(&t_engine->media_thread, thd_attr, text_helper_thread, &t_engine->mh, switch_core_session_get_pool(session)); + + t_engine->mh.ready = 0; + + if (switch_thread_create(&t_engine->media_thread, thd_attr, text_helper_thread, &t_engine->mh, + switch_core_session_get_pool(session)) == SWITCH_STATUS_SUCCESS) { + while(!t_engine->mh.ready) { + switch_cond_next(); + } + } switch_mutex_unlock(smh->control_mutex); return SWITCH_STATUS_SUCCESS; @@ -6854,8 +6873,8 @@ SWITCH_DECLARE(switch_status_t) switch_core_session_start_text_thread(switch_cor static void *SWITCH_THREAD_FUNC video_helper_thread(switch_thread_t *thread, void *obj) { struct media_helper *mh = obj; - switch_core_session_t *session = mh->session; - switch_channel_t *channel = switch_core_session_get_channel(session); + switch_core_session_t *session; + switch_channel_t *channel; switch_status_t status; switch_frame_t *read_frame = NULL; switch_media_handle_t *smh; @@ -6869,10 +6888,21 @@ static void *SWITCH_THREAD_FUNC video_helper_thread(switch_thread_t *thread, voi int buflen = SWITCH_RTP_MAX_BUF_LEN; int blank_enabled = 1; + session = mh->session; + + if (switch_core_session_read_lock(session) != SWITCH_STATUS_SUCCESS) { + mh->ready = -1; + return NULL; + } + + mh->ready = 1; + if (!(smh = session->media_handle)) { return NULL; } + channel = switch_core_session_get_channel(session); + switch_core_autobind_cpu(); if ((var = switch_channel_get_variable(session->channel, "core_video_blank_image"))) { @@ -6895,8 +6925,6 @@ static void *SWITCH_THREAD_FUNC video_helper_thread(switch_thread_t *thread, voi v_engine = &smh->engines[SWITCH_MEDIA_TYPE_VIDEO]; v_engine->thread_id = switch_thread_self(); - switch_core_session_read_lock(session); - mh->up = 1; switch_mutex_lock(mh->cond_mutex); @@ -7052,7 +7080,14 @@ SWITCH_DECLARE(switch_status_t) switch_core_session_start_video_thread(switch_co switch_mutex_init(&v_engine->mh.file_write_mutex, SWITCH_MUTEX_NESTED, pool); switch_mutex_init(&smh->read_mutex[SWITCH_MEDIA_TYPE_VIDEO], SWITCH_MUTEX_NESTED, pool); switch_mutex_init(&smh->write_mutex[SWITCH_MEDIA_TYPE_VIDEO], SWITCH_MUTEX_NESTED, pool); - switch_thread_create(&v_engine->media_thread, thd_attr, video_helper_thread, &v_engine->mh, switch_core_session_get_pool(session)); + v_engine->mh.ready = 0; + + if (switch_thread_create(&v_engine->media_thread, thd_attr, video_helper_thread, &v_engine->mh, + switch_core_session_get_pool(session)) == SWITCH_STATUS_SUCCESS) { + while(!v_engine->mh.ready) { + switch_cond_next(); + } + } switch_mutex_unlock(smh->control_mutex); return SWITCH_STATUS_SUCCESS; diff --git a/src/switch_cpp.cpp b/src/switch_cpp.cpp index 9cf2df3614..bec23291fb 100644 --- a/src/switch_cpp.cpp +++ b/src/switch_cpp.cpp @@ -635,11 +635,10 @@ SWITCH_DECLARE_CONSTRUCTOR CoreSession::CoreSession(switch_core_session_t *new_s { init_vars(); - if (new_session) { + if (new_session && switch_core_session_read_lock_hangup(new_session) == SWITCH_STATUS_SUCCESS) { session = new_session; channel = switch_core_session_get_channel(session); allocated = 1; - switch_core_session_read_lock_hangup(session); uuid = strdup(switch_core_session_get_uuid(session)); } } diff --git a/src/switch_ivr_async.c b/src/switch_ivr_async.c index 103effa575..2c6ed39446 100644 --- a/src/switch_ivr_async.c +++ b/src/switch_ivr_async.c @@ -3990,9 +3990,10 @@ static void *SWITCH_THREAD_FUNC bcast_thread(switch_thread_t *thread, void *obj) return NULL; } - switch_core_session_read_lock(bch->session); - switch_ivr_broadcast(switch_core_session_get_uuid(bch->session), bch->app, bch->flags); - switch_core_session_rwunlock(bch->session); + if (switch_core_session_read_lock(bch->session) == SWITCH_STATUS_SUCCESS) { + switch_ivr_broadcast(switch_core_session_get_uuid(bch->session), bch->app, bch->flags); + switch_core_session_rwunlock(bch->session); + } return NULL; diff --git a/src/switch_ivr_bridge.c b/src/switch_ivr_bridge.c index e229ee7a44..98d446ad8a 100644 --- a/src/switch_ivr_bridge.c +++ b/src/switch_ivr_bridge.c @@ -158,8 +158,16 @@ static void video_bridge_thread(switch_core_session_t *session, void *obj) vh->up = 1; - switch_core_session_read_lock(vh->session_a); - switch_core_session_read_lock(vh->session_b); + if (switch_core_session_read_lock(vh->session_a) != SWITCH_STATUS_SUCCESS) { + vh->up = 0; + return; + } + + if (switch_core_session_read_lock(vh->session_b) != SWITCH_STATUS_SUCCESS) { + vh->up = 0; + switch_core_session_rwunlock(vh->session_a); + return; + } switch_core_session_request_video_refresh(vh->session_a); switch_core_session_request_video_refresh(vh->session_b); diff --git a/src/switch_ivr_originate.c b/src/switch_ivr_originate.c index 9f3f5d099f..6016809fd2 100644 --- a/src/switch_ivr_originate.c +++ b/src/switch_ivr_originate.c @@ -1428,10 +1428,14 @@ static void *SWITCH_THREAD_FUNC enterprise_originate_ringback_thread(switch_thre { struct ent_originate_ringback *rb_data = (struct ent_originate_ringback *) obj; switch_core_session_t *session = rb_data->session; - switch_channel_t *channel = switch_core_session_get_channel(rb_data->session); + switch_channel_t *channel; switch_status_t status = SWITCH_STATUS_FALSE; - switch_core_session_read_lock(session); + if (switch_core_session_read_lock(session) != SWITCH_STATUS_SUCCESS) { + return NULL; + } + + channel = switch_core_session_get_channel(session); while (rb_data->running && switch_channel_ready(channel)) { switch_ivr_parse_all_messages(session);