Skip to content

Commit

Permalink
Merge pull request #8150 from muglug/track-taints-in-static-properties
Browse files Browse the repository at this point in the history
Track taints in static properties
  • Loading branch information
orklah committed Jun 24, 2022
2 parents cbc597f + 7be32f2 commit f2f211c
Show file tree
Hide file tree
Showing 5 changed files with 201 additions and 92 deletions.
Expand Up @@ -463,9 +463,6 @@ private static function taintProperty(

$data_flow_graph = $statements_analyzer->data_flow_graph;

$var_location = new CodeLocation($statements_analyzer->getSource(), $stmt->var);
$property_location = new CodeLocation($statements_analyzer->getSource(), $stmt);

if ($class_storage->specialize_instance) {
$var_id = ExpressionIdentifier::getExtendedVarId(
$stmt->var,
Expand All @@ -487,13 +484,17 @@ private static function taintProperty(
return;
}

$var_location = new CodeLocation($statements_analyzer->getSource(), $stmt->var);

$var_node = DataFlowNode::getForAssignment(
$var_id,
$var_location
);

$data_flow_graph->addNode($var_node);

$property_location = new CodeLocation($statements_analyzer->getSource(), $stmt);

$property_node = DataFlowNode::getForAssignment(
$var_property_id ?: $var_id . '->$property',
$property_location
Expand Down Expand Up @@ -547,77 +548,108 @@ private static function taintProperty(
$statements_analyzer
);

$localized_property_node = DataFlowNode::getForAssignment(
self::taintUnspecializedProperty(
$statements_analyzer,
$stmt,
$property_id,
$class_storage,
$assignment_value_type,
$context,
$var_property_id
?: $property_id . '-' . $property_location->file_name . ':' . $property_location->raw_file_start,
$property_location
);
}
}

$data_flow_graph->addNode($localized_property_node);
public static function taintUnspecializedProperty(
StatementsAnalyzer $statements_analyzer,
PhpParser\Node\Expr $stmt,
string $property_id,
ClassLikeStorage $class_storage,
Union $assignment_value_type,
Context $context,
?string $var_property_id
): void {
$codebase = $statements_analyzer->getCodebase();

$property_node = new DataFlowNode(
$property_id,
$property_id,
null,
null
);
$data_flow_graph = $statements_analyzer->data_flow_graph;

$data_flow_graph->addNode($property_node);
if (!$data_flow_graph) {
return;
}

$event = new AddRemoveTaintsEvent($stmt, $context, $statements_analyzer, $codebase);
$property_location = new CodeLocation($statements_analyzer->getSource(), $stmt);

$added_taints = $codebase->config->eventDispatcher->dispatchAddTaints($event);
$removed_taints = $codebase->config->eventDispatcher->dispatchRemoveTaints($event);
$localized_property_node = DataFlowNode::getForAssignment(
$var_property_id ?: $property_id,
$property_location
);

$data_flow_graph->addPath(
$localized_property_node,
$property_node,
'property-assignment',
$added_taints,
$removed_taints
);
$data_flow_graph->addNode($localized_property_node);

if ($assignment_value_type->parent_nodes) {
foreach ($assignment_value_type->parent_nodes as $parent_node) {
$data_flow_graph->addPath(
$parent_node,
$localized_property_node,
'=',
$added_taints,
$removed_taints
);
}
}
$property_node = new DataFlowNode(
$property_id,
$property_id,
null,
null
);

$declaring_property_class = $codebase->properties->getDeclaringClassForProperty(
$property_id,
false,
$statements_analyzer
);
$data_flow_graph->addNode($property_node);

if ($statements_analyzer->data_flow_graph instanceof TaintFlowGraph
&& $declaring_property_class
&& $declaring_property_class !== $class_storage->name
&& $stmt->name instanceof PhpParser\Node\Identifier
) {
$declaring_property_node = new DataFlowNode(
$declaring_property_class . '::$' . $stmt->name,
$declaring_property_class . '::$' . $stmt->name,
null,
null
);
$event = new AddRemoveTaintsEvent($stmt, $context, $statements_analyzer, $codebase);

$data_flow_graph->addNode($declaring_property_node);
$added_taints = $codebase->config->eventDispatcher->dispatchAddTaints($event);
$removed_taints = $codebase->config->eventDispatcher->dispatchRemoveTaints($event);

$data_flow_graph->addPath(
$localized_property_node,
$property_node,
'property-assignment',
$added_taints,
$removed_taints
);

if ($assignment_value_type->parent_nodes) {
foreach ($assignment_value_type->parent_nodes as $parent_node) {
$data_flow_graph->addPath(
$property_node,
$declaring_property_node,
'property-assignment',
$parent_node,
$localized_property_node,
'=',
$added_taints,
$removed_taints
);
}
}

$declaring_property_class = $codebase->properties->getDeclaringClassForProperty(
$property_id,
false,
$statements_analyzer
);

if ($statements_analyzer->data_flow_graph instanceof TaintFlowGraph
&& $declaring_property_class
&& $declaring_property_class !== $class_storage->name
&& ($stmt instanceof PhpParser\Node\Expr\PropertyFetch
|| $stmt instanceof PhpParser\Node\Expr\StaticPropertyFetch)
&& $stmt->name instanceof PhpParser\Node\Identifier
) {
$declaring_property_node = new DataFlowNode(
$declaring_property_class . '::$' . $stmt->name,
$declaring_property_class . '::$' . $stmt->name,
null,
null
);

$data_flow_graph->addNode($declaring_property_node);

$data_flow_graph->addPath(
$property_node,
$declaring_property_node,
'property-assignment',
$added_taints,
$removed_taints
);
}
}

/**
Expand Down
Expand Up @@ -196,6 +196,16 @@ public static function analyze(
$context->vars_in_scope[$var_id] = $assignment_value_type;
}

InstancePropertyAssignmentAnalyzer::taintUnspecializedProperty(
$statements_analyzer,
$stmt,
$property_id,
$class_storage,
$assignment_value_type,
$context,
null
);

$class_property_type = $codebase->properties->getPropertyType(
$property_id,
true,
Expand Down
Expand Up @@ -773,9 +773,6 @@ public static function processTaints(

$data_flow_graph = $statements_analyzer->data_flow_graph;

$var_location = new CodeLocation($statements_analyzer->getSource(), $stmt->var);
$property_location = new CodeLocation($statements_analyzer->getSource(), $stmt);

$added_taints = [];
$removed_taints = [];

Expand Down Expand Up @@ -811,6 +808,9 @@ public static function processTaints(
return;
}

$var_location = new CodeLocation($statements_analyzer->getSource(), $stmt->var);
$property_location = new CodeLocation($statements_analyzer->getSource(), $stmt);

$var_node = DataFlowNode::getForAssignment(
$var_id,
$var_location
Expand Down Expand Up @@ -849,49 +849,80 @@ public static function processTaints(
$type->parent_nodes = [$property_node->id => $property_node];
}
} else {
$var_property_id = ExpressionIdentifier::getExtendedVarId(
self::processUnspecialTaints(
$statements_analyzer,
$stmt,
null,
$statements_analyzer
$type,
$property_id,
$in_assignment,
$added_taints,
$removed_taints
);
}
}

$localized_property_node = DataFlowNode::getForAssignment(
$var_property_id
?: $property_id . '-' . $property_location->file_name . ':' . $property_location->raw_file_start,
$property_location
);
/**
* @param ?array<string> $added_taints
* @param ?array<string> $removed_taints
*/
public static function processUnspecialTaints(
StatementsAnalyzer $statements_analyzer,
PhpParser\Node\Expr $stmt,
Union $type,
string $property_id,
bool $in_assignment,
?array $added_taints,
?array $removed_taints
): void {
if (!$statements_analyzer->data_flow_graph) {
return;
}

$data_flow_graph->addNode($localized_property_node);
$data_flow_graph = $statements_analyzer->data_flow_graph;

$property_node = new DataFlowNode(
$property_id,
$property_id,
null,
null
);
$var_property_id = ExpressionIdentifier::getExtendedVarId(
$stmt,
null,
$statements_analyzer
);

$data_flow_graph->addNode($property_node);
$property_location = new CodeLocation($statements_analyzer->getSource(), $stmt);

if ($in_assignment) {
$data_flow_graph->addPath(
$localized_property_node,
$property_node,
'property-assignment',
$added_taints,
$removed_taints
);
} else {
$data_flow_graph->addPath(
$property_node,
$localized_property_node,
'property-fetch',
$added_taints,
$removed_taints
);
}
$localized_property_node = DataFlowNode::getForAssignment(
$var_property_id ?: $property_id,
$property_location
);

$data_flow_graph->addNode($localized_property_node);

$type->parent_nodes = [$localized_property_node->id => $localized_property_node];
$property_node = new DataFlowNode(
$property_id,
$property_id,
null,
null
);

$data_flow_graph->addNode($property_node);

if ($in_assignment) {
$data_flow_graph->addPath(
$localized_property_node,
$property_node,
'property-assignment',
$added_taints,
$removed_taints
);
} else {
$data_flow_graph->addPath(
$property_node,
$localized_property_node,
'property-fetch',
$added_taints,
$removed_taints
);
}

$type->parent_nodes = [$localized_property_node->id => $localized_property_node];
}

private static function handleEnumName(
Expand Down
Expand Up @@ -231,6 +231,16 @@ public static function analyze(
);
}

AtomicPropertyFetchAnalyzer::processUnspecialTaints(
$statements_analyzer,
$stmt,
$stmt_type,
$property_id,
false,
[],
[]
);

return true;
}

Expand Down Expand Up @@ -389,6 +399,16 @@ public static function analyze(
$stmt_type->getId()
);
}

AtomicPropertyFetchAnalyzer::processUnspecialTaints(
$statements_analyzer,
$stmt,
$stmt_type,
$property_id,
false,
[],
[]
);
} else {
$statements_analyzer->node_data->setType($stmt, Type::getMixed());
}
Expand Down
16 changes: 16 additions & 0 deletions tests/TaintTest.php
Expand Up @@ -2349,6 +2349,22 @@ function bar(array $arr): void {
}',
'error_message' => 'TaintedHtml',
],
'checkMemoizedStaticMethodCallTaints' => [
'code' => '<?php
class A {
private static string $prev = "";
public static function getPrevious(string $s): string {
$prev = self::$prev;
self::$prev = $s;
return $prev;
}
}
A::getPrevious($_GET["a"]);
echo A::getPrevious("foo");',
'error_message' => 'TaintedHtml',
],
];
}

Expand Down

0 comments on commit f2f211c

Please sign in to comment.