@@ -257,7 +257,7 @@ module VariableCapture {
257
257
e1 = LocalFlow:: getALastEvalNode ( e2 )
258
258
or
259
259
exists ( Ssa:: Definition def |
260
- LocalFlow :: ssaDefAssigns ( def .getAnUltimateDefinition ( ) , e1 ) and
260
+ SsaFlow :: Input :: ssaDefAssigns ( def .getAnUltimateDefinition ( ) , e1 ) and
261
261
exists ( def .getAReadAtNode ( e2 ) )
262
262
)
263
263
}
@@ -481,6 +481,103 @@ module VariableCapture {
481
481
}
482
482
}
483
483
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
+
484
581
/** Provides predicates related to local data flow. */
485
582
module LocalFlow {
486
583
class LocalExprStepConfiguration extends ControlFlowReachabilityConfiguration {
@@ -606,105 +703,6 @@ module LocalFlow {
606
703
any ( LocalExprStepConfiguration x ) .hasDefPath ( _, value , def , cfnDef )
607
704
}
608
705
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
-
708
706
/**
709
707
* Holds if the source variable of SSA definition `def` is an instance field.
710
708
*/
@@ -788,10 +786,7 @@ module LocalFlow {
788
786
node2 .asExpr ( ) instanceof AssignExpr
789
787
)
790
788
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 )
795
790
or
796
791
node2 = node1 .( LocalFunctionCreationNode ) .getAnAccess ( true )
797
792
or
@@ -816,22 +811,10 @@ predicate simpleLocalFlowStep(Node nodeFrom, Node nodeTo, string model) {
816
811
LocalFlow:: localFlowStepCommon ( nodeFrom , nodeTo )
817
812
or
818
813
exists ( SsaImpl:: DefinitionExt def |
814
+ SsaFlow:: localFlowStep ( def , nodeFrom , nodeTo ) and
819
815
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 , _)
835
818
)
836
819
or
837
820
nodeTo .( ObjectCreationNode ) .getPreUpdateNode ( ) = nodeFrom .( ObjectInitializerNode )
@@ -1097,10 +1080,7 @@ private module Cached {
1097
1080
cached
1098
1081
newtype TNode =
1099
1082
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
1104
1084
TAssignableDefinitionNode ( AssignableDefinition def , ControlFlow:: Node cfn ) {
1105
1085
cfn = def .getExpr ( ) .getAControlFlowNode ( )
1106
1086
} or
@@ -1165,17 +1145,7 @@ private module Cached {
1165
1145
predicate localFlowStepImpl ( Node nodeFrom , Node nodeTo ) {
1166
1146
LocalFlow:: localFlowStepCommon ( nodeFrom , nodeTo )
1167
1147
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 )
1179
1149
or
1180
1150
// Simple flow through library code is included in the exposed local
1181
1151
// step relation, even though flow is technically inter-procedural
@@ -1239,7 +1209,7 @@ import Cached
1239
1209
1240
1210
/** Holds if `n` should be hidden from path explanations. */
1241
1211
predicate nodeIsHidden ( Node n ) {
1242
- n instanceof SsaDefinitionExtNode
1212
+ n instanceof SsaNode
1243
1213
or
1244
1214
exists ( Parameter p | p = n .( ParameterNode ) .getParameter ( ) | not p .fromSource ( ) )
1245
1215
or
@@ -1273,13 +1243,16 @@ predicate nodeIsHidden(Node n) {
1273
1243
n instanceof CaptureNode
1274
1244
}
1275
1245
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 ;
1278
1249
SsaImpl:: DefinitionExt def ;
1279
1250
1280
- SsaDefinitionExtNode ( ) { this = TSsaDefinitionExtNode ( def ) }
1251
+ SsaNode ( ) {
1252
+ this = TSsaNode ( node ) and
1253
+ def = node .getDefinitionExt ( )
1254
+ }
1281
1255
1282
- /** Gets the underlying SSA definition. */
1283
1256
SsaImpl:: DefinitionExt getDefinitionExt ( ) { result = def }
1284
1257
1285
1258
override DataFlowCallable getEnclosingCallableImpl ( ) {
@@ -1292,9 +1265,60 @@ class SsaDefinitionExtNode extends NodeImpl, TSsaDefinitionExtNode {
1292
1265
result = def .( Ssa:: Definition ) .getControlFlowNode ( )
1293
1266
}
1294
1267
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 ;
1296
1320
1297
- override string toStringImpl ( ) { result = def . toString ( ) }
1321
+ SsaInputNode ( ) { node . isInputInto ( def , input ) }
1298
1322
}
1299
1323
1300
1324
/** A definition, viewed as a node in a data flow graph. */
@@ -2844,7 +2868,7 @@ private predicate delegateCreationStep(Node nodeFrom, Node nodeTo) {
2844
2868
/** Extra data-flow steps needed for lambda flow analysis. */
2845
2869
predicate additionalLambdaFlowStep ( Node nodeFrom , Node nodeTo , boolean preservesValue ) {
2846
2870
exists ( SsaImpl:: DefinitionExt def |
2847
- LocalFlow :: localSsaFlowStep ( def , nodeFrom , nodeTo ) and
2871
+ SsaFlow :: localFlowStep ( def , nodeFrom , nodeTo ) and
2848
2872
preservesValue = true
2849
2873
|
2850
2874
LocalFlow:: usesInstanceField ( def )
0 commit comments