From 4e0bd036813ef9ffa738fea87a7ad04982f520f6 Mon Sep 17 00:00:00 2001 From: Ilija Tovilo Date: Thu, 23 Mar 2023 20:30:56 +0100 Subject: [PATCH] Reset EG(trampoline).op_array.last_var that FFI may modify Closes GH-10916 --- NEWS | 1 + Zend/zend_object_handlers.c | 6 ++++ ext/ffi/tests/trampoline_reset.phpt | 43 +++++++++++++++++++++++++++++ 3 files changed, 50 insertions(+) create mode 100644 ext/ffi/tests/trampoline_reset.phpt diff --git a/NEWS b/NEWS index 6d4780d08e3..730e0d5d087 100644 --- a/NEWS +++ b/NEWS @@ -15,6 +15,7 @@ PHP NEWS (nielsdos) . Fixed bug GH-10810 (Fix NUL byte terminating Exception::__toString()). (ilutov) + . Fix potential memory corruption when mixing __callStatic() and FFI. (ilutov) - Date: . Fixed bug GH-10583 (DateTime modify with tz pattern should not update diff --git a/Zend/zend_object_handlers.c b/Zend/zend_object_handlers.c index e4ae4450b53..60d27b7c911 100644 --- a/Zend/zend_object_handlers.c +++ b/Zend/zend_object_handlers.c @@ -1253,6 +1253,12 @@ ZEND_API zend_function *zend_get_call_trampoline_func(zend_class_entry *ce, zend ZEND_MAP_PTR_INIT(func->run_time_cache, (void***)&dummy); func->scope = fbc->common.scope; /* reserve space for arguments, local and temporary variables */ + /* EG(trampoline) is reused from other places, like FFI (e.g. zend_ffi_cdata_get_closure()) where + * it is used as an internal function. It may set fields that don't belong to common, thus + * modifying zend_op_array specific data, most significantly last_var. We need to reset this + * value so that it doesn't contain garbage when the engine allocates space for the next stack + * frame. This didn't cause any issues until now due to "lucky" structure layout. */ + func->last_var = 0; func->T = (fbc->type == ZEND_USER_FUNCTION)? MAX(fbc->op_array.last_var + fbc->op_array.T, 2) : 2; func->filename = (fbc->type == ZEND_USER_FUNCTION)? fbc->op_array.filename : ZSTR_EMPTY_ALLOC(); func->line_start = (fbc->type == ZEND_USER_FUNCTION)? fbc->op_array.line_start : 0; diff --git a/ext/ffi/tests/trampoline_reset.phpt b/ext/ffi/tests/trampoline_reset.phpt new file mode 100644 index 00000000000..3a87ec99d2a --- /dev/null +++ b/ext/ffi/tests/trampoline_reset.phpt @@ -0,0 +1,43 @@ +--TEST-- +Memory corruption when mixing __callStatic() and FFI +--EXTENSIONS-- +ffi +--SKIPIF-- + +--INI-- +ffi.enable=1 +--FILE-- +fprintf($ffi->stdout, "FFI\n"); +$ffi->fflush($ffi->stdout); +Test::baz(); +?> +--EXPECT-- +foo called +bar called +FFI +baz called