Skip to content

zstd: add 100 MB decompression size limit#11854

Open
TristanInSec wants to merge 2 commits into
fluent:masterfrom
TristanInSec:fix/zstd-decompression-limit
Open

zstd: add 100 MB decompression size limit#11854
TristanInSec wants to merge 2 commits into
fluent:masterfrom
TristanInSec:fix/zstd-decompression-limit

Conversation

@TristanInSec
Copy link
Copy Markdown

@TristanInSec TristanInSec commented May 26, 2026

The gzip decompressor limits output to 100 MB but the zstd
decompressor has no such cap. A small zstd-compressed payload with
a high compression ratio can expand to gigabytes, exhausting memory
and causing the process to be OOM-killed.

Add FLB_ZSTD_DECOMPRESS_MAX (100 MB) matching the gzip limit,
checked in both the known-size path (ZSTD_getFrameContentSize) and
the streaming path (zstd_uncompress_unknown_size).

Summary by CodeRabbit

  • Bug Fixes
    • Added a 100 MB maximum decompression size to ZSTD handling to prevent excessive memory use.
    • Decompression now rejects inputs that declare or would expand beyond the size limit.
    • Both streaming and frame-based decompression paths enforce this cap for improved stability and safety.

Review Change Stack

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 26, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 59c74d8a-7de8-4e48-8f40-0cea3a0d03e2

📥 Commits

Reviewing files that changed from the base of the PR and between c7ec32a and 5ec1a83.

📒 Files selected for processing (1)
  • src/flb_zstd.c
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/flb_zstd.c

📝 Walkthrough

Walkthrough

Adds a 100 MB decompression-size cap (FLB_ZSTD_DECOMPRESS_MAX) and enforces it in both ZSTD decompression paths: aborting streaming growth when exceeding the cap and rejecting frames whose declared content size exceeds the cap.

Changes

ZSTD Decompression Size Limit

Layer / File(s) Summary
Decompression size limit constant and enforcement
src/flb_zstd.c
Define FLB_ZSTD_DECOMPRESS_MAX (100 MB) and enforce it in the unknown-size streaming decompression loop (pre-realloc check, abort and free on overflow) and in the known-size frame decompression path (reject frames with declared content size > cap).

Sequence Diagram(s)

sequenceDiagram
  participant Caller
  participant flb_zstd as flb_zstd.c
  participant ZSTD
  Caller->>flb_zstd: provide compressed data
  flb_zstd->>flb_zstd: check FLB_ZSTD_DECOMPRESS_MAX (frame or next growth)
  alt size within limit
    flb_zstd->>ZSTD: perform decompression
    ZSTD-->>flb_zstd: decompressed bytes
    flb_zstd-->>Caller: return data
  else exceeds limit
    flb_zstd-->>Caller: log error and return failure
  end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

  • fluent/fluent-bit#10697: Both PRs modify src/flb_zstd.c's ZSTD decompression implementation—the retrieved PR adds the streaming decompressor/dispatcher and context which the current decompression-size cap interacts with.

Suggested labels

backport to v4.1.x, backport to v4.2.x

Suggested reviewers

  • edsiper
  • cosmo0920

Poem

🐰 I watch bytes stretch and buffers grow,
A gentle limit keeps the overflow low.
One hundred megabytes — a guard in the night,
Streaming or framed, it keeps things tight.
Hopping away happy, safe from the bite.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and specifically describes the main change: adding a 100 MB decompression size limit for zstd, which matches the primary objective of preventing unbounded memory expansion.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 820a279780

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread src/flb_zstd.c Outdated
Comment on lines +108 to +110
out_size *= 2;
if (out_size > FLB_ZSTD_DECOMPRESS_MAX) {
flb_error("[zstd] maximum decompression size reached (~100 MB)");
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Allow unknown-size zstd outputs up to configured 100 MB limit

The new limit check rejects valid payloads when ZSTD_CONTENTSIZE_UNKNOWN is used and the decompressed size is between 64 MiB and 100 MiB. In this path, out_size doubles from 64 MiB to 128 MiB, then the > FLB_ZSTD_DECOMPRESS_MAX check fails before attempting to decompress further, so frames that should be accepted under the 100 MB cap now fail. This introduces a functional regression for legitimate unknown-size frames and should instead clamp growth to the max (or otherwise permit expansion up to exactly the limit).

Useful? React with 👍 / 👎.

Copy link
Copy Markdown

@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: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/flb_zstd.c`:
- Around line 109-114: The decompression path incorrectly aborts when the next
doubling would exceed FLB_ZSTD_DECOMPRESS_MAX, which prevents growing buffers up
to the declared max; update the resizing logic where out_size is doubled to
compute new_size = out_size * 2 and if new_size > FLB_ZSTD_DECOMPRESS_MAX set
new_size = FLB_ZSTD_DECOMPRESS_MAX, then realloc buf to new_size (instead of
immediately erroring and freeing buf/ZSTD_freeDCtx/return -1); adjust the check
that currently uses out_size > FLB_ZSTD_DECOMPRESS_MAX to use the computed
new_size so payloads between the last power-of-two and the max are accepted.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 70630876-b77f-41d9-b19b-e658ac2b04d3

📥 Commits

Reviewing files that changed from the base of the PR and between f6126eb and 820a279.

📒 Files selected for processing (1)
  • src/flb_zstd.c

Comment thread src/flb_zstd.c Outdated
@edsiper edsiper added this to the Fluent Bit v5.0.7 milestone May 27, 2026
@edsiper
Copy link
Copy Markdown
Member

edsiper commented May 27, 2026

@TristanInSec would you please sign off the commits ? (DCO error / git commit -s ...)

also note the auto-reviews by the CI agent:

"Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @src/flb_zstd.c:

  • Around line 109-114: The decompression path incorrectly aborts when the next
    doubling would exceed FLB_ZSTD_DECOMPRESS_MAX, which prevents growing buffers up
    to the declared max; update the resizing logic where out_size is doubled to
    compute new_size = out_size * 2 and if new_size > FLB_ZSTD_DECOMPRESS_MAX set
    new_size = FLB_ZSTD_DECOMPRESS_MAX, then realloc buf to new_size (instead of
    immediately erroring and freeing buf/ZSTD_freeDCtx/return -1); adjust the check
    that currently uses out_size > FLB_ZSTD_DECOMPRESS_MAX to use the computed
    new_size so payloads between the last power-of-two and the max are accepted."

The gzip decompressor limits output to 100 MB but the zstd
decompressor has no such cap. A small zstd-compressed payload with
a high compression ratio can expand to gigabytes, exhausting memory
and causing the process to be OOM-killed.

Add FLB_ZSTD_DECOMPRESS_MAX (100 MB) matching the gzip limit,
checked in both the known-size path (ZSTD_getFrameContentSize) and
the streaming path (zstd_uncompress_unknown_size).

Signed-off-by: Tristan <tristan@talencesecurity.com>
@TristanInSec TristanInSec force-pushed the fix/zstd-decompression-limit branch from 820a279 to c7ec32a Compare May 27, 2026 21:56
When the streaming decompression buffer doubles past the 100 MB limit,
cap the allocation at FLB_ZSTD_DECOMPRESS_MAX instead of immediately
aborting. This allows payloads between the last power-of-two (64 MB)
and the 100 MB limit to decompress successfully. Only abort when the
buffer is already at the maximum and still needs more space.

Signed-off-by: Tristan <tristan@talencesecurity.com>
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.

3 participants