Skip to content
Permalink
Browse files

Add support for magic property comprehension

  • Loading branch information...
muglug committed Aug 6, 2019
1 parent 6eb6259 commit 8f6d432dd07d86b12095b2151335e037f7dc6587
@@ -408,6 +408,8 @@ public static function analyzeInstance(
if (!in_array('PossiblyNullReference', $suppressed_issues, true)) {
$statements_analyzer->removeSuppressedIssues(['PossiblyNullReference']);
}
self::taintProperty($statements_analyzer, $stmt, $property_id, $assignment_value_type);
}
/*
@@ -456,44 +458,7 @@ public static function analyzeInstance(
}
}
if ($codebase->taint) {
$method_source = new TypeSource(
$property_id,
new CodeLocation($statements_analyzer->getSource(), $stmt)
);
if ($codebase->taint->hasPreviousSink($method_source)) {
if ($assignment_value_type->sources) {
$codebase->taint->addSinks(
$statements_analyzer,
$assignment_value_type->sources,
new CodeLocation($statements_analyzer->getSource(), $stmt),
$method_source
);
}
}
if ($assignment_value_type->sources) {
foreach ($assignment_value_type->sources as $type_source) {
if ($codebase->taint->hasPreviousSource($type_source)
|| $assignment_value_type->tainted
) {
$codebase->taint->addSources(
$statements_analyzer,
[$method_source],
new CodeLocation($statements_analyzer->getSource(), $stmt),
$type_source
);
}
}
} elseif ($assignment_value_type->tainted) {
throw new \UnexpectedValueException(
'sources should exist for tainted var in '
. $statements_analyzer->getFileName() . ':'
. $stmt->getLine()
);
}
}
self::taintProperty($statements_analyzer, $stmt, $property_id, $assignment_value_type);
if (!$codebase->properties->propertyExists(
$property_id,
@@ -946,6 +911,56 @@ public static function analyzeInstance(
return null;
}
private static function taintProperty(
StatementsAnalyzer $statements_analyzer,
PhpParser\Node\Expr\PropertyFetch $stmt,
string $property_id,
Type\Union $assignment_value_type
) : void {
$codebase = $statements_analyzer->getCodebase();
if (!$codebase->taint) {
return;
}
$method_source = new TypeSource(
$property_id,
new CodeLocation($statements_analyzer->getSource(), $stmt)
);
if ($codebase->taint->hasPreviousSink($method_source)) {
if ($assignment_value_type->sources) {
$codebase->taint->addSinks(
$statements_analyzer,
$assignment_value_type->sources,
new CodeLocation($statements_analyzer->getSource(), $stmt),
$method_source
);
}
}
if ($assignment_value_type->sources) {
foreach ($assignment_value_type->sources as $type_source) {
if ($codebase->taint->hasPreviousSource($type_source)
|| $assignment_value_type->tainted
) {
$codebase->taint->addSources(
$statements_analyzer,
[$method_source],
new CodeLocation($statements_analyzer->getSource(), $stmt),
$type_source
);
}
}
} elseif ($assignment_value_type->tainted) {
throw new \UnexpectedValueException(
'sources should exist for tainted var in '
. $statements_analyzer->getFileName() . ':'
. $stmt->getLine()
);
}
}
/**
* @param StatementsAnalyzer $statements_analyzer
* @param PhpParser\Node\Expr\StaticPropertyFetch $stmt
@@ -544,6 +544,20 @@ public static function analyzeInstance(
$stmt->inferredType = $fake_method_call->inferredType ?? Type::getMixed();
$property_id = $lhs_type_part->value . '::$' . $prop_name;
if ($codebase->taint) {
$method_source = new TypeSource(
$property_id,
new CodeLocation($statements_analyzer, $stmt->name)
);
if ($codebase->taint->hasPreviousSource($method_source)) {
$stmt->inferredType->tainted = 1;
$stmt->inferredType->sources = [$method_source];
}
}
/*
* If we have an explicit list of all allowed magic properties on the class, and we're
* not in that list, fall through
@@ -657,4 +657,37 @@ public function bar() : void {
$this->analyzeFile('somefile.php', new Context());
}
public function testTaintedInputFromMagicProperty() : void
{
$this->expectException(\Psalm\Exception\CodeException::class);
$this->expectExceptionMessage('TaintedInput');
$this->project_analyzer->trackTaintedInputs();
$this->addFile(
'somefile.php',
'<?php
class A {
/** @var array<string, string> */
private $vars = [];
public function __get(string $s) : string {
return $this->vars[$s];
}
public function __set(string $s, string $t) {
$this->vars[$s] = $t;
}
}
function getAppendedUserId() : void {
$a = new A();
$a->userId = (string) $_GET["user_id"];
echo $a->userId;
}'
);
$this->analyzeFile('somefile.php', new Context());
}
}

0 comments on commit 8f6d432

Please sign in to comment.
You can’t perform that action at this time.