Module: sip-router
Branch: 4.1
Commit: 48a3412afe166f5cbd41a057a22a3333337a2856
URL:
http://git.sip-router.org/cgi-bin/gitweb.cgi/sip-router/?a=commit;h=48a3412…
Author: Hugh Waite <hugh.waite(a)crocodile-rcs.com>
Committer: Hugh Waite <hugh.waite(a)crocodile-rcs.com>
Date: Tue Dec 3 13:00:55 2013 +0000
websocket: Set pointers to NULL when freeing ws connection strcutures
- Fixes double free crash FS#364
- Reported by Vitaliy Aleksandrov
(cherry picked from commit 95749afb7129e2909b449b79706f0de5d06a3c5d)
---
modules/websocket/ws_conn.c | 1 -
modules/websocket/ws_frame.c | 51 +++++++++++++++++++++++++------------
modules/websocket/ws_handshake.c | 2 +-
3 files changed, 35 insertions(+), 19 deletions(-)
diff --git a/modules/websocket/ws_conn.c b/modules/websocket/ws_conn.c
index 263b49f..613f14e 100644
--- a/modules/websocket/ws_conn.c
+++ b/modules/websocket/ws_conn.c
@@ -138,7 +138,6 @@ static inline void _wsconn_rm(ws_connection_t *wsc)
update_stat(ws_msrp_current_connections, -1);
shm_free(wsc);
- wsc = NULL;
}
void wsconn_destroy(void)
diff --git a/modules/websocket/ws_frame.c b/modules/websocket/ws_frame.c
index 503722e..a3a4cef 100644
--- a/modules/websocket/ws_frame.c
+++ b/modules/websocket/ws_frame.c
@@ -232,6 +232,7 @@ static int encode_and_send_ws_frame(ws_frame_t *frame, conn_close_t
conn_close)
pkg_free(send_buf);
if (wsconn_rm(frame->wsc, WSCONN_EVENTROUTE_YES) < 0)
LM_ERR("removing WebSocket connection\n");
+ frame->wsc = NULL;
return -1;
}
init_dst_from_rcv(&dst, &con->rcv);
@@ -243,8 +244,10 @@ static int encode_and_send_ws_frame(ws_frame_t *frame, conn_close_t
conn_close)
LM_ERR("removing WebSocket connection\n");
tcpconn_put(con);
pkg_free(send_buf);
+ frame->wsc = NULL;
return -1;
}
+ frame->wsc = NULL;
}
if (dst.proto == PROTO_WS)
@@ -297,6 +300,7 @@ static int encode_and_send_ws_frame(ws_frame_t *frame, conn_close_t
conn_close)
update_stat(ws_msrp_failed_connections, 1);
if (wsconn_rm(frame->wsc, WSCONN_EVENTROUTE_YES) < 0)
LM_ERR("removing WebSocket connection\n");
+ frame->wsc = NULL;
tcpconn_put(con);
return -1;
}
@@ -317,11 +321,19 @@ static int encode_and_send_ws_frame(ws_frame_t *frame, conn_close_t
conn_close)
return 0;
}
-static int close_connection(ws_connection_t *wsc, ws_close_type_t type,
+static int close_connection(ws_connection_t **p_wsc, ws_close_type_t type,
short int status, str reason)
{
char *data;
ws_frame_t frame;
+ ws_connection_t * wsc = NULL;
+ int sub_proto = -1;
+ if (!p_wsc || !(*p_wsc))
+ {
+ LM_ERR("Invalid parameters\n");
+ return -1;
+ }
+ wsc = *p_wsc;
if (wsc->state == WS_S_OPEN)
{
@@ -342,6 +354,7 @@ static int close_connection(ws_connection_t *wsc, ws_close_type_t
type,
frame.payload_len = reason.len + 2;
frame.payload_data = data;
frame.wsc = wsc;
+ sub_proto = wsc->sub_protocol;
if (encode_and_send_ws_frame(&frame,
type ==
@@ -367,16 +380,20 @@ static int close_connection(ws_connection_t *wsc, ws_close_type_t
type,
else
{
update_stat(ws_remote_closed_connections, 1);
- if (frame.wsc->sub_protocol == SUB_PROTOCOL_SIP)
+ if (sub_proto == SUB_PROTOCOL_SIP)
update_stat(ws_sip_remote_closed_connections,
1);
- else if (frame.wsc->sub_protocol == SUB_PROTOCOL_MSRP)
+ else if (sub_proto == SUB_PROTOCOL_MSRP)
update_stat(ws_msrp_remote_closed_connections,
1);
+ *p_wsc = NULL;
}
}
else /* if (frame->wsc->state == WS_S_CLOSING) */
+ {
wsconn_close_now(wsc);
+ *p_wsc = NULL;
+ }
return 0;
}
@@ -402,7 +419,7 @@ static int decode_and_validate_ws_frame(ws_frame_t *frame,
if (len < 2)
{
LM_WARN("message is too short\n");
- if (close_connection(frame->wsc, LOCAL_CLOSE, 1002,
+ if (close_connection(&frame->wsc, LOCAL_CLOSE, 1002,
str_status_protocol_error) < 0)
LM_ERR("closing connection\n");
return -1;
@@ -418,7 +435,7 @@ static int decode_and_validate_ws_frame(ws_frame_t *frame,
{
LM_WARN("WebSocket fragmentation not supported in the sip "
"sub-protocol\n");
- if (close_connection(frame->wsc, LOCAL_CLOSE, 1002,
+ if (close_connection(&frame->wsc, LOCAL_CLOSE, 1002,
str_status_protocol_error) < 0)
LM_ERR("closing connection\n");
return -1;
@@ -427,7 +444,7 @@ static int decode_and_validate_ws_frame(ws_frame_t *frame,
if (frame->rsv1 || frame->rsv2 || frame->rsv3)
{
LM_WARN("WebSocket reserved fields with non-zero values\n");
- if (close_connection(frame->wsc, LOCAL_CLOSE, 1002,
+ if (close_connection(&frame->wsc, LOCAL_CLOSE, 1002,
str_status_protocol_error) < 0)
LM_ERR("closing connection\n");
return -1;
@@ -451,7 +468,7 @@ static int decode_and_validate_ws_frame(ws_frame_t *frame,
default:
LM_WARN("unsupported opcode: 0x%x\n",
(unsigned char) frame->opcode);
- if (close_connection(frame->wsc, LOCAL_CLOSE, 1008,
+ if (close_connection(&frame->wsc, LOCAL_CLOSE, 1008,
str_status_unsupported_opcode) < 0)
LM_ERR("closing connection\n");
return -1;
@@ -461,7 +478,7 @@ static int decode_and_validate_ws_frame(ws_frame_t *frame,
{
LM_WARN("this is a server - all received messages must be "
"masked\n");
- if (close_connection(frame->wsc, LOCAL_CLOSE, 1002,
+ if (close_connection(&frame->wsc, LOCAL_CLOSE, 1002,
str_status_protocol_error) < 0)
LM_ERR("closing connection\n");
return -1;
@@ -474,7 +491,7 @@ static int decode_and_validate_ws_frame(ws_frame_t *frame,
if (len < 4)
{
LM_WARN("message is too short\n");
- if (close_connection(frame->wsc, LOCAL_CLOSE, 1002,
+ if (close_connection(&frame->wsc, LOCAL_CLOSE, 1002,
str_status_protocol_error) < 0)
LM_ERR("closing connection\n");
return -1;
@@ -489,7 +506,7 @@ static int decode_and_validate_ws_frame(ws_frame_t *frame,
if (len < 10)
{
LM_WARN("message is too short\n");
- if (close_connection(frame->wsc, LOCAL_CLOSE, 1002,
+ if (close_connection(&frame->wsc, LOCAL_CLOSE, 1002,
str_status_protocol_error) < 0)
LM_ERR("closing connection\n");
return -1;
@@ -500,7 +517,7 @@ static int decode_and_validate_ws_frame(ws_frame_t *frame,
|| (buf[4] & 0xff) != 0 || (buf[5] & 0xff) != 0)
{
LM_WARN("message is too long\n");
- if (close_connection(frame->wsc, LOCAL_CLOSE, 1009,
+ if (close_connection(&frame->wsc, LOCAL_CLOSE, 1009,
str_status_message_too_big) < 0)
LM_ERR("closing connection\n");
return -1;
@@ -528,7 +545,7 @@ static int decode_and_validate_ws_frame(ws_frame_t *frame,
{
LM_WARN("message not complete frame size %u but received %u\n",
frame->payload_len + mask_start + 4, len);
- if (close_connection(frame->wsc, LOCAL_CLOSE, 1002,
+ if (close_connection(&frame->wsc, LOCAL_CLOSE, 1002,
str_status_protocol_error) < 0)
LM_ERR("closing connection\n");
return -1;
@@ -564,7 +581,7 @@ static int handle_close(ws_frame_t *frame)
LM_DBG("Rx Close: %hu %.*s\n", code, reason.len, reason.s);
- if (close_connection(frame->wsc,
+ if (close_connection(&frame->wsc,
frame->wsc->state == WS_S_OPEN ? REMOTE_CLOSE : LOCAL_CLOSE,
1000, str_status_normal_closure) < 0)
{
@@ -758,7 +775,7 @@ struct mi_root *ws_mi_close(struct mi_root *cmd, void *param)
str_status_bad_param.len);
}
- if (close_connection(wsc, LOCAL_CLOSE, 1000,
+ if (close_connection(&wsc, LOCAL_CLOSE, 1000,
str_status_normal_closure) < 0)
{
LM_WARN("closing connection\n");
@@ -861,7 +878,7 @@ int ws_close(sip_msg_t *msg)
return -1;
}
- return (close_connection(wsc, LOCAL_CLOSE, 1000,
+ return (close_connection(&wsc, LOCAL_CLOSE, 1000,
str_status_normal_closure) == 0) ? 1: 0;
}
@@ -886,7 +903,7 @@ int ws_close2(sip_msg_t *msg, char *_status, char *_reason)
return -1;
}
- return (close_connection(wsc, LOCAL_CLOSE, status, reason) == 0) ? 1: 0;
+ return (close_connection(&wsc, LOCAL_CLOSE, status, reason) == 0) ? 1: 0;
}
int ws_close3(sip_msg_t *msg, char *_status, char *_reason, char *_con)
@@ -916,5 +933,5 @@ int ws_close3(sip_msg_t *msg, char *_status, char *_reason, char
*_con)
return -1;
}
- return (close_connection(wsc, LOCAL_CLOSE, status, reason) == 0) ? 1: 0;
+ return (close_connection(&wsc, LOCAL_CLOSE, status, reason) == 0) ? 1: 0;
}
diff --git a/modules/websocket/ws_handshake.c b/modules/websocket/ws_handshake.c
index 1ca6fe1..c4e3143 100644
--- a/modules/websocket/ws_handshake.c
+++ b/modules/websocket/ws_handshake.c
@@ -122,7 +122,7 @@ int ws_handle_handshake(struct sip_msg *msg)
str key = {0, 0}, headers = {0, 0}, reply_key = {0, 0}, origin = {0, 0};
unsigned char sha1[SHA_DIGEST_LENGTH];
unsigned int hdr_flags = 0, sub_protocol = 0;
- int version;
+ int version = 0;
struct hdr_field *hdr = msg->headers;
struct tcp_connection *con;
ws_connection_t *wsc;