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
........

Merged revisions 410381 from http://svn.asterisk.org/svn/asterisk/branches/11
........

Merged revisions 410383 from http://svn.asterisk.org/svn/asterisk/branches/12


git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@410395 65c4cc65-6c06-0410-ace0-fbb531ad65f3
changes/97/197/1
Richard Mudgett 11 years ago
parent ef69b5176d
commit 7c854d65af

@ -197,9 +197,7 @@ uint32_t ast_http_manid_from_vars(struct ast_variable *headers)
break; break;
} }
} }
if (cookies) { ast_variables_destroy(cookies);
ast_variables_destroy(cookies);
}
return mngid; return mngid;
} }
@ -1083,12 +1081,13 @@ static int ssl_close(void *cookie)
}*/ }*/
#endif /* DO_SSL */ #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; char *cur;
struct ast_variable *vars = NULL, *var; struct ast_variable *vars = NULL, *var;
while ((cur = strsep(&cookies, ";"))) { while ((cur = strsep(&parse, ";"))) {
char *name, *val; char *name, *val;
name = val = cur; name = val = cur;
@ -1118,16 +1117,12 @@ static struct ast_variable *parse_cookies(char *cookies)
/* get cookie from Request headers */ /* get cookie from Request headers */
struct ast_variable *ast_http_get_cookies(struct ast_variable *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) { for (v = headers; v; v = v->next) {
if (!strcasecmp(v->name, "Cookie")) { if (!strcasecmp(v->name, "Cookie")) {
char *tmp = ast_strdupa(v->value); ast_variables_destroy(cookies);
if (cookies) { cookies = parse_cookies(v->value);
ast_variables_destroy(cookies);
}
cookies = parse_cookies(tmp);
} }
} }
return cookies; return cookies;
@ -1226,6 +1221,9 @@ struct ast_http_auth *ast_http_get_auth(struct ast_variable *headers)
return NULL; return NULL;
} }
/*! 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) static void *httpd_helper_thread(void *data)
{ {
char buf[4096]; char buf[4096];
@ -1236,6 +1234,7 @@ static void *httpd_helper_thread(void *data)
char *uri, *method; char *uri, *method;
enum ast_http_method http_method = AST_HTTP_UNKNOWN; enum ast_http_method http_method = AST_HTTP_UNKNOWN;
const char *transfer_encoding; const char *transfer_encoding;
int remaining_headers;
if (ast_atomic_fetchadd_int(&session_count, +1) >= session_limit) { if (ast_atomic_fetchadd_int(&session_count, +1) >= session_limit) {
goto done; goto done;
@ -1274,9 +1273,13 @@ static void *httpd_helper_thread(void *data)
if (*c) { if (*c) {
*c = '\0'; *c = '\0';
} }
} else {
ast_http_error(ser, 400, "Bad Request", "Invalid Request");
goto done;
} }
/* process "Request Headers" lines */ /* process "Request Headers" lines */
remaining_headers = MAX_HTTP_REQUEST_HEADERS;
while (fgets(header_line, sizeof(header_line), ser->f)) { while (fgets(header_line, sizeof(header_line), ser->f)) {
char *name, *value; char *name, *value;
@ -1299,6 +1302,11 @@ static void *httpd_helper_thread(void *data)
ast_trim_blanks(name); 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) { if (!headers) {
headers = ast_variable_new(name, value, __FILE__); headers = ast_variable_new(name, value, __FILE__);
tail = headers; tail = headers;
@ -1306,6 +1314,17 @@ static void *httpd_helper_thread(void *data)
tail->next = ast_variable_new(name, value, __FILE__); tail->next = ast_variable_new(name, value, __FILE__);
tail = tail->next; tail = tail->next;
} }
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;
}
} }
transfer_encoding = get_transfer_encoding(headers); transfer_encoding = get_transfer_encoding(headers);
@ -1325,20 +1344,13 @@ static void *httpd_helper_thread(void *data)
goto done; goto done;
} }
if (!*uri) {
ast_http_error(ser, 400, "Bad Request", "Invalid Request");
goto done;
}
handle_uri(ser, uri, http_method, headers); handle_uri(ser, uri, http_method, headers);
done: done:
ast_atomic_fetchadd_int(&session_count, -1); ast_atomic_fetchadd_int(&session_count, -1);
/* clean up all the header information */ /* clean up all the header information */
if (headers) { ast_variables_destroy(headers);
ast_variables_destroy(headers);
}
if (ser->f) { if (ser->f) {
fclose(ser->f); fclose(ser->f);

Loading…
Cancel
Save