]> git.ipfire.org Git - thirdparty/asterisk.git/commitdiff
res_http_websocket: Fix crash due to double freeing memory when receiving a payload...
authorJoshua Colp <jcolp@digium.com>
Wed, 10 Dec 2014 13:32:48 +0000 (13:32 +0000)
committerJoshua Colp <jcolp@digium.com>
Wed, 10 Dec 2014 13:32:48 +0000 (13:32 +0000)
Frames with a payload length of 0 were incorrectly handled in res_http_websocket.
Provided a frame with a payload had been received prior it was possible for a double
free to occur. The realloc operation would succeed (thus freeing the payload) but be
treated as an error. When the session was then torn down the payload would be
freed again causing a crash. The read function now takes this into account.

This change also fixes assumptions made by users of res_http_websocket. There is no
guarantee that a frame received from it will be NULL terminated.

ASTERISK-24472 #close
Reported by: Badalian Vyacheslav

Review: https://reviewboard.asterisk.org/r/4220/
Review: https://reviewboard.asterisk.org/r/4219/
........

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

git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/12@429272 65c4cc65-6c06-0410-ace0-fbb531ad65f3

channels/chan_sip.c
res/res_http_websocket.c
res/res_pjsip_transport_websocket.c

index a3d8bdcffd6dc5fc3611b6cf0dd528820598121a..836425bbe88b0cc05a12e0d0c43741d22bf14749 100644 (file)
@@ -2686,12 +2686,16 @@ static void sip_websocket_callback(struct ast_websocket *session, struct ast_var
 
                if (opcode == AST_WEBSOCKET_OPCODE_TEXT || opcode == AST_WEBSOCKET_OPCODE_BINARY) {
                        struct sip_request req = { 0, };
+                       char data[payload_len + 1];
 
                        if (!(req.data = ast_str_create(payload_len + 1))) {
                                goto end;
                        }
 
-                       if (ast_str_set(&req.data, -1, "%s", payload) == AST_DYNSTR_BUILD_FAILED) {
+                       strncpy(data, payload, payload_len);
+                       data[payload_len] = '\0';
+
+                       if (ast_str_set(&req.data, -1, "%s", data) == AST_DYNSTR_BUILD_FAILED) {
                                deinit_req(&req);
                                goto end;
                        }
index 29dd9315a535f67f156ae65cdf8a5a6155e31526..67f200670895ae310649eda477f9be0f715ec4b9 100644 (file)
@@ -508,14 +508,6 @@ int AST_OPTIONAL_API_NAME(ast_websocket_read)(struct ast_websocket *session, cha
                        }
                }
 
-               if (!(new_payload = ast_realloc(session->payload, (session->payload_len + *payload_len)))) {
-                       ast_log(LOG_WARNING, "Failed allocation: %p, %zu, %"PRIu64"\n",
-                               session->payload, session->payload_len, *payload_len);
-                       *payload_len = 0;
-                       ast_websocket_close(session, 1009);
-                       return 0;
-               }
-
                /* Per the RFC for PING we need to send back an opcode with the application data as received */
                if ((*opcode == AST_WEBSOCKET_OPCODE_PING) && (ast_websocket_write(session, AST_WEBSOCKET_OPCODE_PONG, *payload, *payload_len))) {
                        *payload_len = 0;
@@ -523,9 +515,22 @@ int AST_OPTIONAL_API_NAME(ast_websocket_read)(struct ast_websocket *session, cha
                        return 0;
                }
 
-               session->payload = new_payload;
-               memcpy((session->payload + session->payload_len), (*payload), (*payload_len));
-               session->payload_len += *payload_len;
+               if (*payload_len) {
+                       if (!(new_payload = ast_realloc(session->payload, (session->payload_len + *payload_len)))) {
+                               ast_log(LOG_WARNING, "Failed allocation: %p, %zu, %"PRIu64"\n",
+                                       session->payload, session->payload_len, *payload_len);
+                               *payload_len = 0;
+                               ast_websocket_close(session, 1009);
+                               return 0;
+                       }
+
+                       session->payload = new_payload;
+                       memcpy((session->payload + session->payload_len), (*payload), (*payload_len));
+                       session->payload_len += *payload_len;
+               } else if (!session->payload_len && session->payload) {
+                       ast_free(session->payload);
+                       session->payload = NULL;
+               }
 
                if (!fin && session->reconstruct && (session->payload_len < session->reconstruct)) {
                        /* If this is not a final message we need to defer returning it until later */
index 01aaabaf30f5c8850cd0aeff91c52284b81bdcc8..12aa9ee5e8e5e059372f43a08bf31b02784f01d7 100644 (file)
@@ -200,7 +200,8 @@ static int transport_read(void *data)
 
        pj_gettimeofday(&rdata->pkt_info.timestamp);
 
-       pj_memcpy(rdata->pkt_info.packet, read_data->payload, sizeof(rdata->pkt_info.packet));
+       pj_memcpy(rdata->pkt_info.packet, read_data->payload,
+               PJSIP_MAX_PKT_LEN < read_data->payload_len ? PJSIP_MAX_PKT_LEN : read_data->payload_len);
        rdata->pkt_info.len = read_data->payload_len;
        rdata->pkt_info.zero = 0;