Files
Marius Ciepluch 0116f9bea6 feat(real-world-vfc-slice): add labeled OpenSSL/Firefox/Chromium/curl pair corpus
Harvest 176 isolated vuln-vs-fix functions (109 CVEs, 352 training rows)
into benchmarks/pairs/vfc with provenance and a JSONL training manifest.
Score the slice as an honesty dashboard (ousast pairs --slice vfc);
keep the pair gate on the local fixtures only.
2026-09-04 16:45:38 +02:00

190 lines
6.5 KiB
C

/* Provenance: openssl/openssl txp_pkt_commit (fixed).
* repo: openssl/openssl
* commit: c902e5f16d6a9e130e96d3ca6d8f64d71652e393
* parent: a1f348ccb328c3afbd4ba6883f9b7c813c043259
* commit_url: https://github.com/openssl/openssl/commit/c902e5f16d6a9e130e96d3ca6d8f64d71652e393
* cve: CVE-2026-63075
* license: Apache-2.0
* function: txp_pkt_commit
* relpath: ssl/quic/quic_txp.c
*/
static int txp_pkt_commit(OSSL_QUIC_TX_PACKETISER *txp,
struct txp_pkt *pkt,
uint32_t archetype,
int *txpim_pkt_reffed)
{
int ack_only, rc = 1;
uint32_t enc_level = pkt->h.enc_level;
uint32_t pn_space = ossl_quic_enc_level_to_pn_space(enc_level);
QUIC_TXPIM_PKT *tpkt = pkt->tpkt;
QUIC_STREAM *stream;
OSSL_QTX_PKT txpkt;
struct archetype_data a;
*txpim_pkt_reffed = 0;
/* Cannot send a packet with an empty payload. */
if (pkt->h.bytes_appended == 0)
return 0;
if (!txp_get_archetype_data(enc_level, archetype, &a))
return 0;
/* Packet Information for QTX */
txpkt.hdr = &pkt->phdr;
txpkt.iovec = txp->el[enc_level].iovec;
txpkt.num_iovec = pkt->h.num_iovec;
txpkt.local = NULL;
txpkt.peer = BIO_ADDR_family(&txp->args.peer) == AF_UNSPEC
? NULL
: &txp->args.peer;
txpkt.pn = txp->next_pn[pn_space];
txpkt.flags = OSSL_QTX_PKT_FLAG_COALESCE; /* always try to coalesce */
/* Generate TXPIM chunks representing STOP_SENDING and RESET_STREAM frames. */
for (stream = pkt->stream_head; stream != NULL; stream = stream->txp_next)
if (stream->txp_sent_stop_sending || stream->txp_sent_reset_stream) {
/* Log STOP_SENDING/RESET_STREAM chunk to TXPIM. */
QUIC_TXPIM_CHUNK chunk;
chunk.stream_id = stream->id;
chunk.start = UINT64_MAX;
chunk.end = 0;
chunk.has_fin = 0;
chunk.has_stop_sending = stream->txp_sent_stop_sending;
chunk.has_reset_stream = stream->txp_sent_reset_stream;
if (!ossl_quic_txpim_pkt_append_chunk(tpkt, &chunk))
return 0; /* alloc error */
}
ack_only = txp_pkt_is_ack_only(tpkt);
/* Dispatch packets that need loss/retransmit callbacks to FIFD. */
if (!ack_only && !ossl_quic_fifd_pkt_commit(&txp->fifd, tpkt))
return 0;
/*
* Transmission and Post-Packet Generation Bookkeeping
* ===================================================
*
* No backing out anymore - at this point we need to increment our next PN
* counter, or the ACKM will complain when we try to record a duplicate
* packet with the same PN later. Non-ACK-only packets have also been
* recorded in ACKM, so if QTX write fails they are handled as though they
* were lost. ACK-only packets are not recorded and will be cleaned up by
* the caller.
*/
++txp->next_pn[pn_space];
if (!ack_only)
*txpim_pkt_reffed = 1;
/* Send the packet. */
if (!ossl_qtx_write_pkt(txp->args.qtx, &txpkt))
return 0;
if (ack_only
&& !ossl_ackm_on_tx_ack_only_packet(txp->args.ackm, &tpkt->ackm_pkt))
rc = 0;
/*
* Record FC and stream abort frames as sent; deactivate streams which no
* longer have anything to do.
*/
for (stream = pkt->stream_head; stream != NULL; stream = stream->txp_next) {
if (stream->txp_sent_fc) {
stream->want_max_stream_data = 0;
ossl_quic_rxfc_has_cwm_changed(&stream->rxfc, 1);
}
if (stream->txp_sent_stop_sending)
stream->want_stop_sending = 0;
if (stream->txp_sent_reset_stream)
stream->want_reset_stream = 0;
if (stream->txp_txfc_new_credit_consumed > 0) {
if (!ossl_assert(ossl_quic_txfc_consume_credit(&stream->txfc,
stream->txp_txfc_new_credit_consumed)))
/*
* Should not be possible, but we should continue with our
* bookkeeping as we have already committed the packet to the
* FIFD. Just change the value we return.
*/
rc = 0;
stream->txp_txfc_new_credit_consumed = 0;
}
/*
* If we no longer need to generate any flow control (MAX_STREAM_DATA),
* STOP_SENDING or RESET_STREAM frames, nor any STREAM frames (because
* the stream is drained of data or TXFC-blocked), we can mark the
* stream as inactive.
*/
ossl_quic_stream_map_update_state(txp->args.qsm, stream);
if (ossl_quic_stream_has_send_buffer(stream)
&& !ossl_quic_sstream_has_pending(stream->sstream)
&& ossl_quic_sstream_get_final_size(stream->sstream, NULL))
/*
* Transition to DATA_SENT if stream has a final size and we have
* sent all data.
*/
ossl_quic_stream_map_notify_all_data_sent(txp->args.qsm, stream);
}
/* We have now sent the packet, so update state accordingly. */
if (tpkt->ackm_pkt.is_ack_eliciting)
txp->force_ack_eliciting &= ~(1UL << pn_space);
if (tpkt->had_handshake_done_frame)
txp->want_handshake_done = 0;
if (tpkt->had_max_data_frame) {
txp->want_max_data = 0;
ossl_quic_rxfc_has_cwm_changed(txp->args.conn_rxfc, 1);
}
if (tpkt->had_max_streams_bidi_frame) {
txp->want_max_streams_bidi = 0;
ossl_quic_rxfc_has_cwm_changed(txp->args.max_streams_bidi_rxfc, 1);
}
if (tpkt->had_max_streams_uni_frame) {
txp->want_max_streams_uni = 0;
ossl_quic_rxfc_has_cwm_changed(txp->args.max_streams_uni_rxfc, 1);
}
if (tpkt->had_ack_frame)
txp->want_ack &= ~(1UL << pn_space);
if (tpkt->had_conn_close)
txp->want_conn_close = 0;
/*
* Decrement probe request counts if we have sent a packet that meets
* the requirement of a probe, namely being ACK-eliciting.
*/
if (tpkt->ackm_pkt.is_ack_eliciting) {
OSSL_ACKM_PROBE_INFO *probe_info
= ossl_ackm_get0_probe_request(txp->args.ackm);
if (enc_level == QUIC_ENC_LEVEL_INITIAL
&& probe_info->anti_deadlock_initial > 0)
--probe_info->anti_deadlock_initial;
if (enc_level == QUIC_ENC_LEVEL_HANDSHAKE
&& probe_info->anti_deadlock_handshake > 0)
--probe_info->anti_deadlock_handshake;
if (a.allow_force_ack_eliciting /* (i.e., not for 0-RTT) */
&& probe_info->pto[pn_space] > 0)
--probe_info->pto[pn_space];
}
ossl_quic_fifd_pkt_discard_unreliable(&txp->fifd, tpkt);
return rc;
}