Skip to content
Permalink
Browse files

Improve taint protection for exec-related commands

  • Loading branch information...
muglug committed Aug 13, 2019
1 parent 2b2988b commit c3949e3194425bec716386b4711250a3d9a7c7a6
@@ -957,6 +957,10 @@ private static function taintProperty(
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 @@ private static function taintProperty(
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],
@@ -161,7 +161,7 @@ public static function analyze(
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(
@@ -859,6 +859,7 @@ private static function processTaints(
if ($tainted_source = $codebase->taint->hasPreviousSource($method_source)) {
$type->tainted = $tainted_source->taint;
$method_source->taint = $type->tainted;
}
}
}
@@ -209,6 +209,8 @@ public static function getCallablesFromCallMap($function_id)
$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 @@ public static function getCallablesFromCallMap($function_id)
$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);
@@ -305,7 +305,7 @@ public function isCallMapFunctionPure(Codebase $codebase, string $function_id, a
'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',
@@ -751,4 +751,23 @@ function foo() : void {
$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());
}
}

0 comments on commit c3949e3

Please sign in to comment.
You can’t perform that action at this time.