Brian Wolff has uploaded a new change for review. ( 
https://gerrit.wikimedia.org/r/395761 )

Change subject: Fix various false positives found when testing with MW
......................................................................

Fix various false positives found when testing with MW

Change-Id: I17f0dbd83c822faa0bcaa823f5adf15d6366d3f4
---
M src/MediaWikiSecurityCheckPlugin.php
M src/TaintednessBaseVisitor.php
M src/TaintednessVisitor.php
M tests/integration/arraynumkey/test.php
M tests/integration/cast/expectedResults.txt
M tests/integration/cast/test.php
M tests/integration/dbarrayplus/test.php
A tests/integration/prop2/expectedResults.txt
A tests/integration/prop2/test.php
9 files changed, 103 insertions(+), 10 deletions(-)


  git pull 
ssh://gerrit.wikimedia.org:29418/mediawiki/tools/phan/SecurityCheckPlugin 
refs/changes/61/395761/1

diff --git a/src/MediaWikiSecurityCheckPlugin.php 
b/src/MediaWikiSecurityCheckPlugin.php
index e67f6d9..0fa770d 100644
--- a/src/MediaWikiSecurityCheckPlugin.php
+++ b/src/MediaWikiSecurityCheckPlugin.php
@@ -131,8 +131,8 @@
                        ],
                        '\Wikimedia\Rdbms\IDatabase::insert' => [
                                self::SQL_EXEC_TAINT, // table name
-                               // Insert values. The keys names are unsafe.
-                               // Unclear how well this works for the multi 
case.
+                               // FIXME This doesn't correctly work
+                               // when inserting multiple things at once.
                                self::SQL_NUMKEY_EXEC_TAINT,
                                self::SQL_EXEC_TAINT, // method name
                                self::SQL_EXEC_TAINT, // options. They are not 
escaped
@@ -362,12 +362,28 @@
                                self::NO_TAINT,
                                'overall' => SecurityCheckPlugin::NO_TAINT,
                        ],
+                       '\ParserOutput::getText' => [
+                               self::NO_TAINT,
+                               'overall' => SecurityCheckPlugin::NO_TAINT,
+                       ],
                        '\Sanitizer::removeHTMLtags' => [
                                self::YES_TAINT & ~self::HTML_TAINT, /* text */
                                self::SHELL_EXEC_TAINT, /* attribute callback */
                                self::NO_TAINT, /* callback args */
                                self::YES_TAINT, /* extra tags */
                                self::NO_TAINT, /* remove tags */
+                               'overall' => SecurityCheckPlugin::NO_TAINT
+                       ],
+                       '\Sanitizer::escapeHtmlAllowEntities' => [
+                               self::YES_TAINT & ~self::HTML_TAINT,
+                               'overall' => SecurityCheckPlugin::NO_TAINT
+                       ],
+                       '\Sanitizer::safeEncodeAttribute' => [
+                               self::YES_TAINT & ~self::HTML_TAINT,
+                               'overall' => SecurityCheckPlugin::NO_TAINT
+                       ],
+                       '\Sanitizer::encodeAttribute' => [
+                               self::YES_TAINT & ~self::HTML_TAINT,
                                'overall' => SecurityCheckPlugin::NO_TAINT
                        ],
                        '\WebRequest::getGPCVal' => [ 'overall' => 
SecurityCheckPlugin::YES_TAINT, ],
@@ -409,10 +425,24 @@
                        'OOUI\ButtonInputWidget::__construct' => [
                                'overall' => self::NO_TAINT
                        ],
+                       'OOUI\HorizontalLayout::__construct' => [
+                               'overall' => self::NO_TAINT
+                       ],
                        'HtmlArmor::__construct' => [
                                self::HTML_EXEC_TAINT,
                                'overall' => self::NO_TAINT
                        ],
+                       // Due to limitations in how we handle list()
+                       // elements, hard code CommentStore stuff.
+                       'CommentStore::insert' => [
+                               'overall' => self::NO_TAINT
+                       ],
+                       'CommentStore::getJoin' => [
+                               'overall' => self::NO_TAINT
+                       ],
+                       'CommentStore::insertWithTempTable' => [
+                               'overall' => self::NO_TAINT
+                       ],
                ];
        }
 
diff --git a/src/TaintednessBaseVisitor.php b/src/TaintednessBaseVisitor.php
index 40c644a..26acefa 100644
--- a/src/TaintednessBaseVisitor.php
+++ b/src/TaintednessBaseVisitor.php
@@ -335,6 +335,10 @@
                        // Built in php.
                        // Assume that anything really dangerous we've already
                        // hardcoded. So just preserve taint
+                       $taintFromReturnType = $this->getTaintByReturnType( 
$func->getUnionType() );
+                       if ( $taintFromReturnType === 
SecurityCheckPlugin::NO_TAINT ) {
+                               return [ 'overall' => 
SecurityCheckPlugin::NO_TAINT ];
+                       }
                        return [ 'overall' => 
SecurityCheckPlugin::PRESERVE_TAINT ];
                }
                if ( property_exists( $func, 'funcTaint' ) ) {
diff --git a/src/TaintednessVisitor.php b/src/TaintednessVisitor.php
index 9325058..db0b046 100644
--- a/src/TaintednessVisitor.php
+++ b/src/TaintednessVisitor.php
@@ -336,8 +336,9 @@
                                $rhsTaintedness &= 
~SecurityCheckPlugin::SQL_NUMKEY_TAINT;
                        } elseif ( $rhsTaintedness & 
SecurityCheckPlugin::SQL_TAINT ) {
                                if (
-                                       $dim === null ||
-                                       $this->nodeIsInt( $dim )
+                                       ( $dim === null ||
+                                       $this->nodeIsInt( $dim ) )
+                                       && !$this->nodeIsArray( 
$node->children['expr'] )
                                ) {
                                        $rhsTaintedness |= 
SecurityCheckPlugin::SQL_NUMKEY_TAINT;
                                }
@@ -768,7 +769,7 @@
                $curTaint = SecurityCheckPlugin::NO_TAINT;
                foreach ( $node->children as $child ) {
                        assert( $child->kind === \ast\AST_ARRAY_ELEM );
-                       $curTaint = $this->mergeAddTaint( $curTaint, 
$this->getTaintedness( $child ) );
+                       $childTaint = $this->getTaintedness( $child );
                        $key = $child->children['key'];
                        $value = $child->children['value'];
                        $sqlTaint = SecurityCheckPlugin::SQL_TAINT;
@@ -776,15 +777,17 @@
                                $this->getTaintedness( $value )
                                & SecurityCheckPlugin::SQL_NUMKEY_TAINT
                        ) {
-                               $curTaint &= 
~SecurityCheckPlugin::SQL_NUMKEY_TAINT;
+                               $childTaint &= 
~SecurityCheckPlugin::SQL_NUMKEY_TAINT;
 
                        } elseif (
                                ( $this->getTaintedness( $key ) & $sqlTaint ) ||
                                ( ( $key === null || $this->nodeIsInt( $key ) )
-                               && ( $this->getTaintedness( $value ) & 
$sqlTaint ) )
+                               && ( $this->getTaintedness( $value ) & 
$sqlTaint )
+                               && !$this->nodeIsArray( $value ) )
                        ) {
-                               $curTaint |= 
SecurityCheckPlugin::SQL_NUMKEY_TAINT;
+                               $childTaint |= 
SecurityCheckPlugin::SQL_NUMKEY_TAINT;
                        }
+                       $curTaint = $this->mergeAddTaint( $curTaint, 
$childTaint );
                }
                return $curTaint;
        }
@@ -1005,7 +1008,7 @@
                        ast\flags\TYPE_OBJECT
                ];
 
-               if ( in_array( $node->flags, $dangerousCasts ) ) {
+               if ( !in_array( $node->flags, $dangerousCasts ) ) {
                        return SecurityCheckPlugin::NO_TAINT;
                }
                return $this->getTaintedness( $node->children['expr'] );
diff --git a/tests/integration/arraynumkey/test.php 
b/tests/integration/arraynumkey/test.php
index 7b16917..e5dace8 100644
--- a/tests/integration/arraynumkey/test.php
+++ b/tests/integration/arraynumkey/test.php
@@ -80,3 +80,6 @@
                'HAVING' => $_GET['string']
        ]
 );
+
+$b = (int)$_GET['b'];
+$db->select( 't', 'f', [ 'foo' => $_GET['a'], "bar > $b" ] );
diff --git a/tests/integration/cast/expectedResults.txt 
b/tests/integration/cast/expectedResults.txt
index 9be25a4..7062b67 100644
--- a/tests/integration/cast/expectedResults.txt
+++ b/tests/integration/cast/expectedResults.txt
@@ -1 +1 @@
-integration/cast/test.php:4 SecurityCheck-XSS Echoing expression that was not 
html escaped
+integration/cast/test.php:7 SecurityCheck-XSS Echoing expression that was not 
html escaped
diff --git a/tests/integration/cast/test.php b/tests/integration/cast/test.php
index ec557c7..2259f47 100644
--- a/tests/integration/cast/test.php
+++ b/tests/integration/cast/test.php
@@ -5,3 +5,5 @@
 
 // Less so
 echo (string)$_GET['bar'];
+
+echo intval( $_GET['bar'] );
diff --git a/tests/integration/dbarrayplus/test.php 
b/tests/integration/dbarrayplus/test.php
index 7728fab..c6c6ab1 100644
--- a/tests/integration/dbarrayplus/test.php
+++ b/tests/integration/dbarrayplus/test.php
@@ -35,3 +35,20 @@
        $rows + $rows2 + $unsafe,
        __METHOD__
 );
+
+$db->insert(
+       'foo',
+       [
+               [ 'first' => $_GET['a'] ],
+               [ 'first' => $_GET['a'] ],
+               [ 'first' => $_GET['a'] ],
+       ],
+       __METHOD__
+);
+
+$items = [];
+$items[] = [ 'first' => $_GET['a'] ];
+$items[] = [ 'first' => $_GET['a'] ];
+$items[] = [ 'first' => $_GET['a'] ];
+
+$db->insert( 'foo', $items, __METHOD__ );
diff --git a/tests/integration/prop2/expectedResults.txt 
b/tests/integration/prop2/expectedResults.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tests/integration/prop2/expectedResults.txt
diff --git a/tests/integration/prop2/test.php b/tests/integration/prop2/test.php
new file mode 100644
index 0000000..358051f
--- /dev/null
+++ b/tests/integration/prop2/test.php
@@ -0,0 +1,34 @@
+<?php
+
+class Foo {
+       public $f = '';
+
+       /** @var Context */
+       private $context;
+
+       public function __construct() {
+               $this->context = new Context;
+       }
+
+       public function bar() {
+               $out = $this->context->getOutput();
+               $out->addHTML( $this->f );
+       }
+}
+
+class Context {
+       /**
+        * @return OutputPage
+        */
+       public function getOutput() {
+               return new OutputPage;
+       }
+}
+
+class OutputPage {
+       public function addHTML( $html ) {
+       }
+}
+
+$foo = new Foo;
+$foo->bar();

-- 
To view, visit https://gerrit.wikimedia.org/r/395761
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings

Gerrit-MessageType: newchange
Gerrit-Change-Id: I17f0dbd83c822faa0bcaa823f5adf15d6366d3f4
Gerrit-PatchSet: 1
Gerrit-Project: mediawiki/tools/phan/SecurityCheckPlugin
Gerrit-Branch: master
Gerrit-Owner: Brian Wolff <bawolff...@gmail.com>

_______________________________________________
MediaWiki-commits mailing list
MediaWiki-commits@lists.wikimedia.org
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits

Reply via email to