Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions src/liblsquic/lsquic_mini_conn_ietf.c
Original file line number Diff line number Diff line change
Expand Up @@ -1537,6 +1537,14 @@ imico_maybe_delay_processing (struct ietf_mini_conn *conn,

if (conn->imc_delayed_packets_count < max_delayed)
{
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;
}

++conn->imc_delayed_packets_count;
lsquic_packet_in_upref(packet_in);
TAILQ_INSERT_TAIL(&conn->imc_app_packets, packet_in, pi_next);
Expand Down
1 change: 1 addition & 0 deletions tests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ SET(TESTS
hkdf
hpi
lsquic_hash
mini_conn_delay
packet_out
packet_resize
packno_len
Expand Down
112 changes: 112 additions & 0 deletions tests/test_mini_conn_delay.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
/* Copyright (c) 2017 - 2022 LiteSpeed Technologies Inc. See LICENSE. */
/* Test for mini connection delayed packet data corruption bug */
Copy link

Copilot AI Nov 28, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing copyright header. Other test files in this repository include a copyright notice at the top (e.g., /* Copyright (c) 2017 - 2022 LiteSpeed Technologies Inc. See LICENSE. */). Consider adding the appropriate copyright header to maintain consistency with the codebase.

Copilot uses AI. Check for mistakes.

#undef LSQUIC_TEST

#include <assert.h>
#include <string.h>
#include <sys/queue.h>
#include <stdio.h>
#include <stdlib.h>

#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!");

Copy link

Copilot AI Nov 28, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Memory leak: The test creates a mini connection but never destroys it. The conn object and its associated resources (including the delayed packet with copied data) are not cleaned up before the test exits. Consider calling conn->cn_if->ci_destroy(conn) before lsquic_mm_cleanup.

Suggested change
conn->cn_if->ci_destroy(conn);

Copilot uses AI. Check for mistakes.
conn->cn_if->ci_destroy(conn);
lsquic_mm_cleanup(&enpub.enp_mm);
}

int main(void) {
test_delayed_packet_corruption();
return 0;
}