Permalink
Browse files

Highly probable crashes after modifying removing or renaming of funct…

…ions, methods, and properties, for which Reflection objects have been instantiated,

were eliminated (#30)
  • Loading branch information...
1 parent cd189c0 commit c37ad348af9a4b7647a96ebc1b41749228ff7964 @zenovich committed Sep 25, 2012
View
@@ -39,6 +39,8 @@ Execute code in restricted environment (sandboxing).
New constant RUNKIT_ACC_RETURN_REFERENCE was introduced for use with functions runkit_method_add and runkit_method_redefine
Critical fixes:
+ * Highly probable crashes after modifying removing or renaming of functions, methods, and properties,
+ for which Reflection objects have been instantiated, were eliminated
* Crash on sandbox creation when register_globals is switched on was fixed
* Building and working with PHP4 were fixed
* Crash on syntax error in source file importing with runkit_import was fixed
View

Large diffs are not rendered by default.

Oops, something went wrong.
View
@@ -162,6 +162,36 @@ PHP_INI_END()
ZEND_GET_MODULE(runkit)
#endif
+#ifdef PHP_RUNKIT_MANIPULATION
+# ifdef ZEND_ENGINE_2
+ZEND_FUNCTION(_php_runkit_removed_function) {
+ php_error_docref(NULL TSRMLS_CC, E_ERROR, "A function removed by runkit was somehow invoked");
+}
+ZEND_FUNCTION(_php_runkit_removed_method) {
+ php_error_docref(NULL TSRMLS_CC, E_ERROR, "A method removed by runkit was somehow invoked");
+}
+
+static inline void _php_runkit_init_stub_function(char *name, void (*handler)(INTERNAL_FUNCTION_PARAMETERS), zend_function **result) {
+ *result = emalloc(sizeof(zend_function));
+ (*result)->common.function_name = name;
+ (*result)->common.scope = NULL;
+ (*result)->common.arg_info = NULL;
+ (*result)->common.num_args = 0;
+ (*result)->common.type = ZEND_INTERNAL_FUNCTION;
+ (*result)->common.fn_flags = ZEND_ACC_PUBLIC | ZEND_ACC_STATIC;
+ (*result)->common.arg_info = NULL;
+#if PHP_MAJOR_VERSION == 5 && PHP_MINOR_VERSION < 4
+ (*result)->common.pass_rest_by_reference = 0;
+#endif
+ (*result)->internal_function.handler = handler;
+#if PHP_MAJOR_VERSION == 5 && PHP_MINOR_VERSION < 4
+ (*result)->internal_function.return_reference = 0;
+#endif
+ (*result)->internal_function.module = &runkit_module_entry;
+}
+# endif
+#endif
+
#if defined(PHP_RUNKIT_SANDBOX) || defined(PHP_RUNKIT_MANIPULATION)
static void php_runkit_globals_ctor(void *pDest TSRMLS_DC)
{
@@ -172,6 +202,21 @@ static void php_runkit_globals_ctor(void *pDest TSRMLS_DC)
#ifdef PHP_RUNKIT_MANIPULATION
runkit_global->replaced_internal_functions = NULL;
runkit_global->misplaced_internal_functions = NULL;
+# ifdef ZEND_ENGINE_2
+ MAKE_STD_ZVAL(runkit_global->name_str_zval);
+ ZVAL_STRINGL(runkit_global->name_str_zval, "name", sizeof("name") - 1, 1);
+ MAKE_STD_ZVAL(runkit_global->removed_method_str_zval);
+ ZVAL_STRINGL(runkit_global->removed_method_str_zval, "__method_removed_by_runkit__", sizeof("__method_removed_by_runkit__") - 1, 1);
+ MAKE_STD_ZVAL(runkit_global->removed_function_str_zval);
+ ZVAL_STRINGL(runkit_global->removed_function_str_zval, "__function_removed_by_runkit__", sizeof("__function_removed_by_runkit__") - 1, 1);
+ MAKE_STD_ZVAL(runkit_global->removed_parameter_str_zval);
+ ZVAL_STRINGL(runkit_global->removed_parameter_str_zval, "__parameter_removed_by_runkit__", sizeof("__parameter_removed_by_runkit__") - 1, 1);
+ MAKE_STD_ZVAL(runkit_global->removed_property_str_zval);
+ ZVAL_STRINGL(runkit_global->removed_property_str_zval, "__property_removed_by_runkit__", sizeof("__property_removed_by_runkit__") - 1, 1);
+
+ _php_runkit_init_stub_function("__function_removed_by_runkit__", ZEND_FN(_php_runkit_removed_function), &runkit_global->removed_function);
+ _php_runkit_init_stub_function("__method_removed_by_runkit__", ZEND_FN(_php_runkit_removed_method), &runkit_global->removed_method);
+# endif
#endif
}
#endif
@@ -275,6 +320,14 @@ PHP_MSHUTDOWN_FUNCTION(runkit)
#if defined(PHP_RUNKIT_SUPERGLOBALS) || defined(PHP_RUNKIT_MANIPULATION)
UNREGISTER_INI_ENTRIES();
#endif
+# ifdef PHP_RUNKIT_MANIPULATION
+# ifdef ZEND_ENGINE_2
+ zval_ptr_dtor(&RUNKIT_G(name_str_zval));
+ zval_ptr_dtor(&RUNKIT_G(removed_method_str_zval));
+ zval_ptr_dtor(&RUNKIT_G(removed_function_str_zval));
+ zval_ptr_dtor(&RUNKIT_G(removed_parameter_str_zval));
+# endif
+#endif
return (1)
#ifdef PHP_RUNKIT_SANDBOX
View
@@ -47,6 +47,9 @@ static int php_runkit_remove_inherited_methods(zend_function *fe, zend_class_ent
zend_hash_apply_with_arguments(RUNKIT_53_TSRMLS_PARAM(EG(class_table)), (apply_func_args_t)php_runkit_clean_children_methods, 5,
ancestor_class, ce, fname_lower, function_name_len, fe);
PHP_RUNKIT_DEL_MAGIC_METHOD(ce, fe);
+#ifdef ZEND_ENGINE_2
+ php_runkit_remove_function_from_reflection_objects(fe TSRMLS_CC);
+#endif
efree(fname_lower);
return ZEND_HASH_APPLY_REMOVE;
View
@@ -369,6 +369,65 @@ void php_runkit_clear_all_functions_runtime_cache(TSRMLS_D)
/* }}} */
#endif
+#ifdef ZEND_ENGINE_2
+/* {{{ php_runkit_remove_function_from_reflection_objects */
+void php_runkit_remove_function_from_reflection_objects(zend_function *fe TSRMLS_DC) {
+ int i;
+ extern PHPAPI zend_class_entry *reflection_function_ptr;
+ extern PHPAPI zend_class_entry *reflection_method_ptr;
+ extern PHPAPI zend_class_entry *reflection_parameter_ptr;
+
+ if (!EG(objects_store).object_buckets) {
+ return;
+ }
+
+ for (i = 1; i < EG(objects_store).top ; i++) {
+ if (EG(objects_store).object_buckets[i].valid && (!EG(objects_store).object_buckets[i].destructor_called) &&
+ EG(objects_store).object_buckets[i].bucket.obj.object) {
+ zend_object *object;
+ object = (zend_object *) EG(objects_store).object_buckets[i].bucket.obj.object;
+ if (object->ce == reflection_function_ptr) {
+ reflection_object *refl_obj = (reflection_object *) object;
+ if (refl_obj->ptr == fe) {
+ PHP_RUNKIT_DELETE_REFLECTION_FUNCTION_PTR(refl_obj);
+ refl_obj->ptr = RUNKIT_G(removed_function);
+#if !RUNKIT_ABOVE53
+ refl_obj->free_ptr = 0;
+#endif
+ PHP_RUNKIT_UPDATE_REFLECTION_OBJECT_NAME(object, i, RUNKIT_G(removed_function_str_zval));
+ }
+ } else if (object->ce == reflection_method_ptr) {
+ reflection_object *refl_obj = (reflection_object *) object;
+ if (refl_obj->ptr == fe) {
+ zend_function *f = emalloc(sizeof(zend_function));
+ memcpy(f, RUNKIT_G(removed_method), sizeof(zend_function));
+ f->common.scope = fe->common.scope;
+ f->internal_function.fn_flags |= ZEND_ACC_CALL_VIA_HANDLER; // This is a trigger to free it from destructor
+#if RUNKIT_ABOVE53
+ f->internal_function.function_name = estrdup(f->internal_function.function_name);
+#endif
+ PHP_RUNKIT_DELETE_REFLECTION_FUNCTION_PTR(refl_obj);
+ refl_obj->ptr = f;
+#if !RUNKIT_ABOVE53
+ refl_obj->free_ptr = 1;
+#endif
+ PHP_RUNKIT_UPDATE_REFLECTION_OBJECT_NAME(object, i, RUNKIT_G(removed_method_str_zval));
+ }
+ } else if (object->ce == reflection_parameter_ptr) {
+ reflection_object *refl_obj = (reflection_object *) object;
+ parameter_reference *reference = (parameter_reference *) refl_obj->ptr;
+ if (reference && reference->fptr == fe) {
+ PHP_RUNKIT_DELETE_REFLECTION_FUNCTION_PTR(refl_obj);
+ refl_obj->ptr = NULL;
+ PHP_RUNKIT_UPDATE_REFLECTION_OBJECT_NAME(object, i, RUNKIT_G(removed_parameter_str_zval));
+ }
+ }
+ }
+ }
+}
+/* }}} */
+#endif
+
/* {{{ php_runkit_generate_lambda_method
Heavily borrowed from ZEND_FUNCTION(create_function) */
int php_runkit_generate_lambda_method(const char *arguments, int arguments_len, const char *phpcode, int phpcode_len,
@@ -517,12 +576,13 @@ PHP_FUNCTION(runkit_function_remove)
PHP_RUNKIT_DECL_STRING_PARAM(funcname)
char *funcname_lower;
int result;
+ zend_function *fe;
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, PHP_RUNKIT_STRING_SPEC "/", PHP_RUNKIT_STRING_PARAM(funcname)) == FAILURE) {
RETURN_FALSE;
}
- if (php_runkit_fetch_function(PHP_RUNKIT_STRING_TYPE(funcname), funcname, funcname_len, NULL, PHP_RUNKIT_FETCH_FUNCTION_REMOVE TSRMLS_CC) == FAILURE) {
+ if (php_runkit_fetch_function(PHP_RUNKIT_STRING_TYPE(funcname), funcname, funcname_len, &fe, PHP_RUNKIT_FETCH_FUNCTION_REMOVE TSRMLS_CC) == FAILURE) {
RETURN_FALSE;
}
@@ -533,6 +593,10 @@ PHP_FUNCTION(runkit_function_remove)
}
php_strtolower(funcname_lower, funcname_len);
+#ifdef ZEND_ENGINE_2
+ php_runkit_remove_function_from_reflection_objects(fe TSRMLS_CC);
+#endif
+
result = (zend_hash_del(EG(function_table), funcname_lower, funcname_len + 1) == SUCCESS);
efree(funcname_lower);
@@ -591,6 +655,10 @@ PHP_FUNCTION(runkit_function_rename)
func = *fe;
PHP_RUNKIT_FUNCTION_ADD_REF(&func);
+#ifdef ZEND_ENGINE_2
+ php_runkit_remove_function_from_reflection_objects(fe TSRMLS_CC);
+#endif
+
if (zend_hash_del(EG(function_table), sfunc_lower, sfunc_len + 1) == FAILURE) {
efree(dfunc_lower);
efree(sfunc_lower);
@@ -632,6 +700,7 @@ PHP_FUNCTION(runkit_function_redefine)
zend_bool return_ref = 0;
char *delta = NULL, *delta_desc;
int retval;
+ zend_function *fe;
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC,
PHP_RUNKIT_STRING_SPEC "/" PHP_RUNKIT_STRING_SPEC PHP_RUNKIT_STRING_SPEC "|b",
@@ -643,7 +712,7 @@ PHP_FUNCTION(runkit_function_redefine)
}
/* UTODO */
- if (php_runkit_fetch_function(PHP_RUNKIT_STRING_TYPE(funcname), funcname, funcname_len, NULL, PHP_RUNKIT_FETCH_FUNCTION_REMOVE TSRMLS_CC) == FAILURE) {
+ if (php_runkit_fetch_function(PHP_RUNKIT_STRING_TYPE(funcname), funcname, funcname_len, &fe, PHP_RUNKIT_FETCH_FUNCTION_REMOVE TSRMLS_CC) == FAILURE) {
RETURN_FALSE;
}
@@ -655,6 +724,10 @@ PHP_FUNCTION(runkit_function_redefine)
funcname_lower_len = funcname_len;
PHP_RUNKIT_STRTOLOWER(funcname_lower);
+#ifdef ZEND_ENGINE_2
+ php_runkit_remove_function_from_reflection_objects(fe TSRMLS_CC);
+#endif
+
if (zend_hash_del(EG(function_table), funcname_lower, funcname_len + 1) == FAILURE) {
efree(funcname_lower);
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to remove old function definition for %s()", funcname);
View
@@ -35,7 +35,7 @@ static int php_runkit_import_functions(HashTable *function_table, long flags
zend_hash_internal_pointer_reset_ex(function_table, &pos);
for(i = 0; i < func_count; i++) {
- zend_function *fe = NULL;
+ zend_function *fe = NULL, *orig_fe;
char *key;
const char *new_key;
uint key_len, new_key_len;
@@ -55,12 +55,15 @@ static int php_runkit_import_functions(HashTable *function_table, long flags
if (type == HASH_KEY_IS_STRING) {
new_key = key;
new_key_len = key_len;
- exists = zend_hash_exists(EG(function_table), (char *) new_key, new_key_len);
+ exists = (zend_hash_find(EG(function_table), (char *) new_key, new_key_len, (void *) &orig_fe) == SUCCESS);
} else {
- exists = zend_hash_index_exists(EG(function_table), idx);
+ exists = (zend_hash_index_find(EG(function_table), idx, (void *) &orig_fe) == SUCCESS);
}
if (exists) {
+#ifdef ZEND_ENGINE_2
+ php_runkit_remove_function_from_reflection_objects(orig_fe TSRMLS_CC);
+#endif
if (flags & PHP_RUNKIT_IMPORT_OVERRIDE) {
if (type == HASH_KEY_IS_STRING) {
if (zend_hash_del(EG(function_table), (char *) new_key, new_key_len) == FAILURE) {
@@ -158,6 +161,9 @@ static int php_runkit_import_class_methods(zend_class_entry *dce, zend_class_ent
#endif
zend_hash_apply_with_arguments(RUNKIT_53_TSRMLS_PARAM(EG(class_table)), (apply_func_args_t)php_runkit_clean_children_methods, 5, scope, dce, fn, fn_len, dfe);
+#ifdef ZEND_ENGINE_2
+ php_runkit_remove_function_from_reflection_objects(dfe TSRMLS_CC);
+#endif
if (zend_hash_del(&dce->function_table, fn, fn_len + 1) == FAILURE) {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Error removing old method in destination class %s::%s", dce->name, fe->common.function_name);
zend_hash_move_forward_ex(&ce->function_table, &pos);
View
@@ -287,9 +287,14 @@ int php_runkit_update_children_methods(RUNKIT_53_TSRMLS_ARG(zend_class_entry *ce
);
#endif
- if (cfe && zend_hash_del(&ce->function_table, fname_lower, fname_len + 1) == FAILURE) {
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "Error updating child class");
- return ZEND_HASH_APPLY_KEEP;
+ if (cfe) {
+#ifdef ZEND_ENGINE_2
+ php_runkit_remove_function_from_reflection_objects(cfe TSRMLS_CC);
+#endif
+ if (zend_hash_del(&ce->function_table, fname_lower, fname_len + 1) == FAILURE) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Error updating child class");
+ return ZEND_HASH_APPLY_KEEP;
+ }
}
if (zend_hash_add(&ce->function_table, fname_lower, fname_len + 1, fe, sizeof(zend_function), NULL) == FAILURE) {
@@ -347,6 +352,10 @@ int php_runkit_clean_children_methods(RUNKIT_53_TSRMLS_ARG(zend_class_entry *ce)
/* Process children of this child */
zend_hash_apply_with_arguments(RUNKIT_53_TSRMLS_PARAM(EG(class_table)), (apply_func_args_t)php_runkit_clean_children_methods, 5, ancestor_class, ce, fname_lower, fname_len, orig_cfe);
+#ifdef ZEND_ENGINE_2
+ php_runkit_remove_function_from_reflection_objects(cfe TSRMLS_CC);
+#endif
+
zend_hash_del(&ce->function_table, fname_lower, fname_len + 1);
PHP_RUNKIT_DEL_MAGIC_METHOD(ce, orig_cfe);
@@ -453,6 +462,12 @@ static void php_runkit_method_add_or_update(INTERNAL_FUNCTION_PARAMETERS, int ad
methodname_len == ce->name_length && !strncmp(ce->name, methodname_lower, ce->name_length));
#endif
+#ifdef ZEND_ENGINE_2
+ if(orig_fe) {
+ php_runkit_remove_function_from_reflection_objects(orig_fe TSRMLS_CC);
+ }
+#endif
+
if (zend_hash_add_or_update(&ce->function_table, methodname_lower, methodname_len + 1, &func, sizeof(zend_function), NULL, add_or_update) == FAILURE) {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to add method to class");
efree(methodname_lower);
@@ -610,6 +625,10 @@ PHP_FUNCTION(runkit_method_remove)
php_runkit_clear_all_functions_runtime_cache(TSRMLS_C);
#endif
+#ifdef ZEND_ENGINE_2
+ php_runkit_remove_function_from_reflection_objects(fe TSRMLS_CC);
+#endif
+
if (zend_hash_del(&ce->function_table, methodname_lower, methodname_len + 1) == FAILURE) {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to remove method from class");
efree(methodname_lower);
@@ -690,6 +709,10 @@ PHP_FUNCTION(runkit_method_rename)
RETURN_FALSE;
}
+#ifdef ZEND_ENGINE_2
+ php_runkit_remove_function_from_reflection_objects(fe TSRMLS_CC);
+#endif
+
if (zend_hash_del(&ce->function_table, methodname_lower, methodname_len + 1) == FAILURE) {
efree(newname_lower);
efree(methodname_lower);
Oops, something went wrong.

0 comments on commit c37ad34

Please sign in to comment.