Skip to content

Commit b6b7520

Browse files
proto_tls/wss: fix crashes when dumping the openssl error stack
This commit serializes the execution of openssl's connect/accept/read/write operations in order to prevent adding/removing entries concurrently to/from the openssl error stack. If the performance penalty is deemed too high, the NO_SSL_GLOBAL_LOCK compilation flag can be used to disable this behavior and retain the risk of crashes. Reported in OpenSIPS#2362 Credits to Alexey Vasilyev for helping troubleshoot this.
1 parent 872c4e8 commit b6b7520

File tree

5 files changed

+257
-37
lines changed

5 files changed

+257
-37
lines changed

Makefile.openssl

+4
Original file line numberDiff line numberDiff line change
@@ -18,3 +18,7 @@ else
1818
-L$(LOCALBASE)/lib64 -L$(LOCALBASE)/ssl/lib64 \
1919
-lssl -lcrypto
2020
endif
21+
22+
# enable this flag to increase performance by not serializing openssl
23+
# connect/accept/read/write operations, at the cost of possible crashes
24+
#DEFS+= -DNO_SSL_GLOBAL_LOCK

modules/proto_tls/proto_tls.c

+49-10
Original file line numberDiff line numberDiff line change
@@ -139,20 +139,26 @@ static mi_response_t *tls_trace_mi_1(const mi_params_t *params,
139139

140140
trace_dest t_dst;
141141

142+
#ifndef NO_SSL_GLOBAL_LOCK
143+
gen_lock_t *ssl_global_lock;
144+
#else
145+
#define ssl_global_lock NULL
146+
#endif
147+
142148
static int w_tls_blocking_write(struct tcp_connection *c, int fd, const char *buf,
143149
size_t len)
144150
{
145151
int ret;
146152

147153
lock_get(&c->write_lock);
148154
ret = tls_blocking_write(c, fd, buf, len,
149-
tls_handshake_tout, tls_send_tout, t_dst);
155+
tls_handshake_tout, tls_send_tout, t_dst, ssl_global_lock);
150156
lock_release(&c->write_lock);
151157
return ret;
152158
}
153159

154160
static int tls_write_on_socket(struct tcp_connection* c, int fd,
155-
char *buf, int len)
161+
char *buf, int len, gen_lock_t *ssl_global_lock)
156162
{
157163
int n;
158164

@@ -168,7 +174,7 @@ static int tls_write_on_socket(struct tcp_connection* c, int fd,
168174
goto release;
169175
}
170176

171-
n = tls_write(c, fd, buf, len, NULL);
177+
n = tls_write(c, fd, buf, len, NULL, ssl_global_lock);
172178
if (n >= 0 && len - n) {
173179
/* if could not write entire buffer, delay it */
174180
n = tcp_async_add_chunk(c, buf + n, len - n, 0);
@@ -178,7 +184,7 @@ static int tls_write_on_socket(struct tcp_connection* c, int fd,
178184
}
179185
} else {
180186
n = tls_blocking_write(c, fd, buf, len,
181-
tls_handshake_tout, tls_send_tout, t_dst);
187+
tls_handshake_tout, tls_send_tout, t_dst, ssl_global_lock);
182188
}
183189
release:
184190
lock_release(&c->write_lock);
@@ -328,6 +334,14 @@ static int mod_init(void)
328334
sroutes->request, RT_NO);
329335
}
330336

337+
#ifndef NO_SSL_GLOBAL_LOCK
338+
ssl_global_lock = lock_alloc();
339+
if (!ssl_global_lock || !lock_init(ssl_global_lock)) {
340+
LM_ERR("could not initialize openssl lock!\n");
341+
return -1;
342+
}
343+
#endif
344+
331345
return 0;
332346
}
333347

@@ -337,6 +351,11 @@ static int mod_init(void)
337351
*/
338352
static void mod_destroy(void)
339353
{
354+
#ifndef NO_SSL_GLOBAL_LOCK
355+
lock_destroy(ssl_global_lock);
356+
lock_dealloc(ssl_global_lock);
357+
#endif
358+
340359
/* library destroy */
341360
ERR_free_strings();
342361
/*SSL_free_comp_methods(); - this function is not on std. openssl*/
@@ -440,7 +459,7 @@ static void proto_tls_conn_clean(struct tcp_connection* c)
440459
c->proto_data = NULL;
441460
}
442461

443-
tls_conn_clean(c, &tls_mgm_api);
462+
tls_conn_clean(c, ssl_global_lock, &tls_mgm_api);
444463
}
445464

446465

@@ -537,7 +556,8 @@ static int proto_tls_send(struct socket_info* send_sock,
537556
/* we connect under lock to make sure no one else is reading our
538557
* connect status */
539558
tls_update_fd(c, fd);
540-
n = tls_async_connect(c, fd, tls_async_handshake_connect_timeout, t_dst);
559+
n = tls_async_connect(c, fd, tls_async_handshake_connect_timeout, t_dst,
560+
ssl_global_lock);
541561
lock_release(&c->write_lock);
542562
if (n<0) {
543563
LM_ERR("failed async TLS connect\n");
@@ -581,7 +601,7 @@ static int proto_tls_send(struct socket_info* send_sock,
581601
send_it:
582602
LM_DBG("sending via fd %d...\n",fd);
583603

584-
rlen = tls_write_on_socket(c, fd, buf, len);
604+
rlen = tls_write_on_socket(c, fd, buf, len, ssl_global_lock);
585605
tcp_conn_set_lifetime( c, tcp_con_lifetime);
586606

587607
LM_DBG("after write: c=%p n=%d fd=%d\n",c, rlen, fd);
@@ -635,7 +655,7 @@ static int tls_read_req(struct tcp_connection* con, int* bytes_read)
635655
}
636656

637657
/* do this trick in order to trace whether if it's an error or not */
638-
ret=tls_fix_read_conn(con, tls_handshake_tout, t_dst);
658+
ret=tls_fix_read_conn(con, tls_handshake_tout, t_dst, ssl_global_lock);
639659
if (ret < 0) {
640660
LM_ERR("failed to do pre-tls handshake!\n");
641661
return -1;
@@ -677,7 +697,7 @@ static int tls_read_req(struct tcp_connection* con, int* bytes_read)
677697
if (req->parsed<req->pos){
678698
bytes=0;
679699
}else{
680-
bytes=tls_read(con,req);
700+
bytes=tls_read(con,req, ssl_global_lock);
681701
if (bytes<0) {
682702
LM_ERR("failed to read \n");
683703
goto error;
@@ -740,7 +760,8 @@ static int tls_async_write(struct tcp_connection* con, int fd)
740760
struct tcp_async_chunk *chunk;
741761
SSL *ssl = (SSL *)con->extra_data;
742762

743-
err = tls_fix_read_conn_unlocked(con, fd, tls_handshake_tout, t_dst);
763+
err = tls_fix_read_conn_unlocked(con, fd, tls_handshake_tout, t_dst,
764+
ssl_global_lock);
744765
if (err < 0) {
745766
LM_ERR("failed to do pre-tls handshake!\n");
746767
return -1;
@@ -753,15 +774,28 @@ static int tls_async_write(struct tcp_connection* con, int fd)
753774
while ((chunk = tcp_async_get_chunk(con)) != NULL) {
754775
LM_DBG("Trying to send %d bytes from chunk %p in conn %p - %d %d \n",
755776
chunk->len, chunk, con, chunk->ticks, get_ticks());
777+
778+
#ifndef NO_SSL_GLOBAL_LOCK
779+
lock_get(ssl_global_lock);
780+
#endif
781+
756782
n=SSL_write(con->extra_data, chunk->buf, chunk->len);
757783
if (n<0) {
758784
err = SSL_get_error(ssl, n);
759785
switch (err) {
760786
case SSL_ERROR_ZERO_RETURN:
787+
#ifndef NO_SSL_GLOBAL_LOCK
788+
lock_release(ssl_global_lock);
789+
#endif
790+
761791
LM_DBG("connection closed cleanly\n");
762792
return -1;
763793
case SSL_ERROR_WANT_READ:
764794
case SSL_ERROR_WANT_WRITE:
795+
#ifndef NO_SSL_GLOBAL_LOCK
796+
lock_release(ssl_global_lock);
797+
#endif
798+
765799
LM_DBG("Can't finish to write chunk %p on conn %p\n",
766800
chunk,con);
767801
/* report back we have more writting to be done */
@@ -770,6 +804,11 @@ static int tls_async_write(struct tcp_connection* con, int fd)
770804
LM_ERR("Error occurred while sending async chunk %d:%d (%s)\n",
771805
err, errno,strerror(errno));
772806
tls_print_errstack();
807+
808+
#ifndef NO_SSL_GLOBAL_LOCK
809+
lock_release(ssl_global_lock);
810+
#endif
811+
773812
/* report the conn as broken */
774813
return -1;
775814
}

modules/proto_wss/proto_wss.c

+27-7
Original file line numberDiff line numberDiff line change
@@ -73,11 +73,17 @@ static str wss_resource = str_init("/");
7373
static int wss_raw_writev(struct tcp_connection *c, int fd,
7474
const struct iovec *iov, int iovcnt, int tout);
7575

76+
#ifndef NO_SSL_GLOBAL_LOCK
77+
gen_lock_t *ssl_global_lock;
78+
#else
79+
#define ssl_global_lock NULL
80+
#endif
81+
7682
#define _ws_common_module "wss"
7783
#define _ws_common_tcp_current_req tcp_current_req
7884
#define _ws_common_current_req wss_current_req
7985
#define _ws_common_max_msg_chunks wss_max_msg_chunks
80-
#define _ws_common_read tls_read
86+
#define _ws_common_read(c, r) tls_read((c), (r), ssl_global_lock)
8187
#define _ws_common_writev wss_raw_writev
8288
#define _ws_common_read_tout wss_hs_read_tout
8389
/*
@@ -105,6 +111,7 @@ static int trace_filter_route_id = -1;
105111
/**/
106112

107113
static int mod_init(void);
114+
static void mod_destroy(void);
108115
static int proto_wss_init(struct proto_info *pi);
109116
static int proto_wss_init_listener(struct socket_info *si);
110117
static int proto_wss_send(struct socket_info* send_sock,
@@ -180,7 +187,7 @@ struct module_exports exports = {
180187
0, /* module pre-initialization function */
181188
mod_init, /* module initialization function */
182189
0, /* response function */
183-
0, /* destroy function */
190+
mod_destroy,/* destroy function */
184191
0, /* per-child init function */
185192
0 /* reload confirm function */
186193
};
@@ -255,11 +262,24 @@ static int mod_init(void)
255262
sroutes->request, RT_NO);
256263
}
257264

258-
265+
#ifndef NO_SSL_GLOBAL_LOCK
266+
ssl_global_lock = lock_alloc();
267+
if (!ssl_global_lock || !lock_init(ssl_global_lock)) {
268+
LM_ERR("could not initialize openssl lock!\n");
269+
return -1;
270+
}
271+
#endif
259272

260273
return 0;
261274
}
262275

276+
static void mod_destroy(void)
277+
{
278+
#ifndef NO_SSL_GLOBAL_LOCK
279+
lock_destroy(ssl_global_lock);
280+
lock_dealloc(ssl_global_lock);
281+
#endif
282+
}
263283

264284
static int wss_conn_init(struct tcp_connection* c)
265285
{
@@ -323,7 +343,7 @@ static void ws_conn_clean(struct tcp_connection* c)
323343

324344
}
325345

326-
tls_conn_clean(c, &tls_mgm_api);
346+
tls_conn_clean(c, ssl_global_lock, &tls_mgm_api);
327347
}
328348

329349

@@ -491,7 +511,7 @@ static int wss_read_req(struct tcp_connection* con, int* bytes_read)
491511
struct ws_data* d;
492512

493513
/* we need to fix the SSL connection before doing anything */
494-
if (tls_fix_read_conn(con, 0, t_dst) < 0) {
514+
if (tls_fix_read_conn(con, 0, t_dst, ssl_global_lock) < 0) {
495515
LM_ERR("cannot fix read connection\n");
496516
if ( (d=con->proto_data) && d->dest && d->tprot ) {
497517
if ( d->message ) {
@@ -561,7 +581,7 @@ static int wss_raw_writev(struct tcp_connection *c, int fd,
561581
lock_get(&c->write_lock);
562582
for (i = 0; i < iovcnt; i++) {
563583
n = tls_blocking_write(c, fd, iov[i].iov_base, iov[i].iov_len,
564-
wss_hs_tls_tout, wss_send_tout, t_dst);
584+
wss_hs_tls_tout, wss_send_tout, t_dst, ssl_global_lock);
565585
if (n < 0) {
566586
ret = -1;
567587
goto end;
@@ -584,7 +604,7 @@ static int wss_raw_writev(struct tcp_connection *c, int fd,
584604
}
585605
lock_get(&c->write_lock);
586606
n = tls_blocking_write(c, fd, buf, n,
587-
wss_hs_tls_tout, wss_send_tout, t_dst);
607+
wss_hs_tls_tout, wss_send_tout, t_dst, ssl_global_lock);
588608
#endif /* TLS_DONT_WRITE_FRAGMENTS */
589609

590610
end:

0 commit comments

Comments
 (0)