changeset 8501:fc16e303003a quic

QUIC: fixed possible use-after-free on stream cleanup. A QUIC stream could be destroyed by handler while in ngx_quic_stream_input(). To detect this, ngx_quic_find_stream() is used to check that it still exists. Previously, a stream id was passed to this routine off the frame structure. In case of stream cleanup, it is freed along with other frames belonging to the stream on cleanup. Then, a cleanup handler reuses last frames to update MAX_STREAMS and serve other purpose. Thus, ngx_quic_find_stream() is passed a reused frame with zeroed out part pointed by stream_id. If a stream with id 0x0 still exists, this leads to use-after-free.
author Sergey Kandaurov <pluknet@nginx.com>
date Fri, 07 Aug 2020 12:34:11 +0300
parents 12576ac9556d
children 69033a50c3ae
files src/event/ngx_event_quic.c
diffstat 1 files changed, 3 insertions(+), 1 deletions(-) [+]
line wrap: on
line diff
--- a/src/event/ngx_event_quic.c
+++ b/src/event/ngx_event_quic.c
@@ -3006,6 +3006,7 @@ ngx_quic_handle_stream_frame(ngx_connect
 static ngx_int_t
 ngx_quic_stream_input(ngx_connection_t *c, ngx_quic_frame_t *frame, void *data)
 {
+    uint64_t                  id;
     ngx_buf_t                *b;
     ngx_event_t              *rev;
     ngx_quic_stream_t        *sn;
@@ -3016,6 +3017,7 @@ ngx_quic_stream_input(ngx_connection_t *
     sn = data;
 
     f = &frame->u.stream;
+    id = f->stream_id;
 
     ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0, "quic existing stream");
 
@@ -3046,7 +3048,7 @@ ngx_quic_stream_input(ngx_connection_t *
     }
 
     /* check if stream was destroyed by handler */
-    if (ngx_quic_find_stream(&qc->streams.tree, f->stream_id) == NULL) {
+    if (ngx_quic_find_stream(&qc->streams.tree, id) == NULL) {
         return NGX_DONE;
     }