-
-
Notifications
You must be signed in to change notification settings - Fork 22
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Is it possible to handle '===' opcode? #39
Comments
As I know, is identical implemented directly as an opcode handler and it doesn't call object handlers at all. But you can install an opcode handler for |
Thank you for quick reply. As I understood: \ZEngine\System\OpCode::setHandler(\ZEngine\System\OpCode::IS_IDENTICAL,
function (\ZEngine\System\ExecutionData $executionState): int {
echo 'is_identical';
});
$o1 === $o2; it should echo is_identical, but I see nothing; Actually what I want to archive - I want to do taint analysis based on your lib. So I need a wrapper class (ValueObject) which can behave like the value it wraps in most cases and in the same time give the ability to call some methods on it. <?php
use ZEngine\ClassExtension\ObjectCastInterface;
use ZEngine\ClassExtension\ObjectCompareValuesInterface;
use ZEngine\ClassExtension\ObjectCreateInterface;
use ZEngine\ClassExtension\ObjectCreateTrait;
use ZEngine\ClassExtension\ObjectDoOperationInterface;
class Tainted implements
ObjectCastInterface,
ObjectCreateInterface,
ObjectCompareValuesInterface,
ObjectDoOperationInterface
{
use ObjectCreateTrait;
private $value;
private $isSafe = false;
public function __construct($value)
{
$this->value = $value;
}
public function value()
{
return $this->value;
}
public function markSafe()
{
$this->isSafe = true;
}
public function markUnsafe()
{
$this->isSafe = false;
}
public function isSafe(): bool
{
return $this->isSafe;
}
/**
* Performs comparison of given object with another value
*
* @param \ZEngine\ClassExtension\Hook\CompareValuesHook $hook Instance of current hook
*
* @return int Result of comparison: 1 is greater, -1 is less, 0 is equal
*/
public static function __compare(\ZEngine\ClassExtension\Hook\CompareValuesHook $hook): int
{
$first = $hook->getFirst();
$second = $hook->getSecond();
if (is_object($first) && get_class($first) === __CLASS__) {
$first = $first->value();
}
if (is_object($second) && get_class($second) === __CLASS__) {
$second = $second->value();
}
return $first <=> $second;
}
/**
* Performs an operation on given object
*
* @param \ZEngine\ClassExtension\Hook\DoOperationHook $hook Instance of current hook
*
* @return mixed Result of operation value
*/
public static function __doOperation(\ZEngine\ClassExtension\Hook\DoOperationHook $hook)
{
$first = $hook->getFirst();
$second = $hook->getSecond();
if (is_object($first) && get_class($first) === __CLASS__) {
$first = $first->value();
}
if (is_object($second) && get_class($second) === __CLASS__) {
$second = $second->value();
}
$opcode = $hook->getOpcode();
switch (true) {
case $opcode === \ZEngine\System\OpCode::ADD;
return new Tainted($first + $second);
case $opcode === \ZEngine\System\OpCode::SUB:
return new Tainted($first - $second);
case $opcode === \ZEngine\System\OpCode::CONCAT:
return new Tainted($first . $second);
case $opcode === \ZEngine\System\OpCode::IS_IDENTICAL:
return $first === $second;
// Here should be handling for all other opcodes...
}
}
/**
* Performs casting of given object to another value
*
* @param \ZEngine\ClassExtension\Hook\CastObjectHook $hook Instance of current hook
*
* @return mixed Casted value
*/
public static function __cast(\ZEngine\ClassExtension\Hook\CastObjectHook $hook)
{
return $hook->getObject()->value();
}
} I expect next behavior: $foo = new Tainted('foo');
$bar = new Tainted('bar');
$one = new Tainted(1);
$two = new Tainted(2);
echo $foo . $bar; //foobar
$one === 1; //true
$one == 1; //true
$two > $one;//true
// also instance of Tainted should pass type hints
function add(int $a, int $b) {
return $a + $b;
}
echo add($one, $two); //3
//And another key feature: ability to know function name in which tainted variable was passed
$xss = '<script>alert(1)</script>';
if (rand(0,1) {
//xss mitigation. **Tainted** should be some how notified in case it was to htmlspecialchars()
$xss = htmlspecialchars($xss);
}
var_dump($xss->isSafe()); Having such class I think it should be possible to wrap any variable at the beginning of the script and check if it safe at the end. |
I'm not sure if your idea is possible right now, because messing with typehints and value boxing/unboxing in runtime is unpredictable. Of course, it is possible to wrap everything during AST processing, but object will violate your Regarding your question about opcode handler: you should install it before the first inclusion of file that contains operations itself. PHP checks if specific opcode has user handler and generates specific version of opcodes to invoke custom handler. If you try to install handler after that - nothing will work... |
Thank you. Yes, it triggers handler if I put it in a separate file. Could provide a little example of how two write such handlers. It's not clear how to access $arguments and which integer should be returned. e.g. if I want to return $o1 === $o2;
\ZEngine\System\OpCode::setHandler(\ZEngine\System\OpCode::IS_IDENTICAL,
function (\ZEngine\System\ExecutionData $executionState): int {
//$executionState->getArguments() returns empty array. $o1 and $o2 expected
return Core::ZEND_USER_OPCODE_DISPATCH;// What should be returned here?
}); |
How to intercept
is identical
(===) check ? e.g.will trigger __compare() handler, while
doesn't trigger neither __compare() nor __doOperation() with \ZEngine\System\OpCode::IS_IDENTICAL;
The text was updated successfully, but these errors were encountered: