AST-2016-004: Fix crash on REGISTER with long URI.

Due to some ignored return values, Asterisk could crash if processing an
incoming REGISTER whose contact URI was above a certain length.

ASTERISK-25707 #close
Reported by George Joseph

Patches:
    0001-res_pjsip-Validate-that-URIs-don-t-exceed-pjproject-.patch

AST-2016-004

Change-Id: I3ea7cee16f29c8088794de3085ca7523c1c4833d
This commit is contained in:
Mark Michelson
2016-04-14 07:23:54 -05:00
parent fddec0c266
commit 7b8b6e2e4f
4 changed files with 93 additions and 2 deletions

View File

@@ -18,6 +18,7 @@
/*** MODULEINFO
<depend>pjproject</depend>
<depend>res_pjproject</depend>
<depend>res_pjsip</depend>
<support_level>core</support_level>
***/
@@ -33,6 +34,7 @@
#include "asterisk/taskprocessor.h"
#include "asterisk/manager.h"
#include "asterisk/named_locks.h"
#include "asterisk/res_pjproject.h"
#include "res_pjsip/include/res_pjsip_private.h"
/*** DOCUMENTATION
@@ -52,6 +54,9 @@
</manager>
***/
static int pj_max_hostname = PJ_MAX_HOSTNAME;
static int pjsip_max_url_size = PJSIP_MAX_URL_SIZE;
/*! \brief Internal function which returns the expiration time for a contact */
static int registrar_get_expiration(const struct ast_sip_aor *aor, const pjsip_contact_hdr *contact, const pjsip_rx_data *rdata)
{
@@ -86,7 +91,7 @@ struct registrar_contact_details {
/*! \brief Pool used for parsing URI */
pj_pool_t *pool;
/*! \brief URI being looked for */
pjsip_uri *uri;
pjsip_sip_uri *uri;
};
/*! \brief Callback function for finding a contact */
@@ -114,6 +119,7 @@ static int registrar_validate_contacts(const pjsip_rx_data *rdata, struct ao2_co
while ((contact = (pjsip_contact_hdr *) pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_CONTACT, contact->next))) {
int expiration = registrar_get_expiration(aor, contact, rdata);
RAII_VAR(struct ast_sip_contact *, existing, NULL, ao2_cleanup);
char contact_uri[pjsip_max_url_size];
if (contact->star) {
/* The expiration MUST be 0 when a '*' contact is used and there must be no other contact */
@@ -135,6 +141,19 @@ static int registrar_validate_contacts(const pjsip_rx_data *rdata, struct ao2_co
details.uri = pjsip_uri_get_uri(contact->uri);
/* pjsip_uri_print returns -1 if there's not enough room in the buffer */
if (pjsip_uri_print(PJSIP_URI_IN_CONTACT_HDR, details.uri, contact_uri, sizeof(contact_uri)) < 0) {
/* If the total length of the uri is greater than pjproject can handle, go no further */
pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(), details.pool);
return -1;
}
if (details.uri->host.slen >= pj_max_hostname) {
/* If the length of the hostname is greater than pjproject can handle, go no further */
pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(), details.pool);
return -1;
}
/* Determine if this is an add, update, or delete for policy enforcement purposes */
if (!(existing = ao2_callback(contacts, 0, registrar_find_contact, &details))) {
if (expiration) {
@@ -472,7 +491,7 @@ static int rx_task_core(struct rx_task_data *task_data, struct ao2_container *co
/* Iterate each provided Contact header and add, update, or delete */
while ((contact_hdr = pjsip_msg_find_hdr(task_data->rdata->msg_info.msg, PJSIP_H_CONTACT, contact_hdr ? contact_hdr->next : NULL))) {
int expiration;
char contact_uri[PJSIP_MAX_URL_SIZE];
char contact_uri[pjsip_max_url_size];
RAII_VAR(struct ast_sip_contact *, contact, NULL, ao2_cleanup);
if (contact_hdr->star) {
@@ -827,6 +846,12 @@ static int load_module(void)
{
const pj_str_t STR_REGISTER = { "REGISTER", 8 };
CHECK_PJPROJECT_MODULE_LOADED();
ast_pjproject_get_buildopt("PJ_MAX_HOSTNAME", "%d", &pj_max_hostname);
/* As of pjproject 2.4.5, PJSIP_MAX_URL_SIZE isn't exposed yet but we try anyway. */
ast_pjproject_get_buildopt("PJSIP_MAX_URL_SIZE", "%d", &pjsip_max_url_size);
CHECK_PJSIP_MODULE_LOADED();
if (!(serializers = ao2_container_alloc(