redis: guard stream format allocation - #15423
Conversation
When Redis output is configured in stream/xadd mode with a positive stream-maxlen, SCConfLogOpenRedis() allocates redis_setup.stream_format and immediately passes it to snprintf(). If SCCalloc() fails, snprintf() receives a NULL destination pointer and the process can crash during Redis output initialization. Handle this unrecoverable setup failure with FatalError(), matching the surrounding Redis initialization error handling. Ticket: 8588
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #15423 +/- ##
==========================================
+ Coverage 82.65% 82.76% +0.11%
==========================================
Files 996 999 +3
Lines 271109 272666 +1557
==========================================
+ Hits 224076 225674 +1598
+ Misses 47033 46992 -41
Flags with carried forward coverage won't be shown. Click here to find out more. 🚀 New features to boost your workflow:
|
| format string, whose length is limited by the length of the | ||
| maxlen integer formatted as a string */ | ||
| log_ctx->redis_setup.stream_format = SCCalloc(100, sizeof(char)); | ||
| if (unlikely(log_ctx->redis_setup.stream_format == NULL)) { |
There was a problem hiding this comment.
Why was this not caught by cocci ? ./qa/coccinelle/malloc-error-check.cocci
There was a problem hiding this comment.
Good catch. The script missed it because of how ... when != x works
in Coccinelle: it excludes statements that assign to x, but not
statements that use x as an argument — so snprintf(x, ...) and
format = x both pass through the ... without triggering the
constraint. Combined with the exists semantics and the allocation
being inside a nested if (maxlen > 0), Coccinelle does not flag the
missing NULL check.
The fix we applied (adding the if (unlikely(...)) guard before the
snprintf) matches the @istested pattern and would be caught
correctly going forward. Let us know if you'd like us to also add a
test case to the cocci script to prevent similar gaps.
There was a problem hiding this comment.
Could we fix the cocci script then ?
There was a problem hiding this comment.
Could we fix the cocci script then ?
Fixed in 4111d98. The root cause: ... when != x in @istested only
excludes statements that reassign x, not statements that use x
as a function argument. So snprintf(x, ...) passed through the ...
undetected.
Added when != callee(..., x, ...) to the constraint so that any use
of the allocated pointer as a function argument before a NULL check
prevents @istested from matching — causing the script to correctly
flag the violation.
There was a problem hiding this comment.
Thanks, checking with #15508 that this cocci change is good
There was a problem hiding this comment.
Also, we would like to have a shorter commit title, see https://docs.suricata.io/en/latest/devguide/contributing/code-submission-process.html#commits
|
Also, we need you yo sign the CLA https://suricata.io/about/contribution-agreement/ to be able to accept your contribution |
…unction args The @istested rule's '... when != x' only excluded reassignments of x, not statements that passed x as a function argument. Add 'when != callee(..., x, ...)' so that any use of the allocated pointer as a function argument before a NULL check is no longer treated as tested and is correctly flagged.
yes, I signed it now |
|
NOTE: This PR may contain new authors. |
catenacyber
left a comment
There was a problem hiding this comment.
The cocci commit does not work : see https://github.com/OISF/suricata/actions/runs/26811739736/job/79043416837?pr=15508 from #15508
The identifier regex used PCRE-style '(A|B)' syntax, but Coccinelle uses OCaml Str where '|' is a literal character. Replace with 'A\|B' so the pattern correctly matches all SC*alloc functions.
Fixed in 3ca8259. The root cause was deeper: the entire script was a no-op because identifier =~ "(SCMalloc|SCCalloc|...)" uses PCRE-style syntax, but Coccinelle uses OCaml Str where | and () are literal characters — so @malloced never matched anything. Fixed by replacing all (A|B) patterns with A\|B (OCaml Str alternation). After this fix the script correctly catches the missing null check: exit 1 on the buggy code, exit 0 on the fixed version. |
|
Cool, but now we see more reports like Could you fix them also ? |
|
NOTE: This PR may contain new authors. |
- decode: replace DEBUG_VALIDATE_BUG_ON with FatalError in PacketAlertCreate - detect-engine-alert: guard SCStrdup result before use - detect-flowbits: check SCRealloc result before overwriting original pointer - detect-reference: guard SCStrdup results in DetectReferenceParse - util-mpm-hs: fix false cocci negative (remove extra parens), add FatalError in SCHSConfigInit
Fixed in 207594e. The repaired cocci script surfaced 6 unchecked allocations across 5 files:
Full scan of |
|
Closing this pull request: its branch was updated after the pull Per our workflow, a new pull request is required when changes are made If you wish to create an in progress pull request that you can push to, Please see our GitHub Pull Request Workflow. |
Continued in #15529 (PR was auto-closed after branch update per the workflow policy). |
Ticket: 8588
Make sure these boxes are checked accordingly before submitting your Pull Request -- thank you.
Contribution style:
https://docs.suricata.io/en/latest/devguide/contributing/contribution-process.html
Our Contribution agreements:
https://suricata.io/about/contribution-agreement/ (note: this is only required once)
Changes (if applicable):
(including schema descriptions)
https://redmine.openinfosecfoundation.org/projects/suricata/issues
Link to ticket: https://redmine.openinfosecfoundation.org/issues/8588
Describe changes:
snprintf().FatalError()for this unrecoverable Redis output initialization failure, matching the existing Redis setup error handling style.stream-maxlenand memory allocation fails.Provide values to any of the below to override the defaults.
link to the pull request in the respective
_BRANCHvariable.SV_REPO=
SV_BRANCH=
SU_REPO=
SU_BRANCH=