From fb8bdbe3eba83265586a44cda2ffc783611680d7 Mon Sep 17 00:00:00 2001 From: Tomas Mraz Date: Tue, 6 Sep 2022 17:34:54 +0200 Subject: [PATCH] Add design document for the QUIC Stream Receive Buffers module Reviewed-by: Paul Dale Reviewed-by: Hugo Landau (Merged from https://github.com/openssl/openssl/pull/19149) --- .../quic-design/stream-receive-buffers.md | 131 ++++++++++++++++++ 1 file changed, 131 insertions(+) create mode 100644 doc/designs/quic-design/stream-receive-buffers.md diff --git a/doc/designs/quic-design/stream-receive-buffers.md b/doc/designs/quic-design/stream-receive-buffers.md new file mode 100644 index 00000000000..2de8cd02e2c --- /dev/null +++ b/doc/designs/quic-design/stream-receive-buffers.md @@ -0,0 +1,131 @@ +Stream Receive Buffers +====================== + +This is a QUIC specific module that retains the received stream data +until the application reads it with SSL_read() or any future stream read +calls. + +Receive Buffers requirements for MVP +------------------------------------ + +These are the requirements that were identified for MVP: + +- As packets with stream frames are received in arbitrary frames the + received data must be stored until all the data with earlier offsets + are received. +- As packets can be received before application calls SSL_read() to read + the data the data must be stored. +- The application should be able to set the limit on how much data should + be stored. The flow controller should be used to limit the peer to not send + more data. Without the flow control limit a rogue peer could trigger + a DoS via unlimited flow of incoming stream data frames. +- After the data is passed via SSL_read() to the application the stored + data can be released and flow control limit can be raised. +- As the peer can recreate stream data frames when resending them, the + implementation must be able to handle properly frames with partially + or fully overlapping data with previously received frames. + +Optional Receive Buffers requirements +------------------------------------- + +These are optional features of the stream receive buffers implementation. +They are not required for MVP but they are otherwise desirable: + +- To support a single copy operation with a future stream read call + the received data should not be copied out of the decrypted packets to + store the data. The only information actually stored would be a list + of offset, length, and pointers to data, along with a pointer to the + decrypted QUIC packet that stores the actual frame. + +Proposed new public API calls +----------------------------- + +```C +int SSL_set_max_stored_stream_data(SSL *stream, size_t length); +``` + +This function adjusts the current data flow control limit on the `stream` +to allow storing `length` bytes of quic stream data before it is read by +the application. + +OpenSSL handles sending MAX_STREAM_DATA frames appropriately when the +application reads the stored data. + +```C +int SSL_set_max_unprocessed_packet_data(SSL *connection, + size_t length); +``` + +This sets the limit on unprocessed quic packet data `length` in bytes that +is allowed to be allocated for the `connection`. +See the [Other considerations](#other-considerations) section below. + +Interfaces to other QUIC implementation modules +----------------------------------------------- + +### Front End I/O API + +SSL_read() copies data out of the stored buffers if available and +eventually triggers release of stored unprocessed packet(s). + +SSL_peek(), SSL_pending(), SSL_has_pending() peek into the stored +buffers for any information about the stored data. + +### RX Depacketizer + +The Receive Buffers module obtains the stream data via the ssl_queue_data() +callback. + +The module uses ossl_qrx_pkt_wrap_up_ref() and ossl_qrx_pkt_wrap_release() +functions to keep and release decrypted packets with unprocessed data. + +### Flow Control + +The Receive Buffers module provides an appropriate value for the Flow +Control module to send MAX_DATA and MAX_STREAM_DATA frames. Details +TBD. + +### QUIC Read Record Layer + +The Receive Buffers module needs to know whether it should stop holding +the decrypted quic packets and start copying the stream data due to +the limit reached. See the `SSL_set_max_unprocessed_quic_packet_data()` +function above and the [Other considerations](#other-considerations) section +below. Details TBD. + +Implementation details +---------------------- + +TBD + +Other considerations +-------------------- + +The peer is allowed to recreate the stream data frames. As we aim for +a single-copy operation a rogue peer could use this to override the stored +data limits by sending duplicate frames with only slight changes in the +offset. For example: 1st frame - offset 0 length 1000, 2nd frame - +offset 1 length 1000, 3rd frame - offset 2 length 1000, and so on. We +would have to keep the packet data for all these frames which would +effectively raise the stream data flow control limit quadratically. + +And this is not the only way how a rogue peer could make us occupy much +more data than what is allowed by the stream data flow control limit +in the single-copy scenario. + +Although intuitively the MAX_DATA flow control limit might be used to +somehow limit the allocated packet buffer size, it is defined as sum +of allowed data to be sent across all the streams in the connection instead. +The packet buffer will contain much more data than just the stream frames +especially with a rogue peer, that means MAX_DATA limit cannot be used +to limit the memory occupied by packet buffers. + +To resolve this problem, we fall back to copying the data off the +decrypted packet buffer once we reach a limit on unprocessed decrypted +packets. We might also consider falling back to copying the data in case +we receive stream data frames that are partially overlapping and one frame +not being a subrange of the other. + +Because in MVP only a single bidirectional stream to receive +any data will be supported, the MAX_DATA flow control limit should be equal +to MAX_STREAM_DATA limit for that stream. -- 2.47.3