Skip to content

Re-apply lost fix 4f33f5b: collection_unpack value_len underflow regression#3560

Open
g4mm4-VCF wants to merge 3 commits intoowasp-modsecurity:v2/masterfrom
g4mm4-VCF:fix/persist-dbm-value-len-regression
Open

Re-apply lost fix 4f33f5b: collection_unpack value_len underflow regression#3560
g4mm4-VCF wants to merge 3 commits intoowasp-modsecurity:v2/masterfrom
g4mm4-VCF:fix/persist-dbm-value-len-regression

Conversation

@g4mm4-VCF
Copy link
Copy Markdown

Summary

Re-applies commit 4f33f5b ("Fix possible segfault in collection_unpack",
@twouters, 2024-03-01) which was silently dropped during merge 649aea7
on 2024-04-04. The drop has been confirmed by:

  • git show 4f33f5b:apache2/persist_dbm.c | sed -n '60,75p' — has the guard
  • git show 649aea7:apache2/persist_dbm.c | sed -n '60,75p' — guard gone
  • git show v2.9.13:apache2/persist_dbm.c | sed -n '60,75p' — still gone

Affected releases: v2.9.10, v2.9.11, v2.9.12, v2.9.13.

What this PR does

  1. Re-introduces the var->name_len < 1 || and var->value_len < 1 ||
    guards in collection_unpack() (one-line change each).
  2. Adds a standalone regression test under
    tests/regression/persist_dbm/ that replicates the unpack
    arithmetic and asserts:
    • the buggy code-path produces copy_len = UINT_MAX for a
      value_len=0 blob (smoking gun)
    • the patched code-path returns NULL before the underflow

Test plan

  • cd tests/regression/persist_dbm && make check passes
  • manual: feed an 8-byte SDBM blob (header + name_len=1 + name="" +
    value_len=0) into a SecDataDir-backed collection; observe the
    previously-crashing worker now ignore the malformed entry.

References

Coordinated with @airween via private security channel.

@g4mm4-VCF g4mm4-VCF force-pushed the fix/persist-dbm-value-len-regression branch from cf1f9c4 to 17f3445 Compare May 10, 2026 09:15
@airween
Copy link
Copy Markdown
Member

airween commented May 10, 2026

Hi @g4mm4-VCF,

thanks for this patch.

Please take a look at the SonarCLoud report and fix those issues.

g4mm4-VCF added 3 commits May 10, 2026 20:21
The fix from owasp-modsecurity#3082 was lost in merge 649aea7 (2024-04-04) and has been
missing from every release v2.9.10 .. v2.9.13. This re-applies the
same one-line guard as the original commit by @twouters.

Refs: owasp-modsecurity#3082
Standalone harness that replicates the unpack arithmetic and asserts
that the patched bound check rejects a value_len=0 blob while the
buggy version would have produced a 4 GiB copy length.

Runs without APR / Apache build dependencies so it integrates into
`make check` as a self-contained TAP test.
Split combined declarations and remove redundant inner casts as
flagged by SonarCloud's static analyser. No functional change —
the regression test still produces buggy_copy = UINT_MAX on the
buggy path and patched_rc = 0 on the patched path.
@g4mm4-VCF g4mm4-VCF force-pushed the fix/persist-dbm-value-len-regression branch from b47c646 to d7759ab Compare May 10, 2026 13:22
@sonarqubecloud
Copy link
Copy Markdown

@g4mm4-VCF
Copy link
Copy Markdown
Author

g4mm4-VCF commented May 10, 2026 via email

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Re-applies a previously lost defensive check in collection_unpack() to prevent value_len - 1 underflow (and resulting huge memcpy/apr_pstrmemdup), and adds a standalone regression test intended to demonstrate the buggy vs fixed arithmetic.

Changes:

  • Reintroduce name_len < 1 / value_len < 1 guards in apache2/persist_dbm.c before subtracting 1 from those lengths.
  • Add a new standalone C regression test for the value_len == 0 underflow scenario.
  • Add an Automake snippet intended to build/run the new regression test.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 5 comments.

File Description
apache2/persist_dbm.c Restores the missing < 1 guards to prevent *_len - 1 unsigned underflow leading to oversized copies.
tests/regression/persist_dbm/test_persist_dbm_value_len.c Adds a standalone test program modeling the buggy vs patched arithmetic around value_len - 1.
tests/regression/persist_dbm/Makefile.am Attempts to hook the new test into an Automake-based make check flow for that subdirectory.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread apache2/persist_dbm.c
Comment on lines +64 to +72
if (var->name_len < 1 || blob_offset + var->name_len > blob_size) return NULL;
var->name = apr_pstrmemdup(msr->mp, (const char *)blob + blob_offset, var->name_len - 1);
blob_offset += var->name_len;
var->name_len--;

var->value_len = (blob[blob_offset] << 8) + blob[blob_offset + 1];
blob_offset += 2;

if (blob_offset + var->value_len > blob_size) return NULL;
if (var->value_len < 1 || blob_offset + var->value_len > blob_size) return NULL;
Comment on lines +1 to +3
TESTS = test_persist_dbm_value_len
check_PROGRAMS = test_persist_dbm_value_len
test_persist_dbm_value_len_SOURCES = test_persist_dbm_value_len.c
Comment on lines +4 to +5
test_persist_dbm_value_len_CFLAGS = -fsanitize=address,undefined -O0 -g -Wall
test_persist_dbm_value_len_LDFLAGS = -fsanitize=address,undefined
Comment on lines +54 to +60
* Faithful replica of collection_unpack's deserialisation arithmetic.
*
* The two functions below differ ONLY in the `value_len < 1 ||` clause
* that 4f33f5b added and 649aea7 removed. The blob layout, the read of
* the 16-bit big-endian length, and the apr_pstrmemdup() argument
* computation are otherwise byte-for-byte identical.
*
*
* 0 = both before-fix and after-fix paths behaved as expected
* (test PASSED — confirms regression and confirms patch fixes it)
* 1 = test FAILED (either path returned an unexpected result)
@airween
Copy link
Copy Markdown
Member

airween commented May 10, 2026

Hi there, I have fixed all the issues, and everything is now working properly.

Thanks - now please take a look at Copilot suggestions. I think all of them make sense.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants