Skip to content

Commit 7acbf54

Browse files
ShelbyZedsiper
authored andcommitted
tests: internal: upstream_tls: verify TLS session destroy prevents double-free
Signed-off-by: Shelby Hagman <shelbyzh@amazon.com>
1 parent 7733667 commit 7acbf54

1 file changed

Lines changed: 96 additions & 28 deletions

File tree

tests/internal/upstream_tls.c

Lines changed: 96 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818

1919
struct test_backend_ctx {
2020
int invalidate_calls;
21+
int destroy_calls;
2122
};
2223

2324
static void test_session_invalidate(void *session)
@@ -29,6 +30,46 @@ static void test_session_invalidate(void *session)
2930
}
3031
}
3132

33+
static int test_session_destroy(void *session)
34+
{
35+
struct test_backend_ctx *ctx = session;
36+
37+
if (ctx != NULL) {
38+
ctx->destroy_calls++;
39+
}
40+
41+
return 0;
42+
}
43+
44+
static int setup_conn(struct flb_connection *conn,
45+
struct flb_upstream *upstream,
46+
struct flb_config *config,
47+
flb_pipefd_t *socket_pair)
48+
{
49+
if (flb_pipe_create(socket_pair) != 0) {
50+
return -1;
51+
}
52+
53+
config->is_shutting_down = FLB_FALSE;
54+
upstream->base.config = config;
55+
upstream->base.net.keepalive = FLB_FALSE;
56+
upstream->tcp_host = "example";
57+
upstream->tcp_port = 443;
58+
flb_upstream_queue_init(&upstream->queue);
59+
60+
conn->fd = socket_pair[0];
61+
conn->event.fd = conn->fd;
62+
conn->event.status = 0;
63+
conn->stream = (struct flb_stream *) upstream;
64+
conn->net = &upstream->base.net;
65+
conn->net_error = 0;
66+
67+
mk_list_init(&conn->_head);
68+
mk_list_add(&conn->_head, &upstream->queue.busy_queue);
69+
70+
return 0;
71+
}
72+
3273
void test_prepare_destroy_conn_marks_tls_session_stale(void)
3374
{
3475
struct test_backend_ctx backend_session = {0};
@@ -38,53 +79,28 @@ void test_prepare_destroy_conn_marks_tls_session_stale(void)
3879
struct flb_connection conn = {0};
3980
struct flb_upstream upstream = {0};
4081
struct flb_config config = {0};
41-
struct flb_upstream_queue *queue;
4282
flb_pipefd_t socket_pair[2];
43-
int ret;
4483

4584
#ifdef FLB_SYSTEM_WINDOWS
4685
WSADATA wsa_data;
47-
4886
WSAStartup(0x0201, &wsa_data);
4987
#endif
5088

51-
ret = flb_pipe_create(socket_pair);
52-
TEST_CHECK(ret == 0);
89+
TEST_CHECK(setup_conn(&conn, &upstream, &config, socket_pair) == 0);
5390

5491
backend_api.session_invalidate = test_session_invalidate;
5592
tls_context.api = &backend_api;
56-
5793
tls_session.ptr = &backend_session;
5894
tls_session.tls = &tls_context;
5995
tls_session.connection = &conn;
60-
61-
config.is_shutting_down = FLB_FALSE;
62-
upstream.base.config = &config;
63-
upstream.base.net.keepalive = FLB_FALSE;
64-
upstream.tcp_host = "example";
65-
upstream.tcp_port = 443;
66-
67-
flb_upstream_queue_init(&upstream.queue);
68-
69-
conn.fd = socket_pair[0];
70-
conn.event.fd = conn.fd;
71-
conn.event.status = 0;
72-
conn.stream = (struct flb_stream *) &upstream;
73-
conn.net = &upstream.base.net;
7496
conn.tls_session = &tls_session;
75-
conn.net_error = 0;
76-
77-
mk_list_init(&conn._head);
78-
queue = &upstream.queue;
79-
mk_list_add(&conn._head, &queue->busy_queue);
8097

81-
ret = flb_upstream_conn_release(&conn);
82-
TEST_CHECK(ret == 0);
98+
TEST_CHECK(flb_upstream_conn_release(&conn) == 0);
8399

84100
TEST_CHECK(backend_session.invalidate_calls == 1);
85101
TEST_CHECK(conn.fd == -1);
86102
TEST_CHECK(conn.event.fd == -1);
87-
TEST_CHECK(mk_list_size(&queue->destroy_queue) == 1);
103+
TEST_CHECK(mk_list_size(&upstream.queue.destroy_queue) == 1);
88104
TEST_CHECK(conn.shutdown_flag == FLB_TRUE);
89105

90106
flb_pipe_close(socket_pair[1]);
@@ -94,11 +110,63 @@ void test_prepare_destroy_conn_marks_tls_session_stale(void)
94110
#endif
95111
}
96112

113+
void test_tls_session_destroy_no_double_free(void)
114+
{
115+
struct test_backend_ctx backend_session = {0};
116+
struct flb_tls_backend backend_api = {0};
117+
struct flb_tls tls_context = {0};
118+
struct flb_tls_session *tls_session;
119+
struct flb_connection *conn;
120+
struct flb_upstream upstream = {0};
121+
struct flb_config config = {0};
122+
flb_pipefd_t socket_pair[2];
123+
124+
#ifdef FLB_SYSTEM_WINDOWS
125+
WSADATA wsa_data;
126+
WSAStartup(0x0201, &wsa_data);
127+
#endif
128+
129+
/* heap-allocate conn to match production; pending_destroy calls flb_free on it */
130+
conn = flb_calloc(1, sizeof(struct flb_connection));
131+
TEST_CHECK(conn != NULL);
132+
conn->dynamically_allocated = FLB_TRUE;
133+
TEST_CHECK(setup_conn(conn, &upstream, &config, socket_pair) == 0);
134+
135+
backend_api.session_invalidate = test_session_invalidate;
136+
backend_api.session_destroy = test_session_destroy;
137+
tls_context.api = &backend_api;
138+
139+
/* heap-allocated to match production; flb_tls_session_destroy calls flb_free */
140+
tls_session = flb_calloc(1, sizeof(struct flb_tls_session));
141+
TEST_CHECK(tls_session != NULL);
142+
tls_session->ptr = &backend_session;
143+
tls_session->tls = &tls_context;
144+
tls_session->connection = conn;
145+
conn->tls_session = tls_session;
146+
147+
/* explicit destroy before release — the fix */
148+
TEST_CHECK(flb_tls_session_destroy(tls_session) == 0);
149+
TEST_CHECK(conn->tls_session == NULL);
150+
151+
TEST_CHECK(flb_upstream_conn_release(conn) == 0);
152+
153+
/* pending_destroy must not double-free the already-destroyed session */
154+
TEST_CHECK(flb_upstream_conn_pending_destroy(&upstream) == 0);
155+
TEST_CHECK(backend_session.destroy_calls == 1);
156+
157+
flb_pipe_close(socket_pair[1]);
158+
159+
#ifdef FLB_SYSTEM_WINDOWS
160+
WSACleanup();
161+
#endif
162+
}
163+
97164
#endif
98165

99166
TEST_LIST = {
100167
#ifdef FLB_HAVE_TLS
101168
{"prepare_destroy_conn_marks_tls_session_stale", test_prepare_destroy_conn_marks_tls_session_stale},
169+
{"tls_session_destroy_no_double_free", test_tls_session_destroy_no_double_free},
102170
#endif
103171
{0}
104172
};

0 commit comments

Comments
 (0)