# zend_execute_internal hook missing from PHP 5

- Thread: https://externals.io/message/60623
- Original archive: https://news-web.php.net/php.internals/60623
- Started by Stefan Esser on 2012-05-21T10:41:24+00:00
- Messages: 10
- Reply by email to internals@lists.php.net
- More for agents: search with https://externals.io/search.md?q={query} · JSON API at https://externals.io/api · documentation at https://externals.io/llms.txt

---

## #60623 — Stefan Esser — 2012-05-21T10:41:24+00:00

URL: https://externals.io/message/60623#60623

Hi,

it recently came to my attention that the function whitelist and blacklist feature inside Suhosin is easily bypassable since PHP 5.0.

The reason for this is that PHP is no longer calling the zend_execute_internal() hook if a function is called from another function (via zend_call_function)

In the days of PHP 4 the code looked like this:

		if (!zend_execute_internal) {
			((zend_internal_function *) EX(function_state).function)->handler(EX(opline)->extended_value, EX(Ts)[EX(opline)->result.u.var].var.ptr, EX(object).ptr, 1 TSRMLS_CC);
		} else {
			zend_execute_internal(&execute_data, 1 TSRMLS_CC);
		}

Nowadays (since PHP 5.0) the code was moved from call_user_function_ex to zend_call_function and just looks like this:

		((zend_internal_function *) EX(function_state).function)->handler(fci->param_count, *fci->retval_ptr_ptr, fci->retval_ptr_ptr, fci->object_ptr, 1 TSRMLS_CC);


While this has no immediate impact for average PHP users, it basically kills the possibility for an extension like Suhosin to catch all function starts.
This should also be a problem for your DTRACE support. And IIRC Xdebug was hooking this point (at least in the past), too.

My suggestion is to change the code to call the hook again.

Regards,
Stefan

---

## #60624 — Derick Rethans — 2012-05-21T12:22:20+00:00

URL: https://externals.io/message/60623#60624 · In reply to: #60623

> While this has no immediate impact for average PHP users, it basically 
> kills the possibility for an extension like Suhosin to catch all 
> function starts. This should also be a problem for your DTRACE 
> support. And IIRC Xdebug was hooking this point (at least in the 
> past), too.

Indeed. And it finally explains why functions called from `array_map()` 
didn't show up in function traces anymore!

> My suggestion is to change the code to call the hook again.

Yes, I'd like that too.

cheers,
Derick

---

## #60625 — Xinchen Hui — 2012-05-21T12:41:48+00:00

URL: https://externals.io/message/60623#60625 · In reply to: #60623

Sent from my iPhone

在 2012-5-21，18:42，Stefan Esser <stefan.esser@sektioneins.de> 写道：

> Hi,
>
> it recently came to my attention that the function whitelist and blacklist feature inside Suhosin is easily bypassable since PHP 5.0.
>
> The reason for this is that PHP is no longer calling the zend_execute_internal() hook if a function is called from another function (via zend_call_function)
>
> In the days of PHP 4 the code looked like this:
>
>        if (!zend_execute_internal) {
>            ((zend_internal_function *) EX(function_state).function)->handler(EX(opline)->extended_value, EX(Ts)[EX(opline)->result.u.var].var.ptr, EX(object).ptr, 1 TSRMLS_CC);
>        } else {
>            zend_execute_internal(&execute_data, 1 TSRMLS_CC);
>        }
>
> Nowadays (since PHP 5.0) the code was moved from call_user_function_ex to zend_call_function and just looks like this:
>
>        ((zend_internal_function *) EX(function_state).function)->handler(fci->param_count, *fci->retval_ptr_ptr, fci->retval_ptr_ptr, fci->object_ptr, 1 TSRMLS_CC);
>
>
> While this has no immediate impact for average PHP users, it basically kills the possibility for an extension like Suhosin to catch all function starts.
Actually, there is one, use user opcode handler hook the fcall series
opcodes, that is how I did in taint extension.

http://svn.php.net/viewvc/pecl/taint/trunk/taint.c?view=markup&pathrev=325586
line 995

Thanks
> This should also be a problem for your DTRACE support. And IIRC Xdebug was hooking this point (at least in the past), too.
>
> My suggestion is to change the code to call the hook again.
>
> Regards,
> Stefan

---

## #60626 — Stefan Esser — 2012-05-21T13:04:59+00:00

URL: https://externals.io/message/60623#60626 · In reply to: #60625

Hi,

> > […]
> Actually, there is one, use user opcode handler hook the fcall series
> opcodes, that is how I did in taint extension.

From what I can see your taint extension also does not catch functions called by `call_user_func()` or `array_map()` or or or…

Regards,
Stefan

---

## #60627 — Xinchen Hui — 2012-05-21T14:38:09+00:00

URL: https://externals.io/message/60623#60627 · In reply to: #60626

发自我的 iPad

在 2012-5-21，21:05，Stefan Esser <stefan.esser@sektioneins.de> 写道：

> Hi,
>
> > […]
>
> From what I can see your taint extension also does not catch functions called by `call_user_func()` or `array_map()` or or or…
I just want to say there is a way in theory ,   If you want a 100%
intercept that you can also use override call_user_function
additionally,  which is also what I did to mark some function's return
value in taint extension.  Of course it's a little ugly, but it works
:)

Thanks
>
> Regards,
> Stefan

---

## #60670 — Stas Malyshev — 2012-05-23T14:50:13+00:00

URL: https://externals.io/message/60623#60670 · In reply to: #60623

Hi!

> Nowadays (since PHP 5.0) the code was moved from
> call_user_function_ex to zend_call_function and just looks like
> this:
> 
> ((zend_internal_function *)
> EX(function_state).function)->handler(fci->param_count,
> *fci->retval_ptr_ptr, fci->retval_ptr_ptr, fci->object_ptr, 1
> TSRMLS_CC);

So in zend_vm_def.h we have:

                if (!zend_execute_internal) {
                        /* saves one function call if
zend_execute_internal is not used */

fbc->internal_function.handler(opline->extended_value, ret->var.ptr,
(fbc->common.fn_flags & ZEND_ACC_RETURN_REFERENCE) ? &ret->var.ptr :
NULL, EX(object), RETURN_VALUE_USED(opline) TSRMLS_CC);
                } else {
                        zend_execute_internal(EXECUTE_DATA,
RETURN_VALUE_USED(opline) TSRMLS_CC);
                }

But in zend_call_function it goes just:

                ((zend_internal_function *)
EX(function_state).function)->handler(fci->param_count,
*fci->retval_ptr_ptr, fci->retval_ptr_ptr, fci->object_ptr, 1 TSRMLS_CC);

So looks like the code is not consistent. You can still catch user
functions with zend_execute override but not the internal ones. No idea
why the difference exists, I'll look through commits and if I find no
reason I guess the should be synchronized.
-- 
Stanislav Malyshev, Software Architect
SugarCRM: http://www.sugarcrm.com/
(408)454-6900 ext. 227

---

## #60690 — Stas Malyshev — 2012-05-29T23:22:23+00:00

URL: https://externals.io/message/60623#60690 · In reply to: #60623

Hi!

> it recently came to my attention that the function whitelist and
> blacklist feature inside Suhosin is easily bypassable since PHP 5.0.

Did you have a bug report for this? If not, could you please submit one
so we could track it properly? If yes, please send me its number.

Thanks,
-- 
Stanislav Malyshev, Software Architect
SugarCRM: http://www.sugarcrm.com/
(408)454-6900 ext. 227

---

## #61264 — Stas Malyshev — 2012-07-16T00:15:38+00:00

URL: https://externals.io/message/60623#61264 · In reply to: #60623

Hi!

> Nowadays (since PHP 5.0) the code was moved from
> call_user_function_ex to zend_call_function and just looks like
> this:
> 
> ((zend_internal_function *)
> EX(function_state).function)->handler(fci->param_count,
> *fci->retval_ptr_ptr, fci->retval_ptr_ptr, fci->object_ptr, 1
> TSRMLS_CC);
> 
> 
> While this has no immediate impact for average PHP users, it
> basically kills the possibility for an extension like Suhosin to
> catch all function starts. This should also be a problem for your
> DTRACE support. And IIRC Xdebug was hooking this point (at least in
> the past), too.
> 
> My suggestion is to change the code to call the hook again.

There's a bit of a problem there. The problem is that execute_internal
looks like this:

	zval **return_value_ptr = &(*(temp_variable *)((char *)
execute_data_ptr->Ts + execute_data_ptr->opline->result.var)).var.ptr;
	((zend_internal_function *)
execute_data_ptr->function_state.function)->handler(execute_data_ptr->opline->extended_value,
*return_value_ptr,
(execute_data_ptr->function_state.function->common.fn_flags &
ZEND_ACC_RETURN_REFERENCE)?return_value_ptr:NULL,
execute_data_ptr->object, return_value_used TSRMLS_CC);

You note it takes return values from opline. Which is fine when running
PHP code, but when running internal function from internal function,
there's no opline. So zend_call_function calls this:

((zend_internal_function *)
EX(function_state).function)->handler(fci->param_count,
*fci->retval_ptr_ptr, fci->retval_ptr_ptr, fci->object_ptr, 1 TSRMLS_CC);

I.e. it uses data from fci. But if we use zend_execute_internal we have
only execute_data_ptr to work with, which has wrong return values. So we
need to either make fake opline somehow or find a way to pass correct
return vars to the handler via execute_internal. I'll see how it can be
done but that'd be probably in 5.5 since it may require some engine
changes, which is not an option for stable versions.

-- 
Stanislav Malyshev, Software Architect
SugarCRM: http://www.sugarcrm.com/
(408)454-6900 ext. 227

---

## #62555 — Stas Malyshev — 2012-08-27T06:37:34+00:00

URL: https://externals.io/message/60623#62555 · In reply to: #60623

Hi!

> While this has no immediate impact for average PHP users, it
> basically kills the possibility for an extension like Suhosin to
> catch all function starts. This should also be a problem for your
> DTRACE support. And IIRC Xdebug was hooking this point (at least in
> the past), too.
> 
> My suggestion is to change the code to call the hook again.

Please take a look at https://github.com/php/php-src/pull/178. Would it
be a satisfactory solution for this problem?

-- 
Stanislav Malyshev, Software Architect
SugarCRM: http://www.sugarcrm.com/
(408)454-6900 ext. 227

---

## #63258 — Derick Rethans — 2012-10-04T07:43:49+00:00

URL: https://externals.io/message/60623#63258 · In reply to: #62555

> > […]
> 
> Please take a look at https://github.com/php/php-src/pull/178. Would 
> it be a satisfactory solution for this problem?

Works for me! I think - I will give it a test with Xdebug.

cheers,
Derick

-- 
http://derickrethans.nl | http://xdebug.org
Like Xdebug? Consider a donation: http://xdebug.org/donate.php
twitter: @derickr and @xdebug
Posted with an email client that doesn't mangle email: alpine
