|
20 | 20 | #include <fluent-bit/flb_log_event_decoder.h> |
21 | 21 | #include <fluent-bit/flb_byteswap.h> |
22 | 22 | #include <fluent-bit/flb_compat.h> |
| 23 | +#include <fluent-bit/flb_log.h> |
| 24 | + |
| 25 | +#define FLB_LOG_EVENT_DECODER_MAX_RECURSION_DEPTH 1000 /* Safety limit for recursion */ |
23 | 26 |
|
24 | 27 | static int create_empty_map(struct flb_log_event_decoder *context) { |
25 | 28 | msgpack_packer packer; |
@@ -74,6 +77,7 @@ void flb_log_event_decoder_reset(struct flb_log_event_decoder *context, |
74 | 77 | context->last_result = FLB_EVENT_DECODER_ERROR_INSUFFICIENT_DATA; |
75 | 78 | context->current_group_metadata = NULL; |
76 | 79 | context->current_group_attributes = NULL; |
| 80 | + context->recursion_depth = 0; /* Reset recursion counter */ |
77 | 81 |
|
78 | 82 | msgpack_unpacked_destroy(&context->unpacked_group_record); |
79 | 83 | msgpack_unpacked_init(&context->unpacked_group_record); |
@@ -309,6 +313,7 @@ int flb_log_event_decoder_next(struct flb_log_event_decoder *context, |
309 | 313 | int result; |
310 | 314 | int record_type; |
311 | 315 | size_t previous_offset; |
| 316 | + int32_t invalid_timestamp; |
312 | 317 |
|
313 | 318 | if (context == NULL) { |
314 | 319 | return FLB_EVENT_DECODER_ERROR_INVALID_CONTEXT; |
@@ -347,22 +352,43 @@ int flb_log_event_decoder_next(struct flb_log_event_decoder *context, |
347 | 352 | &context->unpacked_event.data); |
348 | 353 |
|
349 | 354 | if (context->last_result == FLB_EVENT_DECODER_SUCCESS) { |
| 355 | + /* Check recursion depth limit to prevent stack overflow */ |
| 356 | + if (context->recursion_depth >= FLB_LOG_EVENT_DECODER_MAX_RECURSION_DEPTH) { |
| 357 | + flb_warn("[decoder] Maximum recursion depth (%d) reached, possible corruption or excessive group markers", |
| 358 | + FLB_LOG_EVENT_DECODER_MAX_RECURSION_DEPTH); |
| 359 | + context->last_result = FLB_EVENT_DECODER_ERROR_DESERIALIZATION_FAILURE; |
| 360 | + return context->last_result; |
| 361 | + } |
| 362 | + |
350 | 363 | /* get log event type */ |
351 | 364 | ret = flb_log_event_decoder_get_record_type(event, &record_type); |
352 | 365 | if (ret != 0) { |
353 | | - context->current_group_metadata = NULL; |
354 | | - context->current_group_attributes = NULL; |
355 | | - |
356 | | - context->last_result = FLB_EVENT_DECODER_ERROR_DESERIALIZATION_FAILURE; |
357 | | - return context->last_result; |
| 366 | + /* Invalid group marker (negative timestamp but not -1 or -2). |
| 367 | + * Log the invalid marker for debugging, but preserve group state |
| 368 | + * to avoid losing valid group metadata if corruption occurs mid-group. |
| 369 | + * Skip the record and continue processing. |
| 370 | + */ |
| 371 | + invalid_timestamp = (int32_t) event->timestamp.tm.tv_sec; |
| 372 | + flb_debug("[decoder] Invalid group marker timestamp (%d), skipping record. " |
| 373 | + "Group state preserved.", invalid_timestamp); |
| 374 | + |
| 375 | + /* Increment recursion depth before recursive call */ |
| 376 | + context->recursion_depth++; |
| 377 | + memset(event, 0, sizeof(struct flb_log_event)); |
| 378 | + ret = flb_log_event_decoder_next(context, event); |
| 379 | + context->recursion_depth--; /* Restore after return */ |
| 380 | + return ret; |
358 | 381 | } |
359 | 382 |
|
360 | 383 | /* Meta records such as the group opener and closer are identified by negative |
361 | | - * timestamp values. In these cases we track the current group metadata and |
362 | | - * attributes in order to transparently provide them through the log_event |
363 | | - * structure but we also want to allow the client code raw access to such |
364 | | - * records which is why the read_groups decoder context property is used |
365 | | - * to determine the behavior. |
| 384 | + * timestamp values (-1 for GROUP_START, -2 for GROUP_END). Only these two |
| 385 | + * negative values are valid; any other negative timestamp is considered |
| 386 | + * invalid and is skipped (see handling above). |
| 387 | + * |
| 388 | + * We track the current group metadata and attributes in order to transparently |
| 389 | + * provide them through the log_event structure, but we also want to allow the |
| 390 | + * client code raw access to such records, which is why the read_groups decoder |
| 391 | + * context property is used to determine the behavior. |
366 | 392 | */ |
367 | 393 | if (record_type != FLB_LOG_EVENT_NORMAL) { |
368 | 394 | msgpack_unpacked_destroy(&context->unpacked_group_record); |
@@ -411,9 +437,13 @@ int flb_log_event_decoder_next(struct flb_log_event_decoder *context, |
411 | 437 | * Skip group markers by recursively calling to get next record. |
412 | 438 | * msgpack_unpack_next will properly destroy and reinitialize |
413 | 439 | * unpacked_event, so no explicit cleanup needed here. |
| 440 | + * Increment recursion depth before recursive call. |
414 | 441 | */ |
| 442 | + context->recursion_depth++; |
415 | 443 | memset(event, 0, sizeof(struct flb_log_event)); |
416 | | - return flb_log_event_decoder_next(context, event); |
| 444 | + ret = flb_log_event_decoder_next(context, event); |
| 445 | + context->recursion_depth--; /* Restore after return */ |
| 446 | + return ret; |
417 | 447 | } |
418 | 448 | } |
419 | 449 | else { |
|
0 commit comments