fix(cypher): bound UNWIND literal-list buffer to prevent stack overflow - #1173
Conversation
…ck overflow Signed-off-by: SEPURI-SAI-KRISHNA <saik20533@gmail.com>
ffc88cc to
d0457f2
Compare
|
Thanks for the reproduce-first memory-safety fix. Triage is complete: this is a high-priority |
|
Thanks for this, and sorry for the slow first response. Queued for review. MERGEABLE with all 20 checks green — nothing blocking on your side. Useful context you may not have: #1192 reports that |
|
Thank you — this is a real, agent-reachable stack overflow and the fix is the right shape. Verified independently rather than taking the description on trust: the parser advances One consequence worth stating out loud for whoever reads this later: an oversized literal is now silently truncated, so Merging. |
…return CodeQL flagged two high-severity alerts in the previous commit: the help-list builder accumulated snprintf's return value, which is the length it WOULD have written rather than what it did. Once len passes cap, the next `cap - len` underflows to a huge size_t and the following write lands outside the buffer. That is the same class the Cypher UNWIND list builder was just fixed for in #1173, where blen advanced past a 2KB buffer the same way. The capacity computed here is in fact sufficient for the current registry, so nothing overflows today -- which makes this the more dangerous shape, not the safer one. The code was correct only by an argument made ten lines away in the cap loop, so renaming a tool or changing the wrap rule would have turned it into an out-of-bounds write with nothing in the function to notice. help_append() returns the bytes ACTUALLY written, clamped to the space left, so `len <= cap - 1` becomes a local invariant that holds no matter what the registry or the wrap column later become. Also adds the <stdarg.h> the variadic helper needs. Verified: builds clean under -Werror; --help still renders all 15 tools in registry order with the same wrapping; mcp + cli suites 437 passed, 0 failed; make -f Makefile.cbm lint-ci clean. Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
What does this PR do?
Fixes a stack out-of-bounds write (CWE-787) in the Cypher
UNWINDliteral-listparser (
parse_unwind_clause,src/cypher/cypher.c).When assembling a literal list into the fixed 2 KB stack buffer
char buf[CBM_SZ_2K], the code advances the write cursor by the return value ofsnprintf:snprintfreturns the number of bytes it would have written, so a singleoversized element pushes
blenpastsizeof(buf). The trailing writes are thenunguarded:
and on multi-element lists the next iteration's
sizeof(buf) - blenunderflowsto a huge
size_t, lettingsnprintfwrite far past the buffer.The query string is agent-controlled through the MCP
querytool, and Cypherstring literals lex up to
CBM_SZ_4K - 1(4095) chars with no length cap beforeparsing, so
UNWIND ["<~3000 chars>"] AS x MATCH (n) RETURN nreaches theoverflow.
Reproduced first (UBSan, before the fix):
The fix clamps
blenafter everysnprintfand guards the rawbuf[blen++]stores — the same pattern already used by the sibling functionformat_collect_list(), which builds an identical JSON array into aCBM_SZ_2Kbuffer and was already hardened. After the fix all 161 cypher testspass with zero sanitizer errors.
Two regression tests are added (both fail under UBSan without the fix):
cypher_parse_unwind_oversized_literal_no_overflow— single oversized elementcypher_parse_unwind_many_elements_no_overflow— many elements accumulating past 2 KBChecklist
git commit -s) — required, CI rejectsunsigned commits (DCO, see CONTRIBUTING.md)
make -f Makefile.cbm test)make -f Makefile.cbm lint-ci)