Consolidate all InlineFlowTest libraries in the dataflow qlpack

This commit is contained in:
Jeroen Ketema
2023-08-03 10:59:06 +02:00
parent da403c1a79
commit 9d573e5544
135 changed files with 284 additions and 692 deletions

View File

@@ -3,40 +3,6 @@
* See `shared/util/codeql/util/test/InlineExpectationsTest.qll`
*/
private import java as J
private import codeql.util.test.InlineExpectationsTest
private module Impl implements InlineExpectationsTestSig {
/**
* A class representing line comments in Java, which is simply Javadoc restricted
* to EOL comments, with an extra accessor used by the InlineExpectations core code
*/
abstract class ExpectationComment extends J::Top {
/** Gets the contents of the given comment, _without_ the preceding comment marker (`//`). */
abstract string getContents();
}
private class JavadocExpectationComment extends J::Javadoc, ExpectationComment {
JavadocExpectationComment() { isEolComment(this) }
override string getContents() { result = this.getChild(0).toString() }
}
private class KtExpectationComment extends J::KtComment, ExpectationComment {
KtExpectationComment() { this.isEolComment() }
override string getContents() { result = this.getText().suffix(2).trim() }
}
private class XmlExpectationComment extends ExpectationComment instanceof J::XmlComment {
override string getContents() { result = super.getText().trim() }
override Location getLocation() { result = J::XmlComment.super.getLocation() }
override string toString() { result = J::XmlComment.super.toString() }
}
class Location = J::Location;
}
private import internal.InlineExpectationsTestImpl
import Make<Impl>

View File

@@ -1,119 +1,33 @@
/**
* Provides a simple base test for flow-related tests using inline expectations.
*
* Example for a test.ql:
* ```ql
* import java
* import TestUtilities.InlineFlowTest
* import DefaultFlowTest
* import PathGraph
*
* from PathNode source, PathNode sink
* where flowPath(source, sink)
* select sink, source, sink, "$@", source, source.toString()
* ```
*
* To declare expectations, you can use the $hasTaintFlow or $hasValueFlow comments within the test source files.
* Example of the corresponding test file, e.g. Test.java
* ```java
* public class Test {
*
* Object source() { return null; }
* String taint() { return null; }
* void sink(Object o) { }
*
* public void test() {
* Object s = source();
* sink(s); // $ hasValueFlow
* String t = "foo" + taint();
* sink(t); // $ hasTaintFlow
* }
*
* }
* ```
*
* If you are only interested in value flow, then instead of importing `DefaultFlowTest`, you can import
* `ValueFlowTest<DefaultFlowConfig>`. Similarly, if you are only interested in taint flow, then instead of
* importing `DefaultFlowTest`, you can import `TaintFlowTest<DefaultFlowConfig>`. In both cases
* `DefaultFlowConfig` can be replaced by another implementation of `DataFlow::ConfigSig`.
*
* If you need more fine-grained tuning, consider implementing a test using `InlineExpectationsTest`.
* Inline flow tests for Java.
* See `shared/util/codeql/dataflow/test/InlineFlowTest.qll`
*/
import java
import semmle.code.java.dataflow.DataFlow
import semmle.code.java.dataflow.ExternalFlow
import semmle.code.java.dataflow.TaintTracking
import TestUtilities.InlineExpectationsTest
private import codeql.dataflow.test.InlineFlowTest
private import semmle.code.java.dataflow.internal.DataFlowImplSpecific
private import semmle.code.java.dataflow.internal.TaintTrackingImplSpecific
private import internal.InlineExpectationsTestImpl
private predicate defaultSource(DataFlow::Node source) {
source.asExpr().(MethodAccess).getMethod().getName() = ["source", "taint"]
}
private predicate defaultSink(DataFlow::Node sink) {
exists(MethodAccess ma | ma.getMethod().hasName("sink") | sink.asExpr() = ma.getAnArgument())
}
module DefaultFlowConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node source) { defaultSource(source) }
predicate isSink(DataFlow::Node sink) { defaultSink(sink) }
int fieldFlowBranchLimit() { result = 1000 }
}
private module NoFlowConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node source) { none() }
predicate isSink(DataFlow::Node sink) { none() }
}
private string getSourceArgString(DataFlow::Node src) {
defaultSource(src) and
src.asExpr().(MethodAccess).getAnArgument().(StringLiteral).getValue() = result
}
module FlowTest<DataFlow::ConfigSig ValueFlowConfig, DataFlow::ConfigSig TaintFlowConfig> {
module ValueFlow = DataFlow::Global<ValueFlowConfig>;
module TaintFlow = TaintTracking::Global<TaintFlowConfig>;
private module InlineTest implements TestSig {
string getARelevantTag() { result = ["hasValueFlow", "hasTaintFlow"] }
predicate hasActualResult(Location location, string element, string tag, string value) {
tag = "hasValueFlow" and
exists(DataFlow::Node src, DataFlow::Node sink | ValueFlow::flow(src, sink) |
sink.getLocation() = location and
element = sink.toString() and
if exists(getSourceArgString(src)) then value = getSourceArgString(src) else value = ""
)
or
tag = "hasTaintFlow" and
exists(DataFlow::Node src, DataFlow::Node sink |
TaintFlow::flow(src, sink) and not ValueFlow::flow(src, sink)
|
sink.getLocation() = location and
element = sink.toString() and
if exists(getSourceArgString(src)) then value = getSourceArgString(src) else value = ""
)
}
private module FlowTestImpl implements InputSig<JavaDataFlow> {
predicate defaultSource(DataFlow::Node source) {
source.asExpr().(MethodAccess).getMethod().getName() = ["source", "taint"]
}
import MakeTest<InlineTest>
import DataFlow::MergePathGraph<ValueFlow::PathNode, TaintFlow::PathNode, ValueFlow::PathGraph, TaintFlow::PathGraph>
predicate defaultSink(DataFlow::Node sink) {
exists(MethodAccess ma | ma.getMethod().hasName("sink") | sink.asExpr() = ma.getAnArgument())
}
predicate flowPath(PathNode source, PathNode sink) {
ValueFlow::flowPath(source.asPathNode1(), sink.asPathNode1()) or
TaintFlow::flowPath(source.asPathNode2(), sink.asPathNode2())
private string getSourceArgString(DataFlow::Node src) {
defaultSource(src) and
src.asExpr().(MethodAccess).getAnArgument().(StringLiteral).getValue() = result
}
string getArgString(DataFlow::Node src, DataFlow::Node sink) {
(if exists(getSourceArgString(src)) then result = getSourceArgString(src) else result = "") and
exists(sink)
}
}
module DefaultFlowTest = FlowTest<DefaultFlowConfig, DefaultFlowConfig>;
module ValueFlowTest<DataFlow::ConfigSig ValueFlowConfig> {
import FlowTest<ValueFlowConfig, NoFlowConfig>
}
module TaintFlowTest<DataFlow::ConfigSig TaintFlowConfig> {
import FlowTest<NoFlowConfig, TaintFlowConfig>
}
import InlineFlowTestMake<JavaDataFlow, JavaTaintTracking, Impl, FlowTestImpl>

View File

@@ -0,0 +1,35 @@
private import java as J
private import codeql.util.test.InlineExpectationsTest
module Impl implements InlineExpectationsTestSig {
/**
* A class representing line comments in Java, which is simply Javadoc restricted
* to EOL comments, with an extra accessor used by the InlineExpectations core code
*/
abstract class ExpectationComment extends J::Top {
/** Gets the contents of the given comment, _without_ the preceding comment marker (`//`). */
abstract string getContents();
}
private class JavadocExpectationComment extends J::Javadoc, ExpectationComment {
JavadocExpectationComment() { isEolComment(this) }
override string getContents() { result = this.getChild(0).toString() }
}
private class KtExpectationComment extends J::KtComment, ExpectationComment {
KtExpectationComment() { this.isEolComment() }
override string getContents() { result = this.getText().suffix(2).trim() }
}
private class XmlExpectationComment extends ExpectationComment instanceof J::XmlComment {
override string getContents() { result = super.getText().trim() }
override Location getLocation() { result = J::XmlComment.super.getLocation() }
override string toString() { result = J::XmlComment.super.toString() }
}
class Location = J::Location;
}

View File

@@ -1,2 +0,0 @@
failures
testFailures

View File

@@ -1,5 +1,3 @@
failures
testFailures
| test.kt:28:14:28:21 | getSecond(...) | Unexpected result: hasTaintFlow=a |
| test.kt:35:14:35:27 | component1(...) | Unexpected result: hasTaintFlow=d |
| test.kt:41:14:41:22 | getSecond(...) | Unexpected result: hasTaintFlow=e |

View File

@@ -1,2 +0,0 @@
failures
testFailures

View File

@@ -1,2 +0,0 @@
failures
testFailures

View File

@@ -1,2 +0,0 @@
failures
testFailures

View File

@@ -1,2 +0,0 @@
failures
testFailures

View File

@@ -1,2 +0,0 @@
failures
testFailures

View File

@@ -1,2 +0,0 @@
failures
testFailures

View File

@@ -1,2 +0,0 @@
failures
testFailures

View File

@@ -1,3 +1,2 @@
failures
testFailures
invalidModelRow

View File

@@ -1,4 +1,5 @@
import java
import semmle.code.java.dataflow.ExternalFlow
import TestUtilities.InlineFlowTest
import DefaultFlowTest
import ModelValidation

View File

@@ -1,2 +0,0 @@
failures
testFailures

View File

@@ -1,2 +0,0 @@
failures
testFailures

View File

@@ -1,2 +0,0 @@
failures
testFailures

View File

@@ -1,2 +0,0 @@
failures
testFailures

View File

@@ -1,2 +0,0 @@
failures
testFailures

View File

@@ -1,2 +0,0 @@
failures
testFailures

View File

@@ -1,2 +0,0 @@
failures
testFailures

View File

@@ -1,2 +0,0 @@
failures
testFailures

View File

@@ -1,2 +0,0 @@
failures
testFailures

View File

@@ -1,2 +0,0 @@
failures
testFailures

View File

@@ -1,2 +0,0 @@
failures
testFailures

View File

@@ -1,2 +0,0 @@
failures
testFailures

View File

@@ -1,3 +1,2 @@
failures
testFailures
valueOf

View File

@@ -1,2 +0,0 @@
failures
testFailures

View File

@@ -1,2 +0,0 @@
failures
testFailures

View File

@@ -1,2 +0,0 @@
failures
testFailures

View File

@@ -1,2 +0,0 @@
failures
testFailures

View File

@@ -1,2 +0,0 @@
failures
testFailures

View File

@@ -1,2 +0,0 @@
failures
testFailures

View File

@@ -1,2 +0,0 @@
failures
testFailures

View File

@@ -1,2 +0,0 @@
failures
testFailures

View File

@@ -1,2 +0,0 @@
failures
testFailures

View File

@@ -1,2 +0,0 @@
failures
testFailures

View File

@@ -1,2 +0,0 @@
failures
testFailures

View File

@@ -1,2 +0,0 @@
failures
testFailures

View File

@@ -1,2 +0,0 @@
failures
testFailures

View File

@@ -1,2 +0,0 @@
failures
testFailures

View File

@@ -1,2 +0,0 @@
failures
testFailures

View File

@@ -1,2 +0,0 @@
failures
testFailures

View File

@@ -1,2 +0,0 @@
failures
testFailures

View File

@@ -1,2 +0,0 @@
failures
testFailures

View File

@@ -1,5 +1,6 @@
import java
import semmle.code.java.dataflow.DataFlow
import semmle.code.java.dataflow.ExternalFlow
import TestUtilities.InlineFlowTest
module OkHttpFlowConfig implements DataFlow::ConfigSig {

View File

@@ -1,2 +0,0 @@
failures
testFailures

View File

@@ -1,2 +0,0 @@
failures
testFailures

View File

@@ -1,2 +0,0 @@
failures
testFailures

View File

@@ -1,2 +0,0 @@
failures
testFailures

View File

@@ -1,5 +1,6 @@
import java
import semmle.code.java.dataflow.DataFlow
import semmle.code.java.dataflow.ExternalFlow
import TestUtilities.InlineFlowTest
module FlowConfig implements DataFlow::ConfigSig {

View File

@@ -1,2 +0,0 @@
failures
testFailures

View File

@@ -1,2 +0,0 @@
failures
testFailures

View File

@@ -1,2 +0,0 @@
failures
testFailures

View File

@@ -1,2 +0,0 @@
failures
testFailures

View File

@@ -1,2 +0,0 @@
failures
testFailures

View File

@@ -1,2 +0,0 @@
failures
testFailures

View File

@@ -1,2 +0,0 @@
failures
testFailures

View File

@@ -1,2 +0,0 @@
failures
testFailures

View File

@@ -1,2 +0,0 @@
failures
testFailures

View File

@@ -1,2 +0,0 @@
failures
testFailures

View File

@@ -1,2 +0,0 @@
failures
testFailures

View File

@@ -1,2 +0,0 @@
failures
testFailures

View File

@@ -1,2 +0,0 @@
failures
testFailures

View File

@@ -1,2 +0,0 @@
failures
testFailures

View File

@@ -1,2 +0,0 @@
failures
testFailures

View File

@@ -1,2 +0,0 @@
failures
testFailures

View File

@@ -1,2 +0,0 @@
failures
testFailures

View File

@@ -1,2 +0,0 @@
failures
testFailures

View File

@@ -1,2 +0,0 @@
failures
testFailures

View File

@@ -1,2 +0,0 @@
failures
testFailures

View File

@@ -1,2 +0,0 @@
failures
testFailures

View File

@@ -1,2 +0,0 @@
failures
testFailures

View File

@@ -1,2 +0,0 @@
failures
testFailures

View File

@@ -1,2 +0,0 @@
failures
testFailures

View File

@@ -1,2 +0,0 @@
failures
testFailures