From 69a27a4917fb757298b3addabccc6239029761eb Mon Sep 17 00:00:00 2001 From: Yalu Zhang <yalu.zhang@iopsys.eu> Date: Tue, 21 Jan 2025 16:42:52 +0100 Subject: [PATCH] Fix segmentation fault caused by NULL pointer access, REF 16142 --- src/channels/chan_voicemngr.c | 115 +++++++++++++++------------------- 1 file changed, 52 insertions(+), 63 deletions(-) diff --git a/src/channels/chan_voicemngr.c b/src/channels/chan_voicemngr.c index eee75f6..6d8ebf5 100644 --- a/src/channels/chan_voicemngr.c +++ b/src/channels/chan_voicemngr.c @@ -1390,54 +1390,44 @@ __ret: static int chan_voicemngr_call(struct ast_channel *chan, const char *dest, int timeout) { - struct chan_voicemngr_pvt *p; - struct chan_voicemngr_subchannel *sub; - struct chan_voicemngr_subchannel *sub_peer; - - struct timeval UtcTime = ast_tvnow(); - struct ast_tm tm; - sub = ast_channel_tech_pvt(chan); + struct chan_voicemngr_subchannel *sub = ast_channel_tech_pvt(chan); + struct chan_voicemngr_subchannel *sub_peer = chan_voicemngr_subchannel_get_peer(sub); + struct chan_voicemngr_pvt *p = sub->parent; int sip_client_id = -1; if (!sub || !sub->parent) { - ast_log(LOG_ERROR, "Failed to get peer subchannel\n"); - return -1; + ast_log(LOG_ERROR, "Invalid subchannel\n"); + return -1; } - ast_debug(1, "line %d\n", sub->parent->line_id); - sscanf(sub->parent->context, "sip%d", &sip_client_id); - ast_localtime(&UtcTime, &tm, NULL); - - if ((ast_channel_state(chan) != AST_STATE_DOWN) && (ast_channel_state(chan) != AST_STATE_RESERVED)) { - ast_log(LOG_WARNING, "chan_voicemngr_call called on %s, neither down nor reserved\n", ast_channel_name(chan)); + if (ast_channel_state(chan) != AST_STATE_DOWN && ast_channel_state(chan) != AST_STATE_RESERVED) { + ast_log(LOG_WARNING, "called on channel %s, neither down nor reserved\n", ast_channel_name(chan)); return -1; } - //ast_mutex_lock(&sub->parent->lock); - pvt_lock(sub->parent, "chan_voicemngr_call"); - p = sub->parent; - sub_peer = chan_voicemngr_subchannel_get_peer(sub); - ast_debug(1, "channel state: %s, peer channel state: %s\n", state2str(sub->channel_state), state2str(sub_peer->channel_state)); + ast_debug(1, "line %d, sub channel state %s, peer state %s\n", p->line_id, state2str(sub->channel_state), + state2str(sub_peer->channel_state)); + sscanf(p->context, "sip%d", &sip_client_id); + + pvt_lock(p, "chan_voicemngr_call"); + if (!channel_config[p->line_id].enabled) { ast_debug(1, "tel_line %d disabled!\n", p->line_id); ast_channel_hangupcause_set(chan, AST_CAUSE_CALL_REJECTED); ast_queue_control(chan, AST_CONTROL_BUSY); chan_voicemngr_send_ubus_event("CALL_REJECTED",p->line_id); - } - else if (channel_config[p->line_id].do_not_disturb) { + } else if (channel_config[p->line_id].do_not_disturb) { ast_debug(1, "Do not disturbed\n"); ast_channel_hangupcause_set(chan, AST_CAUSE_USER_BUSY); chan_voicemngr_send_ubus_event("USER_BUSY",p->line_id); ast_queue_control(chan, AST_CONTROL_BUSY); - } - else if(p->emergency) { + } else if(p->emergency) { ast_debug(1, "Emergency Call Ongoing\n"); ast_channel_hangupcause_set(chan, AST_CAUSE_USER_BUSY); chan_voicemngr_send_ubus_event("USER_BUSY",p->line_id); ast_queue_control(chan, AST_CONTROL_BUSY); - } - else if (chan_voicemngr_in_call(p) && // a call is established - is_call_waiting_enabled(p->context)) { // call waiting enabled + } else if (chan_voicemngr_in_call(p) && // a call is established + is_call_waiting_enabled(p->context)) { // call waiting enabled int cw_delay = 100; ast_debug(1, "Call waiting\n"); @@ -1452,9 +1442,8 @@ static int chan_voicemngr_call(struct ast_channel *chan, const char *dest, int t sub->cw_timer_id = ast_sched_add(sched, cwtimeout_ms, cwtimeout_cb, sub); ast_setstate(chan, AST_STATE_RINGING_CW); ast_queue_control(chan, AST_CONTROL_RINGING_CW); - } - else if (!chan_voicemngr_subchannel_is_idle(sub_peer) || - (has_call_in_sip_client(p->context) && sip_line_callmode[sip_client_id] == LINE_CALL_MODE_SINGLE) ) { + } else if (!chan_voicemngr_subchannel_is_idle(sub_peer) || + (has_call_in_sip_client(p->context) && sip_line_callmode[sip_client_id] == LINE_CALL_MODE_SINGLE)) { ast_debug(1, "Line is busy\n"); ast_channel_hangupcause_set(chan, AST_CAUSE_USER_BUSY); ast_queue_control(chan, AST_CONTROL_BUSY); @@ -1462,24 +1451,7 @@ static int chan_voicemngr_call(struct ast_channel *chan, const char *dest, int t if(sub->channel_state == ALLOCATED) sub->channel_state = ONHOOK; chan_voicemngr_send_ubus_event("USER_BUSY",p->line_id); - - struct chan_voicemngr_pvt *tmp = p; - struct chan_voicemngr_subchannel *s = NULL; - int con_id = -1; - - while(tmp) { - s = chan_voicemngr_get_active_subchannel(tmp); - con_id = s->connection_id; - // for local call we need to find the other party and change its subchannel state to CALLENDED - // so the extensionCallStatus is properly set to Disconnected in chan_voicemngr_answer() - if (con_id > 0 && (strncmp(tmp->extensionCallStatus, "Dialing", strlen(tmp->extensionCallStatus)) == 0)) { - s->channel_state = CALLENDED; - break; - } - tmp = chan_voicemngr_get_next_pvt(tmp); - } - } - else { + } else { ast_debug(1, "Not call waiting\n"); /*We can move status to Alerting ,since we are ringing now */ strncpy(p->extensionCallStatus, "Alerting", CALL_STATUS_MAX_LEN); @@ -1507,7 +1479,7 @@ static int chan_voicemngr_call(struct ast_channel *chan, const char *dest, int t chan_voicemngr_send_ubus_event("RINGING",p->line_id); } - //ast_mutex_unlock(&sub->parent->lock); + pvt_unlock(sub->parent); return 0; @@ -2169,8 +2141,10 @@ struct chan_voicemngr_subchannel* chan_voicemngr_get_active_subchannel(const str struct chan_voicemngr_subchannel *sub = NULL; int i; - if(!p) + if(!p) { + ast_log(LOG_ERROR, "Invalid parameter\n"); return NULL; + } for (i=0; i<NUM_SUBCHANNELS; i++) { switch (p->sub[i]->channel_state) { @@ -2203,12 +2177,15 @@ struct chan_voicemngr_subchannel* chan_voicemngr_get_active_subchannel(const str break; default: - ast_log(LOG_WARNING, "Unhandled channel state %d\n", p->sub[i]->channel_state); + ast_log(LOG_WARNING, "Unhandled channel state %s(%d) on line %d sub-channel %d\n", + state2str(p->sub[i]->channel_state), p->sub[i]->channel_state, p->line_id, i); break; } } - ast_assert(sub != NULL); + if(!sub) { + ast_log(LOG_WARNING, "There is no active sub-channel found on line %d\n", p->line_id); + } return sub; } @@ -2230,10 +2207,15 @@ static int setup_conference_call_cb( const void *data) { struct chan_voicemngr_subchannel *sub_peer; struct ast_channel *peer_owner = NULL; + struct chan_voicemngr_pvt *p = (struct chan_voicemngr_pvt *)data; + struct chan_voicemngr_subchannel *sub = chan_voicemngr_get_active_subchannel(p); + + if (!sub) { + return -1; + } ast_log(LOG_NOTICE ,"Set up a conference call\n"); - struct chan_voicemngr_pvt *p = (struct chan_voicemngr_pvt *) data; - struct chan_voicemngr_subchannel *sub = chan_voicemngr_get_active_subchannel(p); + sub_peer = chan_voicemngr_subchannel_get_peer(sub); pvt_lock(sub->parent, "setup_conference_call_cb"); if (sub_peer->owner) { @@ -2451,9 +2433,12 @@ static int onholdhanguptimeout_cb(const void *data) static int handle_busy_internal_call_timeout(const void *data) { - struct chan_voicemngr_pvt *p = (struct chan_voicemngr_pvt *) data; + struct chan_voicemngr_pvt *p = (struct chan_voicemngr_pvt *)data; struct chan_voicemngr_subchannel *sub = chan_voicemngr_get_active_subchannel(p); + if (!sub) + return -1; + ast_debug(9, "busy internal timeout, state:%d, dialtone: %d\n", sub->channel_state, p->dialtone); pvt_lock(p, "busy timeout"); @@ -2527,6 +2512,9 @@ static int handle_audio_announcement_timeout(const void *data) struct chan_voicemngr_subchannel *sub = chan_voicemngr_get_active_subchannel(p); unsigned int old_state; + if (!sub) + return -1; + pvt_lock(p, "audio announcement"); p->audio_announcement_timer_id = -1; @@ -2588,7 +2576,8 @@ static int handle_interdigit_timeout(const void *data) pvt_lock(p, "interdigit callback"); p->interdigit_timer_id = -1; struct chan_voicemngr_subchannel *sub = chan_voicemngr_get_active_subchannel(p); - if (channel_config[p->line_id].minimumnumberdigits && + + if (sub && channel_config[p->line_id].minimumnumberdigits && strlen(p->dtmfbuf) >= channel_config[p->line_id].minimumnumberdigits) { if (ast_exists_extension(NULL, p->invoke_context, p->dtmfbuf, 1, p->cid_num)) { //We have at least one matching extension in "normal" context, @@ -2596,11 +2585,11 @@ static int handle_interdigit_timeout(const void *data) //Asterisk will select the best matching extension if there are more than one possibility. ast_debug(9, "Interdigit timeout, extension(s) matching %s found\n", p->dtmfbuf); chan_voicemngr_start_calling(sub, p->invoke_context); - } - } + } + } //if no limit on minimum digits check extension exits - if(!channel_config[p->line_id].minimumnumberdigits) { + if(sub && !channel_config[p->line_id].minimumnumberdigits) { if (ast_exists_extension(NULL, p->invoke_context, p->dtmfbuf, 1, p->cid_num)) { //We have at least one matching extension in "normal" context, //and interdigit timeout has passed, so have asterisk start calling. @@ -2650,7 +2639,7 @@ static int handle_autodial_timeout(const void *data) struct chan_voicemngr_subchannel *sub = chan_voicemngr_get_active_subchannel(p); channel_settings *s = &channel_config[p->line_id]; - if (ast_exists_extension(NULL, p->invoke_context, s->autodial_ext, 1, p->cid_num)) { + if (sub && ast_exists_extension(NULL, p->invoke_context, s->autodial_ext, 1, p->cid_num)) { chan_voicemngr_stop_dialtone(p); ast_copy_string(p->dtmfbuf, s->autodial_ext, sizeof(p->dtmfbuf)); ast_debug(9, "Autodialing extension: %s\n", p->dtmfbuf); @@ -2723,7 +2712,7 @@ static int handle_emergency_registration(const void *data) p->emergency_registration_timer_count++; struct chan_voicemngr_subchannel *sub = chan_voicemngr_get_active_subchannel(p); - if (is_sip_account_registered(p->invoke_context) || p->emergency_registration_timer_count > 15) { + if (sub && (is_sip_account_registered(p->invoke_context) || p->emergency_registration_timer_count > 15)) { p->emergency_registration_timer_count = 0; chan_voicemngr_start_calling(sub, p->invoke_context_direct); } else { @@ -5906,7 +5895,7 @@ static int chan_voicemngr_signal_ringing(struct chan_voicemngr_pvt *p) { if (channel_config[p->line_id].ringsignal) { struct chan_voicemngr_subchannel *sub = chan_voicemngr_get_active_subchannel(p); - if (sub->is_internal == true) { + if (sub && sub->is_internal == true) { endpt_signal(p->line_id, "ringing_int", "on", NULL); } else { endpt_signal(p->line_id, "ringing", "on", NULL); @@ -5931,7 +5920,7 @@ static int chan_voicemngr_signal_ringing_callerid_pending(struct chan_voicemngr_ { if (channel_config[p->line_id].ringsignal) { struct chan_voicemngr_subchannel *sub = chan_voicemngr_get_active_subchannel(p); - if (sub->is_internal == true) { + if (sub && sub->is_internal == true) { endpt_signal(p->line_id, "callid_ringing_int", "on", NULL); } else { endpt_signal(p->line_id, "callid_ringing", "on", NULL); -- GitLab