From a801543f79a2161815bd98d6846fc1526e9cd612 Mon Sep 17 00:00:00 2001 From: Sean Bright <sean.bright@gmail.com> Date: Thu, 16 Aug 2018 11:45:53 -0400 Subject: [PATCH] AST-2018-009: Fix crash processing websocket HTTP Upgrade requests The HTTP request processing in res_http_websocket allocates additional space on the stack for various headers received during an Upgrade request. An attacker could send a specially crafted request that causes this code to overflow the stack, resulting in a crash. * No longer allocate memory from the stack in a loop to parse the header values. NOTE: There is a slight API change when using the passed in strings as is. We now require the passed in strings to no longer have leading or trailing whitespace. This isn't a problem as the only callers have already done this before passing the strings to the affected function. ASTERISK-28013 #close Change-Id: Ia564825a8a95e085fd17e658cb777fe1afa8091a --- res/res_http_websocket.c | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/res/res_http_websocket.c b/res/res_http_websocket.c index 9a32bf37cc..d64ecba7f7 100644 --- a/res/res_http_websocket.c +++ b/res/res_http_websocket.c @@ -751,7 +751,8 @@ static void websocket_bad_request(struct ast_tcptls_session_instance *ser) int AST_OPTIONAL_API_NAME(ast_websocket_uri_cb)(struct ast_tcptls_session_instance *ser, const struct ast_http_uri *urih, const char *uri, enum ast_http_method method, struct ast_variable *get_vars, struct ast_variable *headers) { struct ast_variable *v; - char *upgrade = NULL, *key = NULL, *key1 = NULL, *key2 = NULL, *protos = NULL, *requested_protocols = NULL, *protocol = NULL; + const char *upgrade = NULL, *key = NULL, *key1 = NULL, *key2 = NULL, *protos = NULL; + char *requested_protocols = NULL, *protocol = NULL; int version = 0, flags = 1; struct ast_websocket_protocol *protocol_handler = NULL; struct ast_websocket *session; @@ -770,16 +771,15 @@ int AST_OPTIONAL_API_NAME(ast_websocket_uri_cb)(struct ast_tcptls_session_instan /* Get the minimum headers required to satisfy our needs */ for (v = headers; v; v = v->next) { if (!strcasecmp(v->name, "Upgrade")) { - upgrade = ast_strip(ast_strdupa(v->value)); + upgrade = v->value; } else if (!strcasecmp(v->name, "Sec-WebSocket-Key")) { - key = ast_strip(ast_strdupa(v->value)); + key = v->value; } else if (!strcasecmp(v->name, "Sec-WebSocket-Key1")) { - key1 = ast_strip(ast_strdupa(v->value)); + key1 = v->value; } else if (!strcasecmp(v->name, "Sec-WebSocket-Key2")) { - key2 = ast_strip(ast_strdupa(v->value)); + key2 = v->value; } else if (!strcasecmp(v->name, "Sec-WebSocket-Protocol")) { - requested_protocols = ast_strip(ast_strdupa(v->value)); - protos = ast_strdupa(requested_protocols); + protos = v->value; } else if (!strcasecmp(v->name, "Sec-WebSocket-Version")) { if (sscanf(v->value, "%30d", &version) != 1) { version = 0; @@ -793,7 +793,7 @@ int AST_OPTIONAL_API_NAME(ast_websocket_uri_cb)(struct ast_tcptls_session_instan ast_sockaddr_stringify(&ser->remote_address)); ast_http_error(ser, 426, "Upgrade Required", NULL); return 0; - } else if (ast_strlen_zero(requested_protocols)) { + } else if (ast_strlen_zero(protos)) { /* If there's only a single protocol registered, and the * client doesn't specify what protocol it's using, go ahead * and accept the connection */ @@ -814,9 +814,12 @@ int AST_OPTIONAL_API_NAME(ast_websocket_uri_cb)(struct ast_tcptls_session_instan return 0; } - /* Iterate through the requested protocols trying to find one that we have a handler for */ - while (!protocol_handler && (protocol = strsep(&requested_protocols, ","))) { - protocol_handler = ao2_find(server->protocols, ast_strip(protocol), OBJ_KEY); + if (!protocol_handler && protos) { + requested_protocols = ast_strdupa(protos); + /* Iterate through the requested protocols trying to find one that we have a handler for */ + while (!protocol_handler && (protocol = strsep(&requested_protocols, ","))) { + protocol_handler = ao2_find(server->protocols, ast_strip(protocol), OBJ_KEY); + } } /* If no protocol handler exists bump this back to the requester */ -- GitLab