From edaae9ba5e2bc6affb5db995c214233e64a264b5 Mon Sep 17 00:00:00 2001 From: saddamr3e Date: Sat, 20 Jun 2026 14:36:10 +0530 Subject: [PATCH 1/2] gzip: skip FCOMMENT terminator in streaming decompressor Signed-off-by: saddamr3e --- src/flb_gzip.c | 2 ++ tests/internal/gzip.c | 71 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 73 insertions(+) diff --git a/src/flb_gzip.c b/src/flb_gzip.c index 9943599ba83..f4181c9949d 100644 --- a/src/flb_gzip.c +++ b/src/flb_gzip.c @@ -807,6 +807,8 @@ static int flb_gzip_decompressor_process_optional_headers( return FLB_DECOMPRESSOR_INSUFFICIENT_DATA; } + xlen++; + context->read_buffer = &context->read_buffer[xlen]; context->input_buffer_length -= xlen; diff --git a/tests/internal/gzip.c b/tests/internal/gzip.c index 7c5d6a3052a..9ce7c9708cf 100644 --- a/tests/internal/gzip.c +++ b/tests/internal/gzip.c @@ -3,6 +3,7 @@ #include #include #include +#include #include "flb_tests_internal.h" @@ -291,8 +292,78 @@ void test_decompress_concatenated() flb_free(out); } +/* + * A gzip stream carrying an FCOMMENT field must decompress through the + * streaming decompressor used by the forward protocol. The comment is a + * NUL terminated string placed between the base header and the deflate + * body, so the parser has to skip its terminating NUL before handing the + * remaining bytes to inflate. + */ +void test_decompress_with_comment() +{ + int ret; + char *in_data = morpheus; + size_t in_len = strlen(morpheus); + void *gz; + size_t gz_len; + const char *comment = "fluent-bit"; + size_t comment_len = strlen(comment) + 1; /* include the NUL */ + uint8_t *stream; + size_t stream_len; + struct flb_decompression_context *dctx; + uint8_t *append_ptr; + char out[8192]; + size_t out_len; + size_t total = 0; + int iterations = 0; + + ret = flb_gzip_compress(in_data, in_len, &gz, &gz_len); + TEST_CHECK(ret == 0); + TEST_CHECK(gz_len > 10); + + /* Re-frame the payload with an FCOMMENT field inserted right after the + * 10 byte base header. */ + stream_len = gz_len + comment_len; + stream = flb_malloc(stream_len); + TEST_CHECK(stream != NULL); + + memcpy(stream, gz, 10); + stream[3] |= 0x10; /* FCOMMENT */ + memcpy(stream + 10, comment, comment_len); + memcpy(stream + 10 + comment_len, (uint8_t *) gz + 10, gz_len - 10); + + dctx = flb_decompression_context_create(FLB_COMPRESSION_ALGORITHM_GZIP, 0); + TEST_CHECK(dctx != NULL); + + append_ptr = flb_decompression_context_get_append_buffer(dctx); + memcpy(append_ptr, stream, stream_len); + dctx->input_buffer_length += stream_len; + + do { + out_len = sizeof(out); + ret = flb_decompress(dctx, out, &out_len); + if (ret != FLB_DECOMPRESSOR_SUCCESS) { + break; + } + if (out_len > 0) { + if (total + out_len <= in_len) { + TEST_CHECK(memcmp(out, morpheus + total, out_len) == 0); + } + total += out_len; + } + } while (dctx->input_buffer_length > 0 && ++iterations < 64); + + TEST_CHECK(ret == FLB_DECOMPRESSOR_SUCCESS); + TEST_CHECK(total == in_len); + + flb_decompression_context_destroy(dctx); + flb_free(stream); + flb_free(gz); +} + TEST_LIST = { {"compress", test_compress}, + {"decompress_with_comment", test_decompress_with_comment}, {"compress_multi", test_compress_multi}, {"compress_large", test_compress_large}, {"header_in_data", test_header_in_gzip_body}, From 7f0d887d2997958cccbf9c2807690f47e3ee4ec3 Mon Sep 17 00:00:00 2001 From: Saddam Date: Mon, 29 Jun 2026 12:35:35 +0530 Subject: [PATCH 2/2] gzip: use size_t for optional-header field length strnlen() returns size_t; widening xlen avoids truncation when skipping long FNAME/FCOMMENT fields. Signed-off-by: Saddam --- src/flb_gzip.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/flb_gzip.c b/src/flb_gzip.c index f4181c9949d..a5bd2454a7d 100644 --- a/src/flb_gzip.c +++ b/src/flb_gzip.c @@ -745,7 +745,7 @@ static int flb_gzip_decompressor_process_optional_headers( struct flb_gzip_decompression_context *inner_context; int status; uint16_t hcrc; - uint16_t xlen; + size_t xlen; uint16_t crc; inner_context = (struct flb_gzip_decompression_context *) \