[asterisk-commits] bebuild: tag certified-1.8.15-cert5 r410430 - in /certified/tags/1.8.15-cert5...
SVN commits to the Asterisk project
asterisk-commits at lists.digium.com
Mon Mar 10 13:12:21 CDT 2014
Author: bebuild
Date: Mon Mar 10 13:12:16 2014
New Revision: 410430
URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=410430
Log:
AST-2014-001: AST-2014-002: Merge into 1.8.15-cert5
Modified:
certified/tags/1.8.15-cert5/ (props changed)
certified/tags/1.8.15-cert5/ChangeLog
certified/tags/1.8.15-cert5/channels/chan_sip.c
certified/tags/1.8.15-cert5/main/http.c
Propchange: certified/tags/1.8.15-cert5/
------------------------------------------------------------------------------
--- svn:mergeinfo (original)
+++ svn:mergeinfo Mon Mar 10 13:12:16 2014
@@ -1,3 +1,3 @@
/branches/1.8:371919
/certified/branches/1.8.11:376302
-/certified/branches/1.8.15:397754,397761,403858,403914
+/certified/branches/1.8.15:397754,397761,403858,403914,410358,410427
Modified: certified/tags/1.8.15-cert5/ChangeLog
URL: http://svnview.digium.com/svn/asterisk/certified/tags/1.8.15-cert5/ChangeLog?view=diff&rev=410430&r1=410429&r2=410430
==============================================================================
--- certified/tags/1.8.15-cert5/ChangeLog (original)
+++ certified/tags/1.8.15-cert5/ChangeLog Mon Mar 10 13:12:16 2014
@@ -1,3 +1,32 @@
+2014-03-10 Asterisk Development Team <asteriskteam at digium.com>
+
+ * Certified Asterisk 1.8.15-cert5 Released.
+
+ * AST-2012-002: chan_sip: Exit early on bad session timers request
+
+ This change allows chan_sip to avoid creation of the channel and
+ consumption of associated file descriptors altogether if the inbound
+ request is going to be rejected anyway.
+
+ (closes issue ASTERISK-23373)
+ Reported by: Corey Farrell
+ Patches:
+ chan_sip-earlier-st-1.8.patch uploaded by Corey Farrell (license 5909)
+ chan_sip-earlier-st-11.patch uploaded by Corey Farrell (license 5909)
+
+ * AST-2014-001: Stack overflow in HTTP processing of Cookie headers.
+
+ Sending a HTTP request that is handled by Asterisk with a large
+ number of Cookie headers could overflow the stack.
+
+ Another vulnerability along similar lines is any HTTP request with a
+ ridiculous number of headers in the request could exhaust system
+ memory.
+
+ (closes issue ASTERISK-23340)
+ Reported by: Lucas Molas, researcher at Programa STIC, Fundacion;
+ and Dr. Manuel Sadosky, Buenos Aires, Argentina
+
2013-12-16 Asterisk Development Team <asteriskteam at digium.com>
* Certified Asterisk 1.8.15-cert4 Released.
Modified: certified/tags/1.8.15-cert5/channels/chan_sip.c
URL: http://svnview.digium.com/svn/asterisk/certified/tags/1.8.15-cert5/channels/chan_sip.c?view=diff&rev=410430&r1=410429&r2=410430
==============================================================================
--- certified/tags/1.8.15-cert5/channels/chan_sip.c (original)
+++ certified/tags/1.8.15-cert5/channels/chan_sip.c Mon Mar 10 13:12:16 2014
@@ -22803,6 +22803,145 @@
return 0;
}
+/*
+ * \internal \brief Check Session Timers for an INVITE request
+ *
+ * \retval 0 ok
+ * \retval -1 failure
+ */
+static int handle_request_invite_st(struct sip_pvt *p, struct sip_request *req,
+ const char *required, int reinvite)
+{
+ const char *p_uac_se_hdr; /* UAC's Session-Expires header string */
+ const char *p_uac_min_se; /* UAC's requested Min-SE interval (char string) */
+ int uac_max_se = -1; /* UAC's Session-Expires in integer format */
+ int uac_min_se = -1; /* UAC's Min-SE in integer format */
+ int st_active = FALSE; /* Session-Timer on/off boolean */
+ int st_interval = 0; /* Session-Timer negotiated refresh interval */
+ enum st_refresher tmp_st_ref = SESSION_TIMER_REFRESHER_AUTO; /* Session-Timer refresher */
+ int dlg_min_se = -1;
+ int dlg_max_se = global_max_se;
+ int rtn;
+
+ /* Session-Timers */
+ if ((p->sipoptions & SIP_OPT_TIMER)) {
+ enum st_refresher_param st_ref_param = SESSION_TIMER_REFRESHER_PARAM_UNKNOWN;
+
+ /* The UAC has requested session-timers for this session. Negotiate
+ the session refresh interval and who will be the refresher */
+ ast_debug(2, "Incoming INVITE with 'timer' option supported\n");
+
+ /* Allocate Session-Timers struct w/in the dialog */
+ if (!p->stimer) {
+ sip_st_alloc(p);
+ }
+
+ /* Parse the Session-Expires header */
+ p_uac_se_hdr = get_header(req, "Session-Expires");
+ if (!ast_strlen_zero(p_uac_se_hdr)) {
+ ast_debug(2, "INVITE also has \"Session-Expires\" header.\n");
+ rtn = parse_session_expires(p_uac_se_hdr, &uac_max_se, &st_ref_param);
+ tmp_st_ref = (st_ref_param == SESSION_TIMER_REFRESHER_PARAM_UAC) ? SESSION_TIMER_REFRESHER_THEM : SESSION_TIMER_REFRESHER_US;
+ if (rtn != 0) {
+ transmit_response_reliable(p, "400 Session-Expires Invalid Syntax", req);
+ return -1;
+ }
+ }
+
+ /* Parse the Min-SE header */
+ p_uac_min_se = get_header(req, "Min-SE");
+ if (!ast_strlen_zero(p_uac_min_se)) {
+ ast_debug(2, "INVITE also has \"Min-SE\" header.\n");
+ rtn = parse_minse(p_uac_min_se, &uac_min_se);
+ if (rtn != 0) {
+ transmit_response_reliable(p, "400 Min-SE Invalid Syntax", req);
+ return -1;
+ }
+ }
+
+ dlg_min_se = st_get_se(p, FALSE);
+ switch (st_get_mode(p, 1)) {
+ case SESSION_TIMER_MODE_ACCEPT:
+ case SESSION_TIMER_MODE_ORIGINATE:
+ if (uac_max_se > 0 && uac_max_se < dlg_min_se) {
+ transmit_response_with_minse(p, "422 Session Interval Too Small", req, dlg_min_se);
+ return -1;
+ }
+
+ p->stimer->st_active_peer_ua = TRUE;
+ st_active = TRUE;
+ if (st_ref_param == SESSION_TIMER_REFRESHER_PARAM_UNKNOWN) {
+ tmp_st_ref = st_get_refresher(p);
+ }
+
+ dlg_max_se = st_get_se(p, TRUE);
+ if (uac_max_se > 0) {
+ if (dlg_max_se >= uac_min_se) {
+ st_interval = (uac_max_se < dlg_max_se) ? uac_max_se : dlg_max_se;
+ } else {
+ st_interval = uac_max_se;
+ }
+ } else if (uac_min_se > 0) {
+ st_interval = MAX(dlg_max_se, uac_min_se);
+ } else {
+ st_interval = dlg_max_se;
+ }
+ break;
+
+ case SESSION_TIMER_MODE_REFUSE:
+ if (p->reqsipoptions & SIP_OPT_TIMER) {
+ transmit_response_with_unsupported(p, "420 Option Disabled", req, required);
+ ast_log(LOG_WARNING, "Received SIP INVITE with supported but disabled option: %s\n", required);
+ return -1;
+ }
+ break;
+
+ default:
+ ast_log(LOG_ERROR, "Internal Error %d at %s:%d\n", st_get_mode(p, 1), __FILE__, __LINE__);
+ break;
+ }
+ } else {
+ /* The UAC did not request session-timers. Asterisk (UAS), will now decide
+ (based on session-timer-mode in sip.conf) whether to run session-timers for
+ this session or not. */
+ switch (st_get_mode(p, 1)) {
+ case SESSION_TIMER_MODE_ORIGINATE:
+ st_active = TRUE;
+ st_interval = st_get_se(p, TRUE);
+ tmp_st_ref = SESSION_TIMER_REFRESHER_US;
+ p->stimer->st_active_peer_ua = (p->sipoptions & SIP_OPT_TIMER) ? TRUE : FALSE;
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ if (reinvite == 0) {
+ /* Session-Timers: Start session refresh timer based on negotiation/config */
+ if (st_active == TRUE) {
+ p->stimer->st_active = TRUE;
+ p->stimer->st_interval = st_interval;
+ p->stimer->st_ref = tmp_st_ref;
+ }
+ } else {
+ if (p->stimer->st_active == TRUE) {
+ /* Session-Timers: A re-invite request sent within a dialog will serve as
+ a refresh request, no matter whether the re-invite was sent for refreshing
+ the session or modifying it.*/
+ ast_debug (2, "Restarting session-timers on a refresh - %s\n", p->callid);
+
+ /* The UAC may be adjusting the session-timers mid-session */
+ if (st_interval > 0) {
+ p->stimer->st_interval = st_interval;
+ p->stimer->st_ref = tmp_st_ref;
+ }
+ }
+ }
+
+ return 0;
+}
+
/*!
* \brief Handle incoming INVITE request
* \note If the INVITE has a Replaces header, it is part of an
@@ -22822,18 +22961,9 @@
struct ast_channel *c = NULL; /* New channel */
struct sip_peer *authpeer = NULL; /* Matching Peer */
int reinvite = 0;
- int rtn;
struct ast_party_redirecting redirecting;
struct ast_set_party_redirecting update_redirecting;
- const char *p_uac_se_hdr; /* UAC's Session-Expires header string */
- const char *p_uac_min_se; /* UAC's requested Min-SE interval (char string) */
- int uac_max_se = -1; /* UAC's Session-Expires in integer format */
- int uac_min_se = -1; /* UAC's Min-SE in integer format */
- int st_active = FALSE; /* Session-Timer on/off boolean */
- int st_interval = 0; /* Session-Timer negotiated refresh interval */
- enum st_refresher tmp_st_ref = SESSION_TIMER_REFRESHER_AUTO; /* Session-Timer refresher */
- int dlg_min_se = -1;
struct {
char exten[AST_MAX_EXTENSION];
char context[AST_MAX_CONTEXT];
@@ -23319,6 +23449,14 @@
/* Initialize our tag */
make_our_tag(p);
+
+ if (handle_request_invite_st(p, req, required, reinvite)) {
+ p->invitestate = INV_COMPLETED;
+ sip_scheddestroy(p, DEFAULT_TRANS_TIMEOUT);
+ res = -1;
+ goto request_invite_cleanup;
+ }
+
/* First invitation - create the channel. Allocation
* failures are handled below. */
c = sip_new(p, AST_STATE_DOWN, S_OR(p->peername, NULL), NULL);
@@ -23351,6 +23489,16 @@
}
if (!req->ignore)
reinvite = 1;
+
+ if (handle_request_invite_st(p, req, required, reinvite)) {
+ p->invitestate = INV_COMPLETED;
+ if (!p->lastinvite) {
+ sip_scheddestroy(p, DEFAULT_TRANS_TIMEOUT);
+ }
+ res = -1;
+ goto request_invite_cleanup;
+ }
+
c = p->owner;
change_redirecting_information(p, req, &redirecting, &update_redirecting, FALSE); /*Will return immediately if no Diversion header is present */
if (c) {
@@ -23359,135 +23507,10 @@
ast_party_redirecting_free(&redirecting);
}
- /* Session-Timers */
- if ((p->sipoptions & SIP_OPT_TIMER) && !ast_strlen_zero(get_header(req, "Session-Expires"))) {
- enum st_refresher_param st_ref_param;
-
- /* The UAC has requested session-timers for this session. Negotiate
- the session refresh interval and who will be the refresher */
- ast_debug(2, "Incoming INVITE with 'timer' option supported and \"Session-Expires\" header.\n");
-
- /* Allocate Session-Timers struct w/in the dialog */
- if (!p->stimer)
- sip_st_alloc(p);
-
- /* Parse the Session-Expires header */
- p_uac_se_hdr = get_header(req, "Session-Expires");
- rtn = parse_session_expires(p_uac_se_hdr, &uac_max_se, &st_ref_param);
- tmp_st_ref = (st_ref_param == SESSION_TIMER_REFRESHER_PARAM_UAC) ? SESSION_TIMER_REFRESHER_THEM : SESSION_TIMER_REFRESHER_US;
- if (rtn != 0) {
- transmit_response_reliable(p, "400 Session-Expires Invalid Syntax", req);
- p->invitestate = INV_COMPLETED;
- if (!p->lastinvite) {
- sip_scheddestroy(p, DEFAULT_TRANS_TIMEOUT);
- }
- res = -1;
- goto request_invite_cleanup;
- }
-
- /* Parse the Min-SE header */
- p_uac_min_se = get_header(req, "Min-SE");
- if (!ast_strlen_zero(p_uac_min_se)) {
- rtn = parse_minse(p_uac_min_se, &uac_min_se);
- if (rtn != 0) {
- transmit_response_reliable(p, "400 Min-SE Invalid Syntax", req);
- p->invitestate = INV_COMPLETED;
- if (!p->lastinvite) {
- sip_scheddestroy(p, DEFAULT_TRANS_TIMEOUT);
- }
- res = -1;
- goto request_invite_cleanup;
- }
- }
-
- dlg_min_se = st_get_se(p, FALSE);
- switch (st_get_mode(p, 1)) {
- case SESSION_TIMER_MODE_ACCEPT:
- case SESSION_TIMER_MODE_ORIGINATE:
- if (uac_max_se > 0 && uac_max_se < dlg_min_se) {
- transmit_response_with_minse(p, "422 Session Interval Too Small", req, dlg_min_se);
- p->invitestate = INV_COMPLETED;
- if (!p->lastinvite) {
- sip_scheddestroy(p, DEFAULT_TRANS_TIMEOUT);
- }
- res = -1;
- goto request_invite_cleanup;
- }
-
- p->stimer->st_active_peer_ua = TRUE;
- st_active = TRUE;
- if (st_ref_param == SESSION_TIMER_REFRESHER_PARAM_UNKNOWN) {
- tmp_st_ref = st_get_refresher(p);
- }
-
- if (uac_max_se > 0) {
- int dlg_max_se = st_get_se(p, TRUE);
- if (dlg_max_se >= uac_min_se) {
- st_interval = (uac_max_se < dlg_max_se) ? uac_max_se : dlg_max_se;
- } else {
- st_interval = uac_max_se;
- }
- } else {
- /* Set to default max value */
- st_interval = global_max_se;
- }
- break;
-
- case SESSION_TIMER_MODE_REFUSE:
- if (p->reqsipoptions & SIP_OPT_TIMER) {
- transmit_response_with_unsupported(p, "420 Option Disabled", req, required);
- ast_log(LOG_WARNING, "Received SIP INVITE with supported but disabled option: %s\n", required);
- p->invitestate = INV_COMPLETED;
- if (!p->lastinvite) {
- sip_scheddestroy(p, DEFAULT_TRANS_TIMEOUT);
- }
- res = -1;
- goto request_invite_cleanup;
- }
- break;
-
- default:
- ast_log(LOG_ERROR, "Internal Error %d at %s:%d\n", st_get_mode(p, 1), __FILE__, __LINE__);
- break;
- }
- } else {
- /* The UAC did not request session-timers. Asterisk (UAS), will now decide
- (based on session-timer-mode in sip.conf) whether to run session-timers for
- this session or not. */
- switch (st_get_mode(p, 1)) {
- case SESSION_TIMER_MODE_ORIGINATE:
- st_active = TRUE;
- st_interval = st_get_se(p, TRUE);
- tmp_st_ref = SESSION_TIMER_REFRESHER_US;
- p->stimer->st_active_peer_ua = FALSE;
- break;
-
- default:
- break;
- }
- }
-
- if (reinvite == 0) {
- /* Session-Timers: Start session refresh timer based on negotiation/config */
- if (st_active == TRUE) {
- p->stimer->st_active = TRUE;
- p->stimer->st_interval = st_interval;
- p->stimer->st_ref = tmp_st_ref;
+ if (p->stimer->st_active == TRUE) {
+ if (reinvite == 0) {
start_session_timer(p);
- }
- } else {
- if (p->stimer->st_active == TRUE) {
- /* Session-Timers: A re-invite request sent within a dialog will serve as
- a refresh request, no matter whether the re-invite was sent for refreshing
- the session or modifying it.*/
- ast_debug (2, "Restarting session-timers on a refresh - %s\n", p->callid);
-
- /* The UAC may be adjusting the session-timers mid-session */
- if (st_interval > 0) {
- p->stimer->st_interval = st_interval;
- p->stimer->st_ref = tmp_st_ref;
- }
-
+ } else {
restart_session_timer(p);
if (p->stimer->st_expirys > 0) {
p->stimer->st_expirys--;
Modified: certified/tags/1.8.15-cert5/main/http.c
URL: http://svnview.digium.com/svn/asterisk/certified/tags/1.8.15-cert5/main/http.c?view=diff&rev=410430&r1=410429&r2=410430
==============================================================================
--- certified/tags/1.8.15-cert5/main/http.c (original)
+++ certified/tags/1.8.15-cert5/main/http.c Mon Mar 10 13:12:16 2014
@@ -187,9 +187,7 @@
break;
}
}
- if (cookies) {
- ast_variables_destroy(cookies);
- }
+ ast_variables_destroy(cookies);
return mngid;
}
@@ -683,7 +681,7 @@
prev = v;
}
}
-
+
done:
ast_free(buf);
return post_vars;
@@ -822,12 +820,13 @@
}*/
#endif /* DO_SSL */
-static struct ast_variable *parse_cookies(char *cookies)
-{
+static struct ast_variable *parse_cookies(const char *cookies)
+{
+ char *parse = ast_strdupa(cookies);
char *cur;
struct ast_variable *vars = NULL, *var;
- while ((cur = strsep(&cookies, ";"))) {
+ while ((cur = strsep(&parse, ";"))) {
char *name, *val;
name = val = cur;
@@ -857,21 +856,19 @@
/* get cookie from Request headers */
struct ast_variable *ast_http_get_cookies(struct ast_variable *headers)
{
- struct ast_variable *v, *cookies=NULL;
+ struct ast_variable *v, *cookies = NULL;
for (v = headers; v; v = v->next) {
- if (!strncasecmp(v->name, "Cookie", 6)) {
- char *tmp = ast_strdupa(v->value);
- if (cookies) {
- ast_variables_destroy(cookies);
- }
-
- cookies = parse_cookies(tmp);
+ if (!strcasecmp(v->name, "Cookie")) {
+ ast_variables_destroy(cookies);
+ cookies = parse_cookies(v->value);
}
}
return cookies;
}
+/*! Limit the number of request headers in case the sender is being ridiculous. */
+#define MAX_HTTP_REQUEST_HEADERS 100
static void *httpd_helper_thread(void *data)
{
@@ -882,6 +879,7 @@
struct ast_variable *tail = headers;
char *uri, *method;
enum ast_http_method http_method = AST_HTTP_UNKNOWN;
+ int remaining_headers;
if (ast_atomic_fetchadd_int(&session_count, +1) >= session_limit) {
goto done;
@@ -916,9 +914,13 @@
if (*c) {
*c = '\0';
}
+ } else {
+ ast_http_error(ser, 400, "Bad Request", "Invalid Request");
+ goto done;
}
/* process "Request Headers" lines */
+ remaining_headers = MAX_HTTP_REQUEST_HEADERS;
while (fgets(header_line, sizeof(header_line), ser->f)) {
char *name, *value;
@@ -941,6 +943,11 @@
ast_trim_blanks(name);
+ if (!remaining_headers--) {
+ /* Too many headers. */
+ ast_http_error(ser, 413, "Request Entity Too Large", "Too many headers");
+ goto done;
+ }
if (!headers) {
headers = ast_variable_new(name, value, __FILE__);
tail = headers;
@@ -948,11 +955,17 @@
tail->next = ast_variable_new(name, value, __FILE__);
tail = tail->next;
}
- }
-
- if (!*uri) {
- ast_http_error(ser, 400, "Bad Request", "Invalid Request");
- goto done;
+ if (!tail) {
+ /*
+ * Variable allocation failure.
+ * Try to make some room.
+ */
+ ast_variables_destroy(headers);
+ headers = NULL;
+
+ ast_http_error(ser, 500, "Server Error", "Out of memory");
+ goto done;
+ }
}
handle_uri(ser, uri, http_method, headers);
@@ -961,9 +974,7 @@
ast_atomic_fetchadd_int(&session_count, -1);
/* clean up all the header information */
- if (headers) {
- ast_variables_destroy(headers);
- }
+ ast_variables_destroy(headers);
if (ser->f) {
fclose(ser->f);
More information about the asterisk-commits
mailing list