From 771a703366af09a144ffa22d9fa7fb3930d56345 Mon Sep 17 00:00:00 2001 From: Richard Mudgett <rmudgett@digium.com> Date: Mon, 10 Mar 2014 17:09:42 +0000 Subject: [PATCH] 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 ........ Merged revisions 410380 from http://svn.asterisk.org/svn/asterisk/branches/1.8 git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/11@410381 65c4cc65-6c06-0410-ace0-fbb531ad65f3 --- main/http.c | 49 ++++++++++++++++++++++++++++++------------------- 1 file changed, 30 insertions(+), 19 deletions(-) diff --git a/main/http.c b/main/http.c index 96e8d76477..81b48cd8f4 100644 --- a/main/http.c +++ b/main/http.c @@ -186,9 +186,7 @@ uint32_t ast_http_manid_from_vars(struct ast_variable *headers) break; } } - if (cookies) { - ast_variables_destroy(cookies); - } + ast_variables_destroy(cookies); return mngid; } @@ -805,12 +803,13 @@ static int ssl_close(void *cookie) }*/ #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; @@ -840,21 +839,19 @@ static struct ast_variable *parse_cookies(char *cookies) /* 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 (!strcasecmp(v->name, "Cookie")) { - char *tmp = ast_strdupa(v->value); - if (cookies) { - ast_variables_destroy(cookies); - } - - cookies = parse_cookies(tmp); + 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) { @@ -865,6 +862,7 @@ static void *httpd_helper_thread(void *data) 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; @@ -899,9 +897,13 @@ static void *httpd_helper_thread(void *data) 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; @@ -924,6 +926,11 @@ static void *httpd_helper_thread(void *data) 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; @@ -931,11 +938,17 @@ static void *httpd_helper_thread(void *data) tail->next = ast_variable_new(name, value, __FILE__); tail = tail->next; } - } + if (!tail) { + /* + * Variable allocation failure. + * Try to make some room. + */ + ast_variables_destroy(headers); + headers = NULL; - if (!*uri) { - ast_http_error(ser, 400, "Bad Request", "Invalid Request"); - goto done; + ast_http_error(ser, 500, "Server Error", "Out of memory"); + goto done; + } } handle_uri(ser, uri, http_method, headers); @@ -944,9 +957,7 @@ done: 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); -- GitLab