BUG/MEDIUM: quic: CRYPTO frame freeing without eb_delete()

Since this commit:

	BUG/MINOR: quic: reorder fragmented RX CRYPTO frames by their offsets

when they are parsed, the CRYPTO frames are ordered by their offsets into an ebtree.
Then their data are provided to the ncbufs.

But in case of error, when qc_handle_crypto_frm() returns QUIC_RX_RET_FRM_FATAL
or QUIC_RX_RET_FRM_AGAIN), they remain attached to their tree. Then
from <err> label, they are deteleted and deleted (with a while(node) { eb_delete();
qc_frm_free();} loop). But before this loop, these statements directly
free the frame without deleting it from its tree, if this is a CRYPTO frame,
leading to a use after free when running the loop:

     if (frm)
	    qc_frm_free(qc, &frm);

This issue was detected by the interop tests, with quic-go as client. Weirdly, this
client sends CRYPTO frames by packet with holes.
Must be backported as far as 2.6 as the commit mentioned above.
This commit is contained in:
Frederic Lecaille 2025-09-01 10:39:00 +02:00
parent 90126ec9b7
commit 800ba73a9c

View File

@ -1101,10 +1101,14 @@ static int qc_parse_pkt_frms(struct quic_conn *qc, struct quic_rx_packet *pkt,
ret = qc_handle_crypto_frm(qc, &frm->crypto, pkt, qel); ret = qc_handle_crypto_frm(qc, &frm->crypto, pkt, qel);
switch (ret) { switch (ret) {
case QUIC_RX_RET_FRM_FATAL: case QUIC_RX_RET_FRM_FATAL:
/* avoid freeing without eb_delete() */
frm = NULL;
goto err; goto err;
case QUIC_RX_RET_FRM_AGAIN: case QUIC_RX_RET_FRM_AGAIN:
TRACE_STATE("AGAIN encountered", QUIC_EV_CONN_PRSHPKT, qc); TRACE_STATE("AGAIN encountered", QUIC_EV_CONN_PRSHPKT, qc);
/* avoid freeing without eb_delete() */
frm = NULL;
goto err; goto err;
case QUIC_RX_RET_FRM_DONE: case QUIC_RX_RET_FRM_DONE: