1
0
mirror of https://github.com/danog/psalm.git synced 2024-11-26 20:34:47 +01:00

Improve taint protection for exec-related commands

This commit is contained in:
Brown 2019-08-13 19:18:50 -04:00
parent 2b2988b072
commit c3949e3194
6 changed files with 47 additions and 3 deletions

View File

@ -957,6 +957,10 @@ class PropertyAssignmentAnalyzer
new CodeLocation($statements_analyzer->getSource(), $stmt)
);
if ($assignment_value_type->tainted) {
$method_source->taint = $assignment_value_type->tainted;
}
if ($codebase->taint->hasPreviousSink($method_source)) {
if ($assignment_value_type->sources) {
$codebase->taint->addSinks(
@ -970,9 +974,13 @@ class PropertyAssignmentAnalyzer
if ($assignment_value_type->sources) {
foreach ($assignment_value_type->sources as $type_source) {
if ($codebase->taint->hasPreviousSource($type_source)
if (($previous_source = $codebase->taint->hasPreviousSource($type_source))
|| $assignment_value_type->tainted
) {
if ($previous_source) {
$method_source->taint = $previous_source->taint;
}
$codebase->taint->addSources(
$statements_analyzer,
[$method_source],

View File

@ -161,7 +161,7 @@ class ArrayFetchAnalyzer
null
);
if ($array_var_id === '$_GET' || $array_var_id === '$_POST') {
if ($array_var_id === '$_GET' || $array_var_id === '$_POST' || $array_var_id === '$_COOKIE') {
$stmt->inferredType->tainted = (int) Type\Union::TAINTED_INPUT;
$stmt->inferredType->sources = [
new TypeSource(

View File

@ -859,6 +859,7 @@ class PropertyFetchAnalyzer
if ($tainted_source = $codebase->taint->hasPreviousSource($method_source)) {
$type->tainted = $tainted_source->taint;
$method_source->taint = $type->tainted;
}
}
}

View File

@ -209,6 +209,8 @@ class CallMap
$function_params = [];
$arg_offset = 0;
/** @var string $arg_name - key type changed with above array_shift */
foreach ($call_map_function_args as $arg_name => $arg_type) {
$by_reference = false;
@ -245,9 +247,23 @@ class CallMap
$variadic
);
if ($arg_offset === 0
&& ($function_id === 'exec'
|| $function_id === 'shell_exec'
|| $function_id === 'passthru'
|| $function_id === 'system'
|| $function_id === 'pcntl_exec'
|| $function_id === 'file_put_contents'
|| $function_id === 'fopen')
) {
$function_param->sink = Type\Union::TAINTED_INPUT_SHELL;
}
$function_param->signature_type = null;
$function_params[] = $function_param;
$arg_offset++;
}
$possible_callables[] = new TCallable('callable', $function_params, $return_type);

View File

@ -305,7 +305,7 @@ class Functions
'newrelic_set_appname',
// execution
'shell_exec', 'exec', 'system', 'passthru',
'shell_exec', 'exec', 'system', 'passthru', 'pcntl_exec',
// well-known functions
'libxml_use_internal_errors', 'array_map', 'curl_exec',

View File

@ -751,4 +751,23 @@ class TaintTest extends TestCase
$this->analyzeFile('somefile.php', new Context());
}
public function testTaintIntoExec() : 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);
}'
);
$this->analyzeFile('somefile.php', new Context());
}
}