1
0
mirror of https://github.com/danog/psalm.git synced 2025-01-22 05:41:20 +01:00

Merge pull request #6993 from orklah/taint-numerics

Taint can't be transmitted through numerics nor bool
This commit is contained in:
orklah 2021-11-25 23:20:38 +01:00 committed by GitHub
commit 2fbad1bbeb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 72 additions and 32 deletions

View File

@ -12,6 +12,7 @@ use Psalm\Context;
use Psalm\Internal\Analyzer\FunctionLike\ReturnTypeAnalyzer;
use Psalm\Internal\Analyzer\FunctionLike\ReturnTypeCollector;
use Psalm\Internal\Analyzer\Statements\ExpressionAnalyzer;
use Psalm\Internal\Codebase\TaintFlowGraph;
use Psalm\Internal\DataFlow\DataFlowNode;
use Psalm\Internal\FileManipulation\FunctionDocblockManipulator;
use Psalm\Internal\Type\Comparator\TypeComparisonResult;
@ -1032,40 +1033,49 @@ abstract class FunctionLikeAnalyzer extends SourceAnalyzer
if ($statements_analyzer->data_flow_graph
&& $function_param->location
) {
$param_assignment = DataFlowNode::getForAssignment(
'$' . $function_param->name,
$function_param->location
);
$statements_analyzer->data_flow_graph->addNode($param_assignment);
if ($cased_method_id) {
$type_source = DataFlowNode::getForMethodArgument(
$cased_method_id,
$cased_method_id,
$offset,
$function_param->location,
null
);
$statements_analyzer->data_flow_graph->addPath($type_source, $param_assignment, 'param');
}
if ($function_param->by_ref
&& $codebase->find_unused_variables
//don't add to taint flow graph if the type can't transmit taints
if (!$statements_analyzer->data_flow_graph instanceof TaintFlowGraph
|| $function_param->type === null
|| !$function_param->type->isSingle()
|| (!$function_param->type->isInt()
&& !$function_param->type->isFloat()
&& !$function_param->type->isBool())
) {
$statements_analyzer->data_flow_graph->addPath(
$param_assignment,
new DataFlowNode('variable-use', 'variable use', null),
'variable-use'
$param_assignment = DataFlowNode::getForAssignment(
'$' . $function_param->name,
$function_param->location
);
}
if ($storage->variadic) {
$this->param_nodes += [$param_assignment->id => $param_assignment];
}
$statements_analyzer->data_flow_graph->addNode($param_assignment);
$var_type->parent_nodes += [$param_assignment->id => $param_assignment];
if ($cased_method_id) {
$type_source = DataFlowNode::getForMethodArgument(
$cased_method_id,
$cased_method_id,
$offset,
$function_param->location,
null
);
$statements_analyzer->data_flow_graph->addPath($type_source, $param_assignment, 'param');
}
if ($function_param->by_ref
&& $codebase->find_unused_variables
) {
$statements_analyzer->data_flow_graph->addPath(
$param_assignment,
new DataFlowNode('variable-use', 'variable use', null),
'variable-use'
);
}
if ($storage->variadic) {
$this->param_nodes += [$param_assignment->id => $param_assignment];
}
$var_type->parent_nodes += [$param_assignment->id => $param_assignment];
}
}
$context->vars_in_scope['$' . $function_param->name] = $var_type;

View File

@ -1505,10 +1505,10 @@ class ArgumentAnalyzer
return $input_type;
}
// numeric types can't be tainted
// numeric types can't be tainted, neither can bool
if ($statements_analyzer->data_flow_graph instanceof TaintFlowGraph
&& $input_type->isSingle()
&& ($input_type->isInt() || $input_type->isFloat())
&& ($input_type->isInt() || $input_type->isFloat() || $input_type->isBool())
) {
return $input_type;
}

View File

@ -671,6 +671,36 @@ class TaintTest extends TestCase
$var = $input + 1;
var_dump($var);'
],
'NoTaintForIntTypeHintUsingAnnotatedSink' => [
'<?php // --taint-analysis
function fetch(int $id): string
{
return query("SELECT * FROM table WHERE id=" . $id);
}
/**
* @return string
* @psalm-taint-sink sql $sql
* @psalm-taint-specialize
*/
function query(string $sql) {}
$value = $_GET["value"];
$result = fetch($value);'
],
'NoTaintForIntTypeCastUsingAnnotatedSink' => [
'<?php // --taint-analysis
function fetch($id): string
{
return query("SELECT * FROM table WHERE id=" . (int)$id);
}
/**
* @return string
* @psalm-taint-sink sql $sql
* @psalm-taint-specialize
*/
function query(string $sql) {}
$value = $_GET["value"];
$result = fetch($value);'
],
];
}