Merge pull request #12186 from aschackmull/dataflow/refactor-configuration

Data flow: Refactor configuration
This commit is contained in:
Anders Schack-Mulligen
2023-03-06 13:38:59 +01:00
committed by GitHub
156 changed files with 46756 additions and 184499 deletions

View File

@@ -47,6 +47,20 @@ private predicate defaultSource(DataFlow::Node src) {
src.asExpr().(MethodAccess).getMethod().getName() = ["source", "taint"]
}
module DefaultFlowConf implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node n) { defaultSource(n) }
predicate isSink(DataFlow::Node n) {
exists(MethodAccess ma | ma.getMethod().hasName("sink") | n.asExpr() = ma.getAnArgument())
}
int fieldFlowBranchLimit() { result = 1000 }
}
private module DefaultValueFlow = DataFlow::Make<DefaultFlowConf>;
private module DefaultTaintFlow = TaintTracking::Make<DefaultFlowConf>;
class DefaultValueFlowConf extends DataFlow::Configuration {
DefaultValueFlowConf() { this = "qltest:defaultValueFlowConf" }
@@ -76,6 +90,8 @@ private string getSourceArgString(DataFlow::Node src) {
src.asExpr().(MethodAccess).getAnArgument().(StringLiteral).getValue() = result
}
abstract class EnableLegacyConfiguration extends Unit { }
class InlineFlowTest extends InlineExpectationsTest {
InlineFlowTest() { this = "HasFlowTest" }
@@ -83,7 +99,7 @@ class InlineFlowTest extends InlineExpectationsTest {
override predicate hasActualResult(Location location, string element, string tag, string value) {
tag = "hasValueFlow" and
exists(DataFlow::Node src, DataFlow::Node sink | getValueFlowConfig().hasFlow(src, sink) |
exists(DataFlow::Node src, DataFlow::Node sink | hasValueFlow(src, sink) |
sink.getLocation() = location and
element = sink.toString() and
if exists(getSourceArgString(src)) then value = getSourceArgString(src) else value = ""
@@ -91,7 +107,7 @@ class InlineFlowTest extends InlineExpectationsTest {
or
tag = "hasTaintFlow" and
exists(DataFlow::Node src, DataFlow::Node sink |
getTaintFlowConfig().hasFlow(src, sink) and not getValueFlowConfig().hasFlow(src, sink)
hasTaintFlow(src, sink) and not hasValueFlow(src, sink)
|
sink.getLocation() = location and
element = sink.toString() and
@@ -99,6 +115,18 @@ class InlineFlowTest extends InlineExpectationsTest {
)
}
predicate hasValueFlow(DataFlow::Node src, DataFlow::Node sink) {
if exists(EnableLegacyConfiguration e)
then getValueFlowConfig().hasFlow(src, sink)
else DefaultValueFlow::hasFlow(src, sink)
}
predicate hasTaintFlow(DataFlow::Node src, DataFlow::Node sink) {
if exists(EnableLegacyConfiguration e)
then getTaintFlowConfig().hasFlow(src, sink)
else DefaultTaintFlow::hasFlow(src, sink)
}
DataFlow::Configuration getValueFlowConfig() { result = any(DefaultValueFlowConf config) }
DataFlow::Configuration getTaintFlowConfig() { result = any(DefaultTaintFlowConf config) }

View File

@@ -1,7 +1,3 @@
import java
import semmle.code.java.dataflow.DataFlow
import TestUtilities.InlineFlowTest
class HasFlowTest extends InlineFlowTest {
override DataFlow::Configuration getTaintFlowConfig() { none() }
}

View File

@@ -42,31 +42,31 @@ public class Test {
public static void test1() {
Test t = new Test();
t.fluentNoop().fluentSet(source()).fluentNoop();
sink(t.get()); // $hasTaintFlow
sink(t.get()); // $hasValueFlow
}
public static void test2() {
Test t = new Test();
Test.identity(t).fluentNoop().fluentSet(source()).fluentNoop();
sink(t.get()); // $hasTaintFlow
sink(t.get()); // $hasValueFlow
}
public static void test3() {
Test t = new Test();
t.indirectlyFluentNoop().fluentSet(source()).fluentNoop();
sink(t.get()); // $hasTaintFlow
sink(t.get()); // $hasValueFlow
}
public static void testModel1() {
Test t = new Test();
t.indirectlyFluentNoop().modelledFluentMethod().fluentSet(source()).fluentNoop();
sink(t.get()); // $hasTaintFlow
sink(t.get()); // $hasValueFlow
}
public static void testModel2() {
Test t = new Test();
Test.modelledIdentity(t).indirectlyFluentNoop().modelledFluentMethod().fluentSet(source()).fluentNoop();
sink(t.get()); // $hasTaintFlow
sink(t.get()); // $hasValueFlow
}
}

View File

@@ -12,7 +12,3 @@ class IdentityModel extends ValuePreservingMethod {
override predicate returnsValue(int arg) { arg = 0 }
}
class HasFlowTest extends InlineFlowTest {
override DataFlow::Configuration getValueFlowConfig() { none() }
}

View File

@@ -14,54 +14,46 @@ predicate sink0(Node n) {
)
}
class Conf1 extends Configuration {
Conf1() { this = "inoutbarriers1" }
module Conf1 implements ConfigSig {
predicate isSource(Node n) { src0(n) }
override predicate isSource(Node n) { src0(n) }
override predicate isSink(Node n) { sink0(n) }
predicate isSink(Node n) { sink0(n) }
}
class Conf2 extends Configuration {
Conf2() { this = "inoutbarriers2" }
module Conf2 implements ConfigSig {
predicate isSource(Node n) { src0(n) }
override predicate isSource(Node n) { src0(n) }
predicate isSink(Node n) { sink0(n) }
override predicate isSink(Node n) { sink0(n) }
override predicate isBarrierIn(Node n) { src0(n) }
predicate isBarrierIn(Node n) { src0(n) }
}
class Conf3 extends Configuration {
Conf3() { this = "inoutbarriers3" }
module Conf3 implements ConfigSig {
predicate isSource(Node n) { src0(n) }
override predicate isSource(Node n) { src0(n) }
predicate isSink(Node n) { sink0(n) }
override predicate isSink(Node n) { sink0(n) }
override predicate isBarrierOut(Node n) { sink0(n) }
predicate isBarrierOut(Node n) { sink0(n) }
}
class Conf4 extends Configuration {
Conf4() { this = "inoutbarriers4" }
module Conf4 implements ConfigSig {
predicate isSource(Node n) { src0(n) }
override predicate isSource(Node n) { src0(n) }
predicate isSink(Node n) { sink0(n) }
override predicate isSink(Node n) { sink0(n) }
predicate isBarrierIn(Node n) { src0(n) }
override predicate isBarrierIn(Node n) { src0(n) }
override predicate isBarrierOut(Node n) { sink0(n) }
predicate isBarrierOut(Node n) { sink0(n) }
}
predicate flow(Node src, Node sink, string s) {
any(Conf1 c).hasFlow(src, sink) and s = "nobarrier"
Make<Conf1>::hasFlow(src, sink) and s = "nobarrier"
or
any(Conf2 c).hasFlow(src, sink) and s = "srcbarrier"
Make<Conf2>::hasFlow(src, sink) and s = "srcbarrier"
or
any(Conf3 c).hasFlow(src, sink) and s = "sinkbarrier"
Make<Conf3>::hasFlow(src, sink) and s = "sinkbarrier"
or
any(Conf4 c).hasFlow(src, sink) and s = "both"
Make<Conf4>::hasFlow(src, sink) and s = "both"
}
from Node src, Node sink, string s

View File

@@ -1,18 +1,19 @@
import java
import semmle.code.java.dataflow.DataFlow
import DataFlow
import PartialPathGraph
class Conf extends Configuration {
Conf() { this = "partial flow" }
module Config implements ConfigSig {
predicate isSource(Node n) { n.asExpr().(MethodAccess).getMethod().hasName("src") }
override predicate isSource(Node n) { n.asExpr().(MethodAccess).getMethod().hasName("src") }
override predicate isSink(Node n) { n.asExpr().(Argument).getCall().getCallee().hasName("sink") }
override int explorationLimit() { result = 10 }
predicate isSink(Node n) { n.asExpr().(Argument).getCall().getCallee().hasName("sink") }
}
from PartialPathNode n, int dist
where any(Conf c).hasPartialFlow(_, n, dist)
int explorationLimit() { result = 10 }
module PartialFlow = Make<Config>::FlowExploration<explorationLimit/0>;
import PartialFlow::PartialPathGraph
from PartialFlow::PartialPathNode n, int dist
where PartialFlow::hasPartialFlow(_, n, dist)
select dist, n

View File

@@ -1,18 +1,19 @@
import java
import semmle.code.java.dataflow.DataFlow
import DataFlow
import PartialPathGraph
class Conf extends Configuration {
Conf() { this = "partial flow" }
module Config implements ConfigSig {
predicate isSource(Node n) { n.asExpr().(MethodAccess).getMethod().hasName("src") }
override predicate isSource(Node n) { n.asExpr().(MethodAccess).getMethod().hasName("src") }
override predicate isSink(Node n) { n.asExpr().(Argument).getCall().getCallee().hasName("sink") }
override int explorationLimit() { result = 10 }
predicate isSink(Node n) { n.asExpr().(Argument).getCall().getCallee().hasName("sink") }
}
from PartialPathNode n, int dist
where any(Conf c).hasPartialFlowRev(n, _, dist)
int explorationLimit() { result = 10 }
module PartialFlow = Make<Config>::FlowExploration<explorationLimit/0>;
import PartialFlow::PartialPathGraph
from PartialFlow::PartialPathNode n, int dist
where PartialFlow::hasPartialFlowRev(n, _, dist)
select dist, n

View File

@@ -39,22 +39,26 @@ predicate step(Node n1, Node n2, string s1, string s2) {
predicate checkNode(Node n) { n.asExpr().(Argument).getCall().getCallee().hasName("check") }
class Conf extends TaintTracking::Configuration {
Conf() { this = "qltest:state" }
module Conf implements DataFlow::StateConfigSig {
class FlowState = string;
override predicate isSource(Node n, FlowState s) { src(n, s) }
predicate isSource(Node n, FlowState s) { src(n, s) }
override predicate isSink(Node n, FlowState s) { sink(n, s) }
predicate isSink(Node n, FlowState s) { sink(n, s) }
override predicate isSanitizer(Node n, FlowState s) { bar(n, s) }
predicate isBarrier(Node n, FlowState s) { bar(n, s) }
override predicate isAdditionalTaintStep(Node n1, FlowState s1, Node n2, FlowState s2) {
predicate isAdditionalFlowStep(Node n1, FlowState s1, Node n2, FlowState s2) {
step(n1, n2, s1, s2)
}
override int explorationLimit() { result = 0 }
}
int explorationLimit() { result = 0 }
module Flow = TaintTracking::MakeWithState<Conf>;
module PartialFlow = Flow::FlowExploration<explorationLimit/0>;
class HasFlowTest extends InlineExpectationsTest {
HasFlowTest() { this = "HasFlowTest" }
@@ -62,16 +66,16 @@ class HasFlowTest extends InlineExpectationsTest {
override predicate hasActualResult(Location location, string element, string tag, string value) {
tag = "flow" and
exists(PathNode src, PathNode sink, Conf conf |
conf.hasFlowPath(src, sink) and
exists(Flow::PathNode src, Flow::PathNode sink |
Flow::hasFlowPath(src, sink) and
sink.getNode().getLocation() = location and
element = sink.toString() and
value = src.getState()
)
or
tag = "pFwd" and
exists(PartialPathNode src, PartialPathNode node, Conf conf |
conf.hasPartialFlow(src, node, _) and
exists(PartialFlow::PartialPathNode src, PartialFlow::PartialPathNode node |
PartialFlow::hasPartialFlow(src, node, _) and
checkNode(node.getNode()) and
node.getNode().getLocation() = location and
element = node.toString() and
@@ -79,8 +83,8 @@ class HasFlowTest extends InlineExpectationsTest {
)
or
tag = "pRev" and
exists(PartialPathNode node, PartialPathNode sink, Conf conf |
conf.hasPartialFlowRev(node, sink, _) and
exists(PartialFlow::PartialPathNode node, PartialFlow::PartialPathNode sink |
PartialFlow::hasPartialFlowRev(node, sink, _) and
checkNode(node.getNode()) and
node.getNode().getLocation() = location and
element = node.toString() and

View File

@@ -6,42 +6,44 @@ class A {
return "tainted";
}
public static void sink(Object o) { }
public static void test1() {
String bad = source(); // $ hasTaintFlow
String bad = source();
String good = "hi";
bad.formatted(good); // $ hasTaintFlow
good.formatted("a", bad, "b", good); // $ hasTaintFlow
String.format("%s%s", bad, good); // $ hasTaintFlow
String.format("%s", good);
String.format("%s %s %s %s %s %s %s %s %s %s ", "a", "a", "a", "a", "a", "a", "a", "a", "a", bad); // $ hasTaintFlow
sink(bad.formatted(good)); // $ hasTaintFlow
sink(good.formatted("a", bad, "b", good)); // $ hasTaintFlow
sink(String.format("%s%s", bad, good)); // $ hasTaintFlow
sink(String.format("%s", good));
sink(String.format("%s %s %s %s %s %s %s %s %s %s ", "a", "a", "a", "a", "a", "a", "a", "a", "a", bad)); // $ hasTaintFlow
}
public static void test2() {
String bad = source(); // $ hasTaintFlow
String bad = source();
Formatter f = new Formatter();
f.toString();
f.format("%s", bad); // $ hasTaintFlow
f.toString(); // $ hasTaintFlow
sink(f.toString());
sink(f.format("%s", bad)); // $ hasTaintFlow
sink(f.toString()); // $ hasTaintFlow
}
public static void test3() {
String bad = source(); // $ hasTaintFlow
String bad = source();
StringBuilder sb = new StringBuilder();
Formatter f = new Formatter(sb);
sb.toString(); // $ hasTaintFlow false positive
f.format("%s", bad); // $ hasTaintFlow
sb.toString(); // $ hasTaintFlow
sink(sb.toString()); // $ SPURIOUS: hasTaintFlow
sink(f.format("%s", bad)); // $ hasTaintFlow
sink(sb.toString()); // $ hasTaintFlow
}
public static void test4() {
String bad = source(); // $ hasTaintFlow
String bad = source();
StringBuilder sb = new StringBuilder();
sb.append(bad); // $ hasTaintFlow
sink(sb.append(bad)); // $ hasTaintFlow
new Formatter(sb).format("ok").toString(); // $ hasTaintFlow
sink(new Formatter(sb).format("ok").toString()); // $ hasTaintFlow
}
}
}

View File

@@ -1,8 +1,2 @@
import java
import semmle.code.java.dataflow.DataFlow
import semmle.code.java.dataflow.TaintTracking
import TestUtilities.InlineFlowTest
class TaintFlowConf extends DefaultTaintFlowConf {
override predicate isSink(DataFlow::Node n) { n instanceof DataFlow::ExprNode }
}

View File

@@ -3,6 +3,10 @@ import semmle.code.java.dataflow.TaintTracking
import semmle.code.java.dataflow.FlowSources
import TestUtilities.InlineFlowTest
class EnableLegacy extends EnableLegacyConfiguration {
EnableLegacy() { exists(this) }
}
class TaintFlowConf extends DefaultTaintFlowConf {
override predicate isSource(DataFlow::Node n) {
super.isSource(n)

View File

@@ -2,6 +2,10 @@ import java
import semmle.code.java.dataflow.FlowSources
import TestUtilities.InlineFlowTest
class EnableLegacy extends EnableLegacyConfiguration {
EnableLegacy() { exists(this) }
}
class ProviderTaintFlowConf extends DefaultTaintFlowConf {
override predicate isSource(DataFlow::Node n) { n instanceof RemoteFlowSource }
}

View File

@@ -3,6 +3,10 @@ import semmle.code.java.dataflow.DataFlow
import semmle.code.java.dataflow.FlowSources
import TestUtilities.InlineFlowTest
class EnableLegacy extends EnableLegacyConfiguration {
EnableLegacy() { exists(this) }
}
class Conf extends TaintTracking::Configuration {
Conf() { this = "test:AndroidExternalFlowConf" }

View File

@@ -2,6 +2,10 @@ import java
import TestUtilities.InlineFlowTest
import semmle.code.java.dataflow.FlowSources
class EnableLegacy extends EnableLegacyConfiguration {
EnableLegacy() { exists(this) }
}
class SliceValueFlowConf extends DefaultValueFlowConf {
override predicate isSource(DataFlow::Node source) {
super.isSource(source) or source instanceof RemoteFlowSource

View File

@@ -2,6 +2,10 @@ import java
import semmle.code.java.dataflow.FlowSources
import TestUtilities.InlineFlowTest
class EnableLegacy extends EnableLegacyConfiguration {
EnableLegacy() { exists(this) }
}
class SourceValueFlowConf extends DefaultValueFlowConf {
override predicate isSource(DataFlow::Node src) { src instanceof RemoteFlowSource }
}

View File

@@ -5,6 +5,10 @@ import semmle.code.java.security.XSS
import semmle.code.java.security.UrlRedirect
import TestUtilities.InlineFlowTest
class EnableLegacy extends EnableLegacyConfiguration {
EnableLegacy() { exists(this) }
}
class Conf extends TaintTracking::Configuration {
Conf() { this = "qltest:frameworks:apache-http" }

View File

@@ -1,6 +1,10 @@
import java
import TestUtilities.InlineFlowTest
class EnableLegacy extends EnableLegacyConfiguration {
EnableLegacy() { exists(this) }
}
class FlowConf extends DefaultValueFlowConf {
override predicate isSink(DataFlow::Node n) { super.isSink(n) or sinkNode(n, "open-url") }
}

View File

@@ -3,6 +3,10 @@ import semmle.code.java.dataflow.TaintTracking
import semmle.code.java.dataflow.FlowSources
import TestUtilities.InlineFlowTest
class EnableLegacy extends EnableLegacyConfiguration {
EnableLegacy() { exists(this) }
}
class Conf extends TaintTracking::Configuration {
Conf() { this = "qltest:frameworks:rabbitmq" }

View File

@@ -1,6 +1,10 @@
import java
import TestUtilities.InlineFlowTest
class EnableLegacy extends EnableLegacyConfiguration {
EnableLegacy() { exists(this) }
}
class FlowConf extends DefaultValueFlowConf {
override predicate isSink(DataFlow::Node n) { super.isSink(n) or sinkNode(n, "open-url") }
}

View File

@@ -2,6 +2,10 @@ import java
import semmle.code.java.dataflow.FlowSources
import TestUtilities.InlineFlowTest
class EnableLegacy extends EnableLegacyConfiguration {
EnableLegacy() { exists(this) }
}
class ValueFlowConf extends DataFlow::Configuration {
ValueFlowConf() { this = "ValueFlowConf" }

View File

@@ -2,6 +2,10 @@ import java
import semmle.code.java.security.PathSanitizer
import TestUtilities.InlineFlowTest
class EnableLegacy extends EnableLegacyConfiguration {
EnableLegacy() { exists(this) }
}
class PathSanitizerConf extends DefaultTaintFlowConf {
override predicate isSanitizer(DataFlow::Node sanitizer) {
sanitizer instanceof PathInjectionSanitizer

View File

@@ -2,6 +2,10 @@ import java
import TestUtilities.InlineFlowTest
import semmle.code.java.security.PartialPathTraversalQuery
class EnableLegacy extends EnableLegacyConfiguration {
EnableLegacy() { exists(this) }
}
class TestRemoteSource extends RemoteFlowSource {
TestRemoteSource() { this.asParameter().hasName(["dir", "path"]) }

View File

@@ -2,6 +2,10 @@ import java
import semmle.code.java.security.LogInjectionQuery
import TestUtilities.InlineFlowTest
class EnableLegacy extends EnableLegacyConfiguration {
EnableLegacy() { exists(this) }
}
private class TestSource extends RemoteFlowSource {
TestSource() { this.asExpr().(MethodAccess).getMethod().hasName("source") }

View File

@@ -2,6 +2,10 @@ import java
import TestUtilities.InlineFlowTest
import semmle.code.java.security.IntentUriPermissionManipulationQuery
class EnableLegacy extends EnableLegacyConfiguration {
EnableLegacy() { exists(this) }
}
class IntentUriPermissionManipulationTest extends InlineFlowTest {
override DataFlow::Configuration getValueFlowConfig() { none() }

View File

@@ -2,6 +2,10 @@ import java
import semmle.code.java.security.InsecureTrustManagerQuery
import TestUtilities.InlineFlowTest
class EnableLegacy extends EnableLegacyConfiguration {
EnableLegacy() { exists(this) }
}
class InsecureTrustManagerTest extends InlineFlowTest {
override DataFlow::Configuration getValueFlowConfig() {
result = any(InsecureTrustManagerConfiguration c)

View File

@@ -2,6 +2,10 @@ import java
import TestUtilities.InlineFlowTest
import semmle.code.java.security.UnsafeContentUriResolutionQuery
class EnableLegacy extends EnableLegacyConfiguration {
EnableLegacy() { exists(this) }
}
class Test extends InlineFlowTest {
override DataFlow::Configuration getValueFlowConfig() { none() }

View File

@@ -2,6 +2,10 @@ import java
import semmle.code.java.security.FragmentInjectionQuery
import TestUtilities.InlineFlowTest
class EnableLegacy extends EnableLegacyConfiguration {
EnableLegacy() { exists(this) }
}
class Test extends InlineFlowTest {
override DataFlow::Configuration getValueFlowConfig() { none() }

View File

@@ -2,6 +2,10 @@ import java
import TestUtilities.InlineFlowTest
import semmle.code.java.security.WebviewDubuggingEnabledQuery
class EnableLegacy extends EnableLegacyConfiguration {
EnableLegacy() { exists(this) }
}
class HasFlowTest extends InlineFlowTest {
override DataFlow::Configuration getTaintFlowConfig() { none() }

View File

@@ -2,6 +2,10 @@ import java
import TestUtilities.InlineFlowTest
import semmle.code.java.security.SensitiveLoggingQuery
class EnableLegacy extends EnableLegacyConfiguration {
EnableLegacy() { exists(this) }
}
class HasFlowTest extends InlineFlowTest {
override DataFlow::Configuration getTaintFlowConfig() {
result instanceof SensitiveLoggerConfiguration

View File

@@ -3,6 +3,10 @@ import TestUtilities.InlineExpectationsTest
import TestUtilities.InlineFlowTest
import semmle.code.java.security.RsaWithoutOaepQuery
class EnableLegacy extends EnableLegacyConfiguration {
EnableLegacy() { exists(this) }
}
class HasFlowTest extends InlineFlowTest {
override DataFlow::Configuration getTaintFlowConfig() { result instanceof RsaWithoutOaepConfig }

View File

@@ -3,6 +3,10 @@ import semmle.code.java.security.AndroidSensitiveCommunicationQuery
import TestUtilities.InlineExpectationsTest
import TestUtilities.InlineFlowTest
class EnableLegacy extends EnableLegacyConfiguration {
EnableLegacy() { exists(this) }
}
class HasFlowTest extends InlineFlowTest {
override DataFlow::Configuration getTaintFlowConfig() {
result = any(SensitiveCommunicationConfig c)