mirror of
https://github.com/danog/psalm.git
synced 2025-01-21 21:31:13 +01:00
Allow limiting connected taint paths
This commit is contained in:
parent
043c4b2a98
commit
953be61cf2
@ -10,6 +10,7 @@
|
||||
<xs:complexType name="PsalmType">
|
||||
<xs:choice maxOccurs="unbounded">
|
||||
<xs:element name="projectFiles" type="ProjectFilesType" minOccurs="1" maxOccurs="1" />
|
||||
<xs:element name="taintAnalysis" type="TaintAnalysisType" minOccurs="0" maxOccurs="1" />
|
||||
<xs:element name="fileExtensions" type="FileExtensionsType" minOccurs="0" maxOccurs="1" />
|
||||
<xs:element name="mockClasses" type="MockClassesType" minOccurs="0" maxOccurs="1" />
|
||||
<xs:element name="stubs" type="StubsType" minOccurs="0" maxOccurs="1" />
|
||||
@ -79,6 +80,12 @@
|
||||
</xs:choice>
|
||||
</xs:complexType>
|
||||
|
||||
<xs:complexType name="TaintAnalysisType">
|
||||
<xs:choice maxOccurs="unbounded">
|
||||
<xs:element name="ignoreFiles" minOccurs="0" maxOccurs="1" type="IgnoreFilesType" />
|
||||
</xs:choice>
|
||||
</xs:complexType>
|
||||
|
||||
<xs:complexType name="NameAttributeType">
|
||||
<xs:attribute name="name" type="xs:string" use="required" />
|
||||
</xs:complexType>
|
||||
|
@ -40,6 +40,7 @@ use function preg_quote;
|
||||
use function preg_replace;
|
||||
use Psalm\Config\IssueHandler;
|
||||
use Psalm\Config\ProjectFileFilter;
|
||||
use Psalm\Config\TaintAnalysisFileFilter;
|
||||
use Psalm\Exception\ConfigException;
|
||||
use Psalm\Internal\Analyzer\ClassLikeAnalyzer;
|
||||
use Psalm\Internal\Analyzer\FileAnalyzer;
|
||||
@ -550,6 +551,11 @@ class Config
|
||||
*/
|
||||
public $max_string_length = 1000;
|
||||
|
||||
/**
|
||||
* @var ProjectFileFilter|null
|
||||
*/
|
||||
protected $taint_analysis_ignored_files;
|
||||
|
||||
protected function __construct()
|
||||
{
|
||||
self::$instance = $this;
|
||||
@ -894,6 +900,14 @@ class Config
|
||||
$config->project_files = ProjectFileFilter::loadFromXMLElement($config_xml->projectFiles, $base_dir, true);
|
||||
}
|
||||
|
||||
if (isset($config_xml->taintAnalysis->ignoreFiles)) {
|
||||
$config->taint_analysis_ignored_files = TaintAnalysisFileFilter::loadFromXMLElement(
|
||||
$config_xml->taintAnalysis->ignoreFiles,
|
||||
$base_dir,
|
||||
false
|
||||
);
|
||||
}
|
||||
|
||||
if (isset($config_xml->fileExtensions)) {
|
||||
$config->file_extensions = [];
|
||||
|
||||
@ -1349,6 +1363,12 @@ class Config
|
||||
return $this->project_files && $this->project_files->forbids($file_path);
|
||||
}
|
||||
|
||||
public function trackTaintsInPath(string $file_path) : bool
|
||||
{
|
||||
return !$this->taint_analysis_ignored_files
|
||||
|| $this->taint_analysis_ignored_files->allows($file_path);
|
||||
}
|
||||
|
||||
public function getReportingLevelForIssue(CodeIssue $e) : string
|
||||
{
|
||||
$fqcn_parts = explode('\\', get_class($e));
|
||||
|
10
src/Psalm/Config/TaintAnalysisFileFilter.php
Normal file
10
src/Psalm/Config/TaintAnalysisFileFilter.php
Normal file
@ -0,0 +1,10 @@
|
||||
<?php
|
||||
namespace Psalm\Config;
|
||||
|
||||
use SimpleXMLElement;
|
||||
use function stripos;
|
||||
use function strpos;
|
||||
|
||||
class TaintAnalysisFileFilter extends FileFilter
|
||||
{
|
||||
}
|
@ -34,7 +34,9 @@ class EchoAnalyzer
|
||||
ExpressionAnalyzer::analyze($statements_analyzer, $expr, $context);
|
||||
$context->inside_call = false;
|
||||
|
||||
if ($codebase->taint) {
|
||||
if ($codebase->taint
|
||||
&& $codebase->config->trackTaintsInPath($statements_analyzer->getFilePath())
|
||||
) {
|
||||
$expr_location = new CodeLocation($statements_analyzer->getSource(), $expr);
|
||||
$call_location = new CodeLocation($statements_analyzer->getSource(), $stmt);
|
||||
|
||||
|
@ -1074,7 +1074,7 @@ class PropertyAssignmentAnalyzer
|
||||
) : void {
|
||||
$codebase = $statements_analyzer->getCodebase();
|
||||
|
||||
if (!$codebase->taint) {
|
||||
if (!$codebase->taint || !$codebase->config->trackTaintsInPath($statements_analyzer->getFilePath())) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -941,7 +941,9 @@ class AssignmentAnalyzer
|
||||
return $context->vars_in_scope[$var_id];
|
||||
}
|
||||
|
||||
if ($codebase->taint) {
|
||||
if ($codebase->taint
|
||||
&& $codebase->config->trackTaintsInPath($statements_analyzer->getFilePath())
|
||||
) {
|
||||
if ($context->vars_in_scope[$var_id]->parent_nodes) {
|
||||
$var_location = new CodeLocation($statements_analyzer->getSource(), $assign_var);
|
||||
|
||||
@ -1117,7 +1119,10 @@ class AssignmentAnalyzer
|
||||
$context->vars_in_scope[$array_var_id] = $result_type;
|
||||
$statements_analyzer->node_data->setType($stmt, clone $context->vars_in_scope[$array_var_id]);
|
||||
|
||||
if ($codebase->taint && $result_type) {
|
||||
if ($codebase->taint
|
||||
&& $result_type
|
||||
&& $codebase->config->trackTaintsInPath($statements_analyzer->getFilePath())
|
||||
) {
|
||||
$stmt_left_type = $statements_analyzer->node_data->getType($stmt->var);
|
||||
$stmt_right_type = $statements_analyzer->node_data->getType($stmt->expr);
|
||||
|
||||
|
@ -106,7 +106,9 @@ class BinaryOpAnalyzer
|
||||
|
||||
$codebase = $statements_analyzer->getCodebase();
|
||||
|
||||
if ($codebase->taint) {
|
||||
if ($codebase->taint
|
||||
&& $codebase->config->trackTaintsInPath($statements_analyzer->getFilePath())
|
||||
) {
|
||||
$stmt_left_type = $statements_analyzer->node_data->getType($stmt->left);
|
||||
$stmt_right_type = $statements_analyzer->node_data->getType($stmt->right);
|
||||
|
||||
|
@ -1127,7 +1127,7 @@ class ArgumentAnalyzer
|
||||
) : void {
|
||||
$codebase = $statements_analyzer->getCodebase();
|
||||
|
||||
if (!$codebase->taint) {
|
||||
if (!$codebase->taint || !$codebase->config->trackTaintsInPath($statements_analyzer->getFilePath())) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -992,7 +992,12 @@ class FunctionCallAnalyzer extends CallAnalyzer
|
||||
}
|
||||
}
|
||||
|
||||
if ($codebase->taint && $function_storage && $function_storage->return_source_params && $stmt_type) {
|
||||
if ($codebase->taint
|
||||
&& $function_storage
|
||||
&& $function_storage->return_source_params
|
||||
&& $stmt_type
|
||||
&& $codebase->config->trackTaintsInPath($statements_analyzer->getFilePath())
|
||||
) {
|
||||
foreach ($function_storage->return_source_params as $i) {
|
||||
if (!isset($stmt->args[$i])) {
|
||||
continue;
|
||||
|
@ -184,7 +184,10 @@ class MethodCallReturnTypeFetcher
|
||||
$return_type_candidate = $method_name === '__tostring' ? Type::getString() : Type::getMixed();
|
||||
}
|
||||
|
||||
if ($codebase->taint && $declaring_method_id) {
|
||||
if ($codebase->taint
|
||||
&& $declaring_method_id
|
||||
&& $codebase->config->trackTaintsInPath($statements_analyzer->getFilePath())
|
||||
) {
|
||||
$method_storage = $codebase->methods->getStorage(
|
||||
$declaring_method_id
|
||||
);
|
||||
|
@ -1152,7 +1152,9 @@ class StaticCallAnalyzer extends \Psalm\Internal\Analyzer\Statements\Expression\
|
||||
}
|
||||
|
||||
if ($return_type_candidate) {
|
||||
if ($codebase->taint) {
|
||||
if ($codebase->taint
|
||||
&& $codebase->config->trackTaintsInPath($statements_analyzer->getFilePath())
|
||||
) {
|
||||
$code_location = new CodeLocation($statements_analyzer->getSource(), $stmt);
|
||||
|
||||
if ($method_storage && $method_storage->pure) {
|
||||
|
@ -25,7 +25,10 @@ class EvalAnalyzer
|
||||
if ($expr_type) {
|
||||
$codebase = $statements_analyzer->getCodebase();
|
||||
|
||||
if ($codebase->taint && $expr_type->parent_nodes) {
|
||||
if ($codebase->taint
|
||||
&& $expr_type->parent_nodes
|
||||
&& $codebase->config->trackTaintsInPath($statements_analyzer->getFilePath())
|
||||
) {
|
||||
$arg_location = new CodeLocation($statements_analyzer->getSource(), $stmt->expr);
|
||||
|
||||
$eval_param_sink = Sink::getForMethodArgument(
|
||||
|
@ -1593,7 +1593,7 @@ class ArrayFetchAnalyzer
|
||||
Type\Union $stmt_type,
|
||||
string $array_var_id
|
||||
) : void {
|
||||
if ($codebase->taint) {
|
||||
if ($codebase->taint && $codebase->config->trackTaintsInPath($statements_analyzer->getFilePath())) {
|
||||
if ($array_var_id === '$_GET' || $array_var_id === '$_POST' || $array_var_id === '$_COOKIE') {
|
||||
$taint_location = new CodeLocation($statements_analyzer->getSource(), $stmt);
|
||||
|
||||
|
@ -1046,7 +1046,7 @@ class PropertyFetchAnalyzer
|
||||
) : void {
|
||||
$codebase = $statements_analyzer->getCodebase();
|
||||
|
||||
if ($codebase->taint) {
|
||||
if ($codebase->taint && $codebase->config->trackTaintsInPath($statements_analyzer->getFilePath())) {
|
||||
$code_location = new CodeLocation($statements_analyzer, $stmt->name);
|
||||
|
||||
$localized_property_node = new TaintNode(
|
||||
|
@ -263,7 +263,10 @@ class IncludeAnalyzer
|
||||
if ($stmt_type && $statements_analyzer) {
|
||||
$codebase = $statements_analyzer->getCodebase();
|
||||
|
||||
if ($codebase->taint && $stmt_type->parent_nodes) {
|
||||
if ($codebase->taint
|
||||
&& $stmt_type->parent_nodes
|
||||
&& $codebase->config->trackTaintsInPath($statements_analyzer->getFilePath())
|
||||
) {
|
||||
$arg_location = new CodeLocation($statements_analyzer->getSource(), $stmt);
|
||||
|
||||
$include_param_sink = Sink::getForMethodArgument(
|
||||
|
@ -192,13 +192,17 @@ class ReturnAnalyzer
|
||||
$source->getParentFQCLN()
|
||||
);
|
||||
|
||||
self::handleTaints(
|
||||
$codebase,
|
||||
$stmt,
|
||||
$cased_method_id,
|
||||
$inferred_type,
|
||||
$storage
|
||||
);
|
||||
if ($codebase->taint
|
||||
&& $codebase->config->trackTaintsInPath($statements_analyzer->getFilePath())
|
||||
) {
|
||||
self::handleTaints(
|
||||
$codebase,
|
||||
$stmt,
|
||||
$cased_method_id,
|
||||
$inferred_type,
|
||||
$storage
|
||||
);
|
||||
}
|
||||
|
||||
if ($storage instanceof \Psalm\Storage\MethodStorage && $context->self) {
|
||||
$self_class = $context->self;
|
||||
@ -493,10 +497,6 @@ class ReturnAnalyzer
|
||||
|
||||
$codebase->taint->addTaintNode($method_node);
|
||||
|
||||
if ($storage->specialize_call) {
|
||||
//$codebase->taint->addSpecializedCall($cased_method_id);
|
||||
}
|
||||
|
||||
if ($inferred_type->parent_nodes) {
|
||||
foreach ($inferred_type->parent_nodes as $parent_node) {
|
||||
$codebase->taint->addPath(
|
||||
|
Loading…
x
Reference in New Issue
Block a user