From c2896d3561dbc5054c0b8f168c8d4864d9822604 Mon Sep 17 00:00:00 2001 From: Sabitov Kirill Date: Fri, 28 Nov 2025 14:16:45 +0000 Subject: [PATCH 1/5] Add unit test to check that delayed packet won't be corrupted --- tests/CMakeLists.txt | 1 + tests/test_mini_conn_delay.c | 110 +++++++++++++++++++++++++++++++++++ 2 files changed, 111 insertions(+) create mode 100644 tests/test_mini_conn_delay.c diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index fab22d334..fb13dca0b 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -46,6 +46,7 @@ SET(TESTS hkdf hpi lsquic_hash + mini_conn_delay packet_out packet_resize packno_len diff --git a/tests/test_mini_conn_delay.c b/tests/test_mini_conn_delay.c new file mode 100644 index 000000000..d993a8dc2 --- /dev/null +++ b/tests/test_mini_conn_delay.c @@ -0,0 +1,110 @@ +/* Test for mini connection delayed packet data corruption bug */ + +#undef LSQUIC_TEST + +#include +#include +#include +#include +#include + +#include "lsquic.h" +#include "lsquic_int_types.h" +#include "lsquic_types.h" +#include "lsquic_mm.h" +#include "lsquic_hash.h" +#include "lsquic_engine_public.h" +#include "lsquic_trechist.h" +#include "lsquic_conn.h" +#include "lsquic_enc_sess.h" +#include "lsquic_packet_common.h" +#include "lsquic_rtt.h" +#include "lsquic_mini_conn_ietf.h" +#include "lsquic_crand.h" +#include "lsquic_ev_log.h" +#include "lsquic_packet_in.h" +#include "lsquic_version.h" + +static enum dec_packin mock_decrypt_packet(enc_session_t *enc_sess, + struct lsquic_engine_public *enpub, + const struct lsquic_conn *lconn, + struct lsquic_packet_in *packet_in) { + // Return DECPI_NOT_YET to trigger delay + return DECPI_NOT_YET; +} + +static void mock_generate_scid(void *ctx, struct lsquic_conn *conn, + uint8_t *scid, unsigned len) { + memset(scid, 0xCC, len); +} + +static void test_delayed_packet_corruption(void) { + unsigned char packet_data[200]; + unsigned char app_data[200]; + lsquic_cid_t dcid = {.len = 8, .idbuf = {1, 2, 3, 4, 5, 6, 7, 8}}; + struct enc_session_funcs_common mock_esf_c; + struct crand crand; + + struct lsquic_engine_public enpub; + memset(&enpub, 0, sizeof(enpub)); + lsquic_mm_init(&enpub.enp_mm); + lsquic_engine_init_settings(&enpub.enp_settings, 0); + enpub.enp_settings.es_ecn = 0; + enpub.enp_generate_scid = mock_generate_scid; + memset(&crand, 0, sizeof(crand)); + enpub.enp_crand = &crand; + + // Setup initial packet + struct lsquic_packet_in *packet_in_init = + lsquic_mm_get_packet_in(&enpub.enp_mm); + packet_in_init->pi_data = packet_data; + packet_in_init->pi_data_sz = 1200; + packet_in_init->pi_header_type = HETY_INITIAL; + packet_in_init->pi_flags = PI_OWN_DATA; + packet_in_init->pi_dcid = dcid; + packet_in_init->pi_received = 1234567890; + + // Create mini connection + struct lsquic_conn *conn = lsquic_mini_conn_ietf_new( + &enpub, packet_in_init, LSQVER_I001, 0, &dcid, 1200); + assert(conn); + struct ietf_mini_conn *mini_conn = (struct ietf_mini_conn *)conn; + + // Setup mock crypto interface to force delay + memcpy(&mock_esf_c, conn->cn_esf_c, sizeof(mock_esf_c)); + mock_esf_c.esf_decrypt_packet = mock_decrypt_packet; + conn->cn_esf_c = &mock_esf_c; + + // Create APP packet to be delayed + memset(app_data, 0x42, sizeof(app_data)); + struct lsquic_packet_in *packet_in_app = + lsquic_mm_get_packet_in(&enpub.enp_mm); + packet_in_app->pi_data = app_data; + packet_in_app->pi_data_sz = sizeof(app_data); + packet_in_app->pi_header_type = HETY_SHORT; + packet_in_app->pi_flags = 0; + packet_in_app->pi_dcid = dcid; + packet_in_app->pi_received = 1234567891; + + // Send APP packet + conn->cn_if->ci_packet_in(conn, packet_in_app); + + // Verify it is delayed + assert(!TAILQ_EMPTY(&mini_conn->imc_app_packets) && "Packet was NOT delayed"); + struct lsquic_packet_in *delayed = TAILQ_FIRST(&mini_conn->imc_app_packets); + assert(delayed == packet_in_app && + "Delayed packet is different from one we sent"); + + // Modify buffer + memset(app_data, 0xAC, sizeof(app_data)); + + // Check delayed packet data is not corrupted + assert(delayed->pi_data[0] == 0x42 && "Delayed data is corrupted!"); + + lsquic_mm_cleanup(&enpub.enp_mm); +} + +int main(void) { + test_delayed_packet_corruption(); + return 0; +} From 0fc0b1522205181e3027d585c9b0a643f3e7e7ec Mon Sep 17 00:00:00 2001 From: Sabitov Kirill Date: Fri, 28 Nov 2025 15:15:01 +0000 Subject: [PATCH 2/5] Add packet data copying when delaying processing --- src/liblsquic/lsquic_mini_conn_ietf.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/liblsquic/lsquic_mini_conn_ietf.c b/src/liblsquic/lsquic_mini_conn_ietf.c index f052387e2..2f1c8bee2 100644 --- a/src/liblsquic/lsquic_mini_conn_ietf.c +++ b/src/liblsquic/lsquic_mini_conn_ietf.c @@ -1539,6 +1539,7 @@ imico_maybe_delay_processing (struct ietf_mini_conn *conn, { ++conn->imc_delayed_packets_count; lsquic_packet_in_upref(packet_in); + lsquic_conn_copy_and_release_pi_data(&conn->imc_conn, conn->imc_enpub, packet_in); TAILQ_INSERT_TAIL(&conn->imc_app_packets, packet_in, pi_next); LSQ_DEBUG("delay processing of packet (now delayed %hhu)", conn->imc_delayed_packets_count); From e41fc865946edccdba81dd06a5ba61637fbc4255 Mon Sep 17 00:00:00 2001 From: Sabitov Kirill Date: Fri, 28 Nov 2025 16:15:38 +0000 Subject: [PATCH 3/5] Handle memory allocation failure --- src/liblsquic/lsquic_mini_conn_ietf.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/liblsquic/lsquic_mini_conn_ietf.c b/src/liblsquic/lsquic_mini_conn_ietf.c index 2f1c8bee2..64bd084e6 100644 --- a/src/liblsquic/lsquic_mini_conn_ietf.c +++ b/src/liblsquic/lsquic_mini_conn_ietf.c @@ -1537,9 +1537,14 @@ imico_maybe_delay_processing (struct ietf_mini_conn *conn, if (conn->imc_delayed_packets_count < max_delayed) { + if (lsquic_conn_copy_and_release_pi_data(&conn->imc_conn, conn->imc_enpub, + packet_in) != 0) { + LSQ_DEBUG("drop packet, copy data failed"); + return; + } + ++conn->imc_delayed_packets_count; lsquic_packet_in_upref(packet_in); - lsquic_conn_copy_and_release_pi_data(&conn->imc_conn, conn->imc_enpub, packet_in); TAILQ_INSERT_TAIL(&conn->imc_app_packets, packet_in, pi_next); LSQ_DEBUG("delay processing of packet (now delayed %hhu)", conn->imc_delayed_packets_count); From 6ccda12c356c3dc8b65ea5860d1a0311ccc6f9f9 Mon Sep 17 00:00:00 2001 From: Sabitov Kirill Date: Fri, 28 Nov 2025 16:48:18 +0000 Subject: [PATCH 4/5] Add check that data is already owned by engine --- src/liblsquic/lsquic_mini_conn_ietf.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/liblsquic/lsquic_mini_conn_ietf.c b/src/liblsquic/lsquic_mini_conn_ietf.c index 64bd084e6..32901dbcc 100644 --- a/src/liblsquic/lsquic_mini_conn_ietf.c +++ b/src/liblsquic/lsquic_mini_conn_ietf.c @@ -1537,8 +1537,10 @@ imico_maybe_delay_processing (struct ietf_mini_conn *conn, if (conn->imc_delayed_packets_count < max_delayed) { - if (lsquic_conn_copy_and_release_pi_data(&conn->imc_conn, conn->imc_enpub, - packet_in) != 0) { + int copy_success = (packet_in->pi_flags & PI_OWN_DATA) || + lsquic_conn_copy_and_release_pi_data( + &conn->imc_conn, conn->imc_enpub, packet_in) == 0; + if (!copy_success) { LSQ_DEBUG("drop packet, copy data failed"); return; } From 2d90f079f566abcc2c40b7014c0be9486e4e8bf8 Mon Sep 17 00:00:00 2001 From: Sabitov Kirill Date: Fri, 28 Nov 2025 17:08:39 +0000 Subject: [PATCH 5/5] Fix mem leak and add copyright header --- tests/test_mini_conn_delay.c | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/tests/test_mini_conn_delay.c b/tests/test_mini_conn_delay.c index d993a8dc2..2560aa74d 100644 --- a/tests/test_mini_conn_delay.c +++ b/tests/test_mini_conn_delay.c @@ -1,3 +1,4 @@ +/* Copyright (c) 2017 - 2022 LiteSpeed Technologies Inc. See LICENSE. */ /* Test for mini connection delayed packet data corruption bug */ #undef LSQUIC_TEST @@ -29,7 +30,7 @@ static enum dec_packin mock_decrypt_packet(enc_session_t *enc_sess, struct lsquic_engine_public *enpub, const struct lsquic_conn *lconn, struct lsquic_packet_in *packet_in) { - // Return DECPI_NOT_YET to trigger delay + /* Return DECPI_NOT_YET to trigger delay */ return DECPI_NOT_YET; } @@ -54,7 +55,7 @@ static void test_delayed_packet_corruption(void) { memset(&crand, 0, sizeof(crand)); enpub.enp_crand = &crand; - // Setup initial packet + /* Setup initial packet */ struct lsquic_packet_in *packet_in_init = lsquic_mm_get_packet_in(&enpub.enp_mm); packet_in_init->pi_data = packet_data; @@ -64,18 +65,18 @@ static void test_delayed_packet_corruption(void) { packet_in_init->pi_dcid = dcid; packet_in_init->pi_received = 1234567890; - // Create mini connection + /* Create mini connection */ struct lsquic_conn *conn = lsquic_mini_conn_ietf_new( &enpub, packet_in_init, LSQVER_I001, 0, &dcid, 1200); assert(conn); struct ietf_mini_conn *mini_conn = (struct ietf_mini_conn *)conn; - // Setup mock crypto interface to force delay + /* Setup mock crypto interface to force delay */ memcpy(&mock_esf_c, conn->cn_esf_c, sizeof(mock_esf_c)); mock_esf_c.esf_decrypt_packet = mock_decrypt_packet; conn->cn_esf_c = &mock_esf_c; - // Create APP packet to be delayed + /* Create APP packet to be delayed */ memset(app_data, 0x42, sizeof(app_data)); struct lsquic_packet_in *packet_in_app = lsquic_mm_get_packet_in(&enpub.enp_mm); @@ -86,21 +87,22 @@ static void test_delayed_packet_corruption(void) { packet_in_app->pi_dcid = dcid; packet_in_app->pi_received = 1234567891; - // Send APP packet - conn->cn_if->ci_packet_in(conn, packet_in_app); + /* Send APP packet */ + conn->cn_if->ci_packet_in(conn, packet_in_app); - // Verify it is delayed + /* Verify it is delayed */ assert(!TAILQ_EMPTY(&mini_conn->imc_app_packets) && "Packet was NOT delayed"); struct lsquic_packet_in *delayed = TAILQ_FIRST(&mini_conn->imc_app_packets); assert(delayed == packet_in_app && "Delayed packet is different from one we sent"); - // Modify buffer + /* Modify buffer */ memset(app_data, 0xAC, sizeof(app_data)); - // Check delayed packet data is not corrupted + /* Check delayed packet data is not corrupted */ assert(delayed->pi_data[0] == 0x42 && "Delayed data is corrupted!"); + conn->cn_if->ci_destroy(conn); lsquic_mm_cleanup(&enpub.enp_mm); }