Skip to content
Closed
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
48 changes: 45 additions & 3 deletions src/config_format/flb_cf_yaml.c
Original file line number Diff line number Diff line change
Expand Up @@ -2905,7 +2905,7 @@ static int read_config(struct flb_cf *conf, struct local_ctx *ctx,
}

flb_debug("============ %s ============", cfg_file);
fh = fopen(include_file, "r");
fh = fopen(include_file, "rb");

if (!fh) {
flb_errno();
Expand All @@ -2925,9 +2925,48 @@ static int read_config(struct flb_cf *conf, struct local_ctx *ctx,
return -1;
}
ctx->level++;

/*
* On Windows, passing FILE* across DLL boundaries can cause crashes due to
* different C runtime libraries. Read the file into a buffer and use
* yaml_parser_set_input_string() instead of yaml_parser_set_input_file().
*/
{
long file_size;
unsigned char *file_buffer = NULL;
size_t bytes_read;

/* Get file size */
fseek(fh, 0, SEEK_END);
file_size = ftell(fh);
fseek(fh, 0, SEEK_SET);

if (file_size < 0) {
flb_error("[config] could not determine file size for %s", cfg_file);
fclose(fh);
flb_sds_destroy(include_dir);
flb_sds_destroy(include_file);
return -1;
}

/* Allocate buffer */
file_buffer = flb_malloc(file_size + 1);
if (!file_buffer) {
flb_error("[config] could not allocate memory for config file %s", cfg_file);
fclose(fh);
flb_sds_destroy(include_dir);
flb_sds_destroy(include_file);
return -1;
}

/* Read file content */
bytes_read = fread(file_buffer, 1, file_size, fh);
fclose(fh);
fh = NULL; /* Mark as closed */
file_buffer[bytes_read] = '\0';
Comment on lines +2962 to +2966

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Treat short reads as errors before parsing

The new buffered read path never checks whether fread consumed the full file_size or whether ferror() was set. If an I/O error or concurrent truncation yields a short read, the parser will consume a truncated buffer and may succeed silently, leaving Fluent Bit running with an incomplete configuration. Please validate bytes_read == file_size (or check ferror) and fail the parse on short reads to preserve the prior behavior of surfacing read errors.

Useful? React with 👍 / 👎.


Comment on lines +2934 to +2967

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Add error checking after fread() to detect incomplete reads.

The code reads the file content but doesn't verify that the expected number of bytes were actually read. If fread() encounters an I/O error or EOF before reading file_size bytes, bytes_read will be less than expected, but the code continues silently. This could result in parsing an incomplete configuration file with cryptic YAML errors.

🔍 Proposed fix to add fread validation
         /* Read file content */
         bytes_read = fread(file_buffer, 1, file_size, fh);
+        if (bytes_read != (size_t)file_size) {
+            flb_error("[config] failed to read complete file %s: expected %ld bytes, got %zu bytes",
+                      cfg_file, file_size, bytes_read);
+            if (ferror(fh)) {
+                flb_error("[config] I/O error occurred while reading %s", cfg_file);
+            }
+            flb_free(file_buffer);
+            fclose(fh);
+            flb_sds_destroy(include_dir);
+            flb_sds_destroy(include_file);
+            return -1;
+        }
         fclose(fh);
         fh = NULL;  /* Mark as closed */
         file_buffer[bytes_read] = '\0';
🤖 Prompt for AI Agents
In `@src/config_format/flb_cf_yaml.c` around lines 2934 - 2967, After
fread(file_buffer, 1, file_size, fh) you must verify bytes_read == file_size and
handle incomplete reads: if bytes_read != file_size or ferror(fh) is set, log an
error with flb_error including cfg_file and the bytes_read/file_size values,
free file_buffer, close fh if not already closed, destroy include_dir and
include_file, and return -1 to avoid parsing a truncated config; use the
existing symbols file_buffer, bytes_read, file_size, fread, flb_error, fclose,
flb_sds_destroy (and flb_free or equivalent) to implement the check and cleanup.

yaml_parser_initialize(&parser);
yaml_parser_set_input_file(&parser, fh);
yaml_parser_set_input_string(&parser, file_buffer, bytes_read);

do {
status = yaml_parser_parse(&parser, &event);
Expand Down Expand Up @@ -2990,7 +3029,10 @@ static int read_config(struct flb_cf *conf, struct local_ctx *ctx,
state = state_pop(ctx);
}

fclose(fh);
/* Free the file buffer that was allocated for yaml_parser_set_input_string */
flb_free(file_buffer);
} /* End of block that declared file_buffer */

ctx->level--;

flb_sds_destroy(include_file);
Expand Down
Loading