Skip to content

Commit 8d08559

Browse files
committed
out_azure_kusto: fix SIGSEGV in nested mk_list_foreach_safe loops
The ingest_all_chunks() function had nested mk_list_foreach_safe loops that both used the same 'tmp' variable as the iterator. The macro stores the 'next' pointer in its second argument for safe iteration during list modification. When the inner loop overwrote 'tmp', it corrupted the outer loop's iteration state, causing undefined behavior and a SIGSEGV crash when processing buffered backlog data on startup. Fix: Add a dedicated 'f_tmp' variable for the inner loop to prevent iterator corruption. Also adds a regression test (buffering_backlog) that exercises the buffering/backlog restart code path to guard against future regressions. Signed-off-by: Yash Ananth <[email protected]>
1 parent f4108db commit 8d08559

File tree

2 files changed

+75
-1
lines changed

2 files changed

+75
-1
lines changed

plugins/out_azure_kusto/azure_kusto.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -409,6 +409,7 @@ static int ingest_all_chunks(struct flb_azure_kusto *ctx, struct flb_config *con
409409
struct azure_kusto_file *chunk;
410410
struct mk_list *tmp;
411411
struct mk_list *head;
412+
struct mk_list *f_tmp;
412413
struct mk_list *f_head;
413414
struct flb_fstore_file *fsf;
414415
struct flb_fstore_stream *fs_stream;
@@ -427,7 +428,7 @@ static int ingest_all_chunks(struct flb_azure_kusto *ctx, struct flb_config *con
427428
continue;
428429
}
429430

430-
mk_list_foreach_safe(f_head, tmp, &fs_stream->files) {
431+
mk_list_foreach_safe(f_head, f_tmp, &fs_stream->files) {
431432
fsf = mk_list_entry(f_head, struct flb_fstore_file, _head);
432433
chunk = fsf->data;
433434

tests/runtime/out_azure_kusto.c

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ void flb_test_azure_kusto_managed_identity_system(void);
3030
void flb_test_azure_kusto_managed_identity_user(void);
3131
void flb_test_azure_kusto_service_principal(void);
3232
void flb_test_azure_kusto_workload_identity(void);
33+
void flb_test_azure_kusto_buffering_backlog(void);
3334

3435
/* Test list */
3536
TEST_LIST = {
@@ -38,6 +39,7 @@ TEST_LIST = {
3839
{"managed_identity_user", flb_test_azure_kusto_managed_identity_user},
3940
{"service_principal", flb_test_azure_kusto_service_principal},
4041
{"workload_identity", flb_test_azure_kusto_workload_identity},
42+
{"buffering_backlog", flb_test_azure_kusto_buffering_backlog},
4143
{NULL, NULL}
4244
};
4345

@@ -208,6 +210,77 @@ void flb_test_azure_kusto_workload_identity(void)
208210
ret = flb_start(ctx);
209211
TEST_CHECK(ret == 0);
210212

213+
flb_stop(ctx);
214+
flb_destroy(ctx);
215+
}
216+
217+
void flb_test_azure_kusto_buffering_backlog(void)
218+
{
219+
int i;
220+
int ret;
221+
int bytes;
222+
char sample[] = "{\"k\":\"v\"}";
223+
size_t sample_size = sizeof(sample) - 1;
224+
flb_ctx_t *ctx;
225+
int in_ffd;
226+
int out_ffd;
227+
228+
/* First run: enable buffering and write data to disk */
229+
ctx = flb_create();
230+
flb_service_set(ctx, "Flush", "1", "Grace", "1", "Log_Level", "error", NULL);
231+
232+
in_ffd = flb_input(ctx, (char *) "lib", NULL);
233+
TEST_CHECK(in_ffd >= 0);
234+
flb_input_set(ctx, in_ffd, "tag", "test", NULL);
235+
236+
out_ffd = flb_output(ctx, (char *) "azure_kusto", NULL);
237+
TEST_CHECK(out_ffd >= 0);
238+
flb_output_set(ctx, out_ffd, "match", "test", NULL);
239+
flb_output_set(ctx, out_ffd, "auth_type", "managed_identity", NULL);
240+
flb_output_set(ctx, out_ffd, "client_id", "system", NULL);
241+
flb_output_set(ctx, out_ffd, "ingestion_endpoint", "https://ingest-CLUSTER.kusto.windows.net", NULL);
242+
flb_output_set(ctx, out_ffd, "database_name", "telemetrydb", NULL);
243+
flb_output_set(ctx, out_ffd, "table_name", "logs", NULL);
244+
flb_output_set(ctx, out_ffd, "buffering_enabled", "true", NULL);
245+
flb_output_set(ctx, out_ffd, "buffer_dir", "/tmp/fluent-bit-kusto-test/", NULL);
246+
247+
ret = flb_start(ctx);
248+
TEST_CHECK(ret == 0);
249+
250+
for (i = 0; i < 5; i++) {
251+
bytes = flb_lib_push(ctx, in_ffd, sample, sample_size);
252+
TEST_CHECK(bytes == (int) sample_size);
253+
}
254+
255+
sleep(1); /* allow flush to write buffered chunks */
256+
257+
flb_stop(ctx);
258+
flb_destroy(ctx);
259+
260+
/* Second run: restart to process backlog from buffer_dir */
261+
ctx = flb_create();
262+
flb_service_set(ctx, "Flush", "1", "Grace", "1", "Log_Level", "error", NULL);
263+
264+
in_ffd = flb_input(ctx, (char *) "lib", NULL);
265+
TEST_CHECK(in_ffd >= 0);
266+
flb_input_set(ctx, in_ffd, "tag", "test", NULL);
267+
268+
out_ffd = flb_output(ctx, (char *) "azure_kusto", NULL);
269+
TEST_CHECK(out_ffd >= 0);
270+
flb_output_set(ctx, out_ffd, "match", "test", NULL);
271+
flb_output_set(ctx, out_ffd, "auth_type", "managed_identity", NULL);
272+
flb_output_set(ctx, out_ffd, "client_id", "system", NULL);
273+
flb_output_set(ctx, out_ffd, "ingestion_endpoint", "https://ingest-CLUSTER.kusto.windows.net", NULL);
274+
flb_output_set(ctx, out_ffd, "database_name", "telemetrydb", NULL);
275+
flb_output_set(ctx, out_ffd, "table_name", "logs", NULL);
276+
flb_output_set(ctx, out_ffd, "buffering_enabled", "true", NULL);
277+
flb_output_set(ctx, out_ffd, "buffer_dir", "/tmp/fluent-bit-kusto-test/", NULL);
278+
279+
ret = flb_start(ctx);
280+
TEST_CHECK(ret == 0);
281+
282+
sleep(1); /* ingest_all_chunks runs on startup for buffered backlog */
283+
211284
flb_stop(ctx);
212285
flb_destroy(ctx);
213286
}

0 commit comments

Comments
 (0)