Skip to content

Commit

Permalink
QUIC RXDP/QSM: Enforce MAX_STREAMS
Browse files Browse the repository at this point in the history
Also use accept queue popping by the application as the retirement
event, i.e., as the cue to increase the limit.

Reviewed-by: Matt Caswell <matt@openssl.org>
Reviewed-by: Tomas Mraz <tomas@openssl.org>
(Merged from #20765)
  • Loading branch information
hlandau committed May 12, 2023
1 parent a6b6ea1 commit 90cecc4
Show file tree
Hide file tree
Showing 5 changed files with 62 additions and 7 deletions.
12 changes: 9 additions & 3 deletions include/internal/quic_stream_map.h
Expand Up @@ -138,6 +138,8 @@ typedef struct quic_stream_map_st {
QUIC_STREAM *rr_cur;
uint64_t (*get_stream_limit_cb)(int uni, void *arg);
void *get_stream_limit_cb_arg;
QUIC_RXFC *max_streams_bidi_rxfc;
QUIC_RXFC *max_streams_uni_rxfc;
} QUIC_STREAM_MAP;

/*
Expand All @@ -155,7 +157,9 @@ typedef struct quic_stream_map_st {
*/
int ossl_quic_stream_map_init(QUIC_STREAM_MAP *qsm,
uint64_t (*get_stream_limit_cb)(int uni, void *arg),
void *get_stream_limit_cb_arg);
void *get_stream_limit_cb_arg,
QUIC_RXFC *max_streams_bidi_rxfc,
QUIC_RXFC *max_streams_uni_rxfc);

/*
* Any streams still in the map will be released as though
Expand Down Expand Up @@ -246,12 +250,14 @@ void ossl_quic_stream_map_push_accept_queue(QUIC_STREAM_MAP *qsm,
QUIC_STREAM *ossl_quic_stream_map_peek_accept_queue(QUIC_STREAM_MAP *qsm);

/*
* Removes a stream from the accept queue.
* Removes a stream from the accept queue. rtt is the estimated connection RTT.
* The stream is retired for the purposes of MAX_STREAMS RXFC.
*
* Precondition: s is in the accept queue.
*/
void ossl_quic_stream_map_remove_from_accept_queue(QUIC_STREAM_MAP *qsm,
QUIC_STREAM *s);
QUIC_STREAM *s,
OSSL_TIME rtt);

/* Returns the length of the accept queue. */
size_t ossl_quic_stream_map_get_accept_queue_len(QUIC_STREAM_MAP *qsm);
Expand Down
5 changes: 4 additions & 1 deletion ssl/quic/quic_impl.c
Expand Up @@ -2231,6 +2231,7 @@ SSL *ossl_quic_accept_stream(SSL *s, uint64_t flags)
QUIC_STREAM_MAP *qsm;
QUIC_STREAM *qs;
QUIC_XSO *xso;
OSSL_RTT_INFO rtt_info;

if (!expect_quic_conn_only(s, &ctx))
return NULL;
Expand Down Expand Up @@ -2270,7 +2271,9 @@ SSL *ossl_quic_accept_stream(SSL *s, uint64_t flags)
if (xso == NULL)
goto out;

ossl_quic_stream_map_remove_from_accept_queue(qsm, qs);
ossl_statm_get_rtt_info(ossl_quic_channel_get_statm(ctx.qc->ch), &rtt_info);
ossl_quic_stream_map_remove_from_accept_queue(qsm, qs,
rtt_info.smoothed_rtt);
new_s = &xso->ssl;

/* Calling this function inhibits default XSO autocreation. */
Expand Down
27 changes: 27 additions & 0 deletions ssl/quic/quic_rx_depack.c
Expand Up @@ -256,6 +256,7 @@ static int depack_do_frame_stream(PACKET *pkt, QUIC_CHANNEL *ch,
if (stream == NULL) {
uint64_t peer_role, stream_ordinal;
uint64_t *p_next_ordinal_local, *p_next_ordinal_remote;
QUIC_RXFC *max_streams_fc;
int is_uni;

/*
Expand Down Expand Up @@ -299,6 +300,32 @@ static int depack_do_frame_stream(PACKET *pkt, QUIC_CHANNEL *ch,
? &ch->next_remote_stream_ordinal_uni
: &ch->next_remote_stream_ordinal_bidi;

/* Check this isn't violating stream count flow control. */
max_streams_fc = is_uni
? &ch->max_streams_uni_rxfc
: &ch->max_streams_bidi_rxfc;

if (!ossl_quic_rxfc_on_rx_stream_frame(max_streams_fc,
stream_ordinal + 1,
/*is_fin=*/0)) {
ossl_quic_channel_raise_protocol_error(ch,
QUIC_ERR_INTERNAL_ERROR,
frame_type,
"internal error (stream count RXFC)");
return 0;
}

if (ossl_quic_rxfc_get_error(max_streams_fc, 0) != QUIC_ERR_NO_ERROR) {
ossl_quic_channel_raise_protocol_error(ch, QUIC_ERR_STREAM_LIMIT_ERROR,
frame_type,
"exceeded maximum allowed streams");
return 0;
}

/*
* Create the named stream and any streams coming before it yet to
* be created.
*/
while (*p_next_ordinal_remote <= stream_ordinal) {
uint64_t stream_id = (*p_next_ordinal_remote << 2) |
(frame_data.stream_id
Expand Down
21 changes: 19 additions & 2 deletions ssl/quic/quic_stream_map.c
Expand Up @@ -102,7 +102,9 @@ static int cmp_stream(const QUIC_STREAM *a, const QUIC_STREAM *b)

int ossl_quic_stream_map_init(QUIC_STREAM_MAP *qsm,
uint64_t (*get_stream_limit_cb)(int uni, void *arg),
void *get_stream_limit_cb_arg)
void *get_stream_limit_cb_arg,
QUIC_RXFC *max_streams_bidi_rxfc,
QUIC_RXFC *max_streams_uni_rxfc)
{
qsm->map = lh_QUIC_STREAM_new(hash_stream, cmp_stream);
qsm->active_list.prev = qsm->active_list.next = &qsm->active_list;
Expand All @@ -114,6 +116,8 @@ int ossl_quic_stream_map_init(QUIC_STREAM_MAP *qsm,

qsm->get_stream_limit_cb = get_stream_limit_cb;
qsm->get_stream_limit_cb_arg = get_stream_limit_cb_arg;
qsm->max_streams_bidi_rxfc = max_streams_bidi_rxfc;
qsm->max_streams_uni_rxfc = max_streams_uni_rxfc;
return 1;
}

Expand Down Expand Up @@ -294,11 +298,24 @@ void ossl_quic_stream_map_push_accept_queue(QUIC_STREAM_MAP *qsm,
++qsm->num_accept;
}

static QUIC_RXFC *qsm_get_max_streams_rxfc(QUIC_STREAM_MAP *qsm, QUIC_STREAM *s)
{
return ossl_quic_stream_is_bidi(s)
? qsm->max_streams_bidi_rxfc
: qsm->max_streams_uni_rxfc;
}

void ossl_quic_stream_map_remove_from_accept_queue(QUIC_STREAM_MAP *qsm,
QUIC_STREAM *s)
QUIC_STREAM *s,
OSSL_TIME rtt)
{
QUIC_RXFC *max_streams_rxfc;

list_remove(&qsm->accept_list, &s->accept_node);
--qsm->num_accept;

if ((max_streams_rxfc = qsm_get_max_streams_rxfc(qsm, s)) != NULL)
ossl_quic_rxfc_on_retire(max_streams_rxfc, 1, rtt);
}

size_t ossl_quic_stream_map_get_accept_queue_len(QUIC_STREAM_MAP *qsm)
Expand Down
4 changes: 3 additions & 1 deletion test/quic_txp_test.c
Expand Up @@ -174,7 +174,9 @@ static int helper_init(struct helper *h)
h->cc_data)))
goto err;

if (!TEST_true(ossl_quic_stream_map_init(&h->qsm, NULL, NULL)))
if (!TEST_true(ossl_quic_stream_map_init(&h->qsm, NULL, NULL,
&h->max_streams_bidi_rxfc,
&h->max_streams_uni_rxfc)))
goto err;

h->have_qsm = 1;
Expand Down

0 comments on commit 90cecc4

Please sign in to comment.