Skip to content

Fix stack over-read in mnet_jsonf() integer conversions - #15

Merged
mattsva merged 2 commits into
mnet-web:mainfrom
mattsva:fix/jsonf-integer-overread
Oct 11, 2026
Merged

mattsva merged 2 commits into
mnet-web:mainfrom
mattsva:fix/jsonf-integer-overread

Conversation

@mattsva

@mattsva mattsva commented Oct 9, 2026

Copy link
Copy Markdown
Contributor

Fixes #8.

The integer path of mnet_jsonfv() formats into a fixed 64-byte stack buffer without sizing it first (unlike the float path, which grows its buffer). snprintf() returns the length the output would have had, so a wide conversion like %4096d truncates into the 64-byte buffer while the returned length still reports 4096; the following memcpy then over-reads ~4 KB of stack and copies adjacent stack memory into the HTTP response.

ASan on the unfixed code:

ERROR: AddressSanitizer: stack-buffer-overflow
READ of size 4096 at ... in mnet_jsonfv
    src/mnet_response.c:739

Fix: the integer path now sizes its buffer like the float path (grow to the needed length).

Tests: wide-integer case added to test/test_security.c — ASan failure before, passes after (62 passed, 0 failed, asan_issues=0).

Stacked on the previous PR in the series; merge in order.

@mattsva
mattsva force-pushed the fix/jsonf-integer-overread branch 2 times, most recently from b759377 to 9180c75 Compare October 11, 2026 13:37
Covers duplicate Content-Length (400), Content-Length with
Transfer-Encoding (501), bare LF line endings, obs-fold continuations,
Expect: 100-continue, negative/overflowing/non-numeric Content-Length
(400/413/400), a version-less request line, a space before a header
colon, and pipelined requests.

No source changes were needed: every case already behaves correctly.
The tests document the behavior and guard it, including the two
deliberately lenient choices (obs-fold and a version-less request line
are served rather than rejected, per the existing lenient policy).

Wired into Make, CMake, Meson and the CI jobs.
The integer conversion path of mnet_jsonfv() formats into a fixed 64-byte
stack buffer without sizing it first, unlike the float path which grows
its buffer to the needed length. snprintf() returns the length the
output *would* have had, so a wide conversion like %4096d truncates into
the 64-byte buffer while the returned length still reports 4096; the
following memcpy (src/mnet_response.c:739) then over-reads ~4 KB of stack
and copies adjacent stack memory into the HTTP response.

Confirmed under AddressSanitizer:

  ERROR: AddressSanitizer: stack-buffer-overflow
  READ of size 4096 at ... in mnet_jsonfv
      src/mnet_response.c:739

Both integer branches now size their buffer with snprintf(NULL, 0, ...)
and grow it, the same way the float path does.

Test: wide-integer case in test/test_security.c — ASan failure before the
fix, passes after (62 passed, 0 failed, asan_issues=0).

The test block names its response variable 'wide' rather than 'r': the
old name shadowed an outer local, which MSVC reports as C4456 and the
project treats as an error under /WX.
@mattsva
mattsva force-pushed the fix/jsonf-integer-overread branch from 9180c75 to cd3ab37 Compare October 11, 2026 13:45
@mattsva
mattsva merged commit 490f8aa into mnet-web:main Oct 11, 2026
8 checks passed
@mattsva mattsva mentioned this pull request Oct 11, 2026
@mattsva
mattsva deleted the fix/jsonf-integer-overread branch October 11, 2026 14:10
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.

mnet_jsonf() integer conversions over-read the stack, leaking adjacent memory into responses

1 participant