@@ -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,100 @@ 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
+ * 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
+
484
578
/** Provides predicates related to local data flow. */
485
579
module LocalFlow {
486
580
class LocalExprStepConfiguration extends ControlFlowReachabilityConfiguration {
@@ -606,105 +700,6 @@ module LocalFlow {
606
700
any ( LocalExprStepConfiguration x ) .hasDefPath ( _, value , def , cfnDef )
607
701
}
608
702
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
703
/**
709
704
* Holds if the source variable of SSA definition `def` is an instance field.
710
705
*/
@@ -788,10 +783,7 @@ module LocalFlow {
788
783
node2 .asExpr ( ) instanceof AssignExpr
789
784
)
790
785
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 )
795
787
or
796
788
node2 = node1 .( LocalFunctionCreationNode ) .getAnAccess ( true )
797
789
or
@@ -816,22 +808,10 @@ predicate simpleLocalFlowStep(Node nodeFrom, Node nodeTo, string model) {
816
808
LocalFlow:: localFlowStepCommon ( nodeFrom , nodeTo )
817
809
or
818
810
exists ( SsaImpl:: DefinitionExt def |
811
+ SsaFlow:: localFlowStep ( def , nodeFrom , nodeTo ) and
819
812
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 , _)
835
815
)
836
816
or
837
817
nodeTo .( ObjectCreationNode ) .getPreUpdateNode ( ) = nodeFrom .( ObjectInitializerNode )
@@ -1097,10 +1077,7 @@ private module Cached {
1097
1077
cached
1098
1078
newtype TNode =
1099
1079
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
1104
1081
TAssignableDefinitionNode ( AssignableDefinition def , ControlFlow:: Node cfn ) {
1105
1082
cfn = def .getExpr ( ) .getAControlFlowNode ( )
1106
1083
} or
@@ -1165,17 +1142,7 @@ private module Cached {
1165
1142
predicate localFlowStepImpl ( Node nodeFrom , Node nodeTo ) {
1166
1143
LocalFlow:: localFlowStepCommon ( nodeFrom , nodeTo )
1167
1144
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 )
1179
1146
or
1180
1147
// Simple flow through library code is included in the exposed local
1181
1148
// step relation, even though flow is technically inter-procedural
@@ -1239,7 +1206,7 @@ import Cached
1239
1206
1240
1207
/** Holds if `n` should be hidden from path explanations. */
1241
1208
predicate nodeIsHidden ( Node n ) {
1242
- n instanceof SsaDefinitionExtNode
1209
+ n instanceof SsaNode
1243
1210
or
1244
1211
exists ( Parameter p | p = n .( ParameterNode ) .getParameter ( ) | not p .fromSource ( ) )
1245
1212
or
@@ -1273,13 +1240,16 @@ predicate nodeIsHidden(Node n) {
1273
1240
n instanceof CaptureNode
1274
1241
}
1275
1242
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 ;
1278
1246
SsaImpl:: DefinitionExt def ;
1279
1247
1280
- SsaDefinitionExtNode ( ) { this = TSsaDefinitionExtNode ( def ) }
1248
+ SsaNode ( ) {
1249
+ this = TSsaNode ( node ) and
1250
+ def = node .getDefinitionExt ( )
1251
+ }
1281
1252
1282
- /** Gets the underlying SSA definition. */
1283
1253
SsaImpl:: DefinitionExt getDefinitionExt ( ) { result = def }
1284
1254
1285
1255
override DataFlowCallable getEnclosingCallableImpl ( ) {
@@ -1292,9 +1262,57 @@ class SsaDefinitionExtNode extends NodeImpl, TSsaDefinitionExtNode {
1292
1262
result = def .( Ssa:: Definition ) .getControlFlowNode ( )
1293
1263
}
1294
1264
1295
- override Location getLocationImpl ( ) { result = def .getLocation ( ) }
1265
+ override Location getLocationImpl ( ) { result = node .getLocation ( ) }
1296
1266
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 ;
1298
1316
}
1299
1317
1300
1318
/** A definition, viewed as a node in a data flow graph. */
@@ -2844,7 +2862,7 @@ private predicate delegateCreationStep(Node nodeFrom, Node nodeTo) {
2844
2862
/** Extra data-flow steps needed for lambda flow analysis. */
2845
2863
predicate additionalLambdaFlowStep ( Node nodeFrom , Node nodeTo , boolean preservesValue ) {
2846
2864
exists ( SsaImpl:: DefinitionExt def |
2847
- LocalFlow :: localSsaFlowStep ( def , nodeFrom , nodeTo ) and
2865
+ SsaFlow :: localFlowStep ( def , nodeFrom , nodeTo ) and
2848
2866
preservesValue = true
2849
2867
|
2850
2868
LocalFlow:: usesInstanceField ( def )
0 commit comments