mirror of
				https://github.com/asterisk/asterisk.git
				synced 2025-10-31 10:47:18 +00:00 
			
		
		
		
	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
This commit is contained in:
		
							
								
								
									
										52
									
								
								main/http.c
									
									
									
									
									
								
							
							
						
						
									
										52
									
								
								main/http.c
									
									
									
									
									
								
							| @@ -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); | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user