@@ -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,103 @@ 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+ * An uncertain SSA definition. Either an uncertain explicit definition or an
509+ * uncertain qualifier definition.
510+ *
511+ * Restricts `Ssa::UncertainDefinition` by excluding implicit call definitions,
512+ * as we---conservatively---consider such definitions to be certain.
513+ */
514+ predicate allowFlowIntoUncertainDef ( SsaImpl:: UncertainWriteDefinition def ) {
515+ def instanceof Ssa:: ExplicitDefinition
516+ or
517+ def =
518+ any ( Ssa:: ImplicitQualifierDefinition qdef |
519+ allowFlowIntoUncertainDef ( qdef .getQualifierDefinition ( ) )
520+ )
521+ }
522+ }
523+
524+ module Impl = SsaImpl:: Impl:: DataFlowIntegration< Input > ;
525+
526+ Impl:: Node asNode ( Node n ) {
527+ n = TSsaNode ( result )
528+ or
529+ result .( Impl:: ExprNode ) .getExpr ( ) = n .( ExprNode ) .getControlFlowNode ( )
530+ or
531+ result .( Impl:: ExprPostUpdateNode ) .getExpr ( ) =
532+ n .( PostUpdateNode ) .getPreUpdateNode ( ) .( ExprNode ) .getControlFlowNode ( )
533+ or
534+ TExplicitParameterNode ( result .( Impl:: ParameterNode ) .getParameter ( ) ) = n
535+ }
536+
537+ predicate localFlowStep ( SsaImpl:: DefinitionExt def , Node nodeFrom , Node nodeTo ) {
538+ Impl:: localFlowStep ( def , asNode ( nodeFrom ) , asNode ( nodeTo ) ) and
539+ // exclude flow directly from RHS to SSA definition, as we instead want to
540+ // go from RHS to matching assingnable definition, and from there to SSA definition
541+ not Input:: ssaDefAssigns ( def , nodeFrom .( ExprNode ) .getControlFlowNode ( ) )
542+ }
543+
544+ predicate localMustFlowStep ( SsaImpl:: DefinitionExt def , Node nodeFrom , Node nodeTo ) {
545+ Impl:: localMustFlowStep ( def , asNode ( nodeFrom ) , asNode ( nodeTo ) )
546+ }
547+
548+ module BarrierGuardsInput implements Impl:: BarrierGuardsInputSig {
549+ private import semmle.code.csharp.controlflow.BasicBlocks
550+ private import semmle.code.csharp.controlflow.Guards as Guards
551+
552+ class Guard extends Guards:: Guard {
553+ predicate hasCfgNode ( ControlFlow:: BasicBlock bb , int i ) {
554+ this .getAControlFlowNode ( ) = bb .getNode ( i )
555+ }
556+ }
557+
558+ /** Holds if the guard `guard` controls block `bb` upon evaluating to `branch`. */
559+ predicate guardControlsBlock ( Guard guard , ControlFlow:: BasicBlock bb , boolean branch ) {
560+ exists ( ConditionBlock conditionBlock , ControlFlow:: SuccessorTypes:: ConditionalSuccessor s |
561+ guard .getAControlFlowNode ( ) = conditionBlock .getLastNode ( ) and
562+ s .getValue ( ) = branch and
563+ conditionBlock .controls ( bb , s )
564+ )
565+ }
566+
567+ /** Gets an immediate conditional successor of basic block `bb`, if any. */
568+ ControlFlow:: BasicBlock getAConditionalBasicBlockSuccessor (
569+ ControlFlow:: BasicBlock bb , boolean branch
570+ ) {
571+ exists ( ControlFlow:: SuccessorTypes:: ConditionalSuccessor s |
572+ result = bb .getASuccessorByType ( s ) and
573+ s .getValue ( ) = branch
574+ )
575+ }
576+ }
577+
578+ module BarrierGuardsImpl = Impl:: BarrierGuards< BarrierGuardsInput > ;
579+ }
580+
484581/** Provides predicates related to local data flow. */
485582module LocalFlow {
486583 class LocalExprStepConfiguration extends ControlFlowReachabilityConfiguration {
@@ -606,105 +703,6 @@ module LocalFlow {
606703 any ( LocalExprStepConfiguration x ) .hasDefPath ( _, value , def , cfnDef )
607704 }
608705
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-
708706 /**
709707 * Holds if the source variable of SSA definition `def` is an instance field.
710708 */
@@ -788,10 +786,7 @@ module LocalFlow {
788786 node2 .asExpr ( ) instanceof AssignExpr
789787 )
790788 or
791- exists ( SsaImpl:: Definition def |
792- def = getSsaDefinitionExt ( node1 ) and
793- exists ( SsaImpl:: getAReadAtNode ( def , node2 .( ExprNode ) .getControlFlowNode ( ) ) )
794- )
789+ SsaFlow:: localMustFlowStep ( _, node1 , node2 )
795790 or
796791 node2 = node1 .( LocalFunctionCreationNode ) .getAnAccess ( true )
797792 or
@@ -816,22 +811,10 @@ predicate simpleLocalFlowStep(Node nodeFrom, Node nodeTo, string model) {
816811 LocalFlow:: localFlowStepCommon ( nodeFrom , nodeTo )
817812 or
818813 exists ( SsaImpl:: DefinitionExt def |
814+ SsaFlow:: localFlowStep ( def , nodeFrom , nodeTo ) and
819815 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- )
816+ not def instanceof VariableCapture:: CapturedSsaDefinitionExt and
817+ not FlowSummaryImpl:: Private:: Steps:: prohibitsUseUseFlow ( nodeFrom , _)
835818 )
836819 or
837820 nodeTo .( ObjectCreationNode ) .getPreUpdateNode ( ) = nodeFrom .( ObjectInitializerNode )
@@ -1097,10 +1080,7 @@ private module Cached {
10971080 cached
10981081 newtype TNode =
10991082 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
1083+ TSsaNode ( SsaFlow:: Impl:: SsaNode node ) or
11041084 TAssignableDefinitionNode ( AssignableDefinition def , ControlFlow:: Node cfn ) {
11051085 cfn = def .getExpr ( ) .getAControlFlowNode ( )
11061086 } or
@@ -1165,17 +1145,7 @@ private module Cached {
11651145 predicate localFlowStepImpl ( Node nodeFrom , Node nodeTo ) {
11661146 LocalFlow:: localFlowStepCommon ( nodeFrom , nodeTo )
11671147 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- )
1148+ SsaFlow:: localFlowStep ( _, nodeFrom , nodeTo )
11791149 or
11801150 // Simple flow through library code is included in the exposed local
11811151 // step relation, even though flow is technically inter-procedural
@@ -1239,7 +1209,7 @@ import Cached
12391209
12401210/** Holds if `n` should be hidden from path explanations. */
12411211predicate nodeIsHidden ( Node n ) {
1242- n instanceof SsaDefinitionExtNode
1212+ n instanceof SsaNode
12431213 or
12441214 exists ( Parameter p | p = n .( ParameterNode ) .getParameter ( ) | not p .fromSource ( ) )
12451215 or
@@ -1273,13 +1243,16 @@ predicate nodeIsHidden(Node n) {
12731243 n instanceof CaptureNode
12741244}
12751245
1276- /** An SSA definition, viewed as a node in a data flow graph. */
1277- class SsaDefinitionExtNode extends NodeImpl , TSsaDefinitionExtNode {
1246+ /** An SSA node. */
1247+ abstract class SsaNode extends NodeImpl , TSsaNode {
1248+ SsaFlow:: Impl:: SsaNode node ;
12781249 SsaImpl:: DefinitionExt def ;
12791250
1280- SsaDefinitionExtNode ( ) { this = TSsaDefinitionExtNode ( def ) }
1251+ SsaNode ( ) {
1252+ this = TSsaNode ( node ) and
1253+ def = node .getDefinitionExt ( )
1254+ }
12811255
1282- /** Gets the underlying SSA definition. */
12831256 SsaImpl:: DefinitionExt getDefinitionExt ( ) { result = def }
12841257
12851258 override DataFlowCallable getEnclosingCallableImpl ( ) {
@@ -1292,9 +1265,60 @@ class SsaDefinitionExtNode extends NodeImpl, TSsaDefinitionExtNode {
12921265 result = def .( Ssa:: Definition ) .getControlFlowNode ( )
12931266 }
12941267
1295- override Location getLocationImpl ( ) { result = def .getLocation ( ) }
1268+ override Location getLocationImpl ( ) { result = node .getLocation ( ) }
1269+
1270+ override string toStringImpl ( ) { result = node .toString ( ) }
1271+ }
1272+
1273+ /** An (extended) SSA definition, viewed as a node in a data flow graph. */
1274+ class SsaDefinitionExtNode extends SsaNode {
1275+ override SsaFlow:: Impl:: SsaDefinitionExtNode node ;
1276+ }
1277+
1278+ /**
1279+ * A node that represents an input to an SSA phi (read) definition.
1280+ *
1281+ * This allows for barrier guards to filter input to phi nodes. For example, in
1282+ *
1283+ * ```csharp
1284+ * var x = taint;
1285+ * if (x != "safe")
1286+ * {
1287+ * x = "safe";
1288+ * }
1289+ * sink(x);
1290+ * ```
1291+ *
1292+ * the `false` edge out of `x != "safe"` guards the input from `x = taint` into the
1293+ * `phi` node after the condition.
1294+ *
1295+ * It is also relevant to filter input into phi read nodes:
1296+ *
1297+ * ```csharp
1298+ * var x = taint;
1299+ * if (b)
1300+ * {
1301+ * if (x != "safe1")
1302+ * {
1303+ * return;
1304+ * }
1305+ * } else {
1306+ * if (x != "safe2")
1307+ * {
1308+ * return;
1309+ * }
1310+ * }
1311+ *
1312+ * sink(x);
1313+ * ```
1314+ *
1315+ * both inputs into the phi read node after the outer condition are guarded.
1316+ */
1317+ class SsaInputNode extends SsaNode {
1318+ override SsaFlow:: Impl:: SsaInputNode node ;
1319+ ControlFlow:: BasicBlock input ;
12961320
1297- override string toStringImpl ( ) { result = def . toString ( ) }
1321+ SsaInputNode ( ) { node . isInputInto ( def , input ) }
12981322}
12991323
13001324/** A definition, viewed as a node in a data flow graph. */
@@ -2844,7 +2868,7 @@ private predicate delegateCreationStep(Node nodeFrom, Node nodeTo) {
28442868/** Extra data-flow steps needed for lambda flow analysis. */
28452869predicate additionalLambdaFlowStep ( Node nodeFrom , Node nodeTo , boolean preservesValue ) {
28462870 exists ( SsaImpl:: DefinitionExt def |
2847- LocalFlow :: localSsaFlowStep ( def , nodeFrom , nodeTo ) and
2871+ SsaFlow :: localFlowStep ( def , nodeFrom , nodeTo ) and
28482872 preservesValue = true
28492873 |
28502874 LocalFlow:: usesInstanceField ( def )
0 commit comments