mirror of
https://github.com/asterisk/asterisk.git
synced 2025-10-25 22:18:07 +00:00
pjsip_transport_events: Fix possible use after free on transport
It was possible for a module that registered for transport monitor
events to pass in a pjsip_transport that had already been freed.
This caused pjsip_transport_events to crash when looking up the
monitor for the transport. The fix is a two pronged approach.
1. We now increment the reference count on pjsip_transports when we
create monitors for them, then decrement the count when the
transport is going to be destroyed.
2. There are now APIs to register and unregister monitor callbacks
by "transport key" which is a string concatenation of the remote ip
address and port. This way the module needing to monitor the
transport doesn't have to hold on to the transport object itself to
unregister. It just has to save the transport_key.
* Added the pjsip_transport reference increment and decrement.
* Changed the internal transport monitor container key from the
transport->obj_name (which may not be unique anyway) to the
transport_key.
* Added a helper macro AST_SIP_MAKE_REMOTE_IPADDR_PORT_STR() that
fills a buffer with the transport_key using a passed-in
pjsip_transport.
* Added the following functions:
ast_sip_transport_monitor_register_key
ast_sip_transport_monitor_register_replace_key
ast_sip_transport_monitor_unregister_key
and marked their non-key counterparts as deprecated.
* Updated res_pjsip_pubsub and res_pjsip_outbound_register to use
the new "key" monitor functions.
NOTE: res_pjsip_registrar also uses the transport monitor
functionality but doesn't have a persistent object other than
contact to store a transport key. At this time, it continues to
use the non-key monitor functions.
ASTERISK-30244
Change-Id: I1a20baf2a8643c272dcf819871d6c395f148f00b
(cherry picked from commit 7684c9e907)
This commit is contained in:
committed by
Friendly Automation
parent
b515b50c08
commit
120aca73ba
@@ -993,6 +993,8 @@ struct registration_response {
|
||||
pjsip_rx_data *rdata;
|
||||
/*! \brief Request for which the response was received */
|
||||
pjsip_tx_data *old_request;
|
||||
/*! \brief Key for the reliable transport in use */
|
||||
char transport_key[IP6ADDR_COLON_PORT_BUFLEN];
|
||||
};
|
||||
|
||||
/*! \brief Registration response structure destructor */
|
||||
@@ -1108,13 +1110,10 @@ static int monitor_matcher(void *a, void *b)
|
||||
return strcmp(ma, mb) == 0;
|
||||
}
|
||||
|
||||
static void registration_transport_monitor_setup(pjsip_transport *transport, const char *registration_name)
|
||||
static void registration_transport_monitor_setup(const char *transport_key, const char *registration_name)
|
||||
{
|
||||
char *monitor;
|
||||
|
||||
if (!PJSIP_TRANSPORT_IS_RELIABLE(transport)) {
|
||||
return;
|
||||
}
|
||||
monitor = ao2_alloc_options(strlen(registration_name) + 1, NULL,
|
||||
AO2_ALLOC_OPT_LOCK_NOLOCK);
|
||||
if (!monitor) {
|
||||
@@ -1127,8 +1126,8 @@ static void registration_transport_monitor_setup(pjsip_transport *transport, con
|
||||
* register the monitor. We might get into a message spamming infinite
|
||||
* loop of registration, shutdown, reregistration...
|
||||
*/
|
||||
ast_sip_transport_monitor_register(transport, registration_transport_shutdown_cb,
|
||||
monitor);
|
||||
ast_sip_transport_monitor_register_replace_key(transport_key, registration_transport_shutdown_cb,
|
||||
monitor, monitor_matcher);
|
||||
ao2_ref(monitor, -1);
|
||||
}
|
||||
|
||||
@@ -1322,14 +1321,18 @@ static int handle_registration_response(void *data)
|
||||
schedule_registration(response->client_state, next_registration_round);
|
||||
|
||||
/* See if we should monitor for transport shutdown */
|
||||
registration_transport_monitor_setup(response->rdata->tp_info.transport,
|
||||
response->client_state->registration_name);
|
||||
if (PJSIP_TRANSPORT_IS_RELIABLE(response->rdata->tp_info.transport)) {
|
||||
registration_transport_monitor_setup(response->transport_key,
|
||||
response->client_state->registration_name);
|
||||
}
|
||||
} else {
|
||||
ast_debug(1, "Outbound unregistration to '%s' with client '%s' successful\n", server_uri, client_uri);
|
||||
update_client_state_status(response->client_state, SIP_REGISTRATION_UNREGISTERED);
|
||||
ast_sip_transport_monitor_unregister(response->rdata->tp_info.transport,
|
||||
registration_transport_shutdown_cb, response->client_state->registration_name,
|
||||
monitor_matcher);
|
||||
if (PJSIP_TRANSPORT_IS_RELIABLE(response->rdata->tp_info.transport)) {
|
||||
ast_sip_transport_monitor_unregister_key(response->transport_key,
|
||||
registration_transport_shutdown_cb, response->client_state->registration_name,
|
||||
monitor_matcher);
|
||||
}
|
||||
}
|
||||
|
||||
save_response_fields_to_transport(response);
|
||||
@@ -1445,6 +1448,9 @@ static void sip_outbound_registration_response_cb(struct pjsip_regc_cbparam *par
|
||||
response->old_request = tsx->last_tx;
|
||||
pjsip_tx_data_add_ref(response->old_request);
|
||||
pjsip_rx_data_clone(param->rdata, 0, &response->rdata);
|
||||
AST_SIP_MAKE_REMOTE_IPADDR_PORT_STR(param->rdata->tp_info.transport,
|
||||
response->transport_key);
|
||||
|
||||
} else {
|
||||
/* old_request steals the reference */
|
||||
response->old_request = client_state->last_tdata;
|
||||
|
||||
Reference in New Issue
Block a user