Skip to content

Commit

Permalink
Avoid using a stack allocated zend_function in Closure::call, to avoi…
Browse files Browse the repository at this point in the history
…d prevent crashes on bailout

Having a stack allocated zend_function may cause crashes if the stack is polluted between bailout and the actual unwinding in zend_observer_fcall_end_all.

Signed-off-by: Bob Weinand <bobwei9@hotmail.com>
  • Loading branch information
bwoebi committed Jul 28, 2022
1 parent 63798e5 commit b576bb9
Showing 1 changed file with 41 additions and 26 deletions.
67 changes: 41 additions & 26 deletions Zend/zend_closures.c
Expand Up @@ -121,7 +121,6 @@ ZEND_METHOD(Closure, call)
zend_closure *closure;
zend_fcall_info fci;
zend_fcall_info_cache fci_cache;
zend_function my_function;
zend_object *newobj;
zend_class_entry *newclass;

Expand All @@ -142,55 +141,71 @@ ZEND_METHOD(Closure, call)
return;
}

fci_cache.called_scope = newclass;
fci_cache.object = fci.object = newobj;

fci.size = sizeof(fci);
ZVAL_OBJ(&fci.function_name, &closure->std);
ZVAL_UNDEF(&closure_result);
fci.retval = &closure_result;

if (closure->func.common.fn_flags & ZEND_ACC_GENERATOR) {
zval new_closure;
zend_create_closure(&new_closure, &closure->func, newclass, closure->called_scope, newthis);
closure = (zend_closure *) Z_OBJ(new_closure);
fci_cache.function_handler = &closure->func;

zend_call_function(&fci, &fci_cache);

/* copied upon generator creation */
GC_DELREF(&closure->std);
} else {
memcpy(&my_function, &closure->func, closure->func.type == ZEND_USER_FUNCTION ? sizeof(zend_op_array) : sizeof(zend_internal_function));
my_function.common.fn_flags &= ~ZEND_ACC_CLOSURE;
zend_function *my_function;
if (ZEND_USER_CODE(closure->func.type)) {
my_function = emalloc(sizeof(zend_op_array));
memcpy(my_function, &closure->func, sizeof(zend_op_array));
} else {
my_function = emalloc(sizeof(zend_internal_function));
memcpy(my_function, &closure->func, sizeof(zend_internal_function));
}
my_function->common.fn_flags &= ~ZEND_ACC_CLOSURE;
/* use scope of passed object */
my_function.common.scope = newclass;
my_function->common.scope = newclass;
if (closure->func.type == ZEND_INTERNAL_FUNCTION) {
my_function.internal_function.handler = closure->orig_internal_handler;
my_function->internal_function.handler = closure->orig_internal_handler;
}
fci_cache.function_handler = &my_function;
fci_cache.function_handler = my_function;

/* Runtime cache relies on bound scope to be immutable, hence we need a separate rt cache in case scope changed */
if (ZEND_USER_CODE(my_function.type)
if (ZEND_USER_CODE(my_function->type)
&& (closure->func.common.scope != newclass
|| (closure->func.common.fn_flags & ZEND_ACC_HEAP_RT_CACHE))) {
void *ptr;

my_function.op_array.fn_flags |= ZEND_ACC_HEAP_RT_CACHE;
ptr = emalloc(my_function.op_array.cache_size);
ZEND_MAP_PTR_INIT(my_function.op_array.run_time_cache, ptr);
memset(ptr, 0, my_function.op_array.cache_size);
my_function->op_array.fn_flags |= ZEND_ACC_HEAP_RT_CACHE;
ptr = emalloc(my_function->op_array.cache_size);
ZEND_MAP_PTR_INIT(my_function->op_array.run_time_cache, ptr);
memset(ptr, 0, my_function->op_array.cache_size);
}
}

fci_cache.called_scope = newclass;
fci_cache.object = fci.object = newobj;
zend_call_function(&fci, &fci_cache);

fci.size = sizeof(fci);
ZVAL_OBJ(&fci.function_name, &closure->std);
fci.retval = &closure_result;
if (ZEND_USER_CODE(my_function->type)) {
if (fci_cache.function_handler->common.fn_flags & ZEND_ACC_HEAP_RT_CACHE) {
efree(ZEND_MAP_PTR(my_function->op_array.run_time_cache));
}
efree_size(my_function, sizeof(zend_op_array));
} else {
efree_size(my_function, sizeof(zend_internal_function));
}
}

if (zend_call_function(&fci, &fci_cache) == SUCCESS && Z_TYPE(closure_result) != IS_UNDEF) {
if (Z_TYPE(closure_result) != IS_UNDEF) {
if (Z_ISREF(closure_result)) {
zend_unwrap_reference(&closure_result);
}
ZVAL_COPY_VALUE(return_value, &closure_result);
}

if (fci_cache.function_handler->common.fn_flags & ZEND_ACC_GENERATOR) {
/* copied upon generator creation */
GC_DELREF(&closure->std);
} else if (ZEND_USER_CODE(my_function.type)
&& (fci_cache.function_handler->common.fn_flags & ZEND_ACC_HEAP_RT_CACHE)) {
efree(ZEND_MAP_PTR(my_function.op_array.run_time_cache));
}
}
/* }}} */

Expand Down

0 comments on commit b576bb9

Please sign in to comment.