mirror of
https://github.com/danog/psalm.git
synced 2024-11-26 20:34:47 +01:00
Perform string casting for taints in ArgumentAnalyzer
This commit is contained in:
parent
1a582fa636
commit
f6e2e0a84a
@ -41,6 +41,7 @@ class EchoAnalyzer
|
||||
$expr_type = CastAnalyzer::castStringAttempt(
|
||||
$statements_analyzer,
|
||||
$context,
|
||||
$expr_type,
|
||||
$expr,
|
||||
false
|
||||
);
|
||||
|
@ -8,6 +8,7 @@ use Psalm\Internal\Analyzer\MethodAnalyzer;
|
||||
use Psalm\Internal\Analyzer\Statements\Block\ForeachAnalyzer;
|
||||
use Psalm\Internal\Analyzer\Statements\Expression\CallAnalyzer;
|
||||
use Psalm\Internal\Analyzer\Statements\Expression\ExpressionIdentifier;
|
||||
use Psalm\Internal\Analyzer\Statements\Expression\CastAnalyzer;
|
||||
use Psalm\Internal\Analyzer\StatementsAnalyzer;
|
||||
use Psalm\Internal\Analyzer\TypeAnalyzer;
|
||||
use Psalm\Internal\Taint\Sink;
|
||||
@ -346,7 +347,7 @@ class ArgumentAnalyzer
|
||||
if ($cased_method_id) {
|
||||
$arg_location = new CodeLocation($statements_analyzer->getSource(), $arg->value);
|
||||
|
||||
self::processTaintedness(
|
||||
$arg_type = self::processTaintedness(
|
||||
$statements_analyzer,
|
||||
$cased_method_id,
|
||||
$argument_offset,
|
||||
@ -354,6 +355,8 @@ class ArgumentAnalyzer
|
||||
$function_call_location,
|
||||
$function_param,
|
||||
$arg_type,
|
||||
$arg->value,
|
||||
$context,
|
||||
$specialize_taint
|
||||
);
|
||||
}
|
||||
@ -479,7 +482,7 @@ class ArgumentAnalyzer
|
||||
}
|
||||
|
||||
if ($cased_method_id) {
|
||||
self::processTaintedness(
|
||||
$input_type = self::processTaintedness(
|
||||
$statements_analyzer,
|
||||
$cased_method_id,
|
||||
$argument_offset,
|
||||
@ -487,6 +490,8 @@ class ArgumentAnalyzer
|
||||
$function_call_location,
|
||||
$function_param,
|
||||
$input_type,
|
||||
$input_expr,
|
||||
$context,
|
||||
$specialize_taint
|
||||
);
|
||||
}
|
||||
@ -542,7 +547,7 @@ class ArgumentAnalyzer
|
||||
}
|
||||
|
||||
if ($cased_method_id) {
|
||||
self::processTaintedness(
|
||||
$input_type = self::processTaintedness(
|
||||
$statements_analyzer,
|
||||
$cased_method_id,
|
||||
$argument_offset,
|
||||
@ -550,6 +555,8 @@ class ArgumentAnalyzer
|
||||
$function_call_location,
|
||||
$function_param,
|
||||
$input_type,
|
||||
$input_expr,
|
||||
$context,
|
||||
$specialize_taint
|
||||
);
|
||||
}
|
||||
@ -628,7 +635,7 @@ class ArgumentAnalyzer
|
||||
if ($cased_method_id) {
|
||||
$old_input_type = $input_type;
|
||||
|
||||
self::processTaintedness(
|
||||
$input_type = self::processTaintedness(
|
||||
$statements_analyzer,
|
||||
$cased_method_id,
|
||||
$argument_offset,
|
||||
@ -636,6 +643,8 @@ class ArgumentAnalyzer
|
||||
$function_call_location,
|
||||
$function_param,
|
||||
$input_type,
|
||||
$input_expr,
|
||||
$context,
|
||||
$specialize_taint
|
||||
);
|
||||
|
||||
@ -1135,13 +1144,25 @@ class ArgumentAnalyzer
|
||||
CodeLocation $arg_location,
|
||||
CodeLocation $function_call_location,
|
||||
FunctionLikeParameter $function_param,
|
||||
Type\Union &$input_type,
|
||||
Type\Union $input_type,
|
||||
PhpParser\Node\Expr $expr,
|
||||
Context $context,
|
||||
bool $specialize_taint
|
||||
) : void {
|
||||
) : Type\Union {
|
||||
$codebase = $statements_analyzer->getCodebase();
|
||||
|
||||
if (!$codebase->taint || !$codebase->config->trackTaintsInPath($statements_analyzer->getFilePath())) {
|
||||
return;
|
||||
return $input_type;
|
||||
}
|
||||
|
||||
if ($function_param->type && $function_param->type->isString()) {
|
||||
$input_type = CastAnalyzer::castStringAttempt(
|
||||
$statements_analyzer,
|
||||
$context,
|
||||
$input_type,
|
||||
$expr,
|
||||
false
|
||||
);
|
||||
}
|
||||
|
||||
if ($specialize_taint) {
|
||||
@ -1243,5 +1264,7 @@ class ArgumentAnalyzer
|
||||
$input_type = clone $input_type;
|
||||
$input_type->parent_nodes = [];
|
||||
}
|
||||
|
||||
return $input_type;
|
||||
}
|
||||
}
|
||||
|
@ -91,7 +91,13 @@ class CastAnalyzer
|
||||
$stmt_expr_type = $statements_analyzer->node_data->getType($stmt->expr);
|
||||
|
||||
if ($stmt_expr_type) {
|
||||
$stmt_type = self::castStringAttempt($statements_analyzer, $context, $stmt->expr, true);
|
||||
$stmt_type = self::castStringAttempt(
|
||||
$statements_analyzer,
|
||||
$context,
|
||||
$stmt_expr_type,
|
||||
$stmt->expr,
|
||||
true
|
||||
);
|
||||
} else {
|
||||
$stmt_type = Type::getString();
|
||||
}
|
||||
@ -177,17 +183,12 @@ class CastAnalyzer
|
||||
public static function castStringAttempt(
|
||||
StatementsAnalyzer $statements_analyzer,
|
||||
Context $context,
|
||||
Type\Union $stmt_type,
|
||||
PhpParser\Node\Expr $stmt,
|
||||
bool $explicit_cast = false
|
||||
) : Type\Union {
|
||||
$codebase = $statements_analyzer->getCodebase();
|
||||
|
||||
$stmt_type = $statements_analyzer->node_data->getType($stmt);
|
||||
|
||||
if (!$stmt_type) {
|
||||
return Type::getString();
|
||||
}
|
||||
|
||||
$invalid_casts = [];
|
||||
$valid_strings = [];
|
||||
$castable_types = [];
|
||||
|
@ -27,7 +27,12 @@ class EncapsulatedStringAnalyzer
|
||||
$part_type = $statements_analyzer->node_data->getType($part);
|
||||
|
||||
if ($part_type) {
|
||||
$casted_part_type = CastAnalyzer::castStringAttempt($statements_analyzer, $context, $part);
|
||||
$casted_part_type = CastAnalyzer::castStringAttempt(
|
||||
$statements_analyzer,
|
||||
$context,
|
||||
$part_type,
|
||||
$part
|
||||
);
|
||||
|
||||
if ($codebase->taint
|
||||
&& $codebase->config->trackTaintsInPath($statements_analyzer->getFilePath())
|
||||
|
@ -1251,6 +1251,23 @@ class TaintTest extends TestCase
|
||||
echo $unsafe;',
|
||||
'error_message' => 'TaintedInput',
|
||||
],
|
||||
'castToStringViaArgument' => [
|
||||
'<?php
|
||||
class MyClass {
|
||||
public function __toString() {
|
||||
return $_GET["blah"];
|
||||
}
|
||||
}
|
||||
|
||||
function doesEcho(string $s) {
|
||||
echo $s;
|
||||
}
|
||||
|
||||
$unsafe = new MyClass();
|
||||
|
||||
doesEcho($unsafe);',
|
||||
'error_message' => 'TaintedInput',
|
||||
],
|
||||
'toStringTaintInSubclass' => [
|
||||
'<?php // --taint-analysis
|
||||
class TaintedBaseClass {
|
||||
|
Loading…
Reference in New Issue
Block a user