diff --git a/NEWS b/NEWS index a2c65685b4ce..a1d4c51a7eb3 100644 --- a/NEWS +++ b/NEWS @@ -36,6 +36,8 @@ PHP NEWS . Fixed a tracing JIT crash when compiling a side trace for a method of a class that could not be stored in the inheritance cache. (GH-21710) (Arnaud, iliaal) + . Fixed a call_stack buffer overflow in zend_analyze_calls() when dead code + elimination has removed the DO_FCALL opcodes. (Mrmaxmeier) - PDO: . Fixed a leak when a persistent connection failed a liveness check diff --git a/Zend/Optimizer/zend_call_graph.c b/Zend/Optimizer/zend_call_graph.c index 8a2f8ea2a7e1..cbb4c906a97e 100644 --- a/Zend/Optimizer/zend_call_graph.c +++ b/Zend/Optimizer/zend_call_graph.c @@ -54,7 +54,10 @@ ZEND_API void zend_analyze_calls(zend_arena **arena, zend_script *script, uint32 ALLOCA_FLAG(use_heap); bool is_prototype; - call_stack = do_alloca((op_array->last / 2) * sizeof(zend_call_info*), use_heap); + // Note: Reserve one call stack slot per operation. Each opcode pushes at + // most one entry to the call stack, and (with dead code elimination) it's + // possible to never pop from the stack. + call_stack = do_alloca(op_array->last * sizeof(zend_call_info*), use_heap); call_info = NULL; while (opline != end) { switch (opline->opcode) { diff --git a/ext/opcache/tests/fuzzer_function_jit_call_graph_stack_overflow.phpt b/ext/opcache/tests/fuzzer_function_jit_call_graph_stack_overflow.phpt new file mode 100644 index 000000000000..ef4fd6a1b923 --- /dev/null +++ b/ext/opcache/tests/fuzzer_function_jit_call_graph_stack_overflow.phpt @@ -0,0 +1,20 @@ +--TEST-- +zend_analyze_calls(): call_stack overflow when dead code elimination removed the DO_FCALLs +--EXTENSIONS-- +opcache +--INI-- +opcache.enable=1 +opcache.enable_cli=1 +opcache.jit=disable +--ENV-- +USE_ZEND_ALLOC=0 +USE_TRACKED_ALLOC=1 +--FILE-- + 2 })))); +} +echo "OK\n"; +?> +--EXPECT-- +OK