changeset 8783:60c6e8d8d3ae quic

QUIC: make sure stream data size is lower than final size. As per quic-transport 34, FINAL_SIZE_ERROR is generated if an endpoint received a STREAM frame or a RESET_STREAM frame containing a final size that was lower than the size of stream data that was already received.
author Roman Arutyunyan <arut@nginx.com>
date Tue, 25 May 2021 16:41:59 +0300
parents b3f6ad181df4
children 7d32c3c93678
files src/event/quic/ngx_event_quic.h src/event/quic/ngx_event_quic_streams.c
diffstat 2 files changed, 17 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- a/src/event/quic/ngx_event_quic.h
+++ b/src/event/quic/ngx_event_quic.h
@@ -79,6 +79,7 @@ struct ngx_quic_stream_s {
     uint64_t                   send_max_data;
     uint64_t                   recv_max_data;
     uint64_t                   recv_offset;
+    uint64_t                   recv_last;
     uint64_t                   final_size;
     ngx_chain_t               *in;
     ngx_uint_t                 cancelable;  /* unsigned  cancelable:1; */
--- a/src/event/quic/ngx_event_quic_streams.c
+++ b/src/event/quic/ngx_event_quic_streams.c
@@ -857,6 +857,8 @@ ngx_quic_handle_stream_frame(ngx_connect
             qs->final_size = last;
         }
 
+        qs->recv_last = last;
+
         if (f->offset == 0) {
             sc->read->ready = 1;
         }
@@ -884,6 +886,10 @@ ngx_quic_handle_stream_frame(ngx_connect
         return NGX_OK;
     }
 
+    if (qs->recv_last < last) {
+        qs->recv_last = last;
+    }
+
     if (f->offset < qs->recv_offset) {
         ngx_quic_trim_bufs(frame->data, qs->recv_offset - f->offset);
         f->offset = qs->recv_offset;
@@ -899,6 +905,11 @@ ngx_quic_handle_stream_frame(ngx_connect
             return NGX_ERROR;
         }
 
+        if (qs->recv_last > last) {
+            qc->error = NGX_QUIC_ERR_FINAL_SIZE_ERROR;
+            return NGX_ERROR;
+        }
+
         qs->connection->read->pending_eof = 1;
         qs->final_size = last;
     }
@@ -1129,6 +1140,11 @@ ngx_quic_handle_reset_stream_frame(ngx_c
         return NGX_ERROR;
     }
 
+    if (qs->recv_last > f->final_size) {
+        qc->error = NGX_QUIC_ERR_FINAL_SIZE_ERROR;
+        return NGX_ERROR;
+    }
+
     qs->final_size = f->final_size;
 
     rev = qs->connection->read;