@@ -11,6 +11,7 @@ private import codeql.dataflow.internal.ContentDataFlowImpl
1111private import codeql.dataflow.internal.DataFlowImplCommon as DataFlowImplCommon
1212private import codeql.util.Location
1313private import ModelPrinting
14+ private import codeql.util.Unit
1415
1516/**
1617 * Provides language-specific model generator parameters.
@@ -464,14 +465,22 @@ module MakeModelGenerator<
464465 override string toString ( ) { result = "TaintStore(" + step + ")" }
465466 }
466467
467- /**
468- * A data flow configuration for tracking flow through APIs.
469- * The sources are the parameters of an API and the sinks are the return values (excluding `this`) and parameters.
470- *
471- * This can be used to generate Flow summaries for APIs from parameter to return.
472- */
473- private module PropagateFlowConfig implements DataFlow:: StateConfigSig {
474- class FlowState = TaintState ;
468+ private signature module PropagateFlowConfigInputSig {
469+ class FlowState ;
470+
471+ FlowState initialState ( ) ;
472+
473+ default predicate isAdditionalFlowStep (
474+ DataFlow:: Node node1 , FlowState state1 , DataFlow:: Node node2 , FlowState state2
475+ ) {
476+ none ( )
477+ }
478+ }
479+
480+ private module PropagateFlowConfig< PropagateFlowConfigInputSig PropagateFlowConfigInput>
481+ implements DataFlow:: StateConfigSig
482+ {
483+ import PropagateFlowConfigInput
475484
476485 predicate isSource ( DataFlow:: Node source , FlowState state ) {
477486 source instanceof DataFlow:: ParameterNode and
@@ -480,7 +489,7 @@ module MakeModelGenerator<
480489 c instanceof DataFlowSummaryTargetApi and
481490 not isUninterestingForHeuristicDataFlowModels ( c )
482491 ) and
483- state . ( TaintRead ) . getStep ( ) = 0
492+ state = initialState ( )
484493 }
485494
486495 predicate isSink ( DataFlow:: Node sink , FlowState state ) {
@@ -494,6 +503,31 @@ module MakeModelGenerator<
494503 not exists ( captureQualifierFlow ( getAsExprEnclosingCallable ( sink ) ) )
495504 }
496505
506+ predicate isAdditionalFlowStep = PropagateFlowConfigInput:: isAdditionalFlowStep / 4 ;
507+
508+ predicate isBarrier ( DataFlow:: Node n ) {
509+ exists ( Type t | t = n .( NodeExtended ) .getType ( ) and not isRelevantType ( t ) )
510+ }
511+
512+ DataFlow:: FlowFeature getAFeature ( ) {
513+ result instanceof DataFlow:: FeatureEqualSourceSinkCallContext
514+ }
515+ }
516+
517+ /**
518+ * A module used to construct a data flow configuration for tracking taint-
519+ * flow through APIs.
520+ * The sources are the parameters of an API and the sinks are the return
521+ * values (excluding `this`) and parameters.
522+ *
523+ * This can be used to generate flow summaries for APIs from parameter to
524+ * return.
525+ */
526+ module PropagateFlowConfigInputTaintInput implements PropagateFlowConfigInputSig {
527+ class FlowState = TaintState ;
528+
529+ FlowState initialState ( ) { result .( TaintRead ) .getStep ( ) = 0 }
530+
497531 predicate isAdditionalFlowStep (
498532 DataFlow:: Node node1 , FlowState state1 , DataFlow:: Node node2 , FlowState state2
499533 ) {
@@ -515,51 +549,108 @@ module MakeModelGenerator<
515549 state1 .( TaintRead ) .getStep ( ) + 1 = state2 .( TaintRead ) .getStep ( )
516550 )
517551 }
552+ }
518553
519- predicate isBarrier ( DataFlow:: Node n ) {
520- exists ( Type t | t = n .( NodeExtended ) .getType ( ) and not isRelevantType ( t ) )
521- }
554+ /**
555+ * A data flow configuration for tracking taint-flow through APIs.
556+ * The sources are the parameters of an API and the sinks are the return
557+ * values (excluding `this`) and parameters.
558+ *
559+ * This can be used to generate flow summaries for APIs from parameter to
560+ * return.
561+ */
562+ private module PropagateTaintFlowConfig =
563+ PropagateFlowConfig< PropagateFlowConfigInputTaintInput > ;
522564
523- DataFlow:: FlowFeature getAFeature ( ) {
524- result instanceof DataFlow:: FeatureEqualSourceSinkCallContext
525- }
565+ module PropagateTaintFlow = TaintTracking:: GlobalWithState< PropagateTaintFlowConfig > ;
566+
567+ /**
568+ * A module used to construct a data flow configuration for tracking
569+ * data flow through APIs.
570+ * The sources are the parameters of an API and the sinks are the return
571+ * values (excluding `this`) and parameters.
572+ *
573+ * This can be used to generate value-preserving flow summaries for APIs
574+ * from parameter to return.
575+ */
576+ module PropagateFlowConfigInputDataFlowInput implements PropagateFlowConfigInputSig {
577+ class FlowState = Unit ;
578+
579+ FlowState initialState ( ) { any ( ) }
526580 }
527581
528- module PropagateFlow = TaintTracking:: GlobalWithState< PropagateFlowConfig > ;
582+ /**
583+ * A data flow configuration for tracking data flow through APIs.
584+ * The sources are the parameters of an API and the sinks are the return
585+ * values (excluding `this`) and parameters.
586+ *
587+ * This can be used to generate flow summaries for APIs from parameter to
588+ * return.
589+ */
590+ private module PropagateDataFlowConfig =
591+ PropagateFlowConfig< PropagateFlowConfigInputDataFlowInput > ;
592+
593+ module PropagateDataFlow = DataFlow:: GlobalWithState< PropagateDataFlowConfig > ;
529594
530595 /**
531- * Gets the summary model(s) of `api`, if there is flow from parameters to return value or parameter.
596+ * Holds if there should be a summary of `api` specifying flow from `p`
597+ * to `returnNodeExt`.
532598 */
533- string captureThroughFlow0 (
599+ predicate captureThroughFlow0 (
534600 DataFlowSummaryTargetApi api , DataFlow:: ParameterNode p , ReturnNodeExt returnNodeExt
535601 ) {
536- exists ( string input , string output |
537- getEnclosingCallable ( p ) = api and
538- getEnclosingCallable ( returnNodeExt ) = api and
539- input = parameterNodeAsInput ( p ) and
540- output = getOutput ( returnNodeExt ) and
541- input != output and
542- result = ModelPrinting:: asLiftedTaintModel ( api , input , output )
543- )
602+ captureThroughFlow0 ( api , p , _, returnNodeExt , _, _)
603+ }
604+
605+ /**
606+ * Holds if there should be a summary of `api` specifying flow
607+ * from `p` (with summary component `input`) to `returnNodeExt` (with
608+ * summary component `output`).
609+ *
610+ * `preservesValue` is true if the summary is value-preserving, or `false`
611+ * otherwise.
612+ */
613+ private predicate captureThroughFlow0 (
614+ DataFlowSummaryTargetApi api , DataFlow:: ParameterNode p , string input ,
615+ ReturnNodeExt returnNodeExt , string output , boolean preservesValue
616+ ) {
617+ (
618+ PropagateDataFlow:: flow ( p , returnNodeExt ) and preservesValue = true
619+ or
620+ not PropagateDataFlow:: flow ( p , returnNodeExt ) and
621+ PropagateTaintFlow:: flow ( p , returnNodeExt ) and
622+ preservesValue = false
623+ ) and
624+ getEnclosingCallable ( p ) = api and
625+ getEnclosingCallable ( returnNodeExt ) = api and
626+ input = parameterNodeAsInput ( p ) and
627+ output = getOutput ( returnNodeExt ) and
628+ input != output
544629 }
545630
546631 /**
547632 * Gets the summary model(s) of `api`, if there is flow from parameters to return value or parameter.
633+ *
634+ * `preservesValue` is `true` if the summary is value-preserving, and `false` otherwise.
548635 */
549- private string captureThroughFlow ( DataFlowSummaryTargetApi api ) {
550- exists ( DataFlow:: ParameterNode p , ReturnNodeExt returnNodeExt |
551- PropagateFlow:: flow ( p , returnNodeExt ) and
552- result = captureThroughFlow0 ( api , p , returnNodeExt )
636+ private string captureThroughFlow ( DataFlowSummaryTargetApi api , boolean preservesValue ) {
637+ exists ( DataFlow:: ParameterNode p , ReturnNodeExt returnNodeExt , string input , string output |
638+ preservesValue =
639+ max ( boolean b | captureThroughFlow0 ( api , p , input , returnNodeExt , output , b ) ) and
640+ result = ModelPrinting:: asLiftedTaintModel ( api , input , output , preservesValue )
553641 )
554642 }
555643
556644 /**
557645 * Gets the summary model(s) of `api`, if there is flow from parameters to the
558646 * return value or parameter or if `api` is a fluent API.
647+ *
648+ * `preservesValue` is `true` if the summary is value-preserving, and `false` otherwise.
559649 */
560- string captureFlow ( DataFlowSummaryTargetApi api ) {
561- result = captureQualifierFlow ( api ) or
562- result = captureThroughFlow ( api )
650+ string captureHeuristicFlow ( DataFlowSummaryTargetApi api , boolean preservesValue ) {
651+ result = captureQualifierFlow ( api ) and preservesValue = true
652+ or
653+ result = captureThroughFlow ( api , preservesValue )
563654 }
564655
565656 /**
@@ -569,7 +660,7 @@ module MakeModelGenerator<
569660 */
570661 string captureNoFlow ( DataFlowSummaryTargetApi api ) {
571662 not exists ( DataFlowSummaryTargetApi api0 |
572- exists ( captureFlow ( api0 ) ) and api0 .lift ( ) = api .lift ( )
663+ exists ( captureFlow ( api0 , _ ) ) and api0 .lift ( ) = api .lift ( )
573664 ) and
574665 api .isRelevant ( ) and
575666 result = ModelPrinting:: asNeutralSummaryModel ( api )
@@ -1024,12 +1115,13 @@ module MakeModelGenerator<
10241115 /**
10251116 * Gets the content based summary model(s) of the API `api` (if there is flow from a parameter to
10261117 * the return value or a parameter). `lift` is true, if the model should be lifted, otherwise false.
1118+ * `preservesValue` is `true` if the summary is value-preserving, and `false` otherwise.
10271119 *
10281120 * Models are lifted to the best type in case the read and store access paths do not
10291121 * contain a field or synthetic field access.
10301122 */
1031- string captureFlow ( ContentDataFlowSummaryTargetApi api , boolean lift ) {
1032- exists ( string input , string output , boolean preservesValue |
1123+ string captureFlow ( ContentDataFlowSummaryTargetApi api , boolean lift , boolean preservesValue ) {
1124+ exists ( string input , string output |
10331125 captureFlow0 ( api , input , output , _, lift ) and
10341126 preservesValue = max ( boolean p | captureFlow0 ( api , input , output , p , lift ) ) and
10351127 result = ContentModelPrinting:: asModel ( api , input , output , preservesValue , lift )
@@ -1046,17 +1138,19 @@ module MakeModelGenerator<
10461138 * generate flow summaries using the heuristic based summary generator.
10471139 */
10481140 string captureFlow ( DataFlowSummaryTargetApi api , boolean lift ) {
1049- result = ContentSensitive:: captureFlow ( api , lift )
1050- or
1051- not exists ( DataFlowSummaryTargetApi api0 |
1052- ( api0 = api or api .lift ( ) = api0 ) and
1053- exists ( ContentSensitive:: captureFlow ( api0 , false ) )
1141+ exists ( boolean preservesValue |
1142+ result = ContentSensitive:: captureFlow ( api , lift , preservesValue )
10541143 or
1055- api0 .lift ( ) = api .lift ( ) and
1056- exists ( ContentSensitive:: captureFlow ( api0 , true ) )
1057- ) and
1058- result = Heuristic:: captureFlow ( api ) and
1059- lift = true
1144+ not exists ( DataFlowSummaryTargetApi api0 |
1145+ ( api0 = api or api .lift ( ) = api0 ) and
1146+ exists ( ContentSensitive:: captureFlow ( api0 , false , preservesValue ) )
1147+ or
1148+ api0 .lift ( ) = api .lift ( ) and
1149+ exists ( ContentSensitive:: captureFlow ( api0 , true , preservesValue ) )
1150+ ) and
1151+ result = Heuristic:: captureHeuristicFlow ( api , preservesValue ) and
1152+ lift = true
1153+ )
10601154 }
10611155
10621156 /**
0 commit comments