Re-apply lost fix 4f33f5b: collection_unpack value_len underflow regression#3560
Re-apply lost fix 4f33f5b: collection_unpack value_len underflow regression#3560g4mm4-VCF wants to merge 4 commits intoowasp-modsecurity:v2/masterfrom
Conversation
cf1f9c4 to
17f3445
Compare
|
Hi @g4mm4-VCF, thanks for this patch. Please take a look at the SonarCLoud report and fix those issues. |
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.
b47c646 to
d7759ab
Compare
|
Hi there,
I have fixed all the issues, and everything is now working properly.
~g4mm4
…On Sun, May 10, 2026 at 5:43 PM Ervin Hegedus ***@***.***> wrote:
*airween* left a comment (owasp-modsecurity/ModSecurity#3560)
<#3560 (comment)>
Hi @g4mm4-VCF <https://github.com/g4mm4-VCF>,
thanks for this patch.
Please take a look at the SonarCLoud report and fix those issues.
—
Reply to this email directly, view it on GitHub
<#3560 (comment)>,
or unsubscribe
<https://github.com/notifications/unsubscribe-auth/CC66HTG37WTJBERASUVT43L42BMNXAVCNFSM6AAAAACYX36OD6VHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHM2DIMJVGA4DIOJRG4>
.
Triage notifications on the go with GitHub Mobile for iOS
<https://apps.apple.com/app/apple-store/id1477376905?ct=notification-email&mt=8&pt=524675>
or Android
<https://play.google.com/store/apps/details?id=com.github.android&referrer=utm_campaign%3Dnotification-email%26utm_medium%3Demail%26utm_source%3Dgithub>.
You are receiving this because you were mentioned.Message ID:
***@***.***>
|
There was a problem hiding this comment.
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 < 1guards inapache2/persist_dbm.cbefore subtracting 1 from those lengths. - Add a new standalone C regression test for the
value_len == 0underflow 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.
| 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; |
| 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 |
| test_persist_dbm_value_len_CFLAGS = -fsanitize=address,undefined -O0 -g -Wall | ||
| test_persist_dbm_value_len_LDFLAGS = -fsanitize=address,undefined |
| * 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) |
Thanks - now please take a look at Copilot suggestions. I think all of them make sense. |
1. Add missing bound check before reading value_len (Copilot owasp-modsecurity#1 — real bug). After consuming the name field, blob_offset can advance to exactly blob_size; the subsequent 16-bit read of value_len from blob[blob_offset] / blob[blob_offset+1] would then OOB-read on a truncated blob. Fixed with the standard 2-byte check. 2. Drop tests/regression/persist_dbm/ (Copilot owasp-modsecurity#2-owasp-modsecurity#5). The directory was not wired into the Autotools build (no AC_CONFIG_FILES nor parent SUBDIRS entry), and the existing tests/regression/ is a Perl-based HTTP integration harness that doesn't fit a unit test of a static function. Wiring it into tests/Makefile.am where msc_test lives would require non-trivial restructuring; keeping the standalone harness outside the upstream tree (in the security advisory's PoC archive) is the cleaner path for now. Refs: PR owasp-modsecurity#3560 review comments by github-actions[bot] / Copilot.
|
Thanks for running Copilot. Pushed f239b02 to address all 5 suggestions. Summary: #1 ( #2–#5 ( The cleanest move was to drop the in-tree test directory entirely. The standalone test harness is preserved outside the upstream tree (in the disclosure PoC archive) for anyone who wants to verify the fix offline: // snippet from the standalone test
unsigned char blob[] = {
0x49, 0x52, 0x01, // SDBM header
0x00, 0x01, // name_len = 1
0x00, // name = ""
0x00, 0x00, // value_len = 0 ← BUG TRIGGER
};
// vulnerable build → apr_pstrmemdup(..., 0xFFFFFFFF) → SIGSEGV
// patched build → second bound check returns NULL earlyHappy to revisit the in-tree test if you'd prefer a Perl-level integration test that drops a malformed SDBM file into Diff vs
CI / SonarCloud should pass on the new commit. Ping me if anything else surfaces. |
1. Add missing bound check before reading value_len (Copilot owasp-modsecurity#1 — real bug). After consuming the name field, blob_offset can advance to exactly blob_size; the subsequent 16-bit read of value_len from blob[blob_offset] / blob[blob_offset+1] would then OOB-read on a truncated blob. Fixed with the standard 2-byte check. 2. Drop tests/regression/persist_dbm/ (Copilot owasp-modsecurity#2-owasp-modsecurity#5). The directory was not wired into the Autotools build (no AC_CONFIG_FILES nor parent SUBDIRS entry), and the existing tests/regression/ is a Perl-based HTTP integration harness that doesn't fit a unit test of a static function. Wiring it into tests/Makefile.am where msc_test lives would require non-trivial restructuring; keeping the standalone harness outside the upstream tree (in the security advisory's PoC archive) is the cleaner path for now. Refs: PR owasp-modsecurity#3560 review comments by github-actions[bot] / Copilot.
f239b02 to
fbdd35a
Compare
|
SonarCloud caught a follow-up: cognitive complexity tipped to 26/25 because of the new bound check. Force-pushed - if (blob_offset + var->name_len > blob_size) return NULL;
+ /* Need name_len bytes for the name body plus 2 more for the value_len header. */
+ if (var->name_len < 1 || blob_offset + var->name_len + 2 > blob_size) return NULL;The strengthened predicate now requires room for both the name body and the 2-byte Final diff vs
CI/SonarCloud should be green again on |
|



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 guardgit show 649aea7:apache2/persist_dbm.c | sed -n '60,75p'— guard gonegit show v2.9.13:apache2/persist_dbm.c | sed -n '60,75p'— still goneAffected releases: v2.9.10, v2.9.11, v2.9.12, v2.9.13.
What this PR does
var->name_len < 1 ||andvar->value_len < 1 ||guards in
collection_unpack()(one-line change each).tests/regression/persist_dbm/that replicates the unpackarithmetic and asserts:
copy_len = UINT_MAXfor avalue_len=0 blob (smoking gun)
Test plan
cd tests/regression/persist_dbm && make checkpassesvalue_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.