From 3a585794e1381d9ef643aabbfc8fa11420fb318a Mon Sep 17 00:00:00 2001 From: George Joseph <gjoseph@digium.com> Date: Tue, 6 Feb 2018 10:28:49 -0700 Subject: [PATCH] AST-2018-005: Fix tdata leaks when calling pjsip_endpt_send_response(2) pjsip_distributor: authenticate() creates a tdata and uses it to send a challenge or failure response. When pjsip_endpt_send_response2() succeeds, it automatically decrements the tdata ref count but when it fails, it doesn't. Since we weren't checking for a return status, we weren't decrementing the count ourselves on error and were therefore leaking tdatas. res_pjsip_session: session_reinvite_on_rx_request wasn't decrementing the ref count if an error happened while sending a 491 response. pre_session_setup wasn't decrementing the ref count if while sending an error after a pjsip_inv_verify_request failure. res_pjsip: ast_sip_send_response wasn't decrementing the ref count on error. ASTERISK-27618 Reported By: Sandro Gauci Change-Id: Iab33a6c7b6fba96148ed465b690ba8534ac961bf --- res/res_pjsip.c | 8 +++++++- res/res_pjsip/pjsip_distributor.c | 8 ++++++-- res/res_pjsip_session.c | 8 ++++++-- 3 files changed, 19 insertions(+), 5 deletions(-) diff --git a/res/res_pjsip.c b/res/res_pjsip.c index 60d997af4d..0d816a33c2 100644 --- a/res/res_pjsip.c +++ b/res/res_pjsip.c @@ -4424,9 +4424,15 @@ static void supplement_outgoing_response(pjsip_tx_data *tdata, struct ast_sip_en int ast_sip_send_response(pjsip_response_addr *res_addr, pjsip_tx_data *tdata, struct ast_sip_endpoint *sip_endpoint) { + pj_status_t status; + supplement_outgoing_response(tdata, sip_endpoint); + status = pjsip_endpt_send_response(ast_sip_get_pjsip_endpoint(), res_addr, tdata, NULL, NULL); + if (status != PJ_SUCCESS) { + pjsip_tx_data_dec_ref(tdata); + } - return pjsip_endpt_send_response(ast_sip_get_pjsip_endpoint(), res_addr, tdata, NULL, NULL); + return status == PJ_SUCCESS ? 0 : -1; } int ast_sip_send_stateful_response(pjsip_rx_data *rdata, pjsip_tx_data *tdata, struct ast_sip_endpoint *sip_endpoint) diff --git a/res/res_pjsip/pjsip_distributor.c b/res/res_pjsip/pjsip_distributor.c index b4828d89fb..7f512d1bb7 100644 --- a/res/res_pjsip/pjsip_distributor.c +++ b/res/res_pjsip/pjsip_distributor.c @@ -854,7 +854,9 @@ static pj_bool_t authenticate(pjsip_rx_data *rdata) case AST_SIP_AUTHENTICATION_CHALLENGE: /* Send the 401 we created for them */ ast_sip_report_auth_challenge_sent(endpoint, rdata, tdata); - pjsip_endpt_send_response2(ast_sip_get_pjsip_endpoint(), rdata, tdata, NULL, NULL); + if (pjsip_endpt_send_response2(ast_sip_get_pjsip_endpoint(), rdata, tdata, NULL, NULL) != PJ_SUCCESS) { + pjsip_tx_data_dec_ref(tdata); + } return PJ_TRUE; case AST_SIP_AUTHENTICATION_SUCCESS: /* See note in endpoint_lookup about not holding an unnecessary write lock */ @@ -867,7 +869,9 @@ static pj_bool_t authenticate(pjsip_rx_data *rdata) case AST_SIP_AUTHENTICATION_FAILED: log_failed_request(rdata, "Failed to authenticate", 0, 0); ast_sip_report_auth_failed_challenge_response(endpoint, rdata); - pjsip_endpt_send_response2(ast_sip_get_pjsip_endpoint(), rdata, tdata, NULL, NULL); + if (pjsip_endpt_send_response2(ast_sip_get_pjsip_endpoint(), rdata, tdata, NULL, NULL) != PJ_SUCCESS) { + pjsip_tx_data_dec_ref(tdata); + } return PJ_TRUE; case AST_SIP_AUTHENTICATION_ERROR: log_failed_request(rdata, "Error to authenticate", 0, 0); diff --git a/res/res_pjsip_session.c b/res/res_pjsip_session.c index 8ad6d3ce49..ea806cda8e 100644 --- a/res/res_pjsip_session.c +++ b/res/res_pjsip_session.c @@ -1083,7 +1083,9 @@ static pj_bool_t session_reinvite_on_rx_request(pjsip_rx_data *rdata) /* Otherwise this is a new re-invite, so reject it */ if (pjsip_dlg_create_response(dlg, rdata, 491, NULL, &tdata) == PJ_SUCCESS) { - pjsip_endpt_send_response2(ast_sip_get_pjsip_endpoint(), rdata, tdata, NULL, NULL); + if (pjsip_endpt_send_response2(ast_sip_get_pjsip_endpoint(), rdata, tdata, NULL, NULL) != PJ_SUCCESS) { + pjsip_tx_data_dec_ref(tdata); + } } return PJ_TRUE; @@ -2045,7 +2047,9 @@ static pjsip_inv_session *pre_session_setup(pjsip_rx_data *rdata, const struct a if (pjsip_inv_verify_request(rdata, &options, NULL, NULL, ast_sip_get_pjsip_endpoint(), &tdata) != PJ_SUCCESS) { if (tdata) { - pjsip_endpt_send_response2(ast_sip_get_pjsip_endpoint(), rdata, tdata, NULL, NULL); + if (pjsip_endpt_send_response2(ast_sip_get_pjsip_endpoint(), rdata, tdata, NULL, NULL) != PJ_SUCCESS) { + pjsip_tx_data_dec_ref(tdata); + } } else { pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 500, NULL, NULL, NULL); }