Skip to content
Merged
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
17 changes: 16 additions & 1 deletion plugins/filter_kubernetes/kubernetes_aws.c
Original file line number Diff line number Diff line change
Expand Up @@ -246,6 +246,11 @@ int fetch_pod_service_map(struct flb_kube *ctx, char *api_server_url,

if (!c) {
flb_error("[kubernetes] could not create HTTP client");
#ifdef FLB_HAVE_TLS
if (u_conn->tls_session != NULL) {
flb_tls_session_destroy(u_conn->tls_session);
}
Comment thread
coderabbitai[bot] marked this conversation as resolved.
#endif
flb_upstream_conn_recycle(u_conn, FLB_FALSE);
flb_upstream_conn_release(u_conn);
flb_upstream_destroy(ctx->aws_pod_association_upstream);
Expand All @@ -267,6 +272,11 @@ int fetch_pod_service_map(struct flb_kube *ctx, char *api_server_url,
c->resp.payload);
}
flb_http_client_destroy(c);
#ifdef FLB_HAVE_TLS
if (u_conn->tls_session != NULL) {
flb_tls_session_destroy(u_conn->tls_session);
}
#endif
flb_upstream_conn_recycle(u_conn, FLB_FALSE);
flb_upstream_conn_release(u_conn);
return -1;
Expand All @@ -279,8 +289,13 @@ int fetch_pod_service_map(struct flb_kube *ctx, char *api_server_url,
parse_pod_service_map(ctx, c->resp.payload, c->resp.payload_size, mutex);
}

/* Cleanup - mark connection as non-recyclable to prevent memory leak */
/* Destroy TLS session explicitly; the background thread's event loop never drains the destroy_queue. */
flb_http_client_destroy(c);
#ifdef FLB_HAVE_TLS
if (u_conn->tls_session != NULL) {
flb_tls_session_destroy(u_conn->tls_session);
}
#endif
flb_upstream_conn_recycle(u_conn, FLB_FALSE);
flb_upstream_conn_release(u_conn);
}
Expand Down
124 changes: 96 additions & 28 deletions tests/internal/upstream_tls.c
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@

struct test_backend_ctx {
int invalidate_calls;
int destroy_calls;
};

static void test_session_invalidate(void *session)
Expand All @@ -29,6 +30,46 @@ static void test_session_invalidate(void *session)
}
}

static int test_session_destroy(void *session)
{
struct test_backend_ctx *ctx = session;

if (ctx != NULL) {
ctx->destroy_calls++;
}

return 0;
}

static int setup_conn(struct flb_connection *conn,
struct flb_upstream *upstream,
struct flb_config *config,
flb_pipefd_t *socket_pair)
{
if (flb_pipe_create(socket_pair) != 0) {
return -1;
}

config->is_shutting_down = FLB_FALSE;
upstream->base.config = config;
upstream->base.net.keepalive = FLB_FALSE;
upstream->tcp_host = "example";
upstream->tcp_port = 443;
flb_upstream_queue_init(&upstream->queue);

conn->fd = socket_pair[0];
conn->event.fd = conn->fd;
conn->event.status = 0;
conn->stream = (struct flb_stream *) upstream;
conn->net = &upstream->base.net;
conn->net_error = 0;

mk_list_init(&conn->_head);
mk_list_add(&conn->_head, &upstream->queue.busy_queue);

return 0;
}

void test_prepare_destroy_conn_marks_tls_session_stale(void)
{
struct test_backend_ctx backend_session = {0};
Expand All @@ -38,53 +79,28 @@ void test_prepare_destroy_conn_marks_tls_session_stale(void)
struct flb_connection conn = {0};
struct flb_upstream upstream = {0};
struct flb_config config = {0};
struct flb_upstream_queue *queue;
flb_pipefd_t socket_pair[2];
int ret;

#ifdef FLB_SYSTEM_WINDOWS
WSADATA wsa_data;

WSAStartup(0x0201, &wsa_data);
#endif

ret = flb_pipe_create(socket_pair);
TEST_CHECK(ret == 0);
TEST_CHECK(setup_conn(&conn, &upstream, &config, socket_pair) == 0);

backend_api.session_invalidate = test_session_invalidate;
tls_context.api = &backend_api;

tls_session.ptr = &backend_session;
tls_session.tls = &tls_context;
tls_session.connection = &conn;

config.is_shutting_down = FLB_FALSE;
upstream.base.config = &config;
upstream.base.net.keepalive = FLB_FALSE;
upstream.tcp_host = "example";
upstream.tcp_port = 443;

flb_upstream_queue_init(&upstream.queue);

conn.fd = socket_pair[0];
conn.event.fd = conn.fd;
conn.event.status = 0;
conn.stream = (struct flb_stream *) &upstream;
conn.net = &upstream.base.net;
conn.tls_session = &tls_session;
conn.net_error = 0;

mk_list_init(&conn._head);
queue = &upstream.queue;
mk_list_add(&conn._head, &queue->busy_queue);

ret = flb_upstream_conn_release(&conn);
TEST_CHECK(ret == 0);
TEST_CHECK(flb_upstream_conn_release(&conn) == 0);

TEST_CHECK(backend_session.invalidate_calls == 1);
TEST_CHECK(conn.fd == -1);
TEST_CHECK(conn.event.fd == -1);
TEST_CHECK(mk_list_size(&queue->destroy_queue) == 1);
TEST_CHECK(mk_list_size(&upstream.queue.destroy_queue) == 1);
TEST_CHECK(conn.shutdown_flag == FLB_TRUE);

flb_pipe_close(socket_pair[1]);
Expand All @@ -94,11 +110,63 @@ void test_prepare_destroy_conn_marks_tls_session_stale(void)
#endif
}

void test_tls_session_destroy_no_double_free(void)
{
struct test_backend_ctx backend_session = {0};
struct flb_tls_backend backend_api = {0};
struct flb_tls tls_context = {0};
struct flb_tls_session *tls_session;
struct flb_connection *conn;
struct flb_upstream upstream = {0};
struct flb_config config = {0};
flb_pipefd_t socket_pair[2];

#ifdef FLB_SYSTEM_WINDOWS
WSADATA wsa_data;
WSAStartup(0x0201, &wsa_data);
#endif

/* heap-allocate conn to match production; pending_destroy calls flb_free on it */
conn = flb_calloc(1, sizeof(struct flb_connection));
TEST_CHECK(conn != NULL);
conn->dynamically_allocated = FLB_TRUE;
TEST_CHECK(setup_conn(conn, &upstream, &config, socket_pair) == 0);

backend_api.session_invalidate = test_session_invalidate;
backend_api.session_destroy = test_session_destroy;
tls_context.api = &backend_api;

/* heap-allocated to match production; flb_tls_session_destroy calls flb_free */
tls_session = flb_calloc(1, sizeof(struct flb_tls_session));
TEST_CHECK(tls_session != NULL);
tls_session->ptr = &backend_session;
tls_session->tls = &tls_context;
tls_session->connection = conn;
conn->tls_session = tls_session;

/* explicit destroy before release β€” the fix */
TEST_CHECK(flb_tls_session_destroy(tls_session) == 0);
TEST_CHECK(conn->tls_session == NULL);

TEST_CHECK(flb_upstream_conn_release(conn) == 0);

/* pending_destroy must not double-free the already-destroyed session */
TEST_CHECK(flb_upstream_conn_pending_destroy(&upstream) == 0);
TEST_CHECK(backend_session.destroy_calls == 1);

flb_pipe_close(socket_pair[1]);

#ifdef FLB_SYSTEM_WINDOWS
WSACleanup();
#endif
}

#endif

TEST_LIST = {
#ifdef FLB_HAVE_TLS
{"prepare_destroy_conn_marks_tls_session_stale", test_prepare_destroy_conn_marks_tls_session_stale},
{"tls_session_destroy_no_double_free", test_tls_session_destroy_no_double_free},
#endif
{0}
};
Loading