4
4
* Example for a test.ql:
5
5
* ```ql
6
6
* import TestUtilities.InlineFlowTest
7
+ * import DefaultFlowTest
7
8
* import PathGraph
8
9
*
9
- * from DataFlow ::PathNode source, DataFlow ::PathNode sink, DefaultValueFlowConf conf
10
- * where conf.hasFlowPath (source, sink)
10
+ * from ValueFlow ::PathNode source, ValueFlow ::PathNode sink
11
+ * where ValueFlow::flowPath (source, sink)
11
12
* select sink, source, sink, "$@", source, source.toString()
12
13
* ```
13
14
*
20
21
* sink(t); // $ hasTaintFlow=2
21
22
* ```
22
23
*
23
- * If you're not interested in a specific flow type, you can disable either value or taint flow expectations as follows:
24
- * ```ql
25
- * class HasFlowTest extends InlineFlowTest {
26
- * override DataFlow::Configuration getTaintFlowConfig() { none() }
27
- *
28
- * override DataFlow::Configuration getValueFlowConfig() { none() }
29
- * }
30
- * ```
24
+ * If you are only interested in value flow, then instead of importing `DefaultFlowTest`, you can import
25
+ * `ValueFlowTest<DefaultFlowConfig>`. Similarly, if you are only interested in taint flow, then instead of
26
+ * importing `DefaultFlowTest`, you can import `TaintFlowTest<DefaultFlowConfig>`. In both cases
27
+ * `DefaultFlowConfig` can be replaced by another implementation of `DataFlow::ConfigSig`.
31
28
*
32
29
* If you need more fine-grained tuning, consider implementing a test using `InlineExpectationsTest`.
33
30
*/
@@ -38,72 +35,62 @@ import codeql.ruby.TaintTracking
38
35
import TestUtilities.InlineExpectationsTest
39
36
import TestUtilities.InlineFlowTestUtil
40
37
41
- class DefaultValueFlowConf extends DataFlow:: Configuration {
42
- DefaultValueFlowConf ( ) { this = "qltest:defaultValueFlowConf" }
43
-
44
- override predicate isSource ( DataFlow:: Node n ) { defaultSource ( n ) }
38
+ module DefaultFlowConfig implements DataFlow:: ConfigSig {
39
+ predicate isSource ( DataFlow:: Node source ) { defaultSource ( source ) }
45
40
46
- override predicate isSink ( DataFlow:: Node n ) { defaultSink ( n ) }
41
+ predicate isSink ( DataFlow:: Node sink ) { defaultSink ( sink ) }
47
42
48
- override int fieldFlowBranchLimit ( ) { result = 1000 }
43
+ int fieldFlowBranchLimit ( ) { result = 1000 }
49
44
}
50
45
51
- class DefaultTaintFlowConf extends TaintTracking :: Configuration {
52
- DefaultTaintFlowConf ( ) { this = "qltest:defaultTaintFlowConf" }
46
+ private module NoFlowConfig implements DataFlow :: ConfigSig {
47
+ predicate isSource ( DataFlow :: Node source ) { none ( ) }
53
48
54
- override predicate isSource ( DataFlow:: Node n ) { defaultSource ( n ) }
55
-
56
- override predicate isSink ( DataFlow:: Node n ) { defaultSink ( n ) }
57
-
58
- override int fieldFlowBranchLimit ( ) { result = 1000 }
49
+ predicate isSink ( DataFlow:: Node sink ) { none ( ) }
59
50
}
60
51
61
- class InlineFlowTest extends InlineExpectationsTest {
62
- InlineFlowTest ( ) { this = "HasFlowTest" }
63
-
64
- override string getARelevantTag ( ) { result = [ "hasValueFlow" , "hasTaintFlow" ] }
65
-
66
- override predicate hasActualResult ( Location location , string element , string tag , string value ) {
67
- tag = "hasValueFlow" and
68
- exists ( DataFlow:: Node src , DataFlow:: Node sink | this .getValueFlowConfig ( ) .hasFlow ( src , sink ) |
69
- sink .getLocation ( ) = location and
70
- element = sink .toString ( ) and
71
- if exists ( getSourceArgString ( src ) ) then value = getSourceArgString ( src ) else value = ""
72
- )
73
- or
74
- tag = "hasTaintFlow" and
75
- exists ( DataFlow:: Node src , DataFlow:: Node sink |
76
- this .getTaintFlowConfig ( ) .hasFlow ( src , sink ) and
77
- not this .getValueFlowConfig ( ) .hasFlow ( src , sink )
78
- |
79
- sink .getLocation ( ) = location and
80
- element = sink .toString ( ) and
81
- if exists ( getSourceArgString ( src ) ) then value = getSourceArgString ( src ) else value = ""
82
- )
52
+ module FlowTest< DataFlow:: ConfigSig ValueFlowConfig, DataFlow:: ConfigSig TaintFlowConfig> {
53
+ module ValueFlow = DataFlow:: Global< ValueFlowConfig > ;
54
+
55
+ module TaintFlow = TaintTracking:: Global< TaintFlowConfig > ;
56
+
57
+ private module InlineTest implements TestSig {
58
+ string getARelevantTag ( ) { result = [ "hasValueFlow" , "hasTaintFlow" ] }
59
+
60
+ predicate hasActualResult ( Location location , string element , string tag , string value ) {
61
+ tag = "hasValueFlow" and
62
+ exists ( DataFlow:: Node src , DataFlow:: Node sink | ValueFlow:: flow ( src , sink ) |
63
+ sink .getLocation ( ) = location and
64
+ element = sink .toString ( ) and
65
+ if exists ( getSourceArgString ( src ) ) then value = getSourceArgString ( src ) else value = ""
66
+ )
67
+ or
68
+ tag = "hasTaintFlow" and
69
+ exists ( DataFlow:: Node src , DataFlow:: Node sink |
70
+ TaintFlow:: flow ( src , sink ) and not ValueFlow:: flow ( src , sink )
71
+ |
72
+ sink .getLocation ( ) = location and
73
+ element = sink .toString ( ) and
74
+ if exists ( getSourceArgString ( src ) ) then value = getSourceArgString ( src ) else value = ""
75
+ )
76
+ }
83
77
}
84
78
85
- DataFlow:: Configuration getValueFlowConfig ( ) { result = any ( DefaultValueFlowConf config ) }
86
-
87
- DataFlow:: Configuration getTaintFlowConfig ( ) { result = any ( DefaultTaintFlowConf config ) }
88
- }
89
-
90
- module PathGraph {
91
- private import DataFlow:: PathGraph as PG
79
+ import MakeTest< InlineTest >
80
+ import DataFlow:: MergePathGraph< ValueFlow:: PathNode , TaintFlow:: PathNode , ValueFlow:: PathGraph , TaintFlow:: PathGraph >
92
81
93
- private class PathNode extends DataFlow:: PathNode {
94
- PathNode ( ) {
95
- this .getConfiguration ( ) =
96
- [ any ( InlineFlowTest t ) .getValueFlowConfig ( ) , any ( InlineFlowTest t ) .getTaintFlowConfig ( ) ]
97
- }
82
+ predicate flowPath ( PathNode source , PathNode sink ) {
83
+ ValueFlow:: flowPath ( source .asPathNode1 ( ) , sink .asPathNode1 ( ) ) or
84
+ TaintFlow:: flowPath ( source .asPathNode2 ( ) , sink .asPathNode2 ( ) )
98
85
}
86
+ }
99
87
100
- /** Holds if `(a,b)` is an edge in the graph of data flow path explanations. */
101
- query predicate edges ( PathNode a , PathNode b ) { PG:: edges ( a , b ) }
88
+ module DefaultFlowTest = FlowTest< DefaultFlowConfig , DefaultFlowConfig > ;
102
89
103
- /** Holds if `n` is a node in the graph of data flow path explanations. */
104
- query predicate nodes ( PathNode n , string key , string val ) { PG:: nodes ( n , key , val ) }
90
+ module ValueFlowTest< DataFlow:: ConfigSig ValueFlowConfig> {
91
+ import FlowTest< ValueFlowConfig , NoFlowConfig >
92
+ }
105
93
106
- query predicate subpaths ( PathNode arg , PathNode par , PathNode ret , PathNode out ) {
107
- PG:: subpaths ( arg , par , ret , out )
108
- }
94
+ module TaintFlowTest< DataFlow:: ConfigSig TaintFlowConfig> {
95
+ import FlowTest< NoFlowConfig , TaintFlowConfig >
109
96
}
0 commit comments