From 81f5d3c6268ff91ee9c36c4cb34f6f9bfd54740d Mon Sep 17 00:00:00 2001 From: Garrett D'Amore Date: Thu, 12 Dec 2024 17:55:48 -0800 Subject: streams: add explicit stop functions This allows us to explicitly stop streams, dialers, and listeners, before we start tearing down things. This hopefully will be useful in resolving use-after-free bugs in http, tls, and websockets. The new functions are not yet documented, but they are nng_stream_stop, nng_stream_dialer_stop, and nng_stream_listener_stop. They should be called after close, and before free. The close functions now close without blocking, but the stop function is allowed to block. --- src/core/tcp.c | 37 ++++++++++++++++++++++++++++++------- 1 file changed, 30 insertions(+), 7 deletions(-) (limited to 'src/core/tcp.c') diff --git a/src/core/tcp.c b/src/core/tcp.c index 5d324a13..d2e08493 100644 --- a/src/core/tcp.c +++ b/src/core/tcp.c @@ -104,6 +104,8 @@ tcp_dial_con_cb(void *arg) if ((d->closed) || ((aio = nni_list_first(&d->conaios)) == NULL)) { if (rv == 0) { // Make sure we discard the underlying connection. + nng_stream_close(nni_aio_get_output(d->conaio, 0)); + nng_stream_stop(nni_aio_get_output(d->conaio, 0)); nng_stream_free(nni_aio_get_output(d->conaio, 0)); nni_aio_set_output(d->conaio, 0, NULL); } @@ -127,14 +129,26 @@ tcp_dialer_close(void *arg) { tcp_dialer *d = arg; nni_aio *aio; - nni_mtx_lock(&d->mtx); - d->closed = true; - while ((aio = nni_list_first(&d->conaios)) != NULL) { - nni_list_remove(&d->conaios, aio); - nni_aio_finish_error(aio, NNG_ECLOSED); + + if (d != NULL) { + nni_mtx_lock(&d->mtx); + d->closed = true; + while ((aio = nni_list_first(&d->conaios)) != NULL) { + nni_list_remove(&d->conaios, aio); + nni_aio_finish_error(aio, NNG_ECLOSED); + } + nni_tcp_dialer_close(d->d); + nni_mtx_unlock(&d->mtx); + } +} + +static void +tcp_dialer_stop(void *arg) +{ + tcp_dialer *d = arg; + if (d != NULL) { + nni_tcp_dialer_stop(d->d); } - nni_tcp_dialer_close(d->d); - nni_mtx_unlock(&d->mtx); } static void @@ -222,6 +236,7 @@ tcp_dialer_alloc(tcp_dialer **dp) d->ops.sd_close = tcp_dialer_close; d->ops.sd_free = tcp_dialer_free; + d->ops.sd_stop = tcp_dialer_stop; d->ops.sd_dial = tcp_dialer_dial; d->ops.sd_get = tcp_dialer_get; d->ops.sd_set = tcp_dialer_set; @@ -275,6 +290,13 @@ tcp_listener_close(void *arg) nni_tcp_listener_close(l->l); } +static void +tcp_listener_stop(void *arg) +{ + tcp_listener *l = arg; + nni_tcp_listener_stop(l->l); +} + static void tcp_listener_free(void *arg) { @@ -372,6 +394,7 @@ tcp_listener_alloc_addr(nng_stream_listener **lp, const nng_sockaddr *sa) l->ops.sl_free = tcp_listener_free; l->ops.sl_close = tcp_listener_close; + l->ops.sl_stop = tcp_listener_stop; l->ops.sl_listen = tcp_listener_listen; l->ops.sl_accept = tcp_listener_accept; l->ops.sl_get = tcp_listener_get; -- cgit v1.2.3-70-g09d2