BUG/MINOR: quic: fix decrement of half_open counter on qc alloc failure

Half open counter is used to comptabilize QUIC connections waiting for
address validation. It was recently reworked to adjust its scope. With
each decrement operation, a BUG_ON() was added to ensure the counter
never wraps.

This BUG_ON() could be triggered if an allocation fails for one of
quic_conn members in qc_new_conn(). This is because half open counter is
incremented at the end of qc_new_conn(). However, in case of alloc
failure, quic_conn_release() is called immediately to ensure the counter
is decremented if a connection is freed before peer address has been
validated.

To fix this, increment half open counter early in qc_new_conn() prior to
every quic_conn members allocations.

This issue was reproduced using -dMfail argument.

This issue has been introduced by
  commit 278808915b
  MINOR: quic: reduce half open counters scope

No need to backport.
This commit is contained in:
Amaury Denoyelle 2023-11-13 10:55:30 +01:00
parent 92da3accfd
commit 78d244e9f7

View File

@ -1289,6 +1289,18 @@ struct quic_conn *qc_new_conn(const struct quic_version *qv, int ipv4,
qc->mux_state = QC_MUX_NULL; qc->mux_state = QC_MUX_NULL;
qc->err = quic_err_transport(QC_ERR_NO_ERROR); qc->err = quic_err_transport(QC_ERR_NO_ERROR);
/* If connection is instantiated due to an INITIAL packet with an
* already checked token, consider the peer address as validated.
*/
if (token_odcid->len) {
TRACE_STATE("validate peer address due to initial token",
QUIC_EV_CONN_INIT, qc);
qc->flags |= QUIC_FL_CONN_PEER_VALIDATED_ADDR;
}
else {
HA_ATOMIC_INC(&qc->prx_counters->half_open_conn);
}
/* Now proceeds to allocation of qc members. */ /* Now proceeds to allocation of qc members. */
qc->rx.buf.area = pool_alloc(pool_head_quic_conn_rxbuf); qc->rx.buf.area = pool_alloc(pool_head_quic_conn_rxbuf);
if (!qc->rx.buf.area) { if (!qc->rx.buf.area) {
@ -1396,18 +1408,6 @@ struct quic_conn *qc_new_conn(const struct quic_version *qv, int ipv4,
LIST_APPEND(&th_ctx->quic_conns, &qc->el_th_ctx); LIST_APPEND(&th_ctx->quic_conns, &qc->el_th_ctx);
qc->qc_epoch = HA_ATOMIC_LOAD(&qc_epoch); qc->qc_epoch = HA_ATOMIC_LOAD(&qc_epoch);
/* If connection is instantiated due to an INITIAL packet with an
* already checked token, consider the peer address as validated.
*/
if (token_odcid->len) {
TRACE_STATE("validate peer address due to initial token",
QUIC_EV_CONN_INIT, qc);
qc->flags |= QUIC_FL_CONN_PEER_VALIDATED_ADDR;
}
else {
HA_ATOMIC_INC(&qc->prx_counters->half_open_conn);
}
TRACE_LEAVE(QUIC_EV_CONN_INIT, qc); TRACE_LEAVE(QUIC_EV_CONN_INIT, qc);
return qc; return qc;