fix(cypher): bounds-check and error-propagate cross_join_nodes allocation#1176
fix(cypher): bounds-check and error-propagate cross_join_nodes allocation#1176SEPURI-SAI-KRISHNA wants to merge 1 commit into
Conversation
|
Thanks for the focused reproduction. The zero-result
Please keep the narrow fix, complete those checks and error semantics, and either link a matching issue or remove the broader #627 association. This feedback is for reviewed head |
…tion Signed-off-by: SEPURI-SAI-KRISHNA <saik20533@gmail.com>
12cdf28 to
b07dbe6
Compare
|
@DeusData Thanks, all four addressed:
Dropped the broader #627 association from the description; this PR is scoped to |
|
Thanks for addressing all four requested points and for tightening the #627 claim. I see current head |
What does this PR do?
Fixes a heap buffer overflow (CWE-787) in
cross_join_nodes(
src/cypher/cypher.c), reached when an additionalMATCH/OPTIONAL MATCHnode pattern is cross-joined into the current bindings. The query text is
agent-controlled via the MCP
querytool.The reachable bug
When an
OPTIONAL MATCH's label matches zero nodes,cross_join_nodesiscalled with
extra_count == 0. The allocation was(bind_count * 0 + 1)=one binding slot, but the OPTIONAL fallback then writes one binding per
existing row (
bind_countof them). Any query whose first pattern binds ≥ 2nodes and whose OPTIONAL pattern matches zero nodes overflows the heap:
Reproduced first (ASan, before the fix — 4 nodes, no large graph needed):
The fix sizes the
OPTIONAL-empty case asbind_countentries so the bufferholds every fallback row. After the fix the query returns one row per bound node
(
bleft unbound — correct OPTIONAL dead-code semantics).Allocation-arithmetic hardening (per review)
The same allocation math is now fully bounds-checked, via a small helper so the
boundary is unit-testable:
alloc_n * sizeof(binding_t)is rejected if it wouldoverflow
size_t.INT_MAXguard. The row count is computed insize_t; if it would not fitthe
intbinding counter (*bind_count = (int)new_count) the join is refusedrather than silently truncating the count. A plain-
intbind_count * extra_countproduct would wrap pastINT_MAXon a large graph(e.g. an unbounded Cartesian
MATCH (a:X) MATCH (b:Y)).cross_join_nodesnow returns an error that
expand_additional_patterns→execute_single→cbm_cypher_executesurface as a query error (out->error), instead ofleaving the original bindings in place and silently skipping the
MATCH— thatwould return a wrong (short) result.
Tests
cypher_exec_optional_empty_label_no_overflow— the reachable zero-labeloverflow (RED under ASan before the fix; returns 4 rows after).
cypher_cross_join_alloc_rejects_overflow— an arithmetic-boundary test thatdrives the helper with
46341 * 46341 > INT_MAXand asserts it is rejected(RED-confirmed: with the guards disabled the helper returns success and the
test fails), plus normal counts (
4×3 → 13,OPTIONAL 4×0 → 5,4×0 → 1).The full
cyphersuite passes with no sanitizer errors (161 tests).Checklist
git commit -s) — required, CI rejectsunsigned commits (DCO, see CONTRIBUTING.md)
make -f Makefile.cbm test)