Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 34
0.00% covered (danger)
0.00%
0 / 6
CRAP
0.00% covered (danger)
0.00%
0 / 1
PreTaintednessVisitor
0.00% covered (danger)
0.00%
0 / 34
0.00% covered (danger)
0.00%
0 / 6
272
0.00% covered (danger)
0.00%
0 / 1
 visitFuncDecl
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 visitClosure
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 visitArrowFunc
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 visitMethod
0.00% covered (danger)
0.00%
0 / 26
0.00% covered (danger)
0.00%
0 / 1
132
 visitAssignOp
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 1
2
 visitPropElem
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
2
1<?php
2
3namespace SecurityCheckPlugin;
4
5use ast\Node;
6use Phan\Language\Element\Parameter;
7use Phan\PluginV3\PluginAwarePreAnalysisVisitor;
8
9/**
10 * Class for visiting any nodes we want to handle in pre-order.
11 *
12 * Unlike TaintednessVisitor, this is solely used to set taint
13 * on variable objects, and not to determine the taint of the
14 * current node, so this class does not return anything.
15 *
16 * Copyright (C) 2017  Brian Wolff <bawolff@gmail.com>
17 *
18 * @license GPL-2.0-or-later
19 */
20class PreTaintednessVisitor extends PluginAwarePreAnalysisVisitor {
21    use TaintednessBaseVisitor;
22
23    /**
24     * @see visitMethod
25     */
26    public function visitFuncDecl( Node $node ): void {
27        $this->visitMethod( $node );
28    }
29
30    /**
31     * @see visitMethod
32     */
33    public function visitClosure( Node $node ): void {
34        $this->visitMethod( $node );
35    }
36
37    public function visitArrowFunc( Node $node ): void {
38        $this->visitMethod( $node );
39    }
40
41    /**
42     * Set the taintedness of parameters to method/function.
43     *
44     * Parameters that are ints (etc) are clearly safe so
45     * this marks them as such. For other parameters, it
46     * creates a map between the function object and the
47     * parameter object so if anyone later calls the method
48     * with a dangerous argument we can determine if we need
49     * to output a warning.
50     *
51     * Also handles FuncDecl and Closure
52     */
53    public function visitMethod( Node $node ): void {
54        // var_dump( __METHOD__ ); Debug::printNode( $node );
55        $method = $this->context->getFunctionLikeInScope( $this->code_base );
56        // Initialize retObjs to avoid recursing on methods that don't return anything.
57        self::initRetObjs( $method );
58        $promotedProps = [];
59        if ( $node->kind === \ast\AST_METHOD && $node->children['name'] === '__construct' ) {
60            foreach ( $method->getParameterList() as $i => $param ) {
61                if ( $param->getFlags() & Parameter::PARAM_MODIFIER_FLAGS ) {
62                    $promotedProps[$i] = $this->getPropInCurrentScopeByName( $param->getName() );
63                }
64            }
65        }
66
67        $scope = $this->context->getScope();
68        // Initially, all variables starts off with no taint.
69        $startTaint = Taintedness::safeSingleton();
70        $params = $node->children['params']->children;
71        foreach ( $params as $i => $param ) {
72            $paramName = $param->children['name'];
73            if ( !$scope->hasVariableWithName( $paramName ) ) {
74                // @codeCoverageIgnoreStart
75                $this->debug( __METHOD__, "Missing variable for param \$" . $paramName );
76                continue;
77                // @codeCoverageIgnoreEnd
78            }
79            $varObj = $scope->getVariableByName( $paramName );
80
81            $paramTypeTaint = $this->getTaintByType( $varObj->getUnionType() );
82            // No point in adding a caused-by line here.
83            self::setTaintednessRaw( $varObj, $startTaint );
84
85            if ( !$paramTypeTaint->isSafe() ) {
86                // If the param is not an integer or something, link it to the func
87                $this->linkParamAndFunc( $varObj, $method, $i );
88            }
89            if ( isset( $promotedProps[$i] ) ) {
90                $this->ensureTaintednessIsSet( $promotedProps[$i] );
91                $paramLinks = self::getMethodLinks( $varObj );
92                if ( $paramLinks ) {
93                    $this->mergeTaintDependencies( $promotedProps[$i], $paramLinks, false );
94                }
95                $this->addTaintError( $promotedProps[$i], $startTaint, $paramLinks );
96            }
97        }
98
99        if ( !self::getFuncTaint( $method ) ) {
100            $this->getSetKnownTaintOfFunctionWithoutAnalysis( $method );
101        }
102    }
103
104    /**
105     * Determine whether this operation is safe, based on the operand types. This needs to be done
106     * in preorder because phan infers types from operators, e.g. from `$a += $b` phan will infer
107     * that they're both numbers. We need to use the types of the operands *before* inferring
108     * types from the operator.
109     */
110    public function visitAssignOp( Node $node ): void {
111        $lhs = $node->children['var'];
112        $rhs = $node->children['expr'];
113        // @phan-suppress-next-line PhanUndeclaredProperty
114        $node->assignTaintMask = $this->getBinOpTaintMask( $node, $lhs, $rhs );
115    }
116
117    /**
118     * When a class property is declared
119     */
120    public function visitPropElem( Node $node ): void {
121        $prop = $this->getPropInCurrentScopeByName( $node->children['name'] );
122        $this->ensureTaintednessIsSet( $prop );
123    }
124}