@@ -257,7 +257,7 @@ module VariableCapture {
257257 e1 = LocalFlow:: getALastEvalNode ( e2 )
258258 or
259259 exists ( Ssa:: Definition def |
260- LocalFlow :: ssaDefAssigns ( def .getAnUltimateDefinition ( ) , e1 ) and
260+ SsaFlow :: Input :: ssaDefAssigns ( def .getAnUltimateDefinition ( ) , e1 ) and
261261 exists ( def .getAReadAtNode ( e2 ) )
262262 )
263263 }
@@ -481,6 +481,100 @@ module VariableCapture {
481481 }
482482}
483483
484+ /** Provides logic related to SSA. */
485+ module SsaFlow {
486+ module Input implements SsaImpl:: Impl:: DataFlowIntegrationInputSig {
487+ private import csharp as Cs
488+
489+ class Expr extends ControlFlow:: Node {
490+ predicate hasCfgNode ( ControlFlow:: BasicBlock bb , int i ) { this = bb .getNode ( i ) }
491+ }
492+
493+ predicate ssaDefAssigns ( SsaImpl:: WriteDefinition def , Expr value ) {
494+ exists ( AssignableDefinition adef , ControlFlow:: Node cfnDef |
495+ any ( LocalFlow:: LocalExprStepConfiguration conf ) .hasDefPath ( _, value , adef , cfnDef ) and
496+ def .( Ssa:: ExplicitDefinition ) .getADefinition ( ) = adef and
497+ def .( Ssa:: ExplicitDefinition ) .getControlFlowNode ( ) = cfnDef
498+ )
499+ }
500+
501+ class Parameter = Cs:: Parameter ;
502+
503+ predicate ssaDefInitializesParam ( SsaImpl:: WriteDefinition def , Parameter p ) {
504+ def .( Ssa:: ImplicitParameterDefinition ) .getParameter ( ) = p
505+ }
506+
507+ /**
508+ * Allows for flow into uncertain defintions that are not call definitions,
509+ * as we, conservatively, consider such definitions to be certain.
510+ */
511+ predicate allowFlowIntoUncertainDef ( SsaImpl:: UncertainWriteDefinition def ) {
512+ def instanceof Ssa:: ExplicitDefinition
513+ or
514+ def =
515+ any ( Ssa:: ImplicitQualifierDefinition qdef |
516+ allowFlowIntoUncertainDef ( qdef .getQualifierDefinition ( ) )
517+ )
518+ }
519+ }
520+
521+ module Impl = SsaImpl:: Impl:: DataFlowIntegration< Input > ;
522+
523+ Impl:: Node asNode ( Node n ) {
524+ n = TSsaNode ( result )
525+ or
526+ result .( Impl:: ExprNode ) .getExpr ( ) = n .( ExprNode ) .getControlFlowNode ( )
527+ or
528+ result .( Impl:: ExprPostUpdateNode ) .getExpr ( ) =
529+ n .( PostUpdateNode ) .getPreUpdateNode ( ) .( ExprNode ) .getControlFlowNode ( )
530+ or
531+ TExplicitParameterNode ( result .( Impl:: ParameterNode ) .getParameter ( ) ) = n
532+ }
533+
534+ predicate localFlowStep ( SsaImpl:: DefinitionExt def , Node nodeFrom , Node nodeTo ) {
535+ Impl:: localFlowStep ( def , asNode ( nodeFrom ) , asNode ( nodeTo ) ) and
536+ // exclude flow directly from RHS to SSA definition, as we instead want to
537+ // go from RHS to matching assingnable definition, and from there to SSA definition
538+ not Input:: ssaDefAssigns ( def , nodeFrom .( ExprNode ) .getControlFlowNode ( ) )
539+ }
540+
541+ predicate localMustFlowStep ( SsaImpl:: DefinitionExt def , Node nodeFrom , Node nodeTo ) {
542+ Impl:: localMustFlowStep ( def , asNode ( nodeFrom ) , asNode ( nodeTo ) )
543+ }
544+
545+ module BarrierGuardsInput implements Impl:: BarrierGuardsInputSig {
546+ private import semmle.code.csharp.controlflow.BasicBlocks
547+ private import semmle.code.csharp.controlflow.Guards as Guards
548+
549+ class Guard extends Guards:: Guard {
550+ predicate hasCfgNode ( ControlFlow:: BasicBlock bb , int i ) {
551+ this .getAControlFlowNode ( ) = bb .getNode ( i )
552+ }
553+ }
554+
555+ /** Holds if the guard `guard` controls block `bb` upon evaluating to `branch`. */
556+ predicate guardControlsBlock ( Guard guard , ControlFlow:: BasicBlock bb , boolean branch ) {
557+ exists ( ConditionBlock conditionBlock , ControlFlow:: SuccessorTypes:: ConditionalSuccessor s |
558+ guard .getAControlFlowNode ( ) = conditionBlock .getLastNode ( ) and
559+ s .getValue ( ) = branch and
560+ conditionBlock .controls ( bb , s )
561+ )
562+ }
563+
564+ /** Gets an immediate conditional successor of basic block `bb`, if any. */
565+ ControlFlow:: BasicBlock getAConditionalBasicBlockSuccessor (
566+ ControlFlow:: BasicBlock bb , boolean branch
567+ ) {
568+ exists ( ControlFlow:: SuccessorTypes:: ConditionalSuccessor s |
569+ result = bb .getASuccessorByType ( s ) and
570+ s .getValue ( ) = branch
571+ )
572+ }
573+ }
574+
575+ module BarrierGuardsImpl = Impl:: BarrierGuards< BarrierGuardsInput > ;
576+ }
577+
484578/** Provides predicates related to local data flow. */
485579module LocalFlow {
486580 class LocalExprStepConfiguration extends ControlFlowReachabilityConfiguration {
@@ -606,105 +700,6 @@ module LocalFlow {
606700 any ( LocalExprStepConfiguration x ) .hasDefPath ( _, value , def , cfnDef )
607701 }
608702
609- predicate ssaDefAssigns ( Ssa:: ExplicitDefinition ssaDef , ControlFlow:: Nodes:: ExprNode value ) {
610- exists ( AssignableDefinition def , ControlFlow:: Node cfnDef |
611- any ( LocalExprStepConfiguration conf ) .hasDefPath ( _, value , def , cfnDef ) and
612- ssaDef .getADefinition ( ) = def and
613- ssaDef .getControlFlowNode ( ) = cfnDef
614- )
615- }
616-
617- /**
618- * An uncertain SSA definition. Either an uncertain explicit definition or an
619- * uncertain qualifier definition.
620- *
621- * Restricts `Ssa::UncertainDefinition` by excluding implicit call definitions,
622- * as we---conservatively---consider such definitions to be certain.
623- */
624- class UncertainExplicitSsaDefinition extends Ssa:: UncertainDefinition {
625- UncertainExplicitSsaDefinition ( ) {
626- this instanceof Ssa:: ExplicitDefinition
627- or
628- this =
629- any ( Ssa:: ImplicitQualifierDefinition qdef |
630- qdef .getQualifierDefinition ( ) instanceof UncertainExplicitSsaDefinition
631- )
632- }
633- }
634-
635- /** An SSA definition into which another SSA definition may flow. */
636- private class SsaInputDefinitionExtNode extends SsaDefinitionExtNode {
637- SsaInputDefinitionExtNode ( ) {
638- def instanceof Ssa:: PhiNode
639- or
640- def instanceof SsaImpl:: PhiReadNode
641- or
642- def instanceof LocalFlow:: UncertainExplicitSsaDefinition
643- }
644- }
645-
646- /**
647- * Holds if `nodeFrom` is a last node referencing SSA definition `def`, which
648- * can reach `next`.
649- */
650- private predicate localFlowSsaInputFromDef (
651- Node nodeFrom , SsaImpl:: DefinitionExt def , SsaInputDefinitionExtNode next
652- ) {
653- exists ( ControlFlow:: BasicBlock bb , int i |
654- SsaImpl:: lastRefBeforeRedefExt ( def , bb , i , next .getDefinitionExt ( ) ) and
655- def .definesAt ( _, bb , i , _) and
656- def = getSsaDefinitionExt ( nodeFrom ) and
657- nodeFrom != next
658- )
659- }
660-
661- /**
662- * Holds if `read` is a last node reading SSA definition `def`, which
663- * can reach `next`.
664- */
665- predicate localFlowSsaInputFromRead (
666- Node read , SsaImpl:: DefinitionExt def , SsaInputDefinitionExtNode next
667- ) {
668- exists ( ControlFlow:: BasicBlock bb , int i |
669- SsaImpl:: lastRefBeforeRedefExt ( def , bb , i , next .getDefinitionExt ( ) ) and
670- read .asExprAtNode ( bb .getNode ( i ) ) instanceof AssignableRead
671- )
672- }
673-
674- private SsaImpl:: DefinitionExt getSsaDefinitionExt ( Node n ) {
675- result = n .( SsaDefinitionExtNode ) .getDefinitionExt ( )
676- or
677- result = n .( ExplicitParameterNode ) .getSsaDefinition ( )
678- }
679-
680- /**
681- * Holds if there is a local use-use flow step from `nodeFrom` to `nodeTo`
682- * involving SSA definition `def`.
683- */
684- predicate localSsaFlowStepUseUse ( SsaImpl:: DefinitionExt def , Node nodeFrom , Node nodeTo ) {
685- exists ( ControlFlow:: Node cfnFrom , ControlFlow:: Node cfnTo |
686- SsaImpl:: adjacentReadPairSameVarExt ( def , cfnFrom , cfnTo ) and
687- nodeTo = TExprNode ( cfnTo ) and
688- nodeFrom = TExprNode ( cfnFrom )
689- )
690- }
691-
692- /**
693- * Holds if there is a local flow step from `nodeFrom` to `nodeTo` involving
694- * SSA definition `def`.
695- */
696- predicate localSsaFlowStep ( SsaImpl:: DefinitionExt def , Node nodeFrom , Node nodeTo ) {
697- // Flow from SSA definition/parameter to first read
698- def = getSsaDefinitionExt ( nodeFrom ) and
699- SsaImpl:: firstReadSameVarExt ( def , nodeTo .( ExprNode ) .getControlFlowNode ( ) )
700- or
701- // Flow from read to next read
702- localSsaFlowStepUseUse ( def , nodeFrom .( PostUpdateNode ) .getPreUpdateNode ( ) , nodeTo )
703- or
704- // Flow into phi (read)/uncertain SSA definition node from def
705- localFlowSsaInputFromDef ( nodeFrom , def , nodeTo )
706- }
707-
708703 /**
709704 * Holds if the source variable of SSA definition `def` is an instance field.
710705 */
@@ -788,10 +783,7 @@ module LocalFlow {
788783 node2 .asExpr ( ) instanceof AssignExpr
789784 )
790785 or
791- exists ( SsaImpl:: Definition def |
792- def = getSsaDefinitionExt ( node1 ) and
793- exists ( SsaImpl:: getAReadAtNode ( def , node2 .( ExprNode ) .getControlFlowNode ( ) ) )
794- )
786+ SsaFlow:: localMustFlowStep ( _, node1 , node2 )
795787 or
796788 node2 = node1 .( LocalFunctionCreationNode ) .getAnAccess ( true )
797789 or
@@ -816,22 +808,10 @@ predicate simpleLocalFlowStep(Node nodeFrom, Node nodeTo, string model) {
816808 LocalFlow:: localFlowStepCommon ( nodeFrom , nodeTo )
817809 or
818810 exists ( SsaImpl:: DefinitionExt def |
811+ SsaFlow:: localFlowStep ( def , nodeFrom , nodeTo ) and
819812 not LocalFlow:: usesInstanceField ( def ) and
820- not def instanceof VariableCapture:: CapturedSsaDefinitionExt
821- |
822- LocalFlow:: localSsaFlowStep ( def , nodeFrom , nodeTo )
823- or
824- LocalFlow:: localSsaFlowStepUseUse ( def , nodeFrom , nodeTo ) and
825- not FlowSummaryImpl:: Private:: Steps:: prohibitsUseUseFlow ( nodeFrom , _) and
826- nodeFrom != nodeTo
827- or
828- // Flow into phi (read)/uncertain SSA definition node from read
829- exists ( Node read | LocalFlow:: localFlowSsaInputFromRead ( read , def , nodeTo ) |
830- nodeFrom = read and
831- not FlowSummaryImpl:: Private:: Steps:: prohibitsUseUseFlow ( nodeFrom , _)
832- or
833- nodeFrom .( PostUpdateNode ) .getPreUpdateNode ( ) = read
834- )
813+ not def instanceof VariableCapture:: CapturedSsaDefinitionExt and
814+ not FlowSummaryImpl:: Private:: Steps:: prohibitsUseUseFlow ( nodeFrom , _)
835815 )
836816 or
837817 nodeTo .( ObjectCreationNode ) .getPreUpdateNode ( ) = nodeFrom .( ObjectInitializerNode )
@@ -1097,10 +1077,7 @@ private module Cached {
10971077 cached
10981078 newtype TNode =
10991079 TExprNode ( ControlFlow:: Nodes:: ElementNode cfn ) { cfn .getAstNode ( ) instanceof Expr } or
1100- TSsaDefinitionExtNode ( SsaImpl:: DefinitionExt def ) {
1101- // Handled by `TExplicitParameterNode` below
1102- not def instanceof Ssa:: ImplicitParameterDefinition
1103- } or
1080+ TSsaNode ( SsaFlow:: Impl:: SsaNode node ) or
11041081 TAssignableDefinitionNode ( AssignableDefinition def , ControlFlow:: Node cfn ) {
11051082 cfn = def .getExpr ( ) .getAControlFlowNode ( )
11061083 } or
@@ -1165,17 +1142,7 @@ private module Cached {
11651142 predicate localFlowStepImpl ( Node nodeFrom , Node nodeTo ) {
11661143 LocalFlow:: localFlowStepCommon ( nodeFrom , nodeTo )
11671144 or
1168- LocalFlow:: localSsaFlowStepUseUse ( _, nodeFrom , nodeTo ) and
1169- nodeFrom != nodeTo
1170- or
1171- LocalFlow:: localSsaFlowStep ( _, nodeFrom , nodeTo )
1172- or
1173- // Flow into phi (read)/uncertain SSA definition node from read
1174- exists ( Node read | LocalFlow:: localFlowSsaInputFromRead ( read , _, nodeTo ) |
1175- nodeFrom = read
1176- or
1177- nodeFrom .( PostUpdateNode ) .getPreUpdateNode ( ) = read
1178- )
1145+ SsaFlow:: localFlowStep ( _, nodeFrom , nodeTo )
11791146 or
11801147 // Simple flow through library code is included in the exposed local
11811148 // step relation, even though flow is technically inter-procedural
@@ -1239,7 +1206,7 @@ import Cached
12391206
12401207/** Holds if `n` should be hidden from path explanations. */
12411208predicate nodeIsHidden ( Node n ) {
1242- n instanceof SsaDefinitionExtNode
1209+ n instanceof SsaNode
12431210 or
12441211 exists ( Parameter p | p = n .( ParameterNode ) .getParameter ( ) | not p .fromSource ( ) )
12451212 or
@@ -1273,13 +1240,16 @@ predicate nodeIsHidden(Node n) {
12731240 n instanceof CaptureNode
12741241}
12751242
1276- /** An SSA definition, viewed as a node in a data flow graph. */
1277- class SsaDefinitionExtNode extends NodeImpl , TSsaDefinitionExtNode {
1243+ /** An SSA node. */
1244+ abstract class SsaNode extends NodeImpl , TSsaNode {
1245+ SsaFlow:: Impl:: SsaNode node ;
12781246 SsaImpl:: DefinitionExt def ;
12791247
1280- SsaDefinitionExtNode ( ) { this = TSsaDefinitionExtNode ( def ) }
1248+ SsaNode ( ) {
1249+ this = TSsaNode ( node ) and
1250+ def = node .getDefinitionExt ( )
1251+ }
12811252
1282- /** Gets the underlying SSA definition. */
12831253 SsaImpl:: DefinitionExt getDefinitionExt ( ) { result = def }
12841254
12851255 override DataFlowCallable getEnclosingCallableImpl ( ) {
@@ -1292,9 +1262,57 @@ class SsaDefinitionExtNode extends NodeImpl, TSsaDefinitionExtNode {
12921262 result = def .( Ssa:: Definition ) .getControlFlowNode ( )
12931263 }
12941264
1295- override Location getLocationImpl ( ) { result = def .getLocation ( ) }
1265+ override Location getLocationImpl ( ) { result = node .getLocation ( ) }
12961266
1297- override string toStringImpl ( ) { result = def .toString ( ) }
1267+ override string toStringImpl ( ) { result = node .toString ( ) }
1268+ }
1269+
1270+ /** An (extended) SSA definition, viewed as a node in a data flow graph. */
1271+ class SsaDefinitionExtNode extends SsaNode {
1272+ override SsaFlow:: Impl:: SsaDefinitionExtNode node ;
1273+ }
1274+
1275+ /**
1276+ * A node that represents an input to an SSA phi (read) definition.
1277+ *
1278+ * This allows for barrier guards to filter input to phi nodes. For example, in
1279+ *
1280+ * ```csharp
1281+ * var x = taint;
1282+ * if (x != "safe")
1283+ * {
1284+ * x = "safe";
1285+ * }
1286+ * sink(x);
1287+ * ```
1288+ *
1289+ * the `false` edge out of `x != "safe"` guards the input from `x = taint` into the
1290+ * `phi` node after the condition.
1291+ *
1292+ * It is also relevant to filter input into phi read nodes:
1293+ *
1294+ * ```csharp
1295+ * var x = taint;
1296+ * if (b)
1297+ * {
1298+ * if (x != "safe1")
1299+ * {
1300+ * return;
1301+ * }
1302+ * } else {
1303+ * if (x != "safe2")
1304+ * {
1305+ * return;
1306+ * }
1307+ * }
1308+ *
1309+ * sink(x);
1310+ * ```
1311+ *
1312+ * both inputs into the phi read node after the outer condition are guarded.
1313+ */
1314+ class SsaInputNode extends SsaNode {
1315+ override SsaFlow:: Impl:: SsaInputNode node ;
12981316}
12991317
13001318/** A definition, viewed as a node in a data flow graph. */
@@ -2844,7 +2862,7 @@ private predicate delegateCreationStep(Node nodeFrom, Node nodeTo) {
28442862/** Extra data-flow steps needed for lambda flow analysis. */
28452863predicate additionalLambdaFlowStep ( Node nodeFrom , Node nodeTo , boolean preservesValue ) {
28462864 exists ( SsaImpl:: DefinitionExt def |
2847- LocalFlow :: localSsaFlowStep ( def , nodeFrom , nodeTo ) and
2865+ SsaFlow :: localFlowStep ( def , nodeFrom , nodeTo ) and
28482866 preservesValue = true
28492867 |
28502868 LocalFlow:: usesInstanceField ( def )
0 commit comments