Skip to content

in_winevtlog: Plug possible SEGV occurrence paths#10849

Merged
edsiper merged 2 commits intomasterfrom
cosmo0920-plug-missing-null-checks-for-in_winevtlog
Sep 8, 2025
Merged

in_winevtlog: Plug possible SEGV occurrence paths#10849
edsiper merged 2 commits intomasterfrom
cosmo0920-plug-missing-null-checks-for-in_winevtlog

Conversation

@cosmo0920
Copy link
Contributor

@cosmo0920 cosmo0920 commented Sep 8, 2025

I checked possible SEGV occurrence paths on in_winetvlog plugin.
And I found some of places could occur SEGV because of NULLs.
So, we need to plug those paths.


Enter [N/A] in the box, if an item is not applicable to your change.

Testing
Before we can approve your change; please submit the following in a comment:

  • Example configuration file for the change
  • Debug log output from testing the change
  • Attached Valgrind output that shows no leaks or memory corruption was found

If this is a change to packaging of containers or native binaries then please confirm it works for all targets.

  • Run local packaging test showing all targets (including any new ones) build.
  • Set ok-package-test label to test for all targets (requires maintainer to do).

Documentation

  • Documentation required for this feature

Backporting

  • Backport to latest stable release.

Fluent Bit is licensed under Apache 2.0, by submitting this pull request I understand that this code will be released under the terms of that license.

Summary by CodeRabbit

  • Bug Fixes

    • Prevented crashes by treating missing/null event fields as absent when packing Windows Event Log data.
    • Ensured GUID fields (ActivityID/RelatedActivityID/ProviderGuid) are only packed when present, avoiding invalid conversions.
    • Aligned character-encoding handling to respect field presence and reduce errors on edge cases.
  • Chores

    • Added defensive input validation and safer null checks to improve stability during event packing.

Signed-off-by: Hiroshi Hatake <hiroshi@chronosphere.io>
@coderabbitai
Copy link

coderabbitai bot commented Sep 8, 2025

Walkthrough

Centralizes string encoding with a new pack_str_codepage, adds pack_astr for ANSI→wide conversion, adds null guards for GUIDs, updates pack_string_inserts to use pack_astr for ANSI types, and makes winevtlog_pack_event Type-aware when packing GUIDs, emitting null strings when Type indicates absence.

Changes

Cohort / File(s) Summary of Changes
Encoding helpers & ANSI handling
plugins/in_winevtlog/pack.c
- Added pack_str_codepage(ctx, wstr, code_page, use_ansi) to centralize WideChar→multi-byte encoding and buffer handling.
- Replaced pack_wstr implementation to call pack_str_codepage(..., CP_UTF8, ctx->use_ansi).
ANSI→wide conversion utility
plugins/in_winevtlog/pack.c
- Added pack_astr(ctx, astr) to convert ANSI char*wchar_t* via CP_ACP and then pack via pack_wstr. Handles allocation and errors.
GUID and null-safety changes
plugins/in_winevtlog/pack.c
- pack_guid now checks for NULL GUID* and returns -1 on NULL.
- pack_string_inserts uses pack_astr for EVTVarTypeAnsiString entries.
- winevtlog_pack_event updated to only attempt packing ActivityID, RelatedActivityID, ProviderGuid when their Type is not EVTVarTypeNull; emits null strings otherwise and treats pack failures by emitting null.

Sequence Diagram(s)

sequenceDiagram
    autonumber
    participant W as winevtlog_pack_event
    participant S as pack_string_inserts
    participant P as pack_guid
    participant C as pack_str_codepage

    Note over W: Event packing entry

    W->>S: iterate event values
    alt value.Type == EVTVarTypeAnsiString
        S->>C: pack_astr -> converts ANSI to wide
        C-->>S: encoded bytes (via pack_str_codepage)
    else value.Type == EVTVarTypeString
        S->>C: pack_wstr -> pack_str_codepage(CP_UTF8 or ANSI)
        C-->>S: encoded bytes
    end

    Note over W: GUID fields handling
    alt GUID Type != EVTVarTypeNull
        W->>P: pack_guid(guid)
        alt success
            P-->>W: packed GUID string
        else failure
            P-->>W: indicate failure -> W emits null string
        end
    else Type == EVTVarTypeNull
        W-->>W: emit null string (skip pack_guid)
    end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Suggested reviewers

  • edsiper
  • koleini
  • fujimotos

Poem

A rabbit tidies bytes with care,
Converts and guards the GUIDs I bear.
If Type says “none,” I softly spare—
Pack a null whisper, light as air.
Hopping clean through code I fare. 🐇

✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch cosmo0920-plug-missing-null-checks-for-in_winevtlog

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
plugins/in_winevtlog/pack.c (1)

395-397: Fix: EvtVarTypeAnsiString passes char to pack_wstr (expects wchar_t) — potential SEGV**

pack_wstr expects UTF-16 (wchar_t*). Feeding values[i].AnsiStringVal (char*) can misalign reads and crash. Convert ANSI -> UTF-16 (CP_ACP) and then reuse pack_wstr, or encode directly to UTF-8.

Apply this diff here:

-        case EvtVarTypeAnsiString:
-            if (pack_wstr(ctx, values[i].AnsiStringVal)) {
+        case EvtVarTypeAnsiString:
+            if (pack_astr(ctx, values[i].AnsiStringVal)) {
                 pack_nullstr(ctx);
             }
             break;

Add this helper (place near pack_wstr):

/* Convert ANSI (CP_ACP) char* to UTF-16 and reuse pack_wstr */
static int pack_astr(struct winevtlog_config *ctx, const char *astr)
{
    int wsize;
    wchar_t *wbuf;

    if (!astr) {
        return -1;
    }

    wsize = MultiByteToWideChar(CP_ACP, 0, astr, -1, NULL, 0);
    if (wsize == 0) {
        return -1;
    }

    wbuf = flb_malloc(sizeof(wchar_t) * wsize);
    if (!wbuf) {
        flb_errno();
        return -1;
    }

    if (MultiByteToWideChar(CP_ACP, 0, astr, -1, wbuf, wsize) == 0) {
        flb_free(wbuf);
        return -1;
    }

    /* pack_wstr handles UTF-16 -> UTF-8/ACP per ctx->use_ansi */
    if (pack_wstr(ctx, wbuf)) {
        flb_free(wbuf);
        return -1;
    }

    flb_free(wbuf);
    return 0;
}
🧹 Nitpick comments (1)
plugins/in_winevtlog/pack.c (1)

45-49: Good null-guard and correct defaultChar type; consider safer fallback

Null check prevents SEGV; switching to const char* fixes the API type. Minor: replacing unrepresentable chars with a space can hide data. Prefer ? or NULL (especially for CP_UTF8 where all code points are representable).

Option A (minimal):

-    const char *defaultChar = " ";
+    const char *defaultChar = "?";

Option B (avoid substitution for UTF-8):

/* after deciding code_page */
if (code_page == CP_UTF8) {
    defaultChar = NULL;
}
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 070e761 and 7f92a16.

📒 Files selected for processing (1)
  • plugins/in_winevtlog/pack.c (3 hunks)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (29)
  • GitHub Check: pr-windows-build / call-build-windows-package (Windows 64bit, x64, x64-windows-static, 3.31.6)
  • GitHub Check: pr-windows-build / call-build-windows-package (Windows 64bit (Arm64), amd64_arm64, -DCMAKE_SYSTEM_NAME=Windows -DCMA...
  • GitHub Check: pr-windows-build / call-build-windows-package (Windows 32bit, x86, x86-windows-static, 3.31.6)
  • GitHub Check: run-ubuntu-unit-tests (-DFLB_COVERAGE=On, 3.31.6, gcc, g++)
  • GitHub Check: run-ubuntu-unit-tests (-DFLB_SIMD=Off, 3.31.6, gcc, g++)
  • GitHub Check: run-ubuntu-unit-tests (-DFLB_SIMD=Off, 3.31.6, clang, clang++)
  • GitHub Check: run-ubuntu-unit-tests (-DFLB_ARROW=On, 3.31.6, gcc, g++)
  • GitHub Check: run-ubuntu-unit-tests (-DFLB_SIMD=On, 3.31.6, gcc, g++)
  • GitHub Check: run-ubuntu-unit-tests (-DFLB_SANITIZE_THREAD=On, 3.31.6, clang, clang++)
  • GitHub Check: run-ubuntu-unit-tests (-DSANITIZE_ADDRESS=On, 3.31.6, gcc, g++)
  • GitHub Check: run-ubuntu-unit-tests (-DFLB_SANITIZE_THREAD=On, 3.31.6, gcc, g++)
  • GitHub Check: run-ubuntu-unit-tests (-DSANITIZE_UNDEFINED=On, 3.31.6, gcc, g++)
  • GitHub Check: run-ubuntu-unit-tests (-DFLB_SIMD=On, 3.31.6, clang, clang++)
  • GitHub Check: run-ubuntu-unit-tests (-DSANITIZE_UNDEFINED=On, 3.31.6, clang, clang++)
  • GitHub Check: run-ubuntu-unit-tests (-DFLB_SANITIZE_MEMORY=On, 3.31.6, clang, clang++)
  • GitHub Check: run-ubuntu-unit-tests (-DFLB_JEMALLOC=Off, 3.31.6, gcc, g++)
  • GitHub Check: run-ubuntu-unit-tests (-DFLB_SANITIZE_MEMORY=On, 3.31.6, gcc, g++)
  • GitHub Check: run-ubuntu-unit-tests (-DFLB_JEMALLOC=Off, 3.31.6, clang, clang++)
  • GitHub Check: run-ubuntu-unit-tests (-DSANITIZE_ADDRESS=On, 3.31.6, clang, clang++)
  • GitHub Check: run-ubuntu-unit-tests (-DFLB_SMALL=On, 3.31.6, gcc, g++)
  • GitHub Check: run-ubuntu-unit-tests (-DFLB_JEMALLOC=On, 3.31.6, gcc, g++)
  • GitHub Check: run-ubuntu-unit-tests (-DFLB_JEMALLOC=On, 3.31.6, clang, clang++)
  • GitHub Check: run-ubuntu-unit-tests (-DFLB_SMALL=On, 3.31.6, clang, clang++)
  • GitHub Check: pr-compile-system-libs (-DFLB_PREFER_SYSTEM_LIBS=On, 3.31.6, clang, clang++, ubuntu-22.04, clang-12)
  • GitHub Check: pr-compile-centos-7
  • GitHub Check: pr-compile-system-libs (-DFLB_PREFER_SYSTEM_LIBS=On, 3.31.6, gcc, g++, ubuntu-22.04, clang-12)
  • GitHub Check: pr-compile-system-libs (-DFLB_PREFER_SYSTEM_LIBS=On, 3.31.6, clang, clang++, ubuntu-24.04, clang-14)
  • GitHub Check: pr-compile-system-libs (-DFLB_PREFER_SYSTEM_LIBS=On, 3.31.6, gcc, g++, ubuntu-24.04, clang-14)
  • GitHub Check: PR - fuzzing test
🔇 Additional comments (3)
plugins/in_winevtlog/pack.c (3)

117-119: LGTM: Defensive null check in pack_guid

Prevents passing NULL to StringFromCLSID. Matches new call-site guards.


649-656: LGTM: Guard ActivityID by variant type before packing GUID

Avoids dereferencing absent GUIDs and aligns with pack_guid’s contract.


661-668: LGTM: Guard RelatedActivityID similarly

Symmetric handling prevents invalid GUID packing on null values.

Signed-off-by: Hiroshi Hatake <hiroshi@chronosphere.io>
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (2)
plugins/in_winevtlog/pack.c (2)

40-72: Centralized encoder: good; consider propagating encoder errors and avoiding best-fit conversions.

  • Wide→multi-byte path looks correct and frees on all error branches.
  • Two small improvements:
    1. Propagate the return value of flb_log_event_encoder_append_body_string so callers can react.
    2. When emitting CP_ACP, add WC_NO_BEST_FIT_CHARS to prevent silent “?” substitutions.
 static int pack_str_codepage(struct winevtlog_config *ctx, const wchar_t *wstr,
                              UINT code_page, BOOL use_ansi)
 {
-    UINT cp = use_ansi ? CP_ACP : code_page;
-    DWORD flags = (cp == CP_UTF8) ? WC_ERR_INVALID_CHARS : 0;
+    UINT cp = use_ansi ? CP_ACP : code_page;
+    DWORD flags = (cp == CP_UTF8) ? WC_ERR_INVALID_CHARS : WC_NO_BEST_FIT_CHARS;
     int size = 0;
     char *buf = NULL;
+    int rc = 0;
@@
-    flb_log_event_encoder_append_body_string(ctx->log_encoder, buf, size - 1);
+    rc = flb_log_event_encoder_append_body_string(ctx->log_encoder, buf, size - 1);
     flb_free(buf);
-    return 0;
+    return (rc == FLB_EVENT_ENCODER_SUCCESS) ? 0 : -1;
 }

79-108: ANSI→wide→encoded path looks solid; add debug on conversion failures.

Great cleanup and ownership handling. Add minimal diagnostics to ease field triage when MultiByteToWideChar fails.

-    wlen = MultiByteToWideChar(CP_ACP, MB_ERR_INVALID_CHARS, astr, -1, NULL, 0);
+    wlen = MultiByteToWideChar(CP_ACP, MB_ERR_INVALID_CHARS, astr, -1, NULL, 0);
     if (wlen == 0) {
-        return -1;
+        flb_plg_debug(ctx->ins, "pack_astr: preflight conversion failed, err=%lu", GetLastError());
+        return -1;
     }
@@
-    if (MultiByteToWideChar(CP_ACP, MB_ERR_INVALID_CHARS, astr, -1, wbuf, wlen) == 0) {
-        flb_free(wbuf);
-        return -1;
-    }
+    if (MultiByteToWideChar(CP_ACP, MB_ERR_INVALID_CHARS, astr, -1, wbuf, wlen) == 0) {
+        DWORD err = GetLastError();
+        flb_free(wbuf);
+        flb_plg_debug(ctx->ins, "pack_astr: conversion failed, err=%lu", err);
+        return -1;
+    }
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 7f92a16 and d433b87.

📒 Files selected for processing (1)
  • plugins/in_winevtlog/pack.c (4 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
plugins/in_winevtlog/pack.c (1)
include/fluent-bit/flb_mem.h (1)
  • flb_free (126-128)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (29)
  • GitHub Check: pr-windows-build / call-build-windows-package (Windows 64bit, x64, x64-windows-static, 3.31.6)
  • GitHub Check: pr-windows-build / call-build-windows-package (Windows 64bit (Arm64), amd64_arm64, -DCMAKE_SYSTEM_NAME=Windows -DCMA...
  • GitHub Check: pr-windows-build / call-build-windows-package (Windows 32bit, x86, x86-windows-static, 3.31.6)
  • GitHub Check: run-ubuntu-unit-tests (-DFLB_SANITIZE_MEMORY=On, 3.31.6, clang, clang++)
  • GitHub Check: run-ubuntu-unit-tests (-DFLB_ARROW=On, 3.31.6, gcc, g++)
  • GitHub Check: run-ubuntu-unit-tests (-DFLB_SIMD=On, 3.31.6, gcc, g++)
  • GitHub Check: run-ubuntu-unit-tests (-DFLB_SANITIZE_THREAD=On, 3.31.6, gcc, g++)
  • GitHub Check: run-ubuntu-unit-tests (-DFLB_SMALL=On, 3.31.6, clang, clang++)
  • GitHub Check: run-ubuntu-unit-tests (-DFLB_SIMD=Off, 3.31.6, gcc, g++)
  • GitHub Check: run-ubuntu-unit-tests (-DFLB_SANITIZE_THREAD=On, 3.31.6, clang, clang++)
  • GitHub Check: run-ubuntu-unit-tests (-DFLB_SIMD=On, 3.31.6, clang, clang++)
  • GitHub Check: run-ubuntu-unit-tests (-DFLB_SIMD=Off, 3.31.6, clang, clang++)
  • GitHub Check: run-ubuntu-unit-tests (-DSANITIZE_UNDEFINED=On, 3.31.6, clang, clang++)
  • GitHub Check: run-ubuntu-unit-tests (-DFLB_COVERAGE=On, 3.31.6, gcc, g++)
  • GitHub Check: run-ubuntu-unit-tests (-DSANITIZE_UNDEFINED=On, 3.31.6, gcc, g++)
  • GitHub Check: run-ubuntu-unit-tests (-DFLB_JEMALLOC=Off, 3.31.6, gcc, g++)
  • GitHub Check: run-ubuntu-unit-tests (-DFLB_JEMALLOC=On, 3.31.6, clang, clang++)
  • GitHub Check: run-ubuntu-unit-tests (-DFLB_SMALL=On, 3.31.6, gcc, g++)
  • GitHub Check: run-ubuntu-unit-tests (-DFLB_JEMALLOC=On, 3.31.6, gcc, g++)
  • GitHub Check: run-ubuntu-unit-tests (-DSANITIZE_ADDRESS=On, 3.31.6, gcc, g++)
  • GitHub Check: run-ubuntu-unit-tests (-DFLB_SANITIZE_MEMORY=On, 3.31.6, gcc, g++)
  • GitHub Check: run-ubuntu-unit-tests (-DSANITIZE_ADDRESS=On, 3.31.6, clang, clang++)
  • GitHub Check: run-ubuntu-unit-tests (-DFLB_JEMALLOC=Off, 3.31.6, clang, clang++)
  • GitHub Check: pr-compile-centos-7
  • GitHub Check: pr-compile-system-libs (-DFLB_PREFER_SYSTEM_LIBS=On, 3.31.6, gcc, g++, ubuntu-24.04, clang-14)
  • GitHub Check: pr-compile-system-libs (-DFLB_PREFER_SYSTEM_LIBS=On, 3.31.6, clang, clang++, ubuntu-22.04, clang-12)
  • GitHub Check: PR - fuzzing test
  • GitHub Check: pr-compile-system-libs (-DFLB_PREFER_SYSTEM_LIBS=On, 3.31.6, clang, clang++, ubuntu-24.04, clang-14)
  • GitHub Check: pr-compile-system-libs (-DFLB_PREFER_SYSTEM_LIBS=On, 3.31.6, gcc, g++, ubuntu-22.04, clang-12)
🔇 Additional comments (5)
plugins/in_winevtlog/pack.c (5)

146-149: Good: guard against NULL GUIDs.

Prevents StringFromCLSID(NULL) crashes along rare event paths.


424-427: Correct handling of EvtVarTypeAnsiString.

Switching to pack_astr removes the prior wchar_t misuse and fixes potential SEGVs on ANSI payloads.


678-685: ActivityID: Type-aware and NULL-safe.

Packing only when Type != Null and falling back to empty string avoids derefs on absent GUIDs.


690-697: RelatedActivityID: mirrors the safe pattern.

Matches ActivityID handling; consistent and prevents NULL deref.


74-77: No action needed – default use_ansi remains false, so pack_wstr continues to emit UTF-8 by default.

Comment on lines +79 to +108
static int pack_astr(struct winevtlog_config *ctx, const char *astr)
{
wchar_t *wbuf = NULL;
int wlen = 0;
int ret;

if (!astr) {
return -1;
}

wlen = MultiByteToWideChar(CP_ACP, MB_ERR_INVALID_CHARS, astr, -1, NULL, 0);
if (wlen == 0) {
return -1;
}

wbuf = flb_malloc(sizeof(wchar_t) * wlen);
if (!wbuf) {
flb_errno();
return -1;
}

if (MultiByteToWideChar(CP_ACP, MB_ERR_INVALID_CHARS, astr, -1, wbuf, wlen) == 0) {
flb_free(wbuf);
return -1;
}

ret = pack_wstr(ctx, wbuf);
flb_free(wbuf);
return ret;
}
Copy link
Contributor Author

Choose a reason for hiding this comment

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

NOTE: The Windows API does not provide a function to directly convert from CP_ACP to CP_UTF8.
In practice, the standard procedure is a two-step conversion:
MultiByteToWideChar(CP_ACP, …) → WideCharToMultiByte(CP_UTF8, …).
So, we need to implement nested function like pack_astr calls pack_wstr.

@edsiper edsiper merged commit 210ca30 into master Sep 8, 2025
55 checks passed
@edsiper edsiper deleted the cosmo0920-plug-missing-null-checks-for-in_winevtlog branch September 8, 2025 17:04
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants