]> git.ipfire.org Git - thirdparty/openssl.git/commitdiff
Add design document for the QUIC Stream Receive Buffers module
authorTomas Mraz <tomas@openssl.org>
Tue, 6 Sep 2022 15:34:54 +0000 (17:34 +0200)
committerTomas Mraz <tomas@openssl.org>
Fri, 7 Oct 2022 18:01:18 +0000 (20:01 +0200)
Reviewed-by: Paul Dale <pauli@openssl.org>
Reviewed-by: Hugo Landau <hlandau@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/19149)

doc/designs/quic-design/stream-receive-buffers.md [new file with mode: 0644]

diff --git a/doc/designs/quic-design/stream-receive-buffers.md b/doc/designs/quic-design/stream-receive-buffers.md
new file mode 100644 (file)
index 0000000..2de8cd0
--- /dev/null
@@ -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.