1
0
mirror of https://github.com/danog/psalm.git synced 2025-01-21 21:31:13 +01:00

Taint arrays in creation

This commit is contained in:
Matthew Brown 2019-10-11 23:28:17 -04:00
parent 5918278af3
commit 4478d31593
3 changed files with 120 additions and 0 deletions

View File

@ -57,6 +57,9 @@ class ArrayAnalyzer
$all_list = true;
$taint_sources = [];
$either_tainted = 0;
foreach ($stmt->items as $int_offset => $item) {
if ($item === null) {
continue;
@ -126,6 +129,18 @@ class ArrayAnalyzer
return false;
}
if ($codebase->taint) {
if (isset($item->value->inferredType)) {
$taint_sources = array_merge($taint_sources, $item->value->inferredType->sources ?: []);
$either_tainted = $either_tainted | $item->value->inferredType->tainted;
}
if (isset($item->key->inferredType)) {
$taint_sources = array_merge($taint_sources, $item->key->inferredType->sources ?: []);
$either_tainted = $either_tainted | $item->key->inferredType->tainted;
}
}
if ($item->byRef) {
$var_id = ExpressionAnalyzer::getArrayVarId(
$item->value,
@ -207,6 +222,14 @@ class ArrayAnalyzer
$stmt->inferredType = new Type\Union([$object_like]);
if ($taint_sources) {
$stmt->inferredType->sources = $taint_sources;
}
if ($either_tainted) {
$stmt->inferredType->tainted = $either_tainted;
}
return null;
}
@ -218,6 +241,14 @@ class ArrayAnalyzer
$array_type,
]);
if ($taint_sources) {
$stmt->inferredType->sources = $taint_sources;
}
if ($either_tainted) {
$stmt->inferredType->tainted = $either_tainted;
}
return null;
}
@ -232,6 +263,14 @@ class ArrayAnalyzer
$array_type,
]);
if ($taint_sources) {
$stmt->inferredType->sources = $taint_sources;
}
if ($either_tainted) {
$stmt->inferredType->tainted = $either_tainted;
}
return null;
}
}

View File

@ -264,6 +264,24 @@ class ArrayFetchAnalyzer
$context->hasVariable($keyed_array_var_id, $statements_analyzer);
}
if ($codebase->taint && isset($stmt->var->inferredType)) {
$sources = [];
$either_tainted = 0;
if (isset($stmt->var->inferredType)) {
$sources = array_merge($sources, $stmt->var->inferredType->sources ?: []);
$either_tainted = $either_tainted | $stmt->var->inferredType->tainted;
}
if ($sources) {
$stmt->inferredType->sources = $sources;
}
if ($either_tainted) {
$stmt->inferredType->tainted = $either_tainted;
}
}
return null;
}

View File

@ -770,4 +770,67 @@ class TaintTest extends TestCase
$this->analyzeFile('somefile.php', new Context());
}
public function testTaintIntoExecMultipleConcat() : void
{
$this->expectException(\Psalm\Exception\CodeException::class);
$this->expectExceptionMessage('TaintedInput');
$this->project_analyzer->trackTaintedInputs();
$this->addFile(
'somefile.php',
'<?php
function foo() : void {
$a = "9" . "a" . "b" . "c" . ((string) $_GET["bad"]) . "d" . "e" . "f";
exec($a);
}'
);
$this->analyzeFile('somefile.php', new Context());
}
public function testTaintIntoNestedArrayUnnestedSeparately() : void
{
$this->expectException(\Psalm\Exception\CodeException::class);
$this->expectExceptionMessage('TaintedInput');
$this->project_analyzer->trackTaintedInputs();
$this->addFile(
'somefile.php',
'<?php
function foo() : void {
$a = [[(string) $_GET["bad"]]];
exec($a[0][0]);
}'
);
$this->analyzeFile('somefile.php', new Context());
}
public function testTaintIntoArrayAndThenOutAgain() : void
{
$this->expectException(\Psalm\Exception\CodeException::class);
$this->expectExceptionMessage('TaintedInput');
$this->project_analyzer->trackTaintedInputs();
$this->addFile(
'somefile.php',
'<?php
class C {
public static function foo() : array {
$a = (string) $_GET["bad"];
return [$a];
}
public static function bar() {
exec(self::foo()[0]);
}
}'
);
$this->analyzeFile('somefile.php', new Context());
}
}