# HG changeset patch # User Roman Arutyunyan # Date 1598365377 -10800 # Node ID f882b1784f30cbbb31f497cb1cc4ba95be35e31a # Parent eaea7dac3292061d0dbdd55919040d4b7b99446e QUIC: enforce flow control on incoming STREAM and CRYPTO frames. diff --git a/src/event/ngx_event_quic.c b/src/event/ngx_event_quic.c --- a/src/event/ngx_event_quic.c +++ b/src/event/ngx_event_quic.c @@ -2802,13 +2802,6 @@ ngx_quic_buffer_frame(ngx_connection_t * /* frame start offset is in the future, buffer it */ - /* check limit on total size used by all buffered frames, not actual data */ - if (NGX_QUIC_MAX_BUFFERED - fs->total < f->length) { - ngx_log_error(NGX_LOG_INFO, c->log, 0, - "quic ordered input buffer limit exceeded"); - return NGX_ERROR; - } - dst = ngx_quic_alloc_frame(c, f->length); if (dst == NULL) { return NGX_ERROR; @@ -2857,11 +2850,22 @@ static ngx_int_t ngx_quic_handle_crypto_frame(ngx_connection_t *c, ngx_quic_header_t *pkt, ngx_quic_frame_t *frame) { + uint64_t last; ngx_quic_connection_t *qc; + ngx_quic_crypto_frame_t *f; ngx_quic_frames_stream_t *fs; qc = c->quic; fs = &qc->crypto[pkt->level]; + f = &frame->u.crypto; + + /* no overflow since both values are 62-bit */ + last = f->offset + f->length; + + if (last > fs->received && last - fs->received > NGX_QUIC_MAX_BUFFERED) { + c->quic->error = NGX_QUIC_ERR_CRYPTO_BUFFER_EXCEEDED; + return NGX_ERROR; + } return ngx_quic_handle_ordered_frame(c, fs, frame, ngx_quic_crypto_input, NULL); @@ -2978,6 +2982,9 @@ static ngx_int_t ngx_quic_handle_stream_frame(ngx_connection_t *c, ngx_quic_header_t *pkt, ngx_quic_frame_t *frame) { + size_t window; + uint64_t last; + ngx_buf_t *b; ngx_pool_t *pool; ngx_connection_t *sc; ngx_quic_stream_t *sn; @@ -2995,6 +3002,9 @@ ngx_quic_handle_stream_frame(ngx_connect return NGX_ERROR; } + /* no overflow since both values are 62-bit */ + last = f->offset + f->length; + sn = ngx_quic_find_stream(&qc->streams.tree, f->stream_id); if (sn == NULL) { @@ -3010,17 +3020,19 @@ ngx_quic_handle_stream_frame(ngx_connect sc = sn->c; fs = &sn->fs; + b = sn->b; + window = b->end - b->last; + + if (last > window) { + c->quic->error = NGX_QUIC_ERR_FLOW_CONTROL_ERROR; + goto cleanup; + } if (ngx_quic_handle_ordered_frame(c, fs, frame, ngx_quic_stream_input, sn) != NGX_OK) { - pool = sc->pool; - - ngx_close_connection(sc); - ngx_destroy_pool(pool); - - return NGX_ERROR; + goto cleanup; } sc->listening->handler(sc); @@ -3029,9 +3041,25 @@ ngx_quic_handle_stream_frame(ngx_connect } fs = &sn->fs; + b = sn->b; + window = (b->pos - b->start) + (b->end - b->last); + + if (last > fs->received && last - fs->received > window) { + c->quic->error = NGX_QUIC_ERR_FLOW_CONTROL_ERROR; + return NGX_ERROR; + } return ngx_quic_handle_ordered_frame(c, fs, frame, ngx_quic_stream_input, sn); + +cleanup: + + pool = sc->pool; + + ngx_close_connection(sc); + ngx_destroy_pool(pool); + + return NGX_ERROR; }