55 * ```ql
66 * import java
77 * import TestUtilities.InlineFlowTest
8+ * import DefaultFlowTest
89 * ```
910 *
1011 * To declare expectations, you can use the $hasTaintFlow or $hasValueFlow comments within the test source files.
1819 *
1920 * public void test() {
2021 * Object s = source();
21- * sink(s); //$ hasValueFlow
22+ * sink(s); // $ hasValueFlow
2223 * String t = "foo" + taint();
23- * sink(t); //$ hasTaintFlow
24+ * sink(t); // $ hasTaintFlow
2425 * }
2526 *
2627 * }
2728 * ```
2829 *
29- * If you're not interested in a specific flow type, you can disable either value or taint flow expectations as follows:
30- * ```ql
31- * class HasFlowTest extends InlineFlowTest {
32- * override DataFlow::Configuration getTaintFlowConfig() { none() }
33- *
34- * override DataFlow::Configuration getValueFlowConfig() { none() }
35- * }
36- * ```
30+ * If you are only interested in value flow, then instead of importing `DefaultFlowTest`, you can import
31+ * `ValueFlowTest<DefaultFlowConfig>`. Similarly, if you are only interested in taint flow, then instead of
32+ * importing `DefaultFlowTest`, you can import `TaintFlowTest<DefaultFlowConfig>`. In both cases
33+ * `DefaultFlowConfig` can be replaced by another implementation of `DataFlow::ConfigSig`.
3734 *
3835 * If you need more fine-grained tuning, consider implementing a test using `InlineExpectationsTest`.
3936 */
@@ -43,57 +40,69 @@ import semmle.code.java.dataflow.ExternalFlow
4340import semmle.code.java.dataflow.TaintTracking
4441import TestUtilities.InlineExpectationsTest
4542
46- private predicate defaultSource ( DataFlow:: Node src ) {
47- src .asExpr ( ) .( MethodAccess ) .getMethod ( ) .getName ( ) = [ "source" , "taint" ]
43+ private predicate defaultSource ( DataFlow:: Node source ) {
44+ source .asExpr ( ) .( MethodAccess ) .getMethod ( ) .getName ( ) = [ "source" , "taint" ]
45+ }
46+
47+ private predicate defaultSink ( DataFlow:: Node sink ) {
48+ exists ( MethodAccess ma | ma .getMethod ( ) .hasName ( "sink" ) | sink .asExpr ( ) = ma .getAnArgument ( ) )
4849}
4950
5051module DefaultFlowConfig implements DataFlow:: ConfigSig {
51- predicate isSource ( DataFlow:: Node n ) { defaultSource ( n ) }
52+ predicate isSource ( DataFlow:: Node source ) { defaultSource ( source ) }
5253
53- predicate isSink ( DataFlow:: Node n ) {
54- exists ( MethodAccess ma | ma .getMethod ( ) .hasName ( "sink" ) | n .asExpr ( ) = ma .getAnArgument ( ) )
55- }
54+ predicate isSink ( DataFlow:: Node sink ) { defaultSink ( sink ) }
5655
5756 int fieldFlowBranchLimit ( ) { result = 1000 }
5857}
5958
60- private module DefaultValueFlow = DataFlow:: Global< DefaultFlowConfig > ;
59+ private module NoFlowConfig implements DataFlow:: ConfigSig {
60+ predicate isSource ( DataFlow:: Node source ) { none ( ) }
6161
62- private module DefaultTaintFlow = TaintTracking:: Global< DefaultFlowConfig > ;
62+ predicate isSink ( DataFlow:: Node sink ) { none ( ) }
63+ }
6364
6465private string getSourceArgString ( DataFlow:: Node src ) {
6566 defaultSource ( src ) and
6667 src .asExpr ( ) .( MethodAccess ) .getAnArgument ( ) .( StringLiteral ) .getValue ( ) = result
6768}
6869
69- class InlineFlowTest extends InlineExpectationsTest {
70- InlineFlowTest ( ) { this = "HasFlowTest" }
71-
72- override string getARelevantTag ( ) { result = [ "hasValueFlow" , "hasTaintFlow" ] }
73-
74- override predicate hasActualResult ( Location location , string element , string tag , string value ) {
75- tag = "hasValueFlow" and
76- exists ( DataFlow:: Node src , DataFlow:: Node sink | this .hasValueFlow ( src , sink ) |
77- sink .getLocation ( ) = location and
78- element = sink .toString ( ) and
79- if exists ( getSourceArgString ( src ) ) then value = getSourceArgString ( src ) else value = ""
80- )
81- or
82- tag = "hasTaintFlow" and
83- exists ( DataFlow:: Node src , DataFlow:: Node sink |
84- this .hasTaintFlow ( src , sink ) and not this .hasValueFlow ( src , sink )
85- |
86- sink .getLocation ( ) = location and
87- element = sink .toString ( ) and
88- if exists ( getSourceArgString ( src ) ) then value = getSourceArgString ( src ) else value = ""
89- )
90- }
70+ module FlowTest< DataFlow:: ConfigSig ValueFlowConfig, DataFlow:: ConfigSig TaintFlowConfig> {
71+ module ValueFlow = DataFlow:: Global< ValueFlowConfig > ;
9172
92- predicate hasValueFlow ( DataFlow:: Node src , DataFlow:: Node sink ) {
93- DefaultValueFlow:: flow ( src , sink )
94- }
73+ module TaintFlow = TaintTracking:: Global< TaintFlowConfig > ;
74+
75+ private module InlineTest implements TestSig {
76+ string getARelevantTag ( ) { result = [ "hasValueFlow" , "hasTaintFlow" ] }
9577
96- predicate hasTaintFlow ( DataFlow:: Node src , DataFlow:: Node sink ) {
97- DefaultTaintFlow:: flow ( src , sink )
78+ predicate hasActualResult ( Location location , string element , string tag , string value ) {
79+ tag = "hasValueFlow" and
80+ exists ( DataFlow:: Node src , DataFlow:: Node sink | ValueFlow:: flow ( src , sink ) |
81+ sink .getLocation ( ) = location and
82+ element = sink .toString ( ) and
83+ if exists ( getSourceArgString ( src ) ) then value = getSourceArgString ( src ) else value = ""
84+ )
85+ or
86+ tag = "hasTaintFlow" and
87+ exists ( DataFlow:: Node src , DataFlow:: Node sink |
88+ TaintFlow:: flow ( src , sink ) and not ValueFlow:: flow ( src , sink )
89+ |
90+ sink .getLocation ( ) = location and
91+ element = sink .toString ( ) and
92+ if exists ( getSourceArgString ( src ) ) then value = getSourceArgString ( src ) else value = ""
93+ )
94+ }
9895 }
96+
97+ import MakeTest< InlineTest >
98+ }
99+
100+ module DefaultFlowTest = FlowTest< DefaultFlowConfig , DefaultFlowConfig > ;
101+
102+ module ValueFlowTest< DataFlow:: ConfigSig ValueFlowConfig> {
103+ import FlowTest< ValueFlowConfig , NoFlowConfig >
104+ }
105+
106+ module TaintFlowTest< DataFlow:: ConfigSig TaintFlowConfig> {
107+ import FlowTest< NoFlowConfig , TaintFlowConfig >
99108}
0 commit comments