From 50c7f498b9a616704faeb48123182eda5fc5e896 Mon Sep 17 00:00:00 2001 From: Ilija Tovilo Date: Wed, 29 Oct 2025 15:14:45 +0100 Subject: [PATCH] Reset Z_EXTRA_P(op2) of ZEND_INIT_FCALL for opcache file cache The offset becomes stale if the environment changes. We're currently relying on other factors in the environment staying constant, e.g. send types. But this seems to be the worst offender. Partially addresses GH-17733 Closes GH-20328 --- NEWS | 2 ++ ext/opcache/zend_file_cache.c | 21 ++++++++++++++++++++- 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/NEWS b/NEWS index a55358c265d..882a17d2ed3 100644 --- a/NEWS +++ b/NEWS @@ -55,6 +55,8 @@ PHP NEWS . Fixed bug GH-19875 (JIT 1205 segfault on large file compiled in subprocess). (Arnaud) . Fixed bug GH-20012 (heap buffer overflow in jit). (Arnaud) + . Partially fixed bug GH-17733 (Avoid calling wrong function when reusing file + caches across differing environments). (ilutov) - PgSql: . Fix memory leak when first string conversion fails. (nielsdos) diff --git a/ext/opcache/zend_file_cache.c b/ext/opcache/zend_file_cache.c index 736d644516a..36ab3f6c9ae 100644 --- a/ext/opcache/zend_file_cache.c +++ b/ext/opcache/zend_file_cache.c @@ -535,13 +535,32 @@ static void zend_file_cache_serialize_op_array(zend_op_array *op_arra } if (opline->op2_type == IS_CONST) { SERIALIZE_PTR(opline->op2.zv); + + /* See GH-17733. Reset Z_EXTRA_P(op2) of ZEND_INIT_FCALL, which + * is an offset into the global function table, to avoid calling + * incorrect functions when environment changes. This, and the + * equivalent code below, can be removed once proper system ID + * validation is implemented. */ + if (opline->opcode == ZEND_INIT_FCALL) { + zval *op2 = opline->op2.zv; + UNSERIALIZE_PTR(op2); + Z_EXTRA_P(op2) = 0; + ZEND_VM_SET_OPCODE_HANDLER(opline); + } } #else if (opline->op1_type == IS_CONST) { opline->op1.constant = RT_CONSTANT(opline, opline->op1) - literals; } if (opline->op2_type == IS_CONST) { - opline->op2.constant = RT_CONSTANT(opline, opline->op2) - literals; + zval *op2 = RT_CONSTANT(opline, opline->op2); + opline->op2.constant = op2 - literals; + + /* See GH-17733 and comment above. */ + if (opline->opcode == ZEND_INIT_FCALL) { + Z_EXTRA_P(op2) = 0; + ZEND_VM_SET_OPCODE_HANDLER(opline); + } } #endif #if ZEND_USE_ABS_JMP_ADDR