From: Hugo Landau Date: Tue, 20 Sep 2022 19:40:36 +0000 (+0100) Subject: Add deferred datagram limit to QUIC Record Layer RX X-Git-Tag: openssl-3.2.0-alpha1~2053 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=0ff98137445ec63249eed3c1e40cf01dc5190c65;p=thirdparty%2Fopenssl.git Add deferred datagram limit to QUIC Record Layer RX Reviewed-by: Tomas Mraz Reviewed-by: Richard Levitte (Merged from https://github.com/openssl/openssl/pull/19251) --- diff --git a/include/internal/quic_demux.h b/include/internal/quic_demux.h index 9912de7a003..d6d3f35bf89 100644 --- a/include/internal/quic_demux.h +++ b/include/internal/quic_demux.h @@ -117,6 +117,12 @@ struct quic_urxe_st { * function was not provided). */ OSSL_TIME time; + + /* + * Used by the QRX to mark whether a datagram has been deferred. Used by the + * QRX only; not used by the demuxer. + */ + char deferred; }; /* Accessors for URXE buffer. */ diff --git a/include/internal/quic_record_rx.h b/include/internal/quic_record_rx.h index c22fc089c71..53b7b7f458e 100644 --- a/include/internal/quic_record_rx.h +++ b/include/internal/quic_record_rx.h @@ -32,6 +32,12 @@ typedef struct ossl_qrx_args_st { /* Length of connection IDs used in short-header packets in bytes. */ size_t short_conn_id_len; + /* + * Maximum number of deferred datagrams buffered at any one time. + * Suggested value: 32. + */ + size_t max_deferred; + /* Initial reference PN used for RX. */ QUIC_PN init_largest_pn[QUIC_PN_SPACE_NUM]; @@ -160,8 +166,8 @@ int ossl_qrx_remove_dst_conn_id(OSSL_QRX *qrx, * as do calls made after a corresponding call to ossl_qrx_discard_enc_level for * that EL. The secret for a EL cannot be changed after it is set because QUIC * has no facility for introducing additional key material after an EL is setup. - * QUIC key updates are managed automatically by the QRX and do not require user - * intervention. + * QUIC key updates are managed semi-automatically by the QRX but do require + * some caller handling (see below). * * md is for internal use and should be NULL. * @@ -258,7 +264,7 @@ void ossl_qrx_release_pkt(OSSL_QRX *qrx, void *handle); int ossl_qrx_processed_read_pending(OSSL_QRX *qrx); /* - * Returns 1 if there arre any unprocessed (i.e. not yet decrypted) packets + * Returns 1 if there are any unprocessed (i.e. not yet decrypted) packets * waiting to be processed by the QRX. These may or may not result in * successfully decrypted packets once processed. This indicates whether * unprocessed data is buffered by the QRX, not whether any data is available in @@ -434,7 +440,7 @@ int ossl_qrx_set_early_validation_cb(OSSL_QRX *qrx, * current substate of the PROVISIONED state is to the DISCARDED state, which is * the terminal state. * - * Note that non-1RTT ELs cannot undergo key update, therefore a non-1RT EL is + * Note that non-1RTT ELs cannot undergo key update, therefore a non-1RTT EL is * always in the NORMAL substate if it is in the PROVISIONED state. */ diff --git a/ssl/quic/quic_record_rx.c b/ssl/quic/quic_record_rx.c index c0bbb5f504a..ee552e83c50 100644 --- a/ssl/quic/quic_record_rx.c +++ b/ssl/quic/quic_record_rx.c @@ -116,6 +116,12 @@ struct ossl_qrx_st { /* Length of connection IDs used in short-header packets in bytes. */ size_t short_conn_id_len; + /* Maximum number of deferred datagrams buffered at any one time. */ + size_t max_deferred; + + /* Current count of deferred datagrams. */ + size_t num_deferred; + /* * List of URXEs which are filled with received encrypted data. * These are returned to the DEMUX's free list as they are processed. @@ -176,7 +182,7 @@ OSSL_QRX *ossl_qrx_new(const OSSL_QRX_ARGS *args) OSSL_QRX *qrx; size_t i; - if (args->demux == NULL) + if (args->demux == NULL || args->max_deferred == 0) return 0; qrx = OPENSSL_zalloc(sizeof(OSSL_QRX)); @@ -191,6 +197,7 @@ OSSL_QRX *ossl_qrx_new(const OSSL_QRX_ARGS *args) qrx->demux = args->demux; qrx->short_conn_id_len = args->short_conn_id_len; qrx->init_key_phase_bit = args->init_key_phase_bit; + qrx->max_deferred = args->max_deferred; return qrx; } @@ -245,6 +252,7 @@ static void qrx_on_rx(QUIC_URXE *urxe, void *arg) /* Initialize our own fields inside the URXE and add to the pending list. */ urxe->processed = 0; urxe->hpr_removed = 0; + urxe->deferred = 0; ossl_quic_urxe_insert_tail(&qrx->urx_pending, urxe); } @@ -1042,10 +1050,20 @@ static int qrx_process_one_urxe(OSSL_QRX *qrx, QUIC_URXE *e) * either the free or deferred list. */ ossl_quic_urxe_remove(&qrx->urx_pending, e); - if (was_deferred > 0) + if (was_deferred > 0 && + (e->deferred || qrx->num_deferred < qrx->max_deferred)) { ossl_quic_urxe_insert_tail(&qrx->urx_deferred, e); - else + if (!e->deferred) { + e->deferred = 1; + ++qrx->num_deferred; + } + } else { + if (e->deferred) { + e->deferred = 0; + --qrx->num_deferred; + } ossl_quic_demux_release_urxe(qrx->demux, e); + } return 1; } diff --git a/test/quic_record_test.c b/test/quic_record_test.c index 523d8ec27b0..a4cafb8c21a 100644 --- a/test/quic_record_test.c +++ b/test/quic_record_test.c @@ -1700,7 +1700,8 @@ static int rx_state_ensure(struct rx_state *s) NULL))) return 0; - s->args.demux = s->demux; + s->args.demux = s->demux; + s->args.max_deferred = 32; if (s->qrx == NULL && !TEST_ptr(s->qrx = ossl_qrx_new(&s->args)))