From d3c564422917a5068faf2335b82b8e154c5353a4 Mon Sep 17 00:00:00 2001 From: Anders Schack-Mulligen Date: Fri, 28 Jun 2019 10:49:59 +0200 Subject: [PATCH 1/7] Java: Add support for in/out barriers on sources and sinks. --- .../java/dataflow/internal/DataFlowImpl.qll | 106 +++++++++++++----- .../dataflow/inoutbarriers/A.java | 17 +++ .../dataflow/inoutbarriers/test.expected | 5 + .../dataflow/inoutbarriers/test.ql | 67 +++++++++++ 4 files changed, 169 insertions(+), 26 deletions(-) create mode 100644 java/ql/test/library-tests/dataflow/inoutbarriers/A.java create mode 100644 java/ql/test/library-tests/dataflow/inoutbarriers/test.expected create mode 100644 java/ql/test/library-tests/dataflow/inoutbarriers/test.ql diff --git a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl.qll b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl.qll index 5a6de5af0f4..992428bcb1e 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl.qll @@ -103,6 +103,22 @@ abstract class Configuration extends string { deprecated predicate hasFlowBackward(Node source, Node sink) { hasFlow(source, sink) } } +private predicate inBarrier(Node node, Configuration config) { + config.isBarrier(node) and + config.isSource(node) +} + +private predicate outBarrier(Node node, Configuration config) { + config.isBarrier(node) and + config.isSink(node) +} + +private predicate fullBarrier(Node node, Configuration config) { + config.isBarrier(node) and + not config.isSource(node) and + not config.isSink(node) +} + private class AdditionalFlowStepSource extends Node { AdditionalFlowStepSource() { any(Configuration c).isAdditionalFlowStep(this, _) } } @@ -119,22 +135,47 @@ private predicate isAdditionalFlowStep( * Holds if data can flow in one local step from `node1` to `node2`. */ private predicate localFlowStep(Node node1, Node node2, Configuration config) { - localFlowStep(node1, node2) and not config.isBarrierEdge(node1, node2) + localFlowStep(node1, node2) and + not config.isBarrierEdge(node1, node2) and + not outBarrier(node1, config) and + not inBarrier(node2, config) and + not fullBarrier(node1, config) and + not fullBarrier(node2, config) } /** * Holds if the additional step from `node1` to `node2` does not jump between callables. */ private predicate additionalLocalFlowStep(Node node1, Node node2, Configuration config) { - isAdditionalFlowStep(node1, node2, node2.getEnclosingCallable(), config) + isAdditionalFlowStep(node1, node2, node2.getEnclosingCallable(), config) and + not outBarrier(node1, config) and + not inBarrier(node2, config) and + not fullBarrier(node1, config) and + not fullBarrier(node2, config) +} + +/** + * Holds if data can flow from `node1` to `node2` in a way that discards call contexts. + */ +private predicate jumpStep(Node node1, Node node2, Configuration config) { + jumpStep(node1, node2) and + not outBarrier(node1, config) and + not inBarrier(node2, config) and + not fullBarrier(node1, config) and + not fullBarrier(node2, config) } /** * Holds if the additional step from `node1` to `node2` jumps between callables. */ private predicate additionalJumpStep(Node node1, Node node2, Configuration config) { - exists(DataFlowCallable callable1 | isAdditionalFlowStep(node1, node2, callable1, config) | - node2.getEnclosingCallable() != callable1 + exists(DataFlowCallable callable1 | + isAdditionalFlowStep(node1, node2, callable1, config) and + node2.getEnclosingCallable() != callable1 and + not outBarrier(node1, config) and + not inBarrier(node2, config) and + not fullBarrier(node1, config) and + not fullBarrier(node2, config) ) } @@ -154,7 +195,7 @@ private ReturnPosition viableReturnPos(DataFlowCall call, ReturnKind kind) { * ignoring call contexts. */ private predicate nodeCandFwd1(Node node, boolean stored, Configuration config) { - not config.isBarrier(node) and + not fullBarrier(node, config) and ( config.isSource(node) and stored = false or @@ -171,7 +212,7 @@ private predicate nodeCandFwd1(Node node, boolean stored, Configuration config) or exists(Node mid | nodeCandFwd1(mid, stored, config) and - jumpStep(mid, node) + jumpStep(mid, node, config) ) or exists(Node mid | @@ -185,7 +226,8 @@ private predicate nodeCandFwd1(Node node, boolean stored, Configuration config) useFieldFlow(config) and nodeCandFwd1(mid, _, config) and store(mid, _, node) and - stored = true + stored = true and + not outBarrier(mid, config) ) or // read @@ -193,7 +235,8 @@ private predicate nodeCandFwd1(Node node, boolean stored, Configuration config) nodeCandFwd1(mid, true, config) and read(mid, f, node) and storeCandFwd1(f, unbind(config)) and - (stored = false or stored = true) + (stored = false or stored = true) and + not inBarrier(node, config) ) or // flow into a callable @@ -223,7 +266,7 @@ private predicate nodeCandFwd1(Node node, boolean stored, Configuration config) */ private predicate storeCandFwd1(Content f, Configuration config) { exists(Node mid, Node node | - not config.isBarrier(node) and + not fullBarrier(node, config) and useFieldFlow(config) and nodeCandFwd1(mid, _, config) and store(mid, f, node) @@ -257,7 +300,7 @@ private predicate nodeCand1(Node node, boolean stored, Configuration config) { ) or exists(Node mid | - jumpStep(node, mid) and + jumpStep(node, mid, config) and nodeCand1(mid, stored, config) ) or @@ -318,6 +361,11 @@ private predicate readCand1(Content f, Configuration config) { ) } +private predicate throughFlowNodeCand(Node node, Configuration config) { + nodeCand1(node, false, config) and + not config.isBarrier(node) +} + /** * Holds if there is a path from `p` to `node` in the same callable that is * part of a path from a source to a sink taking simple call contexts into @@ -329,7 +377,7 @@ pragma[nomagic] private predicate simpleParameterFlow( ParameterNode p, Node node, DataFlowType t, Configuration config ) { - nodeCand1(node, false, config) and + throughFlowNodeCand(node, config) and p = node and t = getErasedRepr(node.getType()) and exists(ReturnNode ret, ReturnKind kind | @@ -338,21 +386,21 @@ private predicate simpleParameterFlow( not parameterValueFlowsThrough(p, kind, _) ) or - nodeCand1(node, false, unbind(config)) and + throughFlowNodeCand(node, unbind(config)) and exists(Node mid | simpleParameterFlow(p, mid, t, config) and localFlowStep(mid, node, config) and compatibleTypes(t, node.getType()) ) or - nodeCand1(node, false, unbind(config)) and + throughFlowNodeCand(node, unbind(config)) and exists(Node mid | simpleParameterFlow(p, mid, _, config) and additionalLocalFlowStep(mid, node, config) and t = getErasedRepr(node.getType()) ) or - nodeCand1(node, false, unbind(config)) and + throughFlowNodeCand(node, unbind(config)) and exists(Node mid | simpleParameterFlow(p, mid, t, config) and localStoreReadStep(mid, node) and @@ -360,7 +408,7 @@ private predicate simpleParameterFlow( ) or // value flow through a callable - nodeCand1(node, false, unbind(config)) and + throughFlowNodeCand(node, unbind(config)) and exists(Node arg | simpleParameterFlow(p, arg, t, config) and argumentValueFlowsThrough(arg, node, _) and @@ -368,7 +416,7 @@ private predicate simpleParameterFlow( ) or // flow through a callable - nodeCand1(node, false, unbind(config)) and + throughFlowNodeCand(node, unbind(config)) and exists(Node arg | simpleParameterFlow(p, arg, _, config) and simpleArgumentFlowsThrough(arg, node, t, config) @@ -380,6 +428,7 @@ private predicate simpleArgumentFlowsThrough0( DataFlowCall call, ArgumentNode arg, ReturnKind kind, DataFlowType t, Configuration config ) { nodeCand1(arg, false, unbind(config)) and + not outBarrier(arg, config) and exists(ParameterNode p, ReturnNode ret | simpleParameterFlow(p, ret, t, config) and kind = ret.getKind() and @@ -399,6 +448,7 @@ private predicate simpleArgumentFlowsThrough( ) { exists(DataFlowCall call, ReturnKind kind | nodeCand1(out, false, unbind(config)) and + not inBarrier(out, config) and simpleArgumentFlowsThrough0(call, arg, kind, t, config) and out = getAnOutNode(call, kind) ) @@ -440,6 +490,8 @@ private predicate additionalLocalFlowStepOrFlowThroughCallable( private predicate flowOutOfCallable(Node node1, Node node2, Configuration config) { nodeCand1(node1, _, unbind(config)) and nodeCand1(node2, _, config) and + not outBarrier(node1, config) and + not inBarrier(node2, config) and ( // flow out of an argument exists(ParameterNode p | @@ -462,7 +514,9 @@ private predicate flowOutOfCallable(Node node1, Node node2, Configuration config private predicate flowIntoCallable(Node node1, Node node2, Configuration config) { viableParamArg(_, node2, node1) and nodeCand1(node1, _, unbind(config)) and - nodeCand1(node2, _, config) + nodeCand1(node2, _, config) and + not outBarrier(node1, config) and + not inBarrier(node2, config) } /** @@ -546,7 +600,7 @@ private predicate nodeCandFwd2(Node node, boolean fromArg, boolean stored, Confi or exists(Node mid | nodeCandFwd2(mid, _, stored, config) and - jumpStep(mid, node) and + jumpStep(mid, node, config) and fromArg = false ) or @@ -626,7 +680,7 @@ private predicate nodeCand2(Node node, boolean toReturn, boolean stored, Configu ) or exists(Node mid | - jumpStep(node, mid) and + jumpStep(node, mid, config) and nodeCand2(mid, _, stored, config) and toReturn = false ) @@ -714,7 +768,7 @@ private predicate localFlowEntry(Node node, Configuration config) { nodeCand(node, config) and ( config.isSource(node) or - jumpStep(_, node) or + jumpStep(_, node, config) or additionalJumpStep(_, node, config) or node instanceof ParameterNode or node instanceof OutNode or @@ -730,7 +784,7 @@ private predicate localFlowEntry(Node node, Configuration config) { */ private predicate localFlowExit(Node node, Configuration config) { exists(Node next | nodeCand(next, config) | - jumpStep(node, next) or + jumpStep(node, next, config) or additionalJumpStep(node, next, config) or flowIntoCallable(node, next, config) or flowOutOfCallable(node, next, config) or @@ -882,7 +936,7 @@ private predicate flowCandFwd0(Node node, boolean fromArg, AccessPathFront apf, or exists(Node mid | flowCandFwd(mid, _, apf, config) and - jumpStep(mid, node) and + jumpStep(mid, node, config) and fromArg = false ) or @@ -973,7 +1027,7 @@ private predicate flowCand0(Node node, boolean toReturn, AccessPathFront apf, Co ) or exists(Node mid | - jumpStep(node, mid) and + jumpStep(node, mid, config) and flowCand(mid, _, apf, config) and toReturn = false ) @@ -1154,7 +1208,7 @@ private predicate flowFwd0( or exists(Node mid | flowFwd(mid, _, apf, ap, config) and - jumpStep(mid, node) and + jumpStep(mid, node, config) and fromArg = false ) or @@ -1263,7 +1317,7 @@ private predicate flow0(Node node, boolean toReturn, AccessPath ap, Configuratio ) or exists(Node mid | - jumpStep(node, mid) and + jumpStep(node, mid, config) and flow(mid, _, ap, config) and toReturn = false ) @@ -1518,7 +1572,7 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, AccessPat mid.getAp() instanceof AccessPathNil and ap = node.(AccessPathNilNode).getAp() or - jumpStep(mid.getNode(), node) and + jumpStep(mid.getNode(), node, mid.getConfiguration()) and cc instanceof CallContextAny and ap = mid.getAp() or diff --git a/java/ql/test/library-tests/dataflow/inoutbarriers/A.java b/java/ql/test/library-tests/dataflow/inoutbarriers/A.java new file mode 100644 index 00000000000..51604991371 --- /dev/null +++ b/java/ql/test/library-tests/dataflow/inoutbarriers/A.java @@ -0,0 +1,17 @@ +class A { + static String fsrc = ""; + + String src(String s) { return s; } + + void sink(String s) { } + + void foo() { + String s = fsrc; + sink(fsrc); + + s = src(s); + sink(s); + + sink(s); + } +} diff --git a/java/ql/test/library-tests/dataflow/inoutbarriers/test.expected b/java/ql/test/library-tests/dataflow/inoutbarriers/test.expected new file mode 100644 index 00000000000..b219a8c5048 --- /dev/null +++ b/java/ql/test/library-tests/dataflow/inoutbarriers/test.expected @@ -0,0 +1,5 @@ +| A.java:9:16:9:19 | fsrc | A.java:13:10:13:10 | s | nobarrier, sinkbarrier | +| A.java:9:16:9:19 | fsrc | A.java:15:10:15:10 | s | nobarrier | +| A.java:10:10:10:13 | fsrc | A.java:10:10:10:13 | fsrc | both, nobarrier, sinkbarrier, srcbarrier | +| A.java:12:9:12:14 | src(...) | A.java:13:10:13:10 | s | both, nobarrier, sinkbarrier, srcbarrier | +| A.java:12:9:12:14 | src(...) | A.java:15:10:15:10 | s | nobarrier, srcbarrier | diff --git a/java/ql/test/library-tests/dataflow/inoutbarriers/test.ql b/java/ql/test/library-tests/dataflow/inoutbarriers/test.ql new file mode 100644 index 00000000000..1b21c9efb25 --- /dev/null +++ b/java/ql/test/library-tests/dataflow/inoutbarriers/test.ql @@ -0,0 +1,67 @@ +import java +import semmle.code.java.dataflow.DataFlow +import DataFlow + +predicate src0(Node n) { + n.asExpr().(MethodAccess).getMethod().hasName("src") or + n.asExpr().(FieldAccess).getField().hasName("fsrc") +} + +predicate sink0(Node n) { + exists(MethodAccess sink | + sink.getMethod().hasName("sink") and + sink.getAnArgument() = n.asExpr() + ) +} + +class Conf1 extends Configuration { + Conf1() { this = "inoutbarriers1" } + + override predicate isSource(Node n) { src0(n) } + + override predicate isSink(Node n) { sink0(n) } +} + +class Conf2 extends Configuration { + Conf2() { this = "inoutbarriers2" } + + override predicate isSource(Node n) { src0(n) } + + override predicate isSink(Node n) { sink0(n) } + + override predicate isBarrier(Node n) { src0(n) } +} + +class Conf3 extends Configuration { + Conf3() { this = "inoutbarriers3" } + + override predicate isSource(Node n) { src0(n) } + + override predicate isSink(Node n) { sink0(n) } + + override predicate isBarrier(Node n) { sink0(n) } +} + +class Conf4 extends Configuration { + Conf4() { this = "inoutbarriers4" } + + override predicate isSource(Node n) { src0(n) } + + override predicate isSink(Node n) { sink0(n) } + + override predicate isBarrier(Node n) { src0(n) or sink0(n) } +} + +predicate flow(Node src, Node sink, string s) { + any(Conf1 c).hasFlow(src, sink) and s = "nobarrier" + or + any(Conf2 c).hasFlow(src, sink) and s = "srcbarrier" + or + any(Conf3 c).hasFlow(src, sink) and s = "sinkbarrier" + or + any(Conf4 c).hasFlow(src, sink) and s = "both" +} + +from Node src, Node sink, string s +where flow(src, sink, _) and s = concat(any(string s0 | flow(src, sink, s0)), ", ") +select src, sink, s From 7c30c1a01c4025b6552ca89d12c3208fa630299b Mon Sep 17 00:00:00 2001 From: Anders Schack-Mulligen Date: Fri, 26 Jul 2019 13:16:19 +0200 Subject: [PATCH 2/7] Java: Deprecate isBarrierEdge. --- .../CWE/CWE-190/ArithmeticWithExtremeValues.ql | 6 ++---- .../src/semmle/code/java/dataflow/TaintTracking.qll | 12 ++++++------ .../code/java/dataflow/internal/DataFlowImpl.qll | 5 ++--- 3 files changed, 10 insertions(+), 13 deletions(-) diff --git a/java/ql/src/Security/CWE/CWE-190/ArithmeticWithExtremeValues.ql b/java/ql/src/Security/CWE/CWE-190/ArithmeticWithExtremeValues.ql index fd199251201..b7a956ec9f1 100644 --- a/java/ql/src/Security/CWE/CWE-190/ArithmeticWithExtremeValues.ql +++ b/java/ql/src/Security/CWE/CWE-190/ArithmeticWithExtremeValues.ql @@ -40,11 +40,9 @@ class ExtremeSourceFlowConfig extends DataFlow::Configuration { override predicate isSink(DataFlow::Node sink) { sink(_, sink.asExpr()) } - override predicate isBarrierEdge(DataFlow::Node node1, DataFlow::Node node2) { - isSource(node1) and isSource(node2) + override predicate isBarrier(DataFlow::Node n) { + n.getType() instanceof BooleanType or isSource(n) } - - override predicate isBarrier(DataFlow::Node n) { n.getType() instanceof BooleanType } } predicate sink(ArithExpr exp, VarAccess use) { diff --git a/java/ql/src/semmle/code/java/dataflow/TaintTracking.qll b/java/ql/src/semmle/code/java/dataflow/TaintTracking.qll index fe6ae7ea144..b2ec74e5efc 100644 --- a/java/ql/src/semmle/code/java/dataflow/TaintTracking.qll +++ b/java/ql/src/semmle/code/java/dataflow/TaintTracking.qll @@ -63,10 +63,10 @@ module TaintTracking { node.asExpr() instanceof ValidatedVariableAccess } - /** Holds if the edge from `node1` to `node2` is a taint sanitizer. */ - predicate isSanitizerEdge(DataFlow::Node node1, DataFlow::Node node2) { none() } + /** DEPRECATED: override `isSanitizer` instead. */ + deprecated predicate isSanitizerEdge(DataFlow::Node node1, DataFlow::Node node2) { none() } - final override predicate isBarrierEdge(DataFlow::Node node1, DataFlow::Node node2) { + deprecated final override predicate isBarrierEdge(DataFlow::Node node1, DataFlow::Node node2) { isSanitizerEdge(node1, node2) } @@ -135,10 +135,10 @@ module TaintTracking { node.asExpr() instanceof ValidatedVariableAccess } - /** Holds if the edge from `node1` to `node2` is a taint sanitizer. */ - predicate isSanitizerEdge(DataFlow::Node node1, DataFlow::Node node2) { none() } + /** DEPRECATED: override `isSanitizer` instead. */ + deprecated predicate isSanitizerEdge(DataFlow::Node node1, DataFlow::Node node2) { none() } - final override predicate isBarrierEdge(DataFlow::Node node1, DataFlow::Node node2) { + deprecated final override predicate isBarrierEdge(DataFlow::Node node1, DataFlow::Node node2) { isSanitizerEdge(node1, node2) } diff --git a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl.qll b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl.qll index 992428bcb1e..cfe85663344 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl.qll @@ -57,8 +57,8 @@ abstract class Configuration extends string { /** Holds if data flow through `node` is prohibited. */ predicate isBarrier(Node node) { none() } - /** Holds if data flow from `node1` to `node2` is prohibited. */ - predicate isBarrierEdge(Node node1, Node node2) { none() } + /** DEPRECATED: override `isBarrier` instead. */ + deprecated predicate isBarrierEdge(Node node1, Node node2) { none() } /** * Holds if the additional flow step from `node1` to `node2` must be taken @@ -136,7 +136,6 @@ private predicate isAdditionalFlowStep( */ private predicate localFlowStep(Node node1, Node node2, Configuration config) { localFlowStep(node1, node2) and - not config.isBarrierEdge(node1, node2) and not outBarrier(node1, config) and not inBarrier(node2, config) and not fullBarrier(node1, config) and From 6d022aa3594c0d840b1f8291a5a87f85465b9477 Mon Sep 17 00:00:00 2001 From: Anders Schack-Mulligen Date: Fri, 26 Jul 2019 13:17:12 +0200 Subject: [PATCH 3/7] Java/C++/C#: Sync dataflow. --- .../cpp/dataflow/internal/DataFlowImpl.qll | 109 +++++++++++++----- .../cpp/dataflow/internal/DataFlowImpl2.qll | 109 +++++++++++++----- .../cpp/dataflow/internal/DataFlowImpl3.qll | 109 +++++++++++++----- .../cpp/dataflow/internal/DataFlowImpl4.qll | 109 +++++++++++++----- .../cpp/ir/dataflow/internal/DataFlowImpl.qll | 109 +++++++++++++----- .../ir/dataflow/internal/DataFlowImpl2.qll | 109 +++++++++++++----- .../ir/dataflow/internal/DataFlowImpl3.qll | 109 +++++++++++++----- .../ir/dataflow/internal/DataFlowImpl4.qll | 109 +++++++++++++----- .../csharp/dataflow/internal/DataFlowImpl.qll | 109 +++++++++++++----- .../java/dataflow/internal/DataFlowImpl2.qll | 109 +++++++++++++----- .../java/dataflow/internal/DataFlowImpl3.qll | 109 +++++++++++++----- .../java/dataflow/internal/DataFlowImpl4.qll | 109 +++++++++++++----- .../java/dataflow/internal/DataFlowImpl5.qll | 109 +++++++++++++----- 13 files changed, 1053 insertions(+), 364 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl.qll b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl.qll index 5a6de5af0f4..cfe85663344 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl.qll @@ -57,8 +57,8 @@ abstract class Configuration extends string { /** Holds if data flow through `node` is prohibited. */ predicate isBarrier(Node node) { none() } - /** Holds if data flow from `node1` to `node2` is prohibited. */ - predicate isBarrierEdge(Node node1, Node node2) { none() } + /** DEPRECATED: override `isBarrier` instead. */ + deprecated predicate isBarrierEdge(Node node1, Node node2) { none() } /** * Holds if the additional flow step from `node1` to `node2` must be taken @@ -103,6 +103,22 @@ abstract class Configuration extends string { deprecated predicate hasFlowBackward(Node source, Node sink) { hasFlow(source, sink) } } +private predicate inBarrier(Node node, Configuration config) { + config.isBarrier(node) and + config.isSource(node) +} + +private predicate outBarrier(Node node, Configuration config) { + config.isBarrier(node) and + config.isSink(node) +} + +private predicate fullBarrier(Node node, Configuration config) { + config.isBarrier(node) and + not config.isSource(node) and + not config.isSink(node) +} + private class AdditionalFlowStepSource extends Node { AdditionalFlowStepSource() { any(Configuration c).isAdditionalFlowStep(this, _) } } @@ -119,22 +135,46 @@ private predicate isAdditionalFlowStep( * Holds if data can flow in one local step from `node1` to `node2`. */ private predicate localFlowStep(Node node1, Node node2, Configuration config) { - localFlowStep(node1, node2) and not config.isBarrierEdge(node1, node2) + localFlowStep(node1, node2) and + not outBarrier(node1, config) and + not inBarrier(node2, config) and + not fullBarrier(node1, config) and + not fullBarrier(node2, config) } /** * Holds if the additional step from `node1` to `node2` does not jump between callables. */ private predicate additionalLocalFlowStep(Node node1, Node node2, Configuration config) { - isAdditionalFlowStep(node1, node2, node2.getEnclosingCallable(), config) + isAdditionalFlowStep(node1, node2, node2.getEnclosingCallable(), config) and + not outBarrier(node1, config) and + not inBarrier(node2, config) and + not fullBarrier(node1, config) and + not fullBarrier(node2, config) +} + +/** + * Holds if data can flow from `node1` to `node2` in a way that discards call contexts. + */ +private predicate jumpStep(Node node1, Node node2, Configuration config) { + jumpStep(node1, node2) and + not outBarrier(node1, config) and + not inBarrier(node2, config) and + not fullBarrier(node1, config) and + not fullBarrier(node2, config) } /** * Holds if the additional step from `node1` to `node2` jumps between callables. */ private predicate additionalJumpStep(Node node1, Node node2, Configuration config) { - exists(DataFlowCallable callable1 | isAdditionalFlowStep(node1, node2, callable1, config) | - node2.getEnclosingCallable() != callable1 + exists(DataFlowCallable callable1 | + isAdditionalFlowStep(node1, node2, callable1, config) and + node2.getEnclosingCallable() != callable1 and + not outBarrier(node1, config) and + not inBarrier(node2, config) and + not fullBarrier(node1, config) and + not fullBarrier(node2, config) ) } @@ -154,7 +194,7 @@ private ReturnPosition viableReturnPos(DataFlowCall call, ReturnKind kind) { * ignoring call contexts. */ private predicate nodeCandFwd1(Node node, boolean stored, Configuration config) { - not config.isBarrier(node) and + not fullBarrier(node, config) and ( config.isSource(node) and stored = false or @@ -171,7 +211,7 @@ private predicate nodeCandFwd1(Node node, boolean stored, Configuration config) or exists(Node mid | nodeCandFwd1(mid, stored, config) and - jumpStep(mid, node) + jumpStep(mid, node, config) ) or exists(Node mid | @@ -185,7 +225,8 @@ private predicate nodeCandFwd1(Node node, boolean stored, Configuration config) useFieldFlow(config) and nodeCandFwd1(mid, _, config) and store(mid, _, node) and - stored = true + stored = true and + not outBarrier(mid, config) ) or // read @@ -193,7 +234,8 @@ private predicate nodeCandFwd1(Node node, boolean stored, Configuration config) nodeCandFwd1(mid, true, config) and read(mid, f, node) and storeCandFwd1(f, unbind(config)) and - (stored = false or stored = true) + (stored = false or stored = true) and + not inBarrier(node, config) ) or // flow into a callable @@ -223,7 +265,7 @@ private predicate nodeCandFwd1(Node node, boolean stored, Configuration config) */ private predicate storeCandFwd1(Content f, Configuration config) { exists(Node mid, Node node | - not config.isBarrier(node) and + not fullBarrier(node, config) and useFieldFlow(config) and nodeCandFwd1(mid, _, config) and store(mid, f, node) @@ -257,7 +299,7 @@ private predicate nodeCand1(Node node, boolean stored, Configuration config) { ) or exists(Node mid | - jumpStep(node, mid) and + jumpStep(node, mid, config) and nodeCand1(mid, stored, config) ) or @@ -318,6 +360,11 @@ private predicate readCand1(Content f, Configuration config) { ) } +private predicate throughFlowNodeCand(Node node, Configuration config) { + nodeCand1(node, false, config) and + not config.isBarrier(node) +} + /** * Holds if there is a path from `p` to `node` in the same callable that is * part of a path from a source to a sink taking simple call contexts into @@ -329,7 +376,7 @@ pragma[nomagic] private predicate simpleParameterFlow( ParameterNode p, Node node, DataFlowType t, Configuration config ) { - nodeCand1(node, false, config) and + throughFlowNodeCand(node, config) and p = node and t = getErasedRepr(node.getType()) and exists(ReturnNode ret, ReturnKind kind | @@ -338,21 +385,21 @@ private predicate simpleParameterFlow( not parameterValueFlowsThrough(p, kind, _) ) or - nodeCand1(node, false, unbind(config)) and + throughFlowNodeCand(node, unbind(config)) and exists(Node mid | simpleParameterFlow(p, mid, t, config) and localFlowStep(mid, node, config) and compatibleTypes(t, node.getType()) ) or - nodeCand1(node, false, unbind(config)) and + throughFlowNodeCand(node, unbind(config)) and exists(Node mid | simpleParameterFlow(p, mid, _, config) and additionalLocalFlowStep(mid, node, config) and t = getErasedRepr(node.getType()) ) or - nodeCand1(node, false, unbind(config)) and + throughFlowNodeCand(node, unbind(config)) and exists(Node mid | simpleParameterFlow(p, mid, t, config) and localStoreReadStep(mid, node) and @@ -360,7 +407,7 @@ private predicate simpleParameterFlow( ) or // value flow through a callable - nodeCand1(node, false, unbind(config)) and + throughFlowNodeCand(node, unbind(config)) and exists(Node arg | simpleParameterFlow(p, arg, t, config) and argumentValueFlowsThrough(arg, node, _) and @@ -368,7 +415,7 @@ private predicate simpleParameterFlow( ) or // flow through a callable - nodeCand1(node, false, unbind(config)) and + throughFlowNodeCand(node, unbind(config)) and exists(Node arg | simpleParameterFlow(p, arg, _, config) and simpleArgumentFlowsThrough(arg, node, t, config) @@ -380,6 +427,7 @@ private predicate simpleArgumentFlowsThrough0( DataFlowCall call, ArgumentNode arg, ReturnKind kind, DataFlowType t, Configuration config ) { nodeCand1(arg, false, unbind(config)) and + not outBarrier(arg, config) and exists(ParameterNode p, ReturnNode ret | simpleParameterFlow(p, ret, t, config) and kind = ret.getKind() and @@ -399,6 +447,7 @@ private predicate simpleArgumentFlowsThrough( ) { exists(DataFlowCall call, ReturnKind kind | nodeCand1(out, false, unbind(config)) and + not inBarrier(out, config) and simpleArgumentFlowsThrough0(call, arg, kind, t, config) and out = getAnOutNode(call, kind) ) @@ -440,6 +489,8 @@ private predicate additionalLocalFlowStepOrFlowThroughCallable( private predicate flowOutOfCallable(Node node1, Node node2, Configuration config) { nodeCand1(node1, _, unbind(config)) and nodeCand1(node2, _, config) and + not outBarrier(node1, config) and + not inBarrier(node2, config) and ( // flow out of an argument exists(ParameterNode p | @@ -462,7 +513,9 @@ private predicate flowOutOfCallable(Node node1, Node node2, Configuration config private predicate flowIntoCallable(Node node1, Node node2, Configuration config) { viableParamArg(_, node2, node1) and nodeCand1(node1, _, unbind(config)) and - nodeCand1(node2, _, config) + nodeCand1(node2, _, config) and + not outBarrier(node1, config) and + not inBarrier(node2, config) } /** @@ -546,7 +599,7 @@ private predicate nodeCandFwd2(Node node, boolean fromArg, boolean stored, Confi or exists(Node mid | nodeCandFwd2(mid, _, stored, config) and - jumpStep(mid, node) and + jumpStep(mid, node, config) and fromArg = false ) or @@ -626,7 +679,7 @@ private predicate nodeCand2(Node node, boolean toReturn, boolean stored, Configu ) or exists(Node mid | - jumpStep(node, mid) and + jumpStep(node, mid, config) and nodeCand2(mid, _, stored, config) and toReturn = false ) @@ -714,7 +767,7 @@ private predicate localFlowEntry(Node node, Configuration config) { nodeCand(node, config) and ( config.isSource(node) or - jumpStep(_, node) or + jumpStep(_, node, config) or additionalJumpStep(_, node, config) or node instanceof ParameterNode or node instanceof OutNode or @@ -730,7 +783,7 @@ private predicate localFlowEntry(Node node, Configuration config) { */ private predicate localFlowExit(Node node, Configuration config) { exists(Node next | nodeCand(next, config) | - jumpStep(node, next) or + jumpStep(node, next, config) or additionalJumpStep(node, next, config) or flowIntoCallable(node, next, config) or flowOutOfCallable(node, next, config) or @@ -882,7 +935,7 @@ private predicate flowCandFwd0(Node node, boolean fromArg, AccessPathFront apf, or exists(Node mid | flowCandFwd(mid, _, apf, config) and - jumpStep(mid, node) and + jumpStep(mid, node, config) and fromArg = false ) or @@ -973,7 +1026,7 @@ private predicate flowCand0(Node node, boolean toReturn, AccessPathFront apf, Co ) or exists(Node mid | - jumpStep(node, mid) and + jumpStep(node, mid, config) and flowCand(mid, _, apf, config) and toReturn = false ) @@ -1154,7 +1207,7 @@ private predicate flowFwd0( or exists(Node mid | flowFwd(mid, _, apf, ap, config) and - jumpStep(mid, node) and + jumpStep(mid, node, config) and fromArg = false ) or @@ -1263,7 +1316,7 @@ private predicate flow0(Node node, boolean toReturn, AccessPath ap, Configuratio ) or exists(Node mid | - jumpStep(node, mid) and + jumpStep(node, mid, config) and flow(mid, _, ap, config) and toReturn = false ) @@ -1518,7 +1571,7 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, AccessPat mid.getAp() instanceof AccessPathNil and ap = node.(AccessPathNilNode).getAp() or - jumpStep(mid.getNode(), node) and + jumpStep(mid.getNode(), node, mid.getConfiguration()) and cc instanceof CallContextAny and ap = mid.getAp() or diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl2.qll b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl2.qll index 5a6de5af0f4..cfe85663344 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl2.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl2.qll @@ -57,8 +57,8 @@ abstract class Configuration extends string { /** Holds if data flow through `node` is prohibited. */ predicate isBarrier(Node node) { none() } - /** Holds if data flow from `node1` to `node2` is prohibited. */ - predicate isBarrierEdge(Node node1, Node node2) { none() } + /** DEPRECATED: override `isBarrier` instead. */ + deprecated predicate isBarrierEdge(Node node1, Node node2) { none() } /** * Holds if the additional flow step from `node1` to `node2` must be taken @@ -103,6 +103,22 @@ abstract class Configuration extends string { deprecated predicate hasFlowBackward(Node source, Node sink) { hasFlow(source, sink) } } +private predicate inBarrier(Node node, Configuration config) { + config.isBarrier(node) and + config.isSource(node) +} + +private predicate outBarrier(Node node, Configuration config) { + config.isBarrier(node) and + config.isSink(node) +} + +private predicate fullBarrier(Node node, Configuration config) { + config.isBarrier(node) and + not config.isSource(node) and + not config.isSink(node) +} + private class AdditionalFlowStepSource extends Node { AdditionalFlowStepSource() { any(Configuration c).isAdditionalFlowStep(this, _) } } @@ -119,22 +135,46 @@ private predicate isAdditionalFlowStep( * Holds if data can flow in one local step from `node1` to `node2`. */ private predicate localFlowStep(Node node1, Node node2, Configuration config) { - localFlowStep(node1, node2) and not config.isBarrierEdge(node1, node2) + localFlowStep(node1, node2) and + not outBarrier(node1, config) and + not inBarrier(node2, config) and + not fullBarrier(node1, config) and + not fullBarrier(node2, config) } /** * Holds if the additional step from `node1` to `node2` does not jump between callables. */ private predicate additionalLocalFlowStep(Node node1, Node node2, Configuration config) { - isAdditionalFlowStep(node1, node2, node2.getEnclosingCallable(), config) + isAdditionalFlowStep(node1, node2, node2.getEnclosingCallable(), config) and + not outBarrier(node1, config) and + not inBarrier(node2, config) and + not fullBarrier(node1, config) and + not fullBarrier(node2, config) +} + +/** + * Holds if data can flow from `node1` to `node2` in a way that discards call contexts. + */ +private predicate jumpStep(Node node1, Node node2, Configuration config) { + jumpStep(node1, node2) and + not outBarrier(node1, config) and + not inBarrier(node2, config) and + not fullBarrier(node1, config) and + not fullBarrier(node2, config) } /** * Holds if the additional step from `node1` to `node2` jumps between callables. */ private predicate additionalJumpStep(Node node1, Node node2, Configuration config) { - exists(DataFlowCallable callable1 | isAdditionalFlowStep(node1, node2, callable1, config) | - node2.getEnclosingCallable() != callable1 + exists(DataFlowCallable callable1 | + isAdditionalFlowStep(node1, node2, callable1, config) and + node2.getEnclosingCallable() != callable1 and + not outBarrier(node1, config) and + not inBarrier(node2, config) and + not fullBarrier(node1, config) and + not fullBarrier(node2, config) ) } @@ -154,7 +194,7 @@ private ReturnPosition viableReturnPos(DataFlowCall call, ReturnKind kind) { * ignoring call contexts. */ private predicate nodeCandFwd1(Node node, boolean stored, Configuration config) { - not config.isBarrier(node) and + not fullBarrier(node, config) and ( config.isSource(node) and stored = false or @@ -171,7 +211,7 @@ private predicate nodeCandFwd1(Node node, boolean stored, Configuration config) or exists(Node mid | nodeCandFwd1(mid, stored, config) and - jumpStep(mid, node) + jumpStep(mid, node, config) ) or exists(Node mid | @@ -185,7 +225,8 @@ private predicate nodeCandFwd1(Node node, boolean stored, Configuration config) useFieldFlow(config) and nodeCandFwd1(mid, _, config) and store(mid, _, node) and - stored = true + stored = true and + not outBarrier(mid, config) ) or // read @@ -193,7 +234,8 @@ private predicate nodeCandFwd1(Node node, boolean stored, Configuration config) nodeCandFwd1(mid, true, config) and read(mid, f, node) and storeCandFwd1(f, unbind(config)) and - (stored = false or stored = true) + (stored = false or stored = true) and + not inBarrier(node, config) ) or // flow into a callable @@ -223,7 +265,7 @@ private predicate nodeCandFwd1(Node node, boolean stored, Configuration config) */ private predicate storeCandFwd1(Content f, Configuration config) { exists(Node mid, Node node | - not config.isBarrier(node) and + not fullBarrier(node, config) and useFieldFlow(config) and nodeCandFwd1(mid, _, config) and store(mid, f, node) @@ -257,7 +299,7 @@ private predicate nodeCand1(Node node, boolean stored, Configuration config) { ) or exists(Node mid | - jumpStep(node, mid) and + jumpStep(node, mid, config) and nodeCand1(mid, stored, config) ) or @@ -318,6 +360,11 @@ private predicate readCand1(Content f, Configuration config) { ) } +private predicate throughFlowNodeCand(Node node, Configuration config) { + nodeCand1(node, false, config) and + not config.isBarrier(node) +} + /** * Holds if there is a path from `p` to `node` in the same callable that is * part of a path from a source to a sink taking simple call contexts into @@ -329,7 +376,7 @@ pragma[nomagic] private predicate simpleParameterFlow( ParameterNode p, Node node, DataFlowType t, Configuration config ) { - nodeCand1(node, false, config) and + throughFlowNodeCand(node, config) and p = node and t = getErasedRepr(node.getType()) and exists(ReturnNode ret, ReturnKind kind | @@ -338,21 +385,21 @@ private predicate simpleParameterFlow( not parameterValueFlowsThrough(p, kind, _) ) or - nodeCand1(node, false, unbind(config)) and + throughFlowNodeCand(node, unbind(config)) and exists(Node mid | simpleParameterFlow(p, mid, t, config) and localFlowStep(mid, node, config) and compatibleTypes(t, node.getType()) ) or - nodeCand1(node, false, unbind(config)) and + throughFlowNodeCand(node, unbind(config)) and exists(Node mid | simpleParameterFlow(p, mid, _, config) and additionalLocalFlowStep(mid, node, config) and t = getErasedRepr(node.getType()) ) or - nodeCand1(node, false, unbind(config)) and + throughFlowNodeCand(node, unbind(config)) and exists(Node mid | simpleParameterFlow(p, mid, t, config) and localStoreReadStep(mid, node) and @@ -360,7 +407,7 @@ private predicate simpleParameterFlow( ) or // value flow through a callable - nodeCand1(node, false, unbind(config)) and + throughFlowNodeCand(node, unbind(config)) and exists(Node arg | simpleParameterFlow(p, arg, t, config) and argumentValueFlowsThrough(arg, node, _) and @@ -368,7 +415,7 @@ private predicate simpleParameterFlow( ) or // flow through a callable - nodeCand1(node, false, unbind(config)) and + throughFlowNodeCand(node, unbind(config)) and exists(Node arg | simpleParameterFlow(p, arg, _, config) and simpleArgumentFlowsThrough(arg, node, t, config) @@ -380,6 +427,7 @@ private predicate simpleArgumentFlowsThrough0( DataFlowCall call, ArgumentNode arg, ReturnKind kind, DataFlowType t, Configuration config ) { nodeCand1(arg, false, unbind(config)) and + not outBarrier(arg, config) and exists(ParameterNode p, ReturnNode ret | simpleParameterFlow(p, ret, t, config) and kind = ret.getKind() and @@ -399,6 +447,7 @@ private predicate simpleArgumentFlowsThrough( ) { exists(DataFlowCall call, ReturnKind kind | nodeCand1(out, false, unbind(config)) and + not inBarrier(out, config) and simpleArgumentFlowsThrough0(call, arg, kind, t, config) and out = getAnOutNode(call, kind) ) @@ -440,6 +489,8 @@ private predicate additionalLocalFlowStepOrFlowThroughCallable( private predicate flowOutOfCallable(Node node1, Node node2, Configuration config) { nodeCand1(node1, _, unbind(config)) and nodeCand1(node2, _, config) and + not outBarrier(node1, config) and + not inBarrier(node2, config) and ( // flow out of an argument exists(ParameterNode p | @@ -462,7 +513,9 @@ private predicate flowOutOfCallable(Node node1, Node node2, Configuration config private predicate flowIntoCallable(Node node1, Node node2, Configuration config) { viableParamArg(_, node2, node1) and nodeCand1(node1, _, unbind(config)) and - nodeCand1(node2, _, config) + nodeCand1(node2, _, config) and + not outBarrier(node1, config) and + not inBarrier(node2, config) } /** @@ -546,7 +599,7 @@ private predicate nodeCandFwd2(Node node, boolean fromArg, boolean stored, Confi or exists(Node mid | nodeCandFwd2(mid, _, stored, config) and - jumpStep(mid, node) and + jumpStep(mid, node, config) and fromArg = false ) or @@ -626,7 +679,7 @@ private predicate nodeCand2(Node node, boolean toReturn, boolean stored, Configu ) or exists(Node mid | - jumpStep(node, mid) and + jumpStep(node, mid, config) and nodeCand2(mid, _, stored, config) and toReturn = false ) @@ -714,7 +767,7 @@ private predicate localFlowEntry(Node node, Configuration config) { nodeCand(node, config) and ( config.isSource(node) or - jumpStep(_, node) or + jumpStep(_, node, config) or additionalJumpStep(_, node, config) or node instanceof ParameterNode or node instanceof OutNode or @@ -730,7 +783,7 @@ private predicate localFlowEntry(Node node, Configuration config) { */ private predicate localFlowExit(Node node, Configuration config) { exists(Node next | nodeCand(next, config) | - jumpStep(node, next) or + jumpStep(node, next, config) or additionalJumpStep(node, next, config) or flowIntoCallable(node, next, config) or flowOutOfCallable(node, next, config) or @@ -882,7 +935,7 @@ private predicate flowCandFwd0(Node node, boolean fromArg, AccessPathFront apf, or exists(Node mid | flowCandFwd(mid, _, apf, config) and - jumpStep(mid, node) and + jumpStep(mid, node, config) and fromArg = false ) or @@ -973,7 +1026,7 @@ private predicate flowCand0(Node node, boolean toReturn, AccessPathFront apf, Co ) or exists(Node mid | - jumpStep(node, mid) and + jumpStep(node, mid, config) and flowCand(mid, _, apf, config) and toReturn = false ) @@ -1154,7 +1207,7 @@ private predicate flowFwd0( or exists(Node mid | flowFwd(mid, _, apf, ap, config) and - jumpStep(mid, node) and + jumpStep(mid, node, config) and fromArg = false ) or @@ -1263,7 +1316,7 @@ private predicate flow0(Node node, boolean toReturn, AccessPath ap, Configuratio ) or exists(Node mid | - jumpStep(node, mid) and + jumpStep(node, mid, config) and flow(mid, _, ap, config) and toReturn = false ) @@ -1518,7 +1571,7 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, AccessPat mid.getAp() instanceof AccessPathNil and ap = node.(AccessPathNilNode).getAp() or - jumpStep(mid.getNode(), node) and + jumpStep(mid.getNode(), node, mid.getConfiguration()) and cc instanceof CallContextAny and ap = mid.getAp() or diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl3.qll b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl3.qll index 5a6de5af0f4..cfe85663344 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl3.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl3.qll @@ -57,8 +57,8 @@ abstract class Configuration extends string { /** Holds if data flow through `node` is prohibited. */ predicate isBarrier(Node node) { none() } - /** Holds if data flow from `node1` to `node2` is prohibited. */ - predicate isBarrierEdge(Node node1, Node node2) { none() } + /** DEPRECATED: override `isBarrier` instead. */ + deprecated predicate isBarrierEdge(Node node1, Node node2) { none() } /** * Holds if the additional flow step from `node1` to `node2` must be taken @@ -103,6 +103,22 @@ abstract class Configuration extends string { deprecated predicate hasFlowBackward(Node source, Node sink) { hasFlow(source, sink) } } +private predicate inBarrier(Node node, Configuration config) { + config.isBarrier(node) and + config.isSource(node) +} + +private predicate outBarrier(Node node, Configuration config) { + config.isBarrier(node) and + config.isSink(node) +} + +private predicate fullBarrier(Node node, Configuration config) { + config.isBarrier(node) and + not config.isSource(node) and + not config.isSink(node) +} + private class AdditionalFlowStepSource extends Node { AdditionalFlowStepSource() { any(Configuration c).isAdditionalFlowStep(this, _) } } @@ -119,22 +135,46 @@ private predicate isAdditionalFlowStep( * Holds if data can flow in one local step from `node1` to `node2`. */ private predicate localFlowStep(Node node1, Node node2, Configuration config) { - localFlowStep(node1, node2) and not config.isBarrierEdge(node1, node2) + localFlowStep(node1, node2) and + not outBarrier(node1, config) and + not inBarrier(node2, config) and + not fullBarrier(node1, config) and + not fullBarrier(node2, config) } /** * Holds if the additional step from `node1` to `node2` does not jump between callables. */ private predicate additionalLocalFlowStep(Node node1, Node node2, Configuration config) { - isAdditionalFlowStep(node1, node2, node2.getEnclosingCallable(), config) + isAdditionalFlowStep(node1, node2, node2.getEnclosingCallable(), config) and + not outBarrier(node1, config) and + not inBarrier(node2, config) and + not fullBarrier(node1, config) and + not fullBarrier(node2, config) +} + +/** + * Holds if data can flow from `node1` to `node2` in a way that discards call contexts. + */ +private predicate jumpStep(Node node1, Node node2, Configuration config) { + jumpStep(node1, node2) and + not outBarrier(node1, config) and + not inBarrier(node2, config) and + not fullBarrier(node1, config) and + not fullBarrier(node2, config) } /** * Holds if the additional step from `node1` to `node2` jumps between callables. */ private predicate additionalJumpStep(Node node1, Node node2, Configuration config) { - exists(DataFlowCallable callable1 | isAdditionalFlowStep(node1, node2, callable1, config) | - node2.getEnclosingCallable() != callable1 + exists(DataFlowCallable callable1 | + isAdditionalFlowStep(node1, node2, callable1, config) and + node2.getEnclosingCallable() != callable1 and + not outBarrier(node1, config) and + not inBarrier(node2, config) and + not fullBarrier(node1, config) and + not fullBarrier(node2, config) ) } @@ -154,7 +194,7 @@ private ReturnPosition viableReturnPos(DataFlowCall call, ReturnKind kind) { * ignoring call contexts. */ private predicate nodeCandFwd1(Node node, boolean stored, Configuration config) { - not config.isBarrier(node) and + not fullBarrier(node, config) and ( config.isSource(node) and stored = false or @@ -171,7 +211,7 @@ private predicate nodeCandFwd1(Node node, boolean stored, Configuration config) or exists(Node mid | nodeCandFwd1(mid, stored, config) and - jumpStep(mid, node) + jumpStep(mid, node, config) ) or exists(Node mid | @@ -185,7 +225,8 @@ private predicate nodeCandFwd1(Node node, boolean stored, Configuration config) useFieldFlow(config) and nodeCandFwd1(mid, _, config) and store(mid, _, node) and - stored = true + stored = true and + not outBarrier(mid, config) ) or // read @@ -193,7 +234,8 @@ private predicate nodeCandFwd1(Node node, boolean stored, Configuration config) nodeCandFwd1(mid, true, config) and read(mid, f, node) and storeCandFwd1(f, unbind(config)) and - (stored = false or stored = true) + (stored = false or stored = true) and + not inBarrier(node, config) ) or // flow into a callable @@ -223,7 +265,7 @@ private predicate nodeCandFwd1(Node node, boolean stored, Configuration config) */ private predicate storeCandFwd1(Content f, Configuration config) { exists(Node mid, Node node | - not config.isBarrier(node) and + not fullBarrier(node, config) and useFieldFlow(config) and nodeCandFwd1(mid, _, config) and store(mid, f, node) @@ -257,7 +299,7 @@ private predicate nodeCand1(Node node, boolean stored, Configuration config) { ) or exists(Node mid | - jumpStep(node, mid) and + jumpStep(node, mid, config) and nodeCand1(mid, stored, config) ) or @@ -318,6 +360,11 @@ private predicate readCand1(Content f, Configuration config) { ) } +private predicate throughFlowNodeCand(Node node, Configuration config) { + nodeCand1(node, false, config) and + not config.isBarrier(node) +} + /** * Holds if there is a path from `p` to `node` in the same callable that is * part of a path from a source to a sink taking simple call contexts into @@ -329,7 +376,7 @@ pragma[nomagic] private predicate simpleParameterFlow( ParameterNode p, Node node, DataFlowType t, Configuration config ) { - nodeCand1(node, false, config) and + throughFlowNodeCand(node, config) and p = node and t = getErasedRepr(node.getType()) and exists(ReturnNode ret, ReturnKind kind | @@ -338,21 +385,21 @@ private predicate simpleParameterFlow( not parameterValueFlowsThrough(p, kind, _) ) or - nodeCand1(node, false, unbind(config)) and + throughFlowNodeCand(node, unbind(config)) and exists(Node mid | simpleParameterFlow(p, mid, t, config) and localFlowStep(mid, node, config) and compatibleTypes(t, node.getType()) ) or - nodeCand1(node, false, unbind(config)) and + throughFlowNodeCand(node, unbind(config)) and exists(Node mid | simpleParameterFlow(p, mid, _, config) and additionalLocalFlowStep(mid, node, config) and t = getErasedRepr(node.getType()) ) or - nodeCand1(node, false, unbind(config)) and + throughFlowNodeCand(node, unbind(config)) and exists(Node mid | simpleParameterFlow(p, mid, t, config) and localStoreReadStep(mid, node) and @@ -360,7 +407,7 @@ private predicate simpleParameterFlow( ) or // value flow through a callable - nodeCand1(node, false, unbind(config)) and + throughFlowNodeCand(node, unbind(config)) and exists(Node arg | simpleParameterFlow(p, arg, t, config) and argumentValueFlowsThrough(arg, node, _) and @@ -368,7 +415,7 @@ private predicate simpleParameterFlow( ) or // flow through a callable - nodeCand1(node, false, unbind(config)) and + throughFlowNodeCand(node, unbind(config)) and exists(Node arg | simpleParameterFlow(p, arg, _, config) and simpleArgumentFlowsThrough(arg, node, t, config) @@ -380,6 +427,7 @@ private predicate simpleArgumentFlowsThrough0( DataFlowCall call, ArgumentNode arg, ReturnKind kind, DataFlowType t, Configuration config ) { nodeCand1(arg, false, unbind(config)) and + not outBarrier(arg, config) and exists(ParameterNode p, ReturnNode ret | simpleParameterFlow(p, ret, t, config) and kind = ret.getKind() and @@ -399,6 +447,7 @@ private predicate simpleArgumentFlowsThrough( ) { exists(DataFlowCall call, ReturnKind kind | nodeCand1(out, false, unbind(config)) and + not inBarrier(out, config) and simpleArgumentFlowsThrough0(call, arg, kind, t, config) and out = getAnOutNode(call, kind) ) @@ -440,6 +489,8 @@ private predicate additionalLocalFlowStepOrFlowThroughCallable( private predicate flowOutOfCallable(Node node1, Node node2, Configuration config) { nodeCand1(node1, _, unbind(config)) and nodeCand1(node2, _, config) and + not outBarrier(node1, config) and + not inBarrier(node2, config) and ( // flow out of an argument exists(ParameterNode p | @@ -462,7 +513,9 @@ private predicate flowOutOfCallable(Node node1, Node node2, Configuration config private predicate flowIntoCallable(Node node1, Node node2, Configuration config) { viableParamArg(_, node2, node1) and nodeCand1(node1, _, unbind(config)) and - nodeCand1(node2, _, config) + nodeCand1(node2, _, config) and + not outBarrier(node1, config) and + not inBarrier(node2, config) } /** @@ -546,7 +599,7 @@ private predicate nodeCandFwd2(Node node, boolean fromArg, boolean stored, Confi or exists(Node mid | nodeCandFwd2(mid, _, stored, config) and - jumpStep(mid, node) and + jumpStep(mid, node, config) and fromArg = false ) or @@ -626,7 +679,7 @@ private predicate nodeCand2(Node node, boolean toReturn, boolean stored, Configu ) or exists(Node mid | - jumpStep(node, mid) and + jumpStep(node, mid, config) and nodeCand2(mid, _, stored, config) and toReturn = false ) @@ -714,7 +767,7 @@ private predicate localFlowEntry(Node node, Configuration config) { nodeCand(node, config) and ( config.isSource(node) or - jumpStep(_, node) or + jumpStep(_, node, config) or additionalJumpStep(_, node, config) or node instanceof ParameterNode or node instanceof OutNode or @@ -730,7 +783,7 @@ private predicate localFlowEntry(Node node, Configuration config) { */ private predicate localFlowExit(Node node, Configuration config) { exists(Node next | nodeCand(next, config) | - jumpStep(node, next) or + jumpStep(node, next, config) or additionalJumpStep(node, next, config) or flowIntoCallable(node, next, config) or flowOutOfCallable(node, next, config) or @@ -882,7 +935,7 @@ private predicate flowCandFwd0(Node node, boolean fromArg, AccessPathFront apf, or exists(Node mid | flowCandFwd(mid, _, apf, config) and - jumpStep(mid, node) and + jumpStep(mid, node, config) and fromArg = false ) or @@ -973,7 +1026,7 @@ private predicate flowCand0(Node node, boolean toReturn, AccessPathFront apf, Co ) or exists(Node mid | - jumpStep(node, mid) and + jumpStep(node, mid, config) and flowCand(mid, _, apf, config) and toReturn = false ) @@ -1154,7 +1207,7 @@ private predicate flowFwd0( or exists(Node mid | flowFwd(mid, _, apf, ap, config) and - jumpStep(mid, node) and + jumpStep(mid, node, config) and fromArg = false ) or @@ -1263,7 +1316,7 @@ private predicate flow0(Node node, boolean toReturn, AccessPath ap, Configuratio ) or exists(Node mid | - jumpStep(node, mid) and + jumpStep(node, mid, config) and flow(mid, _, ap, config) and toReturn = false ) @@ -1518,7 +1571,7 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, AccessPat mid.getAp() instanceof AccessPathNil and ap = node.(AccessPathNilNode).getAp() or - jumpStep(mid.getNode(), node) and + jumpStep(mid.getNode(), node, mid.getConfiguration()) and cc instanceof CallContextAny and ap = mid.getAp() or diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl4.qll b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl4.qll index 5a6de5af0f4..cfe85663344 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl4.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl4.qll @@ -57,8 +57,8 @@ abstract class Configuration extends string { /** Holds if data flow through `node` is prohibited. */ predicate isBarrier(Node node) { none() } - /** Holds if data flow from `node1` to `node2` is prohibited. */ - predicate isBarrierEdge(Node node1, Node node2) { none() } + /** DEPRECATED: override `isBarrier` instead. */ + deprecated predicate isBarrierEdge(Node node1, Node node2) { none() } /** * Holds if the additional flow step from `node1` to `node2` must be taken @@ -103,6 +103,22 @@ abstract class Configuration extends string { deprecated predicate hasFlowBackward(Node source, Node sink) { hasFlow(source, sink) } } +private predicate inBarrier(Node node, Configuration config) { + config.isBarrier(node) and + config.isSource(node) +} + +private predicate outBarrier(Node node, Configuration config) { + config.isBarrier(node) and + config.isSink(node) +} + +private predicate fullBarrier(Node node, Configuration config) { + config.isBarrier(node) and + not config.isSource(node) and + not config.isSink(node) +} + private class AdditionalFlowStepSource extends Node { AdditionalFlowStepSource() { any(Configuration c).isAdditionalFlowStep(this, _) } } @@ -119,22 +135,46 @@ private predicate isAdditionalFlowStep( * Holds if data can flow in one local step from `node1` to `node2`. */ private predicate localFlowStep(Node node1, Node node2, Configuration config) { - localFlowStep(node1, node2) and not config.isBarrierEdge(node1, node2) + localFlowStep(node1, node2) and + not outBarrier(node1, config) and + not inBarrier(node2, config) and + not fullBarrier(node1, config) and + not fullBarrier(node2, config) } /** * Holds if the additional step from `node1` to `node2` does not jump between callables. */ private predicate additionalLocalFlowStep(Node node1, Node node2, Configuration config) { - isAdditionalFlowStep(node1, node2, node2.getEnclosingCallable(), config) + isAdditionalFlowStep(node1, node2, node2.getEnclosingCallable(), config) and + not outBarrier(node1, config) and + not inBarrier(node2, config) and + not fullBarrier(node1, config) and + not fullBarrier(node2, config) +} + +/** + * Holds if data can flow from `node1` to `node2` in a way that discards call contexts. + */ +private predicate jumpStep(Node node1, Node node2, Configuration config) { + jumpStep(node1, node2) and + not outBarrier(node1, config) and + not inBarrier(node2, config) and + not fullBarrier(node1, config) and + not fullBarrier(node2, config) } /** * Holds if the additional step from `node1` to `node2` jumps between callables. */ private predicate additionalJumpStep(Node node1, Node node2, Configuration config) { - exists(DataFlowCallable callable1 | isAdditionalFlowStep(node1, node2, callable1, config) | - node2.getEnclosingCallable() != callable1 + exists(DataFlowCallable callable1 | + isAdditionalFlowStep(node1, node2, callable1, config) and + node2.getEnclosingCallable() != callable1 and + not outBarrier(node1, config) and + not inBarrier(node2, config) and + not fullBarrier(node1, config) and + not fullBarrier(node2, config) ) } @@ -154,7 +194,7 @@ private ReturnPosition viableReturnPos(DataFlowCall call, ReturnKind kind) { * ignoring call contexts. */ private predicate nodeCandFwd1(Node node, boolean stored, Configuration config) { - not config.isBarrier(node) and + not fullBarrier(node, config) and ( config.isSource(node) and stored = false or @@ -171,7 +211,7 @@ private predicate nodeCandFwd1(Node node, boolean stored, Configuration config) or exists(Node mid | nodeCandFwd1(mid, stored, config) and - jumpStep(mid, node) + jumpStep(mid, node, config) ) or exists(Node mid | @@ -185,7 +225,8 @@ private predicate nodeCandFwd1(Node node, boolean stored, Configuration config) useFieldFlow(config) and nodeCandFwd1(mid, _, config) and store(mid, _, node) and - stored = true + stored = true and + not outBarrier(mid, config) ) or // read @@ -193,7 +234,8 @@ private predicate nodeCandFwd1(Node node, boolean stored, Configuration config) nodeCandFwd1(mid, true, config) and read(mid, f, node) and storeCandFwd1(f, unbind(config)) and - (stored = false or stored = true) + (stored = false or stored = true) and + not inBarrier(node, config) ) or // flow into a callable @@ -223,7 +265,7 @@ private predicate nodeCandFwd1(Node node, boolean stored, Configuration config) */ private predicate storeCandFwd1(Content f, Configuration config) { exists(Node mid, Node node | - not config.isBarrier(node) and + not fullBarrier(node, config) and useFieldFlow(config) and nodeCandFwd1(mid, _, config) and store(mid, f, node) @@ -257,7 +299,7 @@ private predicate nodeCand1(Node node, boolean stored, Configuration config) { ) or exists(Node mid | - jumpStep(node, mid) and + jumpStep(node, mid, config) and nodeCand1(mid, stored, config) ) or @@ -318,6 +360,11 @@ private predicate readCand1(Content f, Configuration config) { ) } +private predicate throughFlowNodeCand(Node node, Configuration config) { + nodeCand1(node, false, config) and + not config.isBarrier(node) +} + /** * Holds if there is a path from `p` to `node` in the same callable that is * part of a path from a source to a sink taking simple call contexts into @@ -329,7 +376,7 @@ pragma[nomagic] private predicate simpleParameterFlow( ParameterNode p, Node node, DataFlowType t, Configuration config ) { - nodeCand1(node, false, config) and + throughFlowNodeCand(node, config) and p = node and t = getErasedRepr(node.getType()) and exists(ReturnNode ret, ReturnKind kind | @@ -338,21 +385,21 @@ private predicate simpleParameterFlow( not parameterValueFlowsThrough(p, kind, _) ) or - nodeCand1(node, false, unbind(config)) and + throughFlowNodeCand(node, unbind(config)) and exists(Node mid | simpleParameterFlow(p, mid, t, config) and localFlowStep(mid, node, config) and compatibleTypes(t, node.getType()) ) or - nodeCand1(node, false, unbind(config)) and + throughFlowNodeCand(node, unbind(config)) and exists(Node mid | simpleParameterFlow(p, mid, _, config) and additionalLocalFlowStep(mid, node, config) and t = getErasedRepr(node.getType()) ) or - nodeCand1(node, false, unbind(config)) and + throughFlowNodeCand(node, unbind(config)) and exists(Node mid | simpleParameterFlow(p, mid, t, config) and localStoreReadStep(mid, node) and @@ -360,7 +407,7 @@ private predicate simpleParameterFlow( ) or // value flow through a callable - nodeCand1(node, false, unbind(config)) and + throughFlowNodeCand(node, unbind(config)) and exists(Node arg | simpleParameterFlow(p, arg, t, config) and argumentValueFlowsThrough(arg, node, _) and @@ -368,7 +415,7 @@ private predicate simpleParameterFlow( ) or // flow through a callable - nodeCand1(node, false, unbind(config)) and + throughFlowNodeCand(node, unbind(config)) and exists(Node arg | simpleParameterFlow(p, arg, _, config) and simpleArgumentFlowsThrough(arg, node, t, config) @@ -380,6 +427,7 @@ private predicate simpleArgumentFlowsThrough0( DataFlowCall call, ArgumentNode arg, ReturnKind kind, DataFlowType t, Configuration config ) { nodeCand1(arg, false, unbind(config)) and + not outBarrier(arg, config) and exists(ParameterNode p, ReturnNode ret | simpleParameterFlow(p, ret, t, config) and kind = ret.getKind() and @@ -399,6 +447,7 @@ private predicate simpleArgumentFlowsThrough( ) { exists(DataFlowCall call, ReturnKind kind | nodeCand1(out, false, unbind(config)) and + not inBarrier(out, config) and simpleArgumentFlowsThrough0(call, arg, kind, t, config) and out = getAnOutNode(call, kind) ) @@ -440,6 +489,8 @@ private predicate additionalLocalFlowStepOrFlowThroughCallable( private predicate flowOutOfCallable(Node node1, Node node2, Configuration config) { nodeCand1(node1, _, unbind(config)) and nodeCand1(node2, _, config) and + not outBarrier(node1, config) and + not inBarrier(node2, config) and ( // flow out of an argument exists(ParameterNode p | @@ -462,7 +513,9 @@ private predicate flowOutOfCallable(Node node1, Node node2, Configuration config private predicate flowIntoCallable(Node node1, Node node2, Configuration config) { viableParamArg(_, node2, node1) and nodeCand1(node1, _, unbind(config)) and - nodeCand1(node2, _, config) + nodeCand1(node2, _, config) and + not outBarrier(node1, config) and + not inBarrier(node2, config) } /** @@ -546,7 +599,7 @@ private predicate nodeCandFwd2(Node node, boolean fromArg, boolean stored, Confi or exists(Node mid | nodeCandFwd2(mid, _, stored, config) and - jumpStep(mid, node) and + jumpStep(mid, node, config) and fromArg = false ) or @@ -626,7 +679,7 @@ private predicate nodeCand2(Node node, boolean toReturn, boolean stored, Configu ) or exists(Node mid | - jumpStep(node, mid) and + jumpStep(node, mid, config) and nodeCand2(mid, _, stored, config) and toReturn = false ) @@ -714,7 +767,7 @@ private predicate localFlowEntry(Node node, Configuration config) { nodeCand(node, config) and ( config.isSource(node) or - jumpStep(_, node) or + jumpStep(_, node, config) or additionalJumpStep(_, node, config) or node instanceof ParameterNode or node instanceof OutNode or @@ -730,7 +783,7 @@ private predicate localFlowEntry(Node node, Configuration config) { */ private predicate localFlowExit(Node node, Configuration config) { exists(Node next | nodeCand(next, config) | - jumpStep(node, next) or + jumpStep(node, next, config) or additionalJumpStep(node, next, config) or flowIntoCallable(node, next, config) or flowOutOfCallable(node, next, config) or @@ -882,7 +935,7 @@ private predicate flowCandFwd0(Node node, boolean fromArg, AccessPathFront apf, or exists(Node mid | flowCandFwd(mid, _, apf, config) and - jumpStep(mid, node) and + jumpStep(mid, node, config) and fromArg = false ) or @@ -973,7 +1026,7 @@ private predicate flowCand0(Node node, boolean toReturn, AccessPathFront apf, Co ) or exists(Node mid | - jumpStep(node, mid) and + jumpStep(node, mid, config) and flowCand(mid, _, apf, config) and toReturn = false ) @@ -1154,7 +1207,7 @@ private predicate flowFwd0( or exists(Node mid | flowFwd(mid, _, apf, ap, config) and - jumpStep(mid, node) and + jumpStep(mid, node, config) and fromArg = false ) or @@ -1263,7 +1316,7 @@ private predicate flow0(Node node, boolean toReturn, AccessPath ap, Configuratio ) or exists(Node mid | - jumpStep(node, mid) and + jumpStep(node, mid, config) and flow(mid, _, ap, config) and toReturn = false ) @@ -1518,7 +1571,7 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, AccessPat mid.getAp() instanceof AccessPathNil and ap = node.(AccessPathNilNode).getAp() or - jumpStep(mid.getNode(), node) and + jumpStep(mid.getNode(), node, mid.getConfiguration()) and cc instanceof CallContextAny and ap = mid.getAp() or diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl.qll index 5a6de5af0f4..cfe85663344 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl.qll @@ -57,8 +57,8 @@ abstract class Configuration extends string { /** Holds if data flow through `node` is prohibited. */ predicate isBarrier(Node node) { none() } - /** Holds if data flow from `node1` to `node2` is prohibited. */ - predicate isBarrierEdge(Node node1, Node node2) { none() } + /** DEPRECATED: override `isBarrier` instead. */ + deprecated predicate isBarrierEdge(Node node1, Node node2) { none() } /** * Holds if the additional flow step from `node1` to `node2` must be taken @@ -103,6 +103,22 @@ abstract class Configuration extends string { deprecated predicate hasFlowBackward(Node source, Node sink) { hasFlow(source, sink) } } +private predicate inBarrier(Node node, Configuration config) { + config.isBarrier(node) and + config.isSource(node) +} + +private predicate outBarrier(Node node, Configuration config) { + config.isBarrier(node) and + config.isSink(node) +} + +private predicate fullBarrier(Node node, Configuration config) { + config.isBarrier(node) and + not config.isSource(node) and + not config.isSink(node) +} + private class AdditionalFlowStepSource extends Node { AdditionalFlowStepSource() { any(Configuration c).isAdditionalFlowStep(this, _) } } @@ -119,22 +135,46 @@ private predicate isAdditionalFlowStep( * Holds if data can flow in one local step from `node1` to `node2`. */ private predicate localFlowStep(Node node1, Node node2, Configuration config) { - localFlowStep(node1, node2) and not config.isBarrierEdge(node1, node2) + localFlowStep(node1, node2) and + not outBarrier(node1, config) and + not inBarrier(node2, config) and + not fullBarrier(node1, config) and + not fullBarrier(node2, config) } /** * Holds if the additional step from `node1` to `node2` does not jump between callables. */ private predicate additionalLocalFlowStep(Node node1, Node node2, Configuration config) { - isAdditionalFlowStep(node1, node2, node2.getEnclosingCallable(), config) + isAdditionalFlowStep(node1, node2, node2.getEnclosingCallable(), config) and + not outBarrier(node1, config) and + not inBarrier(node2, config) and + not fullBarrier(node1, config) and + not fullBarrier(node2, config) +} + +/** + * Holds if data can flow from `node1` to `node2` in a way that discards call contexts. + */ +private predicate jumpStep(Node node1, Node node2, Configuration config) { + jumpStep(node1, node2) and + not outBarrier(node1, config) and + not inBarrier(node2, config) and + not fullBarrier(node1, config) and + not fullBarrier(node2, config) } /** * Holds if the additional step from `node1` to `node2` jumps between callables. */ private predicate additionalJumpStep(Node node1, Node node2, Configuration config) { - exists(DataFlowCallable callable1 | isAdditionalFlowStep(node1, node2, callable1, config) | - node2.getEnclosingCallable() != callable1 + exists(DataFlowCallable callable1 | + isAdditionalFlowStep(node1, node2, callable1, config) and + node2.getEnclosingCallable() != callable1 and + not outBarrier(node1, config) and + not inBarrier(node2, config) and + not fullBarrier(node1, config) and + not fullBarrier(node2, config) ) } @@ -154,7 +194,7 @@ private ReturnPosition viableReturnPos(DataFlowCall call, ReturnKind kind) { * ignoring call contexts. */ private predicate nodeCandFwd1(Node node, boolean stored, Configuration config) { - not config.isBarrier(node) and + not fullBarrier(node, config) and ( config.isSource(node) and stored = false or @@ -171,7 +211,7 @@ private predicate nodeCandFwd1(Node node, boolean stored, Configuration config) or exists(Node mid | nodeCandFwd1(mid, stored, config) and - jumpStep(mid, node) + jumpStep(mid, node, config) ) or exists(Node mid | @@ -185,7 +225,8 @@ private predicate nodeCandFwd1(Node node, boolean stored, Configuration config) useFieldFlow(config) and nodeCandFwd1(mid, _, config) and store(mid, _, node) and - stored = true + stored = true and + not outBarrier(mid, config) ) or // read @@ -193,7 +234,8 @@ private predicate nodeCandFwd1(Node node, boolean stored, Configuration config) nodeCandFwd1(mid, true, config) and read(mid, f, node) and storeCandFwd1(f, unbind(config)) and - (stored = false or stored = true) + (stored = false or stored = true) and + not inBarrier(node, config) ) or // flow into a callable @@ -223,7 +265,7 @@ private predicate nodeCandFwd1(Node node, boolean stored, Configuration config) */ private predicate storeCandFwd1(Content f, Configuration config) { exists(Node mid, Node node | - not config.isBarrier(node) and + not fullBarrier(node, config) and useFieldFlow(config) and nodeCandFwd1(mid, _, config) and store(mid, f, node) @@ -257,7 +299,7 @@ private predicate nodeCand1(Node node, boolean stored, Configuration config) { ) or exists(Node mid | - jumpStep(node, mid) and + jumpStep(node, mid, config) and nodeCand1(mid, stored, config) ) or @@ -318,6 +360,11 @@ private predicate readCand1(Content f, Configuration config) { ) } +private predicate throughFlowNodeCand(Node node, Configuration config) { + nodeCand1(node, false, config) and + not config.isBarrier(node) +} + /** * Holds if there is a path from `p` to `node` in the same callable that is * part of a path from a source to a sink taking simple call contexts into @@ -329,7 +376,7 @@ pragma[nomagic] private predicate simpleParameterFlow( ParameterNode p, Node node, DataFlowType t, Configuration config ) { - nodeCand1(node, false, config) and + throughFlowNodeCand(node, config) and p = node and t = getErasedRepr(node.getType()) and exists(ReturnNode ret, ReturnKind kind | @@ -338,21 +385,21 @@ private predicate simpleParameterFlow( not parameterValueFlowsThrough(p, kind, _) ) or - nodeCand1(node, false, unbind(config)) and + throughFlowNodeCand(node, unbind(config)) and exists(Node mid | simpleParameterFlow(p, mid, t, config) and localFlowStep(mid, node, config) and compatibleTypes(t, node.getType()) ) or - nodeCand1(node, false, unbind(config)) and + throughFlowNodeCand(node, unbind(config)) and exists(Node mid | simpleParameterFlow(p, mid, _, config) and additionalLocalFlowStep(mid, node, config) and t = getErasedRepr(node.getType()) ) or - nodeCand1(node, false, unbind(config)) and + throughFlowNodeCand(node, unbind(config)) and exists(Node mid | simpleParameterFlow(p, mid, t, config) and localStoreReadStep(mid, node) and @@ -360,7 +407,7 @@ private predicate simpleParameterFlow( ) or // value flow through a callable - nodeCand1(node, false, unbind(config)) and + throughFlowNodeCand(node, unbind(config)) and exists(Node arg | simpleParameterFlow(p, arg, t, config) and argumentValueFlowsThrough(arg, node, _) and @@ -368,7 +415,7 @@ private predicate simpleParameterFlow( ) or // flow through a callable - nodeCand1(node, false, unbind(config)) and + throughFlowNodeCand(node, unbind(config)) and exists(Node arg | simpleParameterFlow(p, arg, _, config) and simpleArgumentFlowsThrough(arg, node, t, config) @@ -380,6 +427,7 @@ private predicate simpleArgumentFlowsThrough0( DataFlowCall call, ArgumentNode arg, ReturnKind kind, DataFlowType t, Configuration config ) { nodeCand1(arg, false, unbind(config)) and + not outBarrier(arg, config) and exists(ParameterNode p, ReturnNode ret | simpleParameterFlow(p, ret, t, config) and kind = ret.getKind() and @@ -399,6 +447,7 @@ private predicate simpleArgumentFlowsThrough( ) { exists(DataFlowCall call, ReturnKind kind | nodeCand1(out, false, unbind(config)) and + not inBarrier(out, config) and simpleArgumentFlowsThrough0(call, arg, kind, t, config) and out = getAnOutNode(call, kind) ) @@ -440,6 +489,8 @@ private predicate additionalLocalFlowStepOrFlowThroughCallable( private predicate flowOutOfCallable(Node node1, Node node2, Configuration config) { nodeCand1(node1, _, unbind(config)) and nodeCand1(node2, _, config) and + not outBarrier(node1, config) and + not inBarrier(node2, config) and ( // flow out of an argument exists(ParameterNode p | @@ -462,7 +513,9 @@ private predicate flowOutOfCallable(Node node1, Node node2, Configuration config private predicate flowIntoCallable(Node node1, Node node2, Configuration config) { viableParamArg(_, node2, node1) and nodeCand1(node1, _, unbind(config)) and - nodeCand1(node2, _, config) + nodeCand1(node2, _, config) and + not outBarrier(node1, config) and + not inBarrier(node2, config) } /** @@ -546,7 +599,7 @@ private predicate nodeCandFwd2(Node node, boolean fromArg, boolean stored, Confi or exists(Node mid | nodeCandFwd2(mid, _, stored, config) and - jumpStep(mid, node) and + jumpStep(mid, node, config) and fromArg = false ) or @@ -626,7 +679,7 @@ private predicate nodeCand2(Node node, boolean toReturn, boolean stored, Configu ) or exists(Node mid | - jumpStep(node, mid) and + jumpStep(node, mid, config) and nodeCand2(mid, _, stored, config) and toReturn = false ) @@ -714,7 +767,7 @@ private predicate localFlowEntry(Node node, Configuration config) { nodeCand(node, config) and ( config.isSource(node) or - jumpStep(_, node) or + jumpStep(_, node, config) or additionalJumpStep(_, node, config) or node instanceof ParameterNode or node instanceof OutNode or @@ -730,7 +783,7 @@ private predicate localFlowEntry(Node node, Configuration config) { */ private predicate localFlowExit(Node node, Configuration config) { exists(Node next | nodeCand(next, config) | - jumpStep(node, next) or + jumpStep(node, next, config) or additionalJumpStep(node, next, config) or flowIntoCallable(node, next, config) or flowOutOfCallable(node, next, config) or @@ -882,7 +935,7 @@ private predicate flowCandFwd0(Node node, boolean fromArg, AccessPathFront apf, or exists(Node mid | flowCandFwd(mid, _, apf, config) and - jumpStep(mid, node) and + jumpStep(mid, node, config) and fromArg = false ) or @@ -973,7 +1026,7 @@ private predicate flowCand0(Node node, boolean toReturn, AccessPathFront apf, Co ) or exists(Node mid | - jumpStep(node, mid) and + jumpStep(node, mid, config) and flowCand(mid, _, apf, config) and toReturn = false ) @@ -1154,7 +1207,7 @@ private predicate flowFwd0( or exists(Node mid | flowFwd(mid, _, apf, ap, config) and - jumpStep(mid, node) and + jumpStep(mid, node, config) and fromArg = false ) or @@ -1263,7 +1316,7 @@ private predicate flow0(Node node, boolean toReturn, AccessPath ap, Configuratio ) or exists(Node mid | - jumpStep(node, mid) and + jumpStep(node, mid, config) and flow(mid, _, ap, config) and toReturn = false ) @@ -1518,7 +1571,7 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, AccessPat mid.getAp() instanceof AccessPathNil and ap = node.(AccessPathNilNode).getAp() or - jumpStep(mid.getNode(), node) and + jumpStep(mid.getNode(), node, mid.getConfiguration()) and cc instanceof CallContextAny and ap = mid.getAp() or diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl2.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl2.qll index 5a6de5af0f4..cfe85663344 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl2.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl2.qll @@ -57,8 +57,8 @@ abstract class Configuration extends string { /** Holds if data flow through `node` is prohibited. */ predicate isBarrier(Node node) { none() } - /** Holds if data flow from `node1` to `node2` is prohibited. */ - predicate isBarrierEdge(Node node1, Node node2) { none() } + /** DEPRECATED: override `isBarrier` instead. */ + deprecated predicate isBarrierEdge(Node node1, Node node2) { none() } /** * Holds if the additional flow step from `node1` to `node2` must be taken @@ -103,6 +103,22 @@ abstract class Configuration extends string { deprecated predicate hasFlowBackward(Node source, Node sink) { hasFlow(source, sink) } } +private predicate inBarrier(Node node, Configuration config) { + config.isBarrier(node) and + config.isSource(node) +} + +private predicate outBarrier(Node node, Configuration config) { + config.isBarrier(node) and + config.isSink(node) +} + +private predicate fullBarrier(Node node, Configuration config) { + config.isBarrier(node) and + not config.isSource(node) and + not config.isSink(node) +} + private class AdditionalFlowStepSource extends Node { AdditionalFlowStepSource() { any(Configuration c).isAdditionalFlowStep(this, _) } } @@ -119,22 +135,46 @@ private predicate isAdditionalFlowStep( * Holds if data can flow in one local step from `node1` to `node2`. */ private predicate localFlowStep(Node node1, Node node2, Configuration config) { - localFlowStep(node1, node2) and not config.isBarrierEdge(node1, node2) + localFlowStep(node1, node2) and + not outBarrier(node1, config) and + not inBarrier(node2, config) and + not fullBarrier(node1, config) and + not fullBarrier(node2, config) } /** * Holds if the additional step from `node1` to `node2` does not jump between callables. */ private predicate additionalLocalFlowStep(Node node1, Node node2, Configuration config) { - isAdditionalFlowStep(node1, node2, node2.getEnclosingCallable(), config) + isAdditionalFlowStep(node1, node2, node2.getEnclosingCallable(), config) and + not outBarrier(node1, config) and + not inBarrier(node2, config) and + not fullBarrier(node1, config) and + not fullBarrier(node2, config) +} + +/** + * Holds if data can flow from `node1` to `node2` in a way that discards call contexts. + */ +private predicate jumpStep(Node node1, Node node2, Configuration config) { + jumpStep(node1, node2) and + not outBarrier(node1, config) and + not inBarrier(node2, config) and + not fullBarrier(node1, config) and + not fullBarrier(node2, config) } /** * Holds if the additional step from `node1` to `node2` jumps between callables. */ private predicate additionalJumpStep(Node node1, Node node2, Configuration config) { - exists(DataFlowCallable callable1 | isAdditionalFlowStep(node1, node2, callable1, config) | - node2.getEnclosingCallable() != callable1 + exists(DataFlowCallable callable1 | + isAdditionalFlowStep(node1, node2, callable1, config) and + node2.getEnclosingCallable() != callable1 and + not outBarrier(node1, config) and + not inBarrier(node2, config) and + not fullBarrier(node1, config) and + not fullBarrier(node2, config) ) } @@ -154,7 +194,7 @@ private ReturnPosition viableReturnPos(DataFlowCall call, ReturnKind kind) { * ignoring call contexts. */ private predicate nodeCandFwd1(Node node, boolean stored, Configuration config) { - not config.isBarrier(node) and + not fullBarrier(node, config) and ( config.isSource(node) and stored = false or @@ -171,7 +211,7 @@ private predicate nodeCandFwd1(Node node, boolean stored, Configuration config) or exists(Node mid | nodeCandFwd1(mid, stored, config) and - jumpStep(mid, node) + jumpStep(mid, node, config) ) or exists(Node mid | @@ -185,7 +225,8 @@ private predicate nodeCandFwd1(Node node, boolean stored, Configuration config) useFieldFlow(config) and nodeCandFwd1(mid, _, config) and store(mid, _, node) and - stored = true + stored = true and + not outBarrier(mid, config) ) or // read @@ -193,7 +234,8 @@ private predicate nodeCandFwd1(Node node, boolean stored, Configuration config) nodeCandFwd1(mid, true, config) and read(mid, f, node) and storeCandFwd1(f, unbind(config)) and - (stored = false or stored = true) + (stored = false or stored = true) and + not inBarrier(node, config) ) or // flow into a callable @@ -223,7 +265,7 @@ private predicate nodeCandFwd1(Node node, boolean stored, Configuration config) */ private predicate storeCandFwd1(Content f, Configuration config) { exists(Node mid, Node node | - not config.isBarrier(node) and + not fullBarrier(node, config) and useFieldFlow(config) and nodeCandFwd1(mid, _, config) and store(mid, f, node) @@ -257,7 +299,7 @@ private predicate nodeCand1(Node node, boolean stored, Configuration config) { ) or exists(Node mid | - jumpStep(node, mid) and + jumpStep(node, mid, config) and nodeCand1(mid, stored, config) ) or @@ -318,6 +360,11 @@ private predicate readCand1(Content f, Configuration config) { ) } +private predicate throughFlowNodeCand(Node node, Configuration config) { + nodeCand1(node, false, config) and + not config.isBarrier(node) +} + /** * Holds if there is a path from `p` to `node` in the same callable that is * part of a path from a source to a sink taking simple call contexts into @@ -329,7 +376,7 @@ pragma[nomagic] private predicate simpleParameterFlow( ParameterNode p, Node node, DataFlowType t, Configuration config ) { - nodeCand1(node, false, config) and + throughFlowNodeCand(node, config) and p = node and t = getErasedRepr(node.getType()) and exists(ReturnNode ret, ReturnKind kind | @@ -338,21 +385,21 @@ private predicate simpleParameterFlow( not parameterValueFlowsThrough(p, kind, _) ) or - nodeCand1(node, false, unbind(config)) and + throughFlowNodeCand(node, unbind(config)) and exists(Node mid | simpleParameterFlow(p, mid, t, config) and localFlowStep(mid, node, config) and compatibleTypes(t, node.getType()) ) or - nodeCand1(node, false, unbind(config)) and + throughFlowNodeCand(node, unbind(config)) and exists(Node mid | simpleParameterFlow(p, mid, _, config) and additionalLocalFlowStep(mid, node, config) and t = getErasedRepr(node.getType()) ) or - nodeCand1(node, false, unbind(config)) and + throughFlowNodeCand(node, unbind(config)) and exists(Node mid | simpleParameterFlow(p, mid, t, config) and localStoreReadStep(mid, node) and @@ -360,7 +407,7 @@ private predicate simpleParameterFlow( ) or // value flow through a callable - nodeCand1(node, false, unbind(config)) and + throughFlowNodeCand(node, unbind(config)) and exists(Node arg | simpleParameterFlow(p, arg, t, config) and argumentValueFlowsThrough(arg, node, _) and @@ -368,7 +415,7 @@ private predicate simpleParameterFlow( ) or // flow through a callable - nodeCand1(node, false, unbind(config)) and + throughFlowNodeCand(node, unbind(config)) and exists(Node arg | simpleParameterFlow(p, arg, _, config) and simpleArgumentFlowsThrough(arg, node, t, config) @@ -380,6 +427,7 @@ private predicate simpleArgumentFlowsThrough0( DataFlowCall call, ArgumentNode arg, ReturnKind kind, DataFlowType t, Configuration config ) { nodeCand1(arg, false, unbind(config)) and + not outBarrier(arg, config) and exists(ParameterNode p, ReturnNode ret | simpleParameterFlow(p, ret, t, config) and kind = ret.getKind() and @@ -399,6 +447,7 @@ private predicate simpleArgumentFlowsThrough( ) { exists(DataFlowCall call, ReturnKind kind | nodeCand1(out, false, unbind(config)) and + not inBarrier(out, config) and simpleArgumentFlowsThrough0(call, arg, kind, t, config) and out = getAnOutNode(call, kind) ) @@ -440,6 +489,8 @@ private predicate additionalLocalFlowStepOrFlowThroughCallable( private predicate flowOutOfCallable(Node node1, Node node2, Configuration config) { nodeCand1(node1, _, unbind(config)) and nodeCand1(node2, _, config) and + not outBarrier(node1, config) and + not inBarrier(node2, config) and ( // flow out of an argument exists(ParameterNode p | @@ -462,7 +513,9 @@ private predicate flowOutOfCallable(Node node1, Node node2, Configuration config private predicate flowIntoCallable(Node node1, Node node2, Configuration config) { viableParamArg(_, node2, node1) and nodeCand1(node1, _, unbind(config)) and - nodeCand1(node2, _, config) + nodeCand1(node2, _, config) and + not outBarrier(node1, config) and + not inBarrier(node2, config) } /** @@ -546,7 +599,7 @@ private predicate nodeCandFwd2(Node node, boolean fromArg, boolean stored, Confi or exists(Node mid | nodeCandFwd2(mid, _, stored, config) and - jumpStep(mid, node) and + jumpStep(mid, node, config) and fromArg = false ) or @@ -626,7 +679,7 @@ private predicate nodeCand2(Node node, boolean toReturn, boolean stored, Configu ) or exists(Node mid | - jumpStep(node, mid) and + jumpStep(node, mid, config) and nodeCand2(mid, _, stored, config) and toReturn = false ) @@ -714,7 +767,7 @@ private predicate localFlowEntry(Node node, Configuration config) { nodeCand(node, config) and ( config.isSource(node) or - jumpStep(_, node) or + jumpStep(_, node, config) or additionalJumpStep(_, node, config) or node instanceof ParameterNode or node instanceof OutNode or @@ -730,7 +783,7 @@ private predicate localFlowEntry(Node node, Configuration config) { */ private predicate localFlowExit(Node node, Configuration config) { exists(Node next | nodeCand(next, config) | - jumpStep(node, next) or + jumpStep(node, next, config) or additionalJumpStep(node, next, config) or flowIntoCallable(node, next, config) or flowOutOfCallable(node, next, config) or @@ -882,7 +935,7 @@ private predicate flowCandFwd0(Node node, boolean fromArg, AccessPathFront apf, or exists(Node mid | flowCandFwd(mid, _, apf, config) and - jumpStep(mid, node) and + jumpStep(mid, node, config) and fromArg = false ) or @@ -973,7 +1026,7 @@ private predicate flowCand0(Node node, boolean toReturn, AccessPathFront apf, Co ) or exists(Node mid | - jumpStep(node, mid) and + jumpStep(node, mid, config) and flowCand(mid, _, apf, config) and toReturn = false ) @@ -1154,7 +1207,7 @@ private predicate flowFwd0( or exists(Node mid | flowFwd(mid, _, apf, ap, config) and - jumpStep(mid, node) and + jumpStep(mid, node, config) and fromArg = false ) or @@ -1263,7 +1316,7 @@ private predicate flow0(Node node, boolean toReturn, AccessPath ap, Configuratio ) or exists(Node mid | - jumpStep(node, mid) and + jumpStep(node, mid, config) and flow(mid, _, ap, config) and toReturn = false ) @@ -1518,7 +1571,7 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, AccessPat mid.getAp() instanceof AccessPathNil and ap = node.(AccessPathNilNode).getAp() or - jumpStep(mid.getNode(), node) and + jumpStep(mid.getNode(), node, mid.getConfiguration()) and cc instanceof CallContextAny and ap = mid.getAp() or diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl3.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl3.qll index 5a6de5af0f4..cfe85663344 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl3.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl3.qll @@ -57,8 +57,8 @@ abstract class Configuration extends string { /** Holds if data flow through `node` is prohibited. */ predicate isBarrier(Node node) { none() } - /** Holds if data flow from `node1` to `node2` is prohibited. */ - predicate isBarrierEdge(Node node1, Node node2) { none() } + /** DEPRECATED: override `isBarrier` instead. */ + deprecated predicate isBarrierEdge(Node node1, Node node2) { none() } /** * Holds if the additional flow step from `node1` to `node2` must be taken @@ -103,6 +103,22 @@ abstract class Configuration extends string { deprecated predicate hasFlowBackward(Node source, Node sink) { hasFlow(source, sink) } } +private predicate inBarrier(Node node, Configuration config) { + config.isBarrier(node) and + config.isSource(node) +} + +private predicate outBarrier(Node node, Configuration config) { + config.isBarrier(node) and + config.isSink(node) +} + +private predicate fullBarrier(Node node, Configuration config) { + config.isBarrier(node) and + not config.isSource(node) and + not config.isSink(node) +} + private class AdditionalFlowStepSource extends Node { AdditionalFlowStepSource() { any(Configuration c).isAdditionalFlowStep(this, _) } } @@ -119,22 +135,46 @@ private predicate isAdditionalFlowStep( * Holds if data can flow in one local step from `node1` to `node2`. */ private predicate localFlowStep(Node node1, Node node2, Configuration config) { - localFlowStep(node1, node2) and not config.isBarrierEdge(node1, node2) + localFlowStep(node1, node2) and + not outBarrier(node1, config) and + not inBarrier(node2, config) and + not fullBarrier(node1, config) and + not fullBarrier(node2, config) } /** * Holds if the additional step from `node1` to `node2` does not jump between callables. */ private predicate additionalLocalFlowStep(Node node1, Node node2, Configuration config) { - isAdditionalFlowStep(node1, node2, node2.getEnclosingCallable(), config) + isAdditionalFlowStep(node1, node2, node2.getEnclosingCallable(), config) and + not outBarrier(node1, config) and + not inBarrier(node2, config) and + not fullBarrier(node1, config) and + not fullBarrier(node2, config) +} + +/** + * Holds if data can flow from `node1` to `node2` in a way that discards call contexts. + */ +private predicate jumpStep(Node node1, Node node2, Configuration config) { + jumpStep(node1, node2) and + not outBarrier(node1, config) and + not inBarrier(node2, config) and + not fullBarrier(node1, config) and + not fullBarrier(node2, config) } /** * Holds if the additional step from `node1` to `node2` jumps between callables. */ private predicate additionalJumpStep(Node node1, Node node2, Configuration config) { - exists(DataFlowCallable callable1 | isAdditionalFlowStep(node1, node2, callable1, config) | - node2.getEnclosingCallable() != callable1 + exists(DataFlowCallable callable1 | + isAdditionalFlowStep(node1, node2, callable1, config) and + node2.getEnclosingCallable() != callable1 and + not outBarrier(node1, config) and + not inBarrier(node2, config) and + not fullBarrier(node1, config) and + not fullBarrier(node2, config) ) } @@ -154,7 +194,7 @@ private ReturnPosition viableReturnPos(DataFlowCall call, ReturnKind kind) { * ignoring call contexts. */ private predicate nodeCandFwd1(Node node, boolean stored, Configuration config) { - not config.isBarrier(node) and + not fullBarrier(node, config) and ( config.isSource(node) and stored = false or @@ -171,7 +211,7 @@ private predicate nodeCandFwd1(Node node, boolean stored, Configuration config) or exists(Node mid | nodeCandFwd1(mid, stored, config) and - jumpStep(mid, node) + jumpStep(mid, node, config) ) or exists(Node mid | @@ -185,7 +225,8 @@ private predicate nodeCandFwd1(Node node, boolean stored, Configuration config) useFieldFlow(config) and nodeCandFwd1(mid, _, config) and store(mid, _, node) and - stored = true + stored = true and + not outBarrier(mid, config) ) or // read @@ -193,7 +234,8 @@ private predicate nodeCandFwd1(Node node, boolean stored, Configuration config) nodeCandFwd1(mid, true, config) and read(mid, f, node) and storeCandFwd1(f, unbind(config)) and - (stored = false or stored = true) + (stored = false or stored = true) and + not inBarrier(node, config) ) or // flow into a callable @@ -223,7 +265,7 @@ private predicate nodeCandFwd1(Node node, boolean stored, Configuration config) */ private predicate storeCandFwd1(Content f, Configuration config) { exists(Node mid, Node node | - not config.isBarrier(node) and + not fullBarrier(node, config) and useFieldFlow(config) and nodeCandFwd1(mid, _, config) and store(mid, f, node) @@ -257,7 +299,7 @@ private predicate nodeCand1(Node node, boolean stored, Configuration config) { ) or exists(Node mid | - jumpStep(node, mid) and + jumpStep(node, mid, config) and nodeCand1(mid, stored, config) ) or @@ -318,6 +360,11 @@ private predicate readCand1(Content f, Configuration config) { ) } +private predicate throughFlowNodeCand(Node node, Configuration config) { + nodeCand1(node, false, config) and + not config.isBarrier(node) +} + /** * Holds if there is a path from `p` to `node` in the same callable that is * part of a path from a source to a sink taking simple call contexts into @@ -329,7 +376,7 @@ pragma[nomagic] private predicate simpleParameterFlow( ParameterNode p, Node node, DataFlowType t, Configuration config ) { - nodeCand1(node, false, config) and + throughFlowNodeCand(node, config) and p = node and t = getErasedRepr(node.getType()) and exists(ReturnNode ret, ReturnKind kind | @@ -338,21 +385,21 @@ private predicate simpleParameterFlow( not parameterValueFlowsThrough(p, kind, _) ) or - nodeCand1(node, false, unbind(config)) and + throughFlowNodeCand(node, unbind(config)) and exists(Node mid | simpleParameterFlow(p, mid, t, config) and localFlowStep(mid, node, config) and compatibleTypes(t, node.getType()) ) or - nodeCand1(node, false, unbind(config)) and + throughFlowNodeCand(node, unbind(config)) and exists(Node mid | simpleParameterFlow(p, mid, _, config) and additionalLocalFlowStep(mid, node, config) and t = getErasedRepr(node.getType()) ) or - nodeCand1(node, false, unbind(config)) and + throughFlowNodeCand(node, unbind(config)) and exists(Node mid | simpleParameterFlow(p, mid, t, config) and localStoreReadStep(mid, node) and @@ -360,7 +407,7 @@ private predicate simpleParameterFlow( ) or // value flow through a callable - nodeCand1(node, false, unbind(config)) and + throughFlowNodeCand(node, unbind(config)) and exists(Node arg | simpleParameterFlow(p, arg, t, config) and argumentValueFlowsThrough(arg, node, _) and @@ -368,7 +415,7 @@ private predicate simpleParameterFlow( ) or // flow through a callable - nodeCand1(node, false, unbind(config)) and + throughFlowNodeCand(node, unbind(config)) and exists(Node arg | simpleParameterFlow(p, arg, _, config) and simpleArgumentFlowsThrough(arg, node, t, config) @@ -380,6 +427,7 @@ private predicate simpleArgumentFlowsThrough0( DataFlowCall call, ArgumentNode arg, ReturnKind kind, DataFlowType t, Configuration config ) { nodeCand1(arg, false, unbind(config)) and + not outBarrier(arg, config) and exists(ParameterNode p, ReturnNode ret | simpleParameterFlow(p, ret, t, config) and kind = ret.getKind() and @@ -399,6 +447,7 @@ private predicate simpleArgumentFlowsThrough( ) { exists(DataFlowCall call, ReturnKind kind | nodeCand1(out, false, unbind(config)) and + not inBarrier(out, config) and simpleArgumentFlowsThrough0(call, arg, kind, t, config) and out = getAnOutNode(call, kind) ) @@ -440,6 +489,8 @@ private predicate additionalLocalFlowStepOrFlowThroughCallable( private predicate flowOutOfCallable(Node node1, Node node2, Configuration config) { nodeCand1(node1, _, unbind(config)) and nodeCand1(node2, _, config) and + not outBarrier(node1, config) and + not inBarrier(node2, config) and ( // flow out of an argument exists(ParameterNode p | @@ -462,7 +513,9 @@ private predicate flowOutOfCallable(Node node1, Node node2, Configuration config private predicate flowIntoCallable(Node node1, Node node2, Configuration config) { viableParamArg(_, node2, node1) and nodeCand1(node1, _, unbind(config)) and - nodeCand1(node2, _, config) + nodeCand1(node2, _, config) and + not outBarrier(node1, config) and + not inBarrier(node2, config) } /** @@ -546,7 +599,7 @@ private predicate nodeCandFwd2(Node node, boolean fromArg, boolean stored, Confi or exists(Node mid | nodeCandFwd2(mid, _, stored, config) and - jumpStep(mid, node) and + jumpStep(mid, node, config) and fromArg = false ) or @@ -626,7 +679,7 @@ private predicate nodeCand2(Node node, boolean toReturn, boolean stored, Configu ) or exists(Node mid | - jumpStep(node, mid) and + jumpStep(node, mid, config) and nodeCand2(mid, _, stored, config) and toReturn = false ) @@ -714,7 +767,7 @@ private predicate localFlowEntry(Node node, Configuration config) { nodeCand(node, config) and ( config.isSource(node) or - jumpStep(_, node) or + jumpStep(_, node, config) or additionalJumpStep(_, node, config) or node instanceof ParameterNode or node instanceof OutNode or @@ -730,7 +783,7 @@ private predicate localFlowEntry(Node node, Configuration config) { */ private predicate localFlowExit(Node node, Configuration config) { exists(Node next | nodeCand(next, config) | - jumpStep(node, next) or + jumpStep(node, next, config) or additionalJumpStep(node, next, config) or flowIntoCallable(node, next, config) or flowOutOfCallable(node, next, config) or @@ -882,7 +935,7 @@ private predicate flowCandFwd0(Node node, boolean fromArg, AccessPathFront apf, or exists(Node mid | flowCandFwd(mid, _, apf, config) and - jumpStep(mid, node) and + jumpStep(mid, node, config) and fromArg = false ) or @@ -973,7 +1026,7 @@ private predicate flowCand0(Node node, boolean toReturn, AccessPathFront apf, Co ) or exists(Node mid | - jumpStep(node, mid) and + jumpStep(node, mid, config) and flowCand(mid, _, apf, config) and toReturn = false ) @@ -1154,7 +1207,7 @@ private predicate flowFwd0( or exists(Node mid | flowFwd(mid, _, apf, ap, config) and - jumpStep(mid, node) and + jumpStep(mid, node, config) and fromArg = false ) or @@ -1263,7 +1316,7 @@ private predicate flow0(Node node, boolean toReturn, AccessPath ap, Configuratio ) or exists(Node mid | - jumpStep(node, mid) and + jumpStep(node, mid, config) and flow(mid, _, ap, config) and toReturn = false ) @@ -1518,7 +1571,7 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, AccessPat mid.getAp() instanceof AccessPathNil and ap = node.(AccessPathNilNode).getAp() or - jumpStep(mid.getNode(), node) and + jumpStep(mid.getNode(), node, mid.getConfiguration()) and cc instanceof CallContextAny and ap = mid.getAp() or diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl4.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl4.qll index 5a6de5af0f4..cfe85663344 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl4.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl4.qll @@ -57,8 +57,8 @@ abstract class Configuration extends string { /** Holds if data flow through `node` is prohibited. */ predicate isBarrier(Node node) { none() } - /** Holds if data flow from `node1` to `node2` is prohibited. */ - predicate isBarrierEdge(Node node1, Node node2) { none() } + /** DEPRECATED: override `isBarrier` instead. */ + deprecated predicate isBarrierEdge(Node node1, Node node2) { none() } /** * Holds if the additional flow step from `node1` to `node2` must be taken @@ -103,6 +103,22 @@ abstract class Configuration extends string { deprecated predicate hasFlowBackward(Node source, Node sink) { hasFlow(source, sink) } } +private predicate inBarrier(Node node, Configuration config) { + config.isBarrier(node) and + config.isSource(node) +} + +private predicate outBarrier(Node node, Configuration config) { + config.isBarrier(node) and + config.isSink(node) +} + +private predicate fullBarrier(Node node, Configuration config) { + config.isBarrier(node) and + not config.isSource(node) and + not config.isSink(node) +} + private class AdditionalFlowStepSource extends Node { AdditionalFlowStepSource() { any(Configuration c).isAdditionalFlowStep(this, _) } } @@ -119,22 +135,46 @@ private predicate isAdditionalFlowStep( * Holds if data can flow in one local step from `node1` to `node2`. */ private predicate localFlowStep(Node node1, Node node2, Configuration config) { - localFlowStep(node1, node2) and not config.isBarrierEdge(node1, node2) + localFlowStep(node1, node2) and + not outBarrier(node1, config) and + not inBarrier(node2, config) and + not fullBarrier(node1, config) and + not fullBarrier(node2, config) } /** * Holds if the additional step from `node1` to `node2` does not jump between callables. */ private predicate additionalLocalFlowStep(Node node1, Node node2, Configuration config) { - isAdditionalFlowStep(node1, node2, node2.getEnclosingCallable(), config) + isAdditionalFlowStep(node1, node2, node2.getEnclosingCallable(), config) and + not outBarrier(node1, config) and + not inBarrier(node2, config) and + not fullBarrier(node1, config) and + not fullBarrier(node2, config) +} + +/** + * Holds if data can flow from `node1` to `node2` in a way that discards call contexts. + */ +private predicate jumpStep(Node node1, Node node2, Configuration config) { + jumpStep(node1, node2) and + not outBarrier(node1, config) and + not inBarrier(node2, config) and + not fullBarrier(node1, config) and + not fullBarrier(node2, config) } /** * Holds if the additional step from `node1` to `node2` jumps between callables. */ private predicate additionalJumpStep(Node node1, Node node2, Configuration config) { - exists(DataFlowCallable callable1 | isAdditionalFlowStep(node1, node2, callable1, config) | - node2.getEnclosingCallable() != callable1 + exists(DataFlowCallable callable1 | + isAdditionalFlowStep(node1, node2, callable1, config) and + node2.getEnclosingCallable() != callable1 and + not outBarrier(node1, config) and + not inBarrier(node2, config) and + not fullBarrier(node1, config) and + not fullBarrier(node2, config) ) } @@ -154,7 +194,7 @@ private ReturnPosition viableReturnPos(DataFlowCall call, ReturnKind kind) { * ignoring call contexts. */ private predicate nodeCandFwd1(Node node, boolean stored, Configuration config) { - not config.isBarrier(node) and + not fullBarrier(node, config) and ( config.isSource(node) and stored = false or @@ -171,7 +211,7 @@ private predicate nodeCandFwd1(Node node, boolean stored, Configuration config) or exists(Node mid | nodeCandFwd1(mid, stored, config) and - jumpStep(mid, node) + jumpStep(mid, node, config) ) or exists(Node mid | @@ -185,7 +225,8 @@ private predicate nodeCandFwd1(Node node, boolean stored, Configuration config) useFieldFlow(config) and nodeCandFwd1(mid, _, config) and store(mid, _, node) and - stored = true + stored = true and + not outBarrier(mid, config) ) or // read @@ -193,7 +234,8 @@ private predicate nodeCandFwd1(Node node, boolean stored, Configuration config) nodeCandFwd1(mid, true, config) and read(mid, f, node) and storeCandFwd1(f, unbind(config)) and - (stored = false or stored = true) + (stored = false or stored = true) and + not inBarrier(node, config) ) or // flow into a callable @@ -223,7 +265,7 @@ private predicate nodeCandFwd1(Node node, boolean stored, Configuration config) */ private predicate storeCandFwd1(Content f, Configuration config) { exists(Node mid, Node node | - not config.isBarrier(node) and + not fullBarrier(node, config) and useFieldFlow(config) and nodeCandFwd1(mid, _, config) and store(mid, f, node) @@ -257,7 +299,7 @@ private predicate nodeCand1(Node node, boolean stored, Configuration config) { ) or exists(Node mid | - jumpStep(node, mid) and + jumpStep(node, mid, config) and nodeCand1(mid, stored, config) ) or @@ -318,6 +360,11 @@ private predicate readCand1(Content f, Configuration config) { ) } +private predicate throughFlowNodeCand(Node node, Configuration config) { + nodeCand1(node, false, config) and + not config.isBarrier(node) +} + /** * Holds if there is a path from `p` to `node` in the same callable that is * part of a path from a source to a sink taking simple call contexts into @@ -329,7 +376,7 @@ pragma[nomagic] private predicate simpleParameterFlow( ParameterNode p, Node node, DataFlowType t, Configuration config ) { - nodeCand1(node, false, config) and + throughFlowNodeCand(node, config) and p = node and t = getErasedRepr(node.getType()) and exists(ReturnNode ret, ReturnKind kind | @@ -338,21 +385,21 @@ private predicate simpleParameterFlow( not parameterValueFlowsThrough(p, kind, _) ) or - nodeCand1(node, false, unbind(config)) and + throughFlowNodeCand(node, unbind(config)) and exists(Node mid | simpleParameterFlow(p, mid, t, config) and localFlowStep(mid, node, config) and compatibleTypes(t, node.getType()) ) or - nodeCand1(node, false, unbind(config)) and + throughFlowNodeCand(node, unbind(config)) and exists(Node mid | simpleParameterFlow(p, mid, _, config) and additionalLocalFlowStep(mid, node, config) and t = getErasedRepr(node.getType()) ) or - nodeCand1(node, false, unbind(config)) and + throughFlowNodeCand(node, unbind(config)) and exists(Node mid | simpleParameterFlow(p, mid, t, config) and localStoreReadStep(mid, node) and @@ -360,7 +407,7 @@ private predicate simpleParameterFlow( ) or // value flow through a callable - nodeCand1(node, false, unbind(config)) and + throughFlowNodeCand(node, unbind(config)) and exists(Node arg | simpleParameterFlow(p, arg, t, config) and argumentValueFlowsThrough(arg, node, _) and @@ -368,7 +415,7 @@ private predicate simpleParameterFlow( ) or // flow through a callable - nodeCand1(node, false, unbind(config)) and + throughFlowNodeCand(node, unbind(config)) and exists(Node arg | simpleParameterFlow(p, arg, _, config) and simpleArgumentFlowsThrough(arg, node, t, config) @@ -380,6 +427,7 @@ private predicate simpleArgumentFlowsThrough0( DataFlowCall call, ArgumentNode arg, ReturnKind kind, DataFlowType t, Configuration config ) { nodeCand1(arg, false, unbind(config)) and + not outBarrier(arg, config) and exists(ParameterNode p, ReturnNode ret | simpleParameterFlow(p, ret, t, config) and kind = ret.getKind() and @@ -399,6 +447,7 @@ private predicate simpleArgumentFlowsThrough( ) { exists(DataFlowCall call, ReturnKind kind | nodeCand1(out, false, unbind(config)) and + not inBarrier(out, config) and simpleArgumentFlowsThrough0(call, arg, kind, t, config) and out = getAnOutNode(call, kind) ) @@ -440,6 +489,8 @@ private predicate additionalLocalFlowStepOrFlowThroughCallable( private predicate flowOutOfCallable(Node node1, Node node2, Configuration config) { nodeCand1(node1, _, unbind(config)) and nodeCand1(node2, _, config) and + not outBarrier(node1, config) and + not inBarrier(node2, config) and ( // flow out of an argument exists(ParameterNode p | @@ -462,7 +513,9 @@ private predicate flowOutOfCallable(Node node1, Node node2, Configuration config private predicate flowIntoCallable(Node node1, Node node2, Configuration config) { viableParamArg(_, node2, node1) and nodeCand1(node1, _, unbind(config)) and - nodeCand1(node2, _, config) + nodeCand1(node2, _, config) and + not outBarrier(node1, config) and + not inBarrier(node2, config) } /** @@ -546,7 +599,7 @@ private predicate nodeCandFwd2(Node node, boolean fromArg, boolean stored, Confi or exists(Node mid | nodeCandFwd2(mid, _, stored, config) and - jumpStep(mid, node) and + jumpStep(mid, node, config) and fromArg = false ) or @@ -626,7 +679,7 @@ private predicate nodeCand2(Node node, boolean toReturn, boolean stored, Configu ) or exists(Node mid | - jumpStep(node, mid) and + jumpStep(node, mid, config) and nodeCand2(mid, _, stored, config) and toReturn = false ) @@ -714,7 +767,7 @@ private predicate localFlowEntry(Node node, Configuration config) { nodeCand(node, config) and ( config.isSource(node) or - jumpStep(_, node) or + jumpStep(_, node, config) or additionalJumpStep(_, node, config) or node instanceof ParameterNode or node instanceof OutNode or @@ -730,7 +783,7 @@ private predicate localFlowEntry(Node node, Configuration config) { */ private predicate localFlowExit(Node node, Configuration config) { exists(Node next | nodeCand(next, config) | - jumpStep(node, next) or + jumpStep(node, next, config) or additionalJumpStep(node, next, config) or flowIntoCallable(node, next, config) or flowOutOfCallable(node, next, config) or @@ -882,7 +935,7 @@ private predicate flowCandFwd0(Node node, boolean fromArg, AccessPathFront apf, or exists(Node mid | flowCandFwd(mid, _, apf, config) and - jumpStep(mid, node) and + jumpStep(mid, node, config) and fromArg = false ) or @@ -973,7 +1026,7 @@ private predicate flowCand0(Node node, boolean toReturn, AccessPathFront apf, Co ) or exists(Node mid | - jumpStep(node, mid) and + jumpStep(node, mid, config) and flowCand(mid, _, apf, config) and toReturn = false ) @@ -1154,7 +1207,7 @@ private predicate flowFwd0( or exists(Node mid | flowFwd(mid, _, apf, ap, config) and - jumpStep(mid, node) and + jumpStep(mid, node, config) and fromArg = false ) or @@ -1263,7 +1316,7 @@ private predicate flow0(Node node, boolean toReturn, AccessPath ap, Configuratio ) or exists(Node mid | - jumpStep(node, mid) and + jumpStep(node, mid, config) and flow(mid, _, ap, config) and toReturn = false ) @@ -1518,7 +1571,7 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, AccessPat mid.getAp() instanceof AccessPathNil and ap = node.(AccessPathNilNode).getAp() or - jumpStep(mid.getNode(), node) and + jumpStep(mid.getNode(), node, mid.getConfiguration()) and cc instanceof CallContextAny and ap = mid.getAp() or diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl.qll index 5a6de5af0f4..cfe85663344 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl.qll @@ -57,8 +57,8 @@ abstract class Configuration extends string { /** Holds if data flow through `node` is prohibited. */ predicate isBarrier(Node node) { none() } - /** Holds if data flow from `node1` to `node2` is prohibited. */ - predicate isBarrierEdge(Node node1, Node node2) { none() } + /** DEPRECATED: override `isBarrier` instead. */ + deprecated predicate isBarrierEdge(Node node1, Node node2) { none() } /** * Holds if the additional flow step from `node1` to `node2` must be taken @@ -103,6 +103,22 @@ abstract class Configuration extends string { deprecated predicate hasFlowBackward(Node source, Node sink) { hasFlow(source, sink) } } +private predicate inBarrier(Node node, Configuration config) { + config.isBarrier(node) and + config.isSource(node) +} + +private predicate outBarrier(Node node, Configuration config) { + config.isBarrier(node) and + config.isSink(node) +} + +private predicate fullBarrier(Node node, Configuration config) { + config.isBarrier(node) and + not config.isSource(node) and + not config.isSink(node) +} + private class AdditionalFlowStepSource extends Node { AdditionalFlowStepSource() { any(Configuration c).isAdditionalFlowStep(this, _) } } @@ -119,22 +135,46 @@ private predicate isAdditionalFlowStep( * Holds if data can flow in one local step from `node1` to `node2`. */ private predicate localFlowStep(Node node1, Node node2, Configuration config) { - localFlowStep(node1, node2) and not config.isBarrierEdge(node1, node2) + localFlowStep(node1, node2) and + not outBarrier(node1, config) and + not inBarrier(node2, config) and + not fullBarrier(node1, config) and + not fullBarrier(node2, config) } /** * Holds if the additional step from `node1` to `node2` does not jump between callables. */ private predicate additionalLocalFlowStep(Node node1, Node node2, Configuration config) { - isAdditionalFlowStep(node1, node2, node2.getEnclosingCallable(), config) + isAdditionalFlowStep(node1, node2, node2.getEnclosingCallable(), config) and + not outBarrier(node1, config) and + not inBarrier(node2, config) and + not fullBarrier(node1, config) and + not fullBarrier(node2, config) +} + +/** + * Holds if data can flow from `node1` to `node2` in a way that discards call contexts. + */ +private predicate jumpStep(Node node1, Node node2, Configuration config) { + jumpStep(node1, node2) and + not outBarrier(node1, config) and + not inBarrier(node2, config) and + not fullBarrier(node1, config) and + not fullBarrier(node2, config) } /** * Holds if the additional step from `node1` to `node2` jumps between callables. */ private predicate additionalJumpStep(Node node1, Node node2, Configuration config) { - exists(DataFlowCallable callable1 | isAdditionalFlowStep(node1, node2, callable1, config) | - node2.getEnclosingCallable() != callable1 + exists(DataFlowCallable callable1 | + isAdditionalFlowStep(node1, node2, callable1, config) and + node2.getEnclosingCallable() != callable1 and + not outBarrier(node1, config) and + not inBarrier(node2, config) and + not fullBarrier(node1, config) and + not fullBarrier(node2, config) ) } @@ -154,7 +194,7 @@ private ReturnPosition viableReturnPos(DataFlowCall call, ReturnKind kind) { * ignoring call contexts. */ private predicate nodeCandFwd1(Node node, boolean stored, Configuration config) { - not config.isBarrier(node) and + not fullBarrier(node, config) and ( config.isSource(node) and stored = false or @@ -171,7 +211,7 @@ private predicate nodeCandFwd1(Node node, boolean stored, Configuration config) or exists(Node mid | nodeCandFwd1(mid, stored, config) and - jumpStep(mid, node) + jumpStep(mid, node, config) ) or exists(Node mid | @@ -185,7 +225,8 @@ private predicate nodeCandFwd1(Node node, boolean stored, Configuration config) useFieldFlow(config) and nodeCandFwd1(mid, _, config) and store(mid, _, node) and - stored = true + stored = true and + not outBarrier(mid, config) ) or // read @@ -193,7 +234,8 @@ private predicate nodeCandFwd1(Node node, boolean stored, Configuration config) nodeCandFwd1(mid, true, config) and read(mid, f, node) and storeCandFwd1(f, unbind(config)) and - (stored = false or stored = true) + (stored = false or stored = true) and + not inBarrier(node, config) ) or // flow into a callable @@ -223,7 +265,7 @@ private predicate nodeCandFwd1(Node node, boolean stored, Configuration config) */ private predicate storeCandFwd1(Content f, Configuration config) { exists(Node mid, Node node | - not config.isBarrier(node) and + not fullBarrier(node, config) and useFieldFlow(config) and nodeCandFwd1(mid, _, config) and store(mid, f, node) @@ -257,7 +299,7 @@ private predicate nodeCand1(Node node, boolean stored, Configuration config) { ) or exists(Node mid | - jumpStep(node, mid) and + jumpStep(node, mid, config) and nodeCand1(mid, stored, config) ) or @@ -318,6 +360,11 @@ private predicate readCand1(Content f, Configuration config) { ) } +private predicate throughFlowNodeCand(Node node, Configuration config) { + nodeCand1(node, false, config) and + not config.isBarrier(node) +} + /** * Holds if there is a path from `p` to `node` in the same callable that is * part of a path from a source to a sink taking simple call contexts into @@ -329,7 +376,7 @@ pragma[nomagic] private predicate simpleParameterFlow( ParameterNode p, Node node, DataFlowType t, Configuration config ) { - nodeCand1(node, false, config) and + throughFlowNodeCand(node, config) and p = node and t = getErasedRepr(node.getType()) and exists(ReturnNode ret, ReturnKind kind | @@ -338,21 +385,21 @@ private predicate simpleParameterFlow( not parameterValueFlowsThrough(p, kind, _) ) or - nodeCand1(node, false, unbind(config)) and + throughFlowNodeCand(node, unbind(config)) and exists(Node mid | simpleParameterFlow(p, mid, t, config) and localFlowStep(mid, node, config) and compatibleTypes(t, node.getType()) ) or - nodeCand1(node, false, unbind(config)) and + throughFlowNodeCand(node, unbind(config)) and exists(Node mid | simpleParameterFlow(p, mid, _, config) and additionalLocalFlowStep(mid, node, config) and t = getErasedRepr(node.getType()) ) or - nodeCand1(node, false, unbind(config)) and + throughFlowNodeCand(node, unbind(config)) and exists(Node mid | simpleParameterFlow(p, mid, t, config) and localStoreReadStep(mid, node) and @@ -360,7 +407,7 @@ private predicate simpleParameterFlow( ) or // value flow through a callable - nodeCand1(node, false, unbind(config)) and + throughFlowNodeCand(node, unbind(config)) and exists(Node arg | simpleParameterFlow(p, arg, t, config) and argumentValueFlowsThrough(arg, node, _) and @@ -368,7 +415,7 @@ private predicate simpleParameterFlow( ) or // flow through a callable - nodeCand1(node, false, unbind(config)) and + throughFlowNodeCand(node, unbind(config)) and exists(Node arg | simpleParameterFlow(p, arg, _, config) and simpleArgumentFlowsThrough(arg, node, t, config) @@ -380,6 +427,7 @@ private predicate simpleArgumentFlowsThrough0( DataFlowCall call, ArgumentNode arg, ReturnKind kind, DataFlowType t, Configuration config ) { nodeCand1(arg, false, unbind(config)) and + not outBarrier(arg, config) and exists(ParameterNode p, ReturnNode ret | simpleParameterFlow(p, ret, t, config) and kind = ret.getKind() and @@ -399,6 +447,7 @@ private predicate simpleArgumentFlowsThrough( ) { exists(DataFlowCall call, ReturnKind kind | nodeCand1(out, false, unbind(config)) and + not inBarrier(out, config) and simpleArgumentFlowsThrough0(call, arg, kind, t, config) and out = getAnOutNode(call, kind) ) @@ -440,6 +489,8 @@ private predicate additionalLocalFlowStepOrFlowThroughCallable( private predicate flowOutOfCallable(Node node1, Node node2, Configuration config) { nodeCand1(node1, _, unbind(config)) and nodeCand1(node2, _, config) and + not outBarrier(node1, config) and + not inBarrier(node2, config) and ( // flow out of an argument exists(ParameterNode p | @@ -462,7 +513,9 @@ private predicate flowOutOfCallable(Node node1, Node node2, Configuration config private predicate flowIntoCallable(Node node1, Node node2, Configuration config) { viableParamArg(_, node2, node1) and nodeCand1(node1, _, unbind(config)) and - nodeCand1(node2, _, config) + nodeCand1(node2, _, config) and + not outBarrier(node1, config) and + not inBarrier(node2, config) } /** @@ -546,7 +599,7 @@ private predicate nodeCandFwd2(Node node, boolean fromArg, boolean stored, Confi or exists(Node mid | nodeCandFwd2(mid, _, stored, config) and - jumpStep(mid, node) and + jumpStep(mid, node, config) and fromArg = false ) or @@ -626,7 +679,7 @@ private predicate nodeCand2(Node node, boolean toReturn, boolean stored, Configu ) or exists(Node mid | - jumpStep(node, mid) and + jumpStep(node, mid, config) and nodeCand2(mid, _, stored, config) and toReturn = false ) @@ -714,7 +767,7 @@ private predicate localFlowEntry(Node node, Configuration config) { nodeCand(node, config) and ( config.isSource(node) or - jumpStep(_, node) or + jumpStep(_, node, config) or additionalJumpStep(_, node, config) or node instanceof ParameterNode or node instanceof OutNode or @@ -730,7 +783,7 @@ private predicate localFlowEntry(Node node, Configuration config) { */ private predicate localFlowExit(Node node, Configuration config) { exists(Node next | nodeCand(next, config) | - jumpStep(node, next) or + jumpStep(node, next, config) or additionalJumpStep(node, next, config) or flowIntoCallable(node, next, config) or flowOutOfCallable(node, next, config) or @@ -882,7 +935,7 @@ private predicate flowCandFwd0(Node node, boolean fromArg, AccessPathFront apf, or exists(Node mid | flowCandFwd(mid, _, apf, config) and - jumpStep(mid, node) and + jumpStep(mid, node, config) and fromArg = false ) or @@ -973,7 +1026,7 @@ private predicate flowCand0(Node node, boolean toReturn, AccessPathFront apf, Co ) or exists(Node mid | - jumpStep(node, mid) and + jumpStep(node, mid, config) and flowCand(mid, _, apf, config) and toReturn = false ) @@ -1154,7 +1207,7 @@ private predicate flowFwd0( or exists(Node mid | flowFwd(mid, _, apf, ap, config) and - jumpStep(mid, node) and + jumpStep(mid, node, config) and fromArg = false ) or @@ -1263,7 +1316,7 @@ private predicate flow0(Node node, boolean toReturn, AccessPath ap, Configuratio ) or exists(Node mid | - jumpStep(node, mid) and + jumpStep(node, mid, config) and flow(mid, _, ap, config) and toReturn = false ) @@ -1518,7 +1571,7 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, AccessPat mid.getAp() instanceof AccessPathNil and ap = node.(AccessPathNilNode).getAp() or - jumpStep(mid.getNode(), node) and + jumpStep(mid.getNode(), node, mid.getConfiguration()) and cc instanceof CallContextAny and ap = mid.getAp() or diff --git a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl2.qll b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl2.qll index 5a6de5af0f4..cfe85663344 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl2.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl2.qll @@ -57,8 +57,8 @@ abstract class Configuration extends string { /** Holds if data flow through `node` is prohibited. */ predicate isBarrier(Node node) { none() } - /** Holds if data flow from `node1` to `node2` is prohibited. */ - predicate isBarrierEdge(Node node1, Node node2) { none() } + /** DEPRECATED: override `isBarrier` instead. */ + deprecated predicate isBarrierEdge(Node node1, Node node2) { none() } /** * Holds if the additional flow step from `node1` to `node2` must be taken @@ -103,6 +103,22 @@ abstract class Configuration extends string { deprecated predicate hasFlowBackward(Node source, Node sink) { hasFlow(source, sink) } } +private predicate inBarrier(Node node, Configuration config) { + config.isBarrier(node) and + config.isSource(node) +} + +private predicate outBarrier(Node node, Configuration config) { + config.isBarrier(node) and + config.isSink(node) +} + +private predicate fullBarrier(Node node, Configuration config) { + config.isBarrier(node) and + not config.isSource(node) and + not config.isSink(node) +} + private class AdditionalFlowStepSource extends Node { AdditionalFlowStepSource() { any(Configuration c).isAdditionalFlowStep(this, _) } } @@ -119,22 +135,46 @@ private predicate isAdditionalFlowStep( * Holds if data can flow in one local step from `node1` to `node2`. */ private predicate localFlowStep(Node node1, Node node2, Configuration config) { - localFlowStep(node1, node2) and not config.isBarrierEdge(node1, node2) + localFlowStep(node1, node2) and + not outBarrier(node1, config) and + not inBarrier(node2, config) and + not fullBarrier(node1, config) and + not fullBarrier(node2, config) } /** * Holds if the additional step from `node1` to `node2` does not jump between callables. */ private predicate additionalLocalFlowStep(Node node1, Node node2, Configuration config) { - isAdditionalFlowStep(node1, node2, node2.getEnclosingCallable(), config) + isAdditionalFlowStep(node1, node2, node2.getEnclosingCallable(), config) and + not outBarrier(node1, config) and + not inBarrier(node2, config) and + not fullBarrier(node1, config) and + not fullBarrier(node2, config) +} + +/** + * Holds if data can flow from `node1` to `node2` in a way that discards call contexts. + */ +private predicate jumpStep(Node node1, Node node2, Configuration config) { + jumpStep(node1, node2) and + not outBarrier(node1, config) and + not inBarrier(node2, config) and + not fullBarrier(node1, config) and + not fullBarrier(node2, config) } /** * Holds if the additional step from `node1` to `node2` jumps between callables. */ private predicate additionalJumpStep(Node node1, Node node2, Configuration config) { - exists(DataFlowCallable callable1 | isAdditionalFlowStep(node1, node2, callable1, config) | - node2.getEnclosingCallable() != callable1 + exists(DataFlowCallable callable1 | + isAdditionalFlowStep(node1, node2, callable1, config) and + node2.getEnclosingCallable() != callable1 and + not outBarrier(node1, config) and + not inBarrier(node2, config) and + not fullBarrier(node1, config) and + not fullBarrier(node2, config) ) } @@ -154,7 +194,7 @@ private ReturnPosition viableReturnPos(DataFlowCall call, ReturnKind kind) { * ignoring call contexts. */ private predicate nodeCandFwd1(Node node, boolean stored, Configuration config) { - not config.isBarrier(node) and + not fullBarrier(node, config) and ( config.isSource(node) and stored = false or @@ -171,7 +211,7 @@ private predicate nodeCandFwd1(Node node, boolean stored, Configuration config) or exists(Node mid | nodeCandFwd1(mid, stored, config) and - jumpStep(mid, node) + jumpStep(mid, node, config) ) or exists(Node mid | @@ -185,7 +225,8 @@ private predicate nodeCandFwd1(Node node, boolean stored, Configuration config) useFieldFlow(config) and nodeCandFwd1(mid, _, config) and store(mid, _, node) and - stored = true + stored = true and + not outBarrier(mid, config) ) or // read @@ -193,7 +234,8 @@ private predicate nodeCandFwd1(Node node, boolean stored, Configuration config) nodeCandFwd1(mid, true, config) and read(mid, f, node) and storeCandFwd1(f, unbind(config)) and - (stored = false or stored = true) + (stored = false or stored = true) and + not inBarrier(node, config) ) or // flow into a callable @@ -223,7 +265,7 @@ private predicate nodeCandFwd1(Node node, boolean stored, Configuration config) */ private predicate storeCandFwd1(Content f, Configuration config) { exists(Node mid, Node node | - not config.isBarrier(node) and + not fullBarrier(node, config) and useFieldFlow(config) and nodeCandFwd1(mid, _, config) and store(mid, f, node) @@ -257,7 +299,7 @@ private predicate nodeCand1(Node node, boolean stored, Configuration config) { ) or exists(Node mid | - jumpStep(node, mid) and + jumpStep(node, mid, config) and nodeCand1(mid, stored, config) ) or @@ -318,6 +360,11 @@ private predicate readCand1(Content f, Configuration config) { ) } +private predicate throughFlowNodeCand(Node node, Configuration config) { + nodeCand1(node, false, config) and + not config.isBarrier(node) +} + /** * Holds if there is a path from `p` to `node` in the same callable that is * part of a path from a source to a sink taking simple call contexts into @@ -329,7 +376,7 @@ pragma[nomagic] private predicate simpleParameterFlow( ParameterNode p, Node node, DataFlowType t, Configuration config ) { - nodeCand1(node, false, config) and + throughFlowNodeCand(node, config) and p = node and t = getErasedRepr(node.getType()) and exists(ReturnNode ret, ReturnKind kind | @@ -338,21 +385,21 @@ private predicate simpleParameterFlow( not parameterValueFlowsThrough(p, kind, _) ) or - nodeCand1(node, false, unbind(config)) and + throughFlowNodeCand(node, unbind(config)) and exists(Node mid | simpleParameterFlow(p, mid, t, config) and localFlowStep(mid, node, config) and compatibleTypes(t, node.getType()) ) or - nodeCand1(node, false, unbind(config)) and + throughFlowNodeCand(node, unbind(config)) and exists(Node mid | simpleParameterFlow(p, mid, _, config) and additionalLocalFlowStep(mid, node, config) and t = getErasedRepr(node.getType()) ) or - nodeCand1(node, false, unbind(config)) and + throughFlowNodeCand(node, unbind(config)) and exists(Node mid | simpleParameterFlow(p, mid, t, config) and localStoreReadStep(mid, node) and @@ -360,7 +407,7 @@ private predicate simpleParameterFlow( ) or // value flow through a callable - nodeCand1(node, false, unbind(config)) and + throughFlowNodeCand(node, unbind(config)) and exists(Node arg | simpleParameterFlow(p, arg, t, config) and argumentValueFlowsThrough(arg, node, _) and @@ -368,7 +415,7 @@ private predicate simpleParameterFlow( ) or // flow through a callable - nodeCand1(node, false, unbind(config)) and + throughFlowNodeCand(node, unbind(config)) and exists(Node arg | simpleParameterFlow(p, arg, _, config) and simpleArgumentFlowsThrough(arg, node, t, config) @@ -380,6 +427,7 @@ private predicate simpleArgumentFlowsThrough0( DataFlowCall call, ArgumentNode arg, ReturnKind kind, DataFlowType t, Configuration config ) { nodeCand1(arg, false, unbind(config)) and + not outBarrier(arg, config) and exists(ParameterNode p, ReturnNode ret | simpleParameterFlow(p, ret, t, config) and kind = ret.getKind() and @@ -399,6 +447,7 @@ private predicate simpleArgumentFlowsThrough( ) { exists(DataFlowCall call, ReturnKind kind | nodeCand1(out, false, unbind(config)) and + not inBarrier(out, config) and simpleArgumentFlowsThrough0(call, arg, kind, t, config) and out = getAnOutNode(call, kind) ) @@ -440,6 +489,8 @@ private predicate additionalLocalFlowStepOrFlowThroughCallable( private predicate flowOutOfCallable(Node node1, Node node2, Configuration config) { nodeCand1(node1, _, unbind(config)) and nodeCand1(node2, _, config) and + not outBarrier(node1, config) and + not inBarrier(node2, config) and ( // flow out of an argument exists(ParameterNode p | @@ -462,7 +513,9 @@ private predicate flowOutOfCallable(Node node1, Node node2, Configuration config private predicate flowIntoCallable(Node node1, Node node2, Configuration config) { viableParamArg(_, node2, node1) and nodeCand1(node1, _, unbind(config)) and - nodeCand1(node2, _, config) + nodeCand1(node2, _, config) and + not outBarrier(node1, config) and + not inBarrier(node2, config) } /** @@ -546,7 +599,7 @@ private predicate nodeCandFwd2(Node node, boolean fromArg, boolean stored, Confi or exists(Node mid | nodeCandFwd2(mid, _, stored, config) and - jumpStep(mid, node) and + jumpStep(mid, node, config) and fromArg = false ) or @@ -626,7 +679,7 @@ private predicate nodeCand2(Node node, boolean toReturn, boolean stored, Configu ) or exists(Node mid | - jumpStep(node, mid) and + jumpStep(node, mid, config) and nodeCand2(mid, _, stored, config) and toReturn = false ) @@ -714,7 +767,7 @@ private predicate localFlowEntry(Node node, Configuration config) { nodeCand(node, config) and ( config.isSource(node) or - jumpStep(_, node) or + jumpStep(_, node, config) or additionalJumpStep(_, node, config) or node instanceof ParameterNode or node instanceof OutNode or @@ -730,7 +783,7 @@ private predicate localFlowEntry(Node node, Configuration config) { */ private predicate localFlowExit(Node node, Configuration config) { exists(Node next | nodeCand(next, config) | - jumpStep(node, next) or + jumpStep(node, next, config) or additionalJumpStep(node, next, config) or flowIntoCallable(node, next, config) or flowOutOfCallable(node, next, config) or @@ -882,7 +935,7 @@ private predicate flowCandFwd0(Node node, boolean fromArg, AccessPathFront apf, or exists(Node mid | flowCandFwd(mid, _, apf, config) and - jumpStep(mid, node) and + jumpStep(mid, node, config) and fromArg = false ) or @@ -973,7 +1026,7 @@ private predicate flowCand0(Node node, boolean toReturn, AccessPathFront apf, Co ) or exists(Node mid | - jumpStep(node, mid) and + jumpStep(node, mid, config) and flowCand(mid, _, apf, config) and toReturn = false ) @@ -1154,7 +1207,7 @@ private predicate flowFwd0( or exists(Node mid | flowFwd(mid, _, apf, ap, config) and - jumpStep(mid, node) and + jumpStep(mid, node, config) and fromArg = false ) or @@ -1263,7 +1316,7 @@ private predicate flow0(Node node, boolean toReturn, AccessPath ap, Configuratio ) or exists(Node mid | - jumpStep(node, mid) and + jumpStep(node, mid, config) and flow(mid, _, ap, config) and toReturn = false ) @@ -1518,7 +1571,7 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, AccessPat mid.getAp() instanceof AccessPathNil and ap = node.(AccessPathNilNode).getAp() or - jumpStep(mid.getNode(), node) and + jumpStep(mid.getNode(), node, mid.getConfiguration()) and cc instanceof CallContextAny and ap = mid.getAp() or diff --git a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl3.qll b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl3.qll index 5a6de5af0f4..cfe85663344 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl3.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl3.qll @@ -57,8 +57,8 @@ abstract class Configuration extends string { /** Holds if data flow through `node` is prohibited. */ predicate isBarrier(Node node) { none() } - /** Holds if data flow from `node1` to `node2` is prohibited. */ - predicate isBarrierEdge(Node node1, Node node2) { none() } + /** DEPRECATED: override `isBarrier` instead. */ + deprecated predicate isBarrierEdge(Node node1, Node node2) { none() } /** * Holds if the additional flow step from `node1` to `node2` must be taken @@ -103,6 +103,22 @@ abstract class Configuration extends string { deprecated predicate hasFlowBackward(Node source, Node sink) { hasFlow(source, sink) } } +private predicate inBarrier(Node node, Configuration config) { + config.isBarrier(node) and + config.isSource(node) +} + +private predicate outBarrier(Node node, Configuration config) { + config.isBarrier(node) and + config.isSink(node) +} + +private predicate fullBarrier(Node node, Configuration config) { + config.isBarrier(node) and + not config.isSource(node) and + not config.isSink(node) +} + private class AdditionalFlowStepSource extends Node { AdditionalFlowStepSource() { any(Configuration c).isAdditionalFlowStep(this, _) } } @@ -119,22 +135,46 @@ private predicate isAdditionalFlowStep( * Holds if data can flow in one local step from `node1` to `node2`. */ private predicate localFlowStep(Node node1, Node node2, Configuration config) { - localFlowStep(node1, node2) and not config.isBarrierEdge(node1, node2) + localFlowStep(node1, node2) and + not outBarrier(node1, config) and + not inBarrier(node2, config) and + not fullBarrier(node1, config) and + not fullBarrier(node2, config) } /** * Holds if the additional step from `node1` to `node2` does not jump between callables. */ private predicate additionalLocalFlowStep(Node node1, Node node2, Configuration config) { - isAdditionalFlowStep(node1, node2, node2.getEnclosingCallable(), config) + isAdditionalFlowStep(node1, node2, node2.getEnclosingCallable(), config) and + not outBarrier(node1, config) and + not inBarrier(node2, config) and + not fullBarrier(node1, config) and + not fullBarrier(node2, config) +} + +/** + * Holds if data can flow from `node1` to `node2` in a way that discards call contexts. + */ +private predicate jumpStep(Node node1, Node node2, Configuration config) { + jumpStep(node1, node2) and + not outBarrier(node1, config) and + not inBarrier(node2, config) and + not fullBarrier(node1, config) and + not fullBarrier(node2, config) } /** * Holds if the additional step from `node1` to `node2` jumps between callables. */ private predicate additionalJumpStep(Node node1, Node node2, Configuration config) { - exists(DataFlowCallable callable1 | isAdditionalFlowStep(node1, node2, callable1, config) | - node2.getEnclosingCallable() != callable1 + exists(DataFlowCallable callable1 | + isAdditionalFlowStep(node1, node2, callable1, config) and + node2.getEnclosingCallable() != callable1 and + not outBarrier(node1, config) and + not inBarrier(node2, config) and + not fullBarrier(node1, config) and + not fullBarrier(node2, config) ) } @@ -154,7 +194,7 @@ private ReturnPosition viableReturnPos(DataFlowCall call, ReturnKind kind) { * ignoring call contexts. */ private predicate nodeCandFwd1(Node node, boolean stored, Configuration config) { - not config.isBarrier(node) and + not fullBarrier(node, config) and ( config.isSource(node) and stored = false or @@ -171,7 +211,7 @@ private predicate nodeCandFwd1(Node node, boolean stored, Configuration config) or exists(Node mid | nodeCandFwd1(mid, stored, config) and - jumpStep(mid, node) + jumpStep(mid, node, config) ) or exists(Node mid | @@ -185,7 +225,8 @@ private predicate nodeCandFwd1(Node node, boolean stored, Configuration config) useFieldFlow(config) and nodeCandFwd1(mid, _, config) and store(mid, _, node) and - stored = true + stored = true and + not outBarrier(mid, config) ) or // read @@ -193,7 +234,8 @@ private predicate nodeCandFwd1(Node node, boolean stored, Configuration config) nodeCandFwd1(mid, true, config) and read(mid, f, node) and storeCandFwd1(f, unbind(config)) and - (stored = false or stored = true) + (stored = false or stored = true) and + not inBarrier(node, config) ) or // flow into a callable @@ -223,7 +265,7 @@ private predicate nodeCandFwd1(Node node, boolean stored, Configuration config) */ private predicate storeCandFwd1(Content f, Configuration config) { exists(Node mid, Node node | - not config.isBarrier(node) and + not fullBarrier(node, config) and useFieldFlow(config) and nodeCandFwd1(mid, _, config) and store(mid, f, node) @@ -257,7 +299,7 @@ private predicate nodeCand1(Node node, boolean stored, Configuration config) { ) or exists(Node mid | - jumpStep(node, mid) and + jumpStep(node, mid, config) and nodeCand1(mid, stored, config) ) or @@ -318,6 +360,11 @@ private predicate readCand1(Content f, Configuration config) { ) } +private predicate throughFlowNodeCand(Node node, Configuration config) { + nodeCand1(node, false, config) and + not config.isBarrier(node) +} + /** * Holds if there is a path from `p` to `node` in the same callable that is * part of a path from a source to a sink taking simple call contexts into @@ -329,7 +376,7 @@ pragma[nomagic] private predicate simpleParameterFlow( ParameterNode p, Node node, DataFlowType t, Configuration config ) { - nodeCand1(node, false, config) and + throughFlowNodeCand(node, config) and p = node and t = getErasedRepr(node.getType()) and exists(ReturnNode ret, ReturnKind kind | @@ -338,21 +385,21 @@ private predicate simpleParameterFlow( not parameterValueFlowsThrough(p, kind, _) ) or - nodeCand1(node, false, unbind(config)) and + throughFlowNodeCand(node, unbind(config)) and exists(Node mid | simpleParameterFlow(p, mid, t, config) and localFlowStep(mid, node, config) and compatibleTypes(t, node.getType()) ) or - nodeCand1(node, false, unbind(config)) and + throughFlowNodeCand(node, unbind(config)) and exists(Node mid | simpleParameterFlow(p, mid, _, config) and additionalLocalFlowStep(mid, node, config) and t = getErasedRepr(node.getType()) ) or - nodeCand1(node, false, unbind(config)) and + throughFlowNodeCand(node, unbind(config)) and exists(Node mid | simpleParameterFlow(p, mid, t, config) and localStoreReadStep(mid, node) and @@ -360,7 +407,7 @@ private predicate simpleParameterFlow( ) or // value flow through a callable - nodeCand1(node, false, unbind(config)) and + throughFlowNodeCand(node, unbind(config)) and exists(Node arg | simpleParameterFlow(p, arg, t, config) and argumentValueFlowsThrough(arg, node, _) and @@ -368,7 +415,7 @@ private predicate simpleParameterFlow( ) or // flow through a callable - nodeCand1(node, false, unbind(config)) and + throughFlowNodeCand(node, unbind(config)) and exists(Node arg | simpleParameterFlow(p, arg, _, config) and simpleArgumentFlowsThrough(arg, node, t, config) @@ -380,6 +427,7 @@ private predicate simpleArgumentFlowsThrough0( DataFlowCall call, ArgumentNode arg, ReturnKind kind, DataFlowType t, Configuration config ) { nodeCand1(arg, false, unbind(config)) and + not outBarrier(arg, config) and exists(ParameterNode p, ReturnNode ret | simpleParameterFlow(p, ret, t, config) and kind = ret.getKind() and @@ -399,6 +447,7 @@ private predicate simpleArgumentFlowsThrough( ) { exists(DataFlowCall call, ReturnKind kind | nodeCand1(out, false, unbind(config)) and + not inBarrier(out, config) and simpleArgumentFlowsThrough0(call, arg, kind, t, config) and out = getAnOutNode(call, kind) ) @@ -440,6 +489,8 @@ private predicate additionalLocalFlowStepOrFlowThroughCallable( private predicate flowOutOfCallable(Node node1, Node node2, Configuration config) { nodeCand1(node1, _, unbind(config)) and nodeCand1(node2, _, config) and + not outBarrier(node1, config) and + not inBarrier(node2, config) and ( // flow out of an argument exists(ParameterNode p | @@ -462,7 +513,9 @@ private predicate flowOutOfCallable(Node node1, Node node2, Configuration config private predicate flowIntoCallable(Node node1, Node node2, Configuration config) { viableParamArg(_, node2, node1) and nodeCand1(node1, _, unbind(config)) and - nodeCand1(node2, _, config) + nodeCand1(node2, _, config) and + not outBarrier(node1, config) and + not inBarrier(node2, config) } /** @@ -546,7 +599,7 @@ private predicate nodeCandFwd2(Node node, boolean fromArg, boolean stored, Confi or exists(Node mid | nodeCandFwd2(mid, _, stored, config) and - jumpStep(mid, node) and + jumpStep(mid, node, config) and fromArg = false ) or @@ -626,7 +679,7 @@ private predicate nodeCand2(Node node, boolean toReturn, boolean stored, Configu ) or exists(Node mid | - jumpStep(node, mid) and + jumpStep(node, mid, config) and nodeCand2(mid, _, stored, config) and toReturn = false ) @@ -714,7 +767,7 @@ private predicate localFlowEntry(Node node, Configuration config) { nodeCand(node, config) and ( config.isSource(node) or - jumpStep(_, node) or + jumpStep(_, node, config) or additionalJumpStep(_, node, config) or node instanceof ParameterNode or node instanceof OutNode or @@ -730,7 +783,7 @@ private predicate localFlowEntry(Node node, Configuration config) { */ private predicate localFlowExit(Node node, Configuration config) { exists(Node next | nodeCand(next, config) | - jumpStep(node, next) or + jumpStep(node, next, config) or additionalJumpStep(node, next, config) or flowIntoCallable(node, next, config) or flowOutOfCallable(node, next, config) or @@ -882,7 +935,7 @@ private predicate flowCandFwd0(Node node, boolean fromArg, AccessPathFront apf, or exists(Node mid | flowCandFwd(mid, _, apf, config) and - jumpStep(mid, node) and + jumpStep(mid, node, config) and fromArg = false ) or @@ -973,7 +1026,7 @@ private predicate flowCand0(Node node, boolean toReturn, AccessPathFront apf, Co ) or exists(Node mid | - jumpStep(node, mid) and + jumpStep(node, mid, config) and flowCand(mid, _, apf, config) and toReturn = false ) @@ -1154,7 +1207,7 @@ private predicate flowFwd0( or exists(Node mid | flowFwd(mid, _, apf, ap, config) and - jumpStep(mid, node) and + jumpStep(mid, node, config) and fromArg = false ) or @@ -1263,7 +1316,7 @@ private predicate flow0(Node node, boolean toReturn, AccessPath ap, Configuratio ) or exists(Node mid | - jumpStep(node, mid) and + jumpStep(node, mid, config) and flow(mid, _, ap, config) and toReturn = false ) @@ -1518,7 +1571,7 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, AccessPat mid.getAp() instanceof AccessPathNil and ap = node.(AccessPathNilNode).getAp() or - jumpStep(mid.getNode(), node) and + jumpStep(mid.getNode(), node, mid.getConfiguration()) and cc instanceof CallContextAny and ap = mid.getAp() or diff --git a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl4.qll b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl4.qll index 5a6de5af0f4..cfe85663344 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl4.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl4.qll @@ -57,8 +57,8 @@ abstract class Configuration extends string { /** Holds if data flow through `node` is prohibited. */ predicate isBarrier(Node node) { none() } - /** Holds if data flow from `node1` to `node2` is prohibited. */ - predicate isBarrierEdge(Node node1, Node node2) { none() } + /** DEPRECATED: override `isBarrier` instead. */ + deprecated predicate isBarrierEdge(Node node1, Node node2) { none() } /** * Holds if the additional flow step from `node1` to `node2` must be taken @@ -103,6 +103,22 @@ abstract class Configuration extends string { deprecated predicate hasFlowBackward(Node source, Node sink) { hasFlow(source, sink) } } +private predicate inBarrier(Node node, Configuration config) { + config.isBarrier(node) and + config.isSource(node) +} + +private predicate outBarrier(Node node, Configuration config) { + config.isBarrier(node) and + config.isSink(node) +} + +private predicate fullBarrier(Node node, Configuration config) { + config.isBarrier(node) and + not config.isSource(node) and + not config.isSink(node) +} + private class AdditionalFlowStepSource extends Node { AdditionalFlowStepSource() { any(Configuration c).isAdditionalFlowStep(this, _) } } @@ -119,22 +135,46 @@ private predicate isAdditionalFlowStep( * Holds if data can flow in one local step from `node1` to `node2`. */ private predicate localFlowStep(Node node1, Node node2, Configuration config) { - localFlowStep(node1, node2) and not config.isBarrierEdge(node1, node2) + localFlowStep(node1, node2) and + not outBarrier(node1, config) and + not inBarrier(node2, config) and + not fullBarrier(node1, config) and + not fullBarrier(node2, config) } /** * Holds if the additional step from `node1` to `node2` does not jump between callables. */ private predicate additionalLocalFlowStep(Node node1, Node node2, Configuration config) { - isAdditionalFlowStep(node1, node2, node2.getEnclosingCallable(), config) + isAdditionalFlowStep(node1, node2, node2.getEnclosingCallable(), config) and + not outBarrier(node1, config) and + not inBarrier(node2, config) and + not fullBarrier(node1, config) and + not fullBarrier(node2, config) +} + +/** + * Holds if data can flow from `node1` to `node2` in a way that discards call contexts. + */ +private predicate jumpStep(Node node1, Node node2, Configuration config) { + jumpStep(node1, node2) and + not outBarrier(node1, config) and + not inBarrier(node2, config) and + not fullBarrier(node1, config) and + not fullBarrier(node2, config) } /** * Holds if the additional step from `node1` to `node2` jumps between callables. */ private predicate additionalJumpStep(Node node1, Node node2, Configuration config) { - exists(DataFlowCallable callable1 | isAdditionalFlowStep(node1, node2, callable1, config) | - node2.getEnclosingCallable() != callable1 + exists(DataFlowCallable callable1 | + isAdditionalFlowStep(node1, node2, callable1, config) and + node2.getEnclosingCallable() != callable1 and + not outBarrier(node1, config) and + not inBarrier(node2, config) and + not fullBarrier(node1, config) and + not fullBarrier(node2, config) ) } @@ -154,7 +194,7 @@ private ReturnPosition viableReturnPos(DataFlowCall call, ReturnKind kind) { * ignoring call contexts. */ private predicate nodeCandFwd1(Node node, boolean stored, Configuration config) { - not config.isBarrier(node) and + not fullBarrier(node, config) and ( config.isSource(node) and stored = false or @@ -171,7 +211,7 @@ private predicate nodeCandFwd1(Node node, boolean stored, Configuration config) or exists(Node mid | nodeCandFwd1(mid, stored, config) and - jumpStep(mid, node) + jumpStep(mid, node, config) ) or exists(Node mid | @@ -185,7 +225,8 @@ private predicate nodeCandFwd1(Node node, boolean stored, Configuration config) useFieldFlow(config) and nodeCandFwd1(mid, _, config) and store(mid, _, node) and - stored = true + stored = true and + not outBarrier(mid, config) ) or // read @@ -193,7 +234,8 @@ private predicate nodeCandFwd1(Node node, boolean stored, Configuration config) nodeCandFwd1(mid, true, config) and read(mid, f, node) and storeCandFwd1(f, unbind(config)) and - (stored = false or stored = true) + (stored = false or stored = true) and + not inBarrier(node, config) ) or // flow into a callable @@ -223,7 +265,7 @@ private predicate nodeCandFwd1(Node node, boolean stored, Configuration config) */ private predicate storeCandFwd1(Content f, Configuration config) { exists(Node mid, Node node | - not config.isBarrier(node) and + not fullBarrier(node, config) and useFieldFlow(config) and nodeCandFwd1(mid, _, config) and store(mid, f, node) @@ -257,7 +299,7 @@ private predicate nodeCand1(Node node, boolean stored, Configuration config) { ) or exists(Node mid | - jumpStep(node, mid) and + jumpStep(node, mid, config) and nodeCand1(mid, stored, config) ) or @@ -318,6 +360,11 @@ private predicate readCand1(Content f, Configuration config) { ) } +private predicate throughFlowNodeCand(Node node, Configuration config) { + nodeCand1(node, false, config) and + not config.isBarrier(node) +} + /** * Holds if there is a path from `p` to `node` in the same callable that is * part of a path from a source to a sink taking simple call contexts into @@ -329,7 +376,7 @@ pragma[nomagic] private predicate simpleParameterFlow( ParameterNode p, Node node, DataFlowType t, Configuration config ) { - nodeCand1(node, false, config) and + throughFlowNodeCand(node, config) and p = node and t = getErasedRepr(node.getType()) and exists(ReturnNode ret, ReturnKind kind | @@ -338,21 +385,21 @@ private predicate simpleParameterFlow( not parameterValueFlowsThrough(p, kind, _) ) or - nodeCand1(node, false, unbind(config)) and + throughFlowNodeCand(node, unbind(config)) and exists(Node mid | simpleParameterFlow(p, mid, t, config) and localFlowStep(mid, node, config) and compatibleTypes(t, node.getType()) ) or - nodeCand1(node, false, unbind(config)) and + throughFlowNodeCand(node, unbind(config)) and exists(Node mid | simpleParameterFlow(p, mid, _, config) and additionalLocalFlowStep(mid, node, config) and t = getErasedRepr(node.getType()) ) or - nodeCand1(node, false, unbind(config)) and + throughFlowNodeCand(node, unbind(config)) and exists(Node mid | simpleParameterFlow(p, mid, t, config) and localStoreReadStep(mid, node) and @@ -360,7 +407,7 @@ private predicate simpleParameterFlow( ) or // value flow through a callable - nodeCand1(node, false, unbind(config)) and + throughFlowNodeCand(node, unbind(config)) and exists(Node arg | simpleParameterFlow(p, arg, t, config) and argumentValueFlowsThrough(arg, node, _) and @@ -368,7 +415,7 @@ private predicate simpleParameterFlow( ) or // flow through a callable - nodeCand1(node, false, unbind(config)) and + throughFlowNodeCand(node, unbind(config)) and exists(Node arg | simpleParameterFlow(p, arg, _, config) and simpleArgumentFlowsThrough(arg, node, t, config) @@ -380,6 +427,7 @@ private predicate simpleArgumentFlowsThrough0( DataFlowCall call, ArgumentNode arg, ReturnKind kind, DataFlowType t, Configuration config ) { nodeCand1(arg, false, unbind(config)) and + not outBarrier(arg, config) and exists(ParameterNode p, ReturnNode ret | simpleParameterFlow(p, ret, t, config) and kind = ret.getKind() and @@ -399,6 +447,7 @@ private predicate simpleArgumentFlowsThrough( ) { exists(DataFlowCall call, ReturnKind kind | nodeCand1(out, false, unbind(config)) and + not inBarrier(out, config) and simpleArgumentFlowsThrough0(call, arg, kind, t, config) and out = getAnOutNode(call, kind) ) @@ -440,6 +489,8 @@ private predicate additionalLocalFlowStepOrFlowThroughCallable( private predicate flowOutOfCallable(Node node1, Node node2, Configuration config) { nodeCand1(node1, _, unbind(config)) and nodeCand1(node2, _, config) and + not outBarrier(node1, config) and + not inBarrier(node2, config) and ( // flow out of an argument exists(ParameterNode p | @@ -462,7 +513,9 @@ private predicate flowOutOfCallable(Node node1, Node node2, Configuration config private predicate flowIntoCallable(Node node1, Node node2, Configuration config) { viableParamArg(_, node2, node1) and nodeCand1(node1, _, unbind(config)) and - nodeCand1(node2, _, config) + nodeCand1(node2, _, config) and + not outBarrier(node1, config) and + not inBarrier(node2, config) } /** @@ -546,7 +599,7 @@ private predicate nodeCandFwd2(Node node, boolean fromArg, boolean stored, Confi or exists(Node mid | nodeCandFwd2(mid, _, stored, config) and - jumpStep(mid, node) and + jumpStep(mid, node, config) and fromArg = false ) or @@ -626,7 +679,7 @@ private predicate nodeCand2(Node node, boolean toReturn, boolean stored, Configu ) or exists(Node mid | - jumpStep(node, mid) and + jumpStep(node, mid, config) and nodeCand2(mid, _, stored, config) and toReturn = false ) @@ -714,7 +767,7 @@ private predicate localFlowEntry(Node node, Configuration config) { nodeCand(node, config) and ( config.isSource(node) or - jumpStep(_, node) or + jumpStep(_, node, config) or additionalJumpStep(_, node, config) or node instanceof ParameterNode or node instanceof OutNode or @@ -730,7 +783,7 @@ private predicate localFlowEntry(Node node, Configuration config) { */ private predicate localFlowExit(Node node, Configuration config) { exists(Node next | nodeCand(next, config) | - jumpStep(node, next) or + jumpStep(node, next, config) or additionalJumpStep(node, next, config) or flowIntoCallable(node, next, config) or flowOutOfCallable(node, next, config) or @@ -882,7 +935,7 @@ private predicate flowCandFwd0(Node node, boolean fromArg, AccessPathFront apf, or exists(Node mid | flowCandFwd(mid, _, apf, config) and - jumpStep(mid, node) and + jumpStep(mid, node, config) and fromArg = false ) or @@ -973,7 +1026,7 @@ private predicate flowCand0(Node node, boolean toReturn, AccessPathFront apf, Co ) or exists(Node mid | - jumpStep(node, mid) and + jumpStep(node, mid, config) and flowCand(mid, _, apf, config) and toReturn = false ) @@ -1154,7 +1207,7 @@ private predicate flowFwd0( or exists(Node mid | flowFwd(mid, _, apf, ap, config) and - jumpStep(mid, node) and + jumpStep(mid, node, config) and fromArg = false ) or @@ -1263,7 +1316,7 @@ private predicate flow0(Node node, boolean toReturn, AccessPath ap, Configuratio ) or exists(Node mid | - jumpStep(node, mid) and + jumpStep(node, mid, config) and flow(mid, _, ap, config) and toReturn = false ) @@ -1518,7 +1571,7 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, AccessPat mid.getAp() instanceof AccessPathNil and ap = node.(AccessPathNilNode).getAp() or - jumpStep(mid.getNode(), node) and + jumpStep(mid.getNode(), node, mid.getConfiguration()) and cc instanceof CallContextAny and ap = mid.getAp() or diff --git a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl5.qll b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl5.qll index 5a6de5af0f4..cfe85663344 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl5.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl5.qll @@ -57,8 +57,8 @@ abstract class Configuration extends string { /** Holds if data flow through `node` is prohibited. */ predicate isBarrier(Node node) { none() } - /** Holds if data flow from `node1` to `node2` is prohibited. */ - predicate isBarrierEdge(Node node1, Node node2) { none() } + /** DEPRECATED: override `isBarrier` instead. */ + deprecated predicate isBarrierEdge(Node node1, Node node2) { none() } /** * Holds if the additional flow step from `node1` to `node2` must be taken @@ -103,6 +103,22 @@ abstract class Configuration extends string { deprecated predicate hasFlowBackward(Node source, Node sink) { hasFlow(source, sink) } } +private predicate inBarrier(Node node, Configuration config) { + config.isBarrier(node) and + config.isSource(node) +} + +private predicate outBarrier(Node node, Configuration config) { + config.isBarrier(node) and + config.isSink(node) +} + +private predicate fullBarrier(Node node, Configuration config) { + config.isBarrier(node) and + not config.isSource(node) and + not config.isSink(node) +} + private class AdditionalFlowStepSource extends Node { AdditionalFlowStepSource() { any(Configuration c).isAdditionalFlowStep(this, _) } } @@ -119,22 +135,46 @@ private predicate isAdditionalFlowStep( * Holds if data can flow in one local step from `node1` to `node2`. */ private predicate localFlowStep(Node node1, Node node2, Configuration config) { - localFlowStep(node1, node2) and not config.isBarrierEdge(node1, node2) + localFlowStep(node1, node2) and + not outBarrier(node1, config) and + not inBarrier(node2, config) and + not fullBarrier(node1, config) and + not fullBarrier(node2, config) } /** * Holds if the additional step from `node1` to `node2` does not jump between callables. */ private predicate additionalLocalFlowStep(Node node1, Node node2, Configuration config) { - isAdditionalFlowStep(node1, node2, node2.getEnclosingCallable(), config) + isAdditionalFlowStep(node1, node2, node2.getEnclosingCallable(), config) and + not outBarrier(node1, config) and + not inBarrier(node2, config) and + not fullBarrier(node1, config) and + not fullBarrier(node2, config) +} + +/** + * Holds if data can flow from `node1` to `node2` in a way that discards call contexts. + */ +private predicate jumpStep(Node node1, Node node2, Configuration config) { + jumpStep(node1, node2) and + not outBarrier(node1, config) and + not inBarrier(node2, config) and + not fullBarrier(node1, config) and + not fullBarrier(node2, config) } /** * Holds if the additional step from `node1` to `node2` jumps between callables. */ private predicate additionalJumpStep(Node node1, Node node2, Configuration config) { - exists(DataFlowCallable callable1 | isAdditionalFlowStep(node1, node2, callable1, config) | - node2.getEnclosingCallable() != callable1 + exists(DataFlowCallable callable1 | + isAdditionalFlowStep(node1, node2, callable1, config) and + node2.getEnclosingCallable() != callable1 and + not outBarrier(node1, config) and + not inBarrier(node2, config) and + not fullBarrier(node1, config) and + not fullBarrier(node2, config) ) } @@ -154,7 +194,7 @@ private ReturnPosition viableReturnPos(DataFlowCall call, ReturnKind kind) { * ignoring call contexts. */ private predicate nodeCandFwd1(Node node, boolean stored, Configuration config) { - not config.isBarrier(node) and + not fullBarrier(node, config) and ( config.isSource(node) and stored = false or @@ -171,7 +211,7 @@ private predicate nodeCandFwd1(Node node, boolean stored, Configuration config) or exists(Node mid | nodeCandFwd1(mid, stored, config) and - jumpStep(mid, node) + jumpStep(mid, node, config) ) or exists(Node mid | @@ -185,7 +225,8 @@ private predicate nodeCandFwd1(Node node, boolean stored, Configuration config) useFieldFlow(config) and nodeCandFwd1(mid, _, config) and store(mid, _, node) and - stored = true + stored = true and + not outBarrier(mid, config) ) or // read @@ -193,7 +234,8 @@ private predicate nodeCandFwd1(Node node, boolean stored, Configuration config) nodeCandFwd1(mid, true, config) and read(mid, f, node) and storeCandFwd1(f, unbind(config)) and - (stored = false or stored = true) + (stored = false or stored = true) and + not inBarrier(node, config) ) or // flow into a callable @@ -223,7 +265,7 @@ private predicate nodeCandFwd1(Node node, boolean stored, Configuration config) */ private predicate storeCandFwd1(Content f, Configuration config) { exists(Node mid, Node node | - not config.isBarrier(node) and + not fullBarrier(node, config) and useFieldFlow(config) and nodeCandFwd1(mid, _, config) and store(mid, f, node) @@ -257,7 +299,7 @@ private predicate nodeCand1(Node node, boolean stored, Configuration config) { ) or exists(Node mid | - jumpStep(node, mid) and + jumpStep(node, mid, config) and nodeCand1(mid, stored, config) ) or @@ -318,6 +360,11 @@ private predicate readCand1(Content f, Configuration config) { ) } +private predicate throughFlowNodeCand(Node node, Configuration config) { + nodeCand1(node, false, config) and + not config.isBarrier(node) +} + /** * Holds if there is a path from `p` to `node` in the same callable that is * part of a path from a source to a sink taking simple call contexts into @@ -329,7 +376,7 @@ pragma[nomagic] private predicate simpleParameterFlow( ParameterNode p, Node node, DataFlowType t, Configuration config ) { - nodeCand1(node, false, config) and + throughFlowNodeCand(node, config) and p = node and t = getErasedRepr(node.getType()) and exists(ReturnNode ret, ReturnKind kind | @@ -338,21 +385,21 @@ private predicate simpleParameterFlow( not parameterValueFlowsThrough(p, kind, _) ) or - nodeCand1(node, false, unbind(config)) and + throughFlowNodeCand(node, unbind(config)) and exists(Node mid | simpleParameterFlow(p, mid, t, config) and localFlowStep(mid, node, config) and compatibleTypes(t, node.getType()) ) or - nodeCand1(node, false, unbind(config)) and + throughFlowNodeCand(node, unbind(config)) and exists(Node mid | simpleParameterFlow(p, mid, _, config) and additionalLocalFlowStep(mid, node, config) and t = getErasedRepr(node.getType()) ) or - nodeCand1(node, false, unbind(config)) and + throughFlowNodeCand(node, unbind(config)) and exists(Node mid | simpleParameterFlow(p, mid, t, config) and localStoreReadStep(mid, node) and @@ -360,7 +407,7 @@ private predicate simpleParameterFlow( ) or // value flow through a callable - nodeCand1(node, false, unbind(config)) and + throughFlowNodeCand(node, unbind(config)) and exists(Node arg | simpleParameterFlow(p, arg, t, config) and argumentValueFlowsThrough(arg, node, _) and @@ -368,7 +415,7 @@ private predicate simpleParameterFlow( ) or // flow through a callable - nodeCand1(node, false, unbind(config)) and + throughFlowNodeCand(node, unbind(config)) and exists(Node arg | simpleParameterFlow(p, arg, _, config) and simpleArgumentFlowsThrough(arg, node, t, config) @@ -380,6 +427,7 @@ private predicate simpleArgumentFlowsThrough0( DataFlowCall call, ArgumentNode arg, ReturnKind kind, DataFlowType t, Configuration config ) { nodeCand1(arg, false, unbind(config)) and + not outBarrier(arg, config) and exists(ParameterNode p, ReturnNode ret | simpleParameterFlow(p, ret, t, config) and kind = ret.getKind() and @@ -399,6 +447,7 @@ private predicate simpleArgumentFlowsThrough( ) { exists(DataFlowCall call, ReturnKind kind | nodeCand1(out, false, unbind(config)) and + not inBarrier(out, config) and simpleArgumentFlowsThrough0(call, arg, kind, t, config) and out = getAnOutNode(call, kind) ) @@ -440,6 +489,8 @@ private predicate additionalLocalFlowStepOrFlowThroughCallable( private predicate flowOutOfCallable(Node node1, Node node2, Configuration config) { nodeCand1(node1, _, unbind(config)) and nodeCand1(node2, _, config) and + not outBarrier(node1, config) and + not inBarrier(node2, config) and ( // flow out of an argument exists(ParameterNode p | @@ -462,7 +513,9 @@ private predicate flowOutOfCallable(Node node1, Node node2, Configuration config private predicate flowIntoCallable(Node node1, Node node2, Configuration config) { viableParamArg(_, node2, node1) and nodeCand1(node1, _, unbind(config)) and - nodeCand1(node2, _, config) + nodeCand1(node2, _, config) and + not outBarrier(node1, config) and + not inBarrier(node2, config) } /** @@ -546,7 +599,7 @@ private predicate nodeCandFwd2(Node node, boolean fromArg, boolean stored, Confi or exists(Node mid | nodeCandFwd2(mid, _, stored, config) and - jumpStep(mid, node) and + jumpStep(mid, node, config) and fromArg = false ) or @@ -626,7 +679,7 @@ private predicate nodeCand2(Node node, boolean toReturn, boolean stored, Configu ) or exists(Node mid | - jumpStep(node, mid) and + jumpStep(node, mid, config) and nodeCand2(mid, _, stored, config) and toReturn = false ) @@ -714,7 +767,7 @@ private predicate localFlowEntry(Node node, Configuration config) { nodeCand(node, config) and ( config.isSource(node) or - jumpStep(_, node) or + jumpStep(_, node, config) or additionalJumpStep(_, node, config) or node instanceof ParameterNode or node instanceof OutNode or @@ -730,7 +783,7 @@ private predicate localFlowEntry(Node node, Configuration config) { */ private predicate localFlowExit(Node node, Configuration config) { exists(Node next | nodeCand(next, config) | - jumpStep(node, next) or + jumpStep(node, next, config) or additionalJumpStep(node, next, config) or flowIntoCallable(node, next, config) or flowOutOfCallable(node, next, config) or @@ -882,7 +935,7 @@ private predicate flowCandFwd0(Node node, boolean fromArg, AccessPathFront apf, or exists(Node mid | flowCandFwd(mid, _, apf, config) and - jumpStep(mid, node) and + jumpStep(mid, node, config) and fromArg = false ) or @@ -973,7 +1026,7 @@ private predicate flowCand0(Node node, boolean toReturn, AccessPathFront apf, Co ) or exists(Node mid | - jumpStep(node, mid) and + jumpStep(node, mid, config) and flowCand(mid, _, apf, config) and toReturn = false ) @@ -1154,7 +1207,7 @@ private predicate flowFwd0( or exists(Node mid | flowFwd(mid, _, apf, ap, config) and - jumpStep(mid, node) and + jumpStep(mid, node, config) and fromArg = false ) or @@ -1263,7 +1316,7 @@ private predicate flow0(Node node, boolean toReturn, AccessPath ap, Configuratio ) or exists(Node mid | - jumpStep(node, mid) and + jumpStep(node, mid, config) and flow(mid, _, ap, config) and toReturn = false ) @@ -1518,7 +1571,7 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, AccessPat mid.getAp() instanceof AccessPathNil and ap = node.(AccessPathNilNode).getAp() or - jumpStep(mid.getNode(), node) and + jumpStep(mid.getNode(), node, mid.getConfiguration()) and cc instanceof CallContextAny and ap = mid.getAp() or From f8804943ee78286c72fbc169cb77e2d49039ae4f Mon Sep 17 00:00:00 2001 From: Anders Schack-Mulligen Date: Mon, 5 Aug 2019 12:05:12 +0200 Subject: [PATCH 4/7] Java: Change in/out barriers to be explicit in the configuration. --- .../CWE-190/ArithmeticWithExtremeValues.ql | 6 ++--- .../code/java/dataflow/TaintTracking.qll | 24 +++++++++++++++++-- .../java/dataflow/internal/DataFlowImpl.qll | 20 ++++++++++++---- .../dataflow/inoutbarriers/test.ql | 8 ++++--- 4 files changed, 45 insertions(+), 13 deletions(-) diff --git a/java/ql/src/Security/CWE/CWE-190/ArithmeticWithExtremeValues.ql b/java/ql/src/Security/CWE/CWE-190/ArithmeticWithExtremeValues.ql index b7a956ec9f1..46818b3efff 100644 --- a/java/ql/src/Security/CWE/CWE-190/ArithmeticWithExtremeValues.ql +++ b/java/ql/src/Security/CWE/CWE-190/ArithmeticWithExtremeValues.ql @@ -40,9 +40,9 @@ class ExtremeSourceFlowConfig extends DataFlow::Configuration { override predicate isSink(DataFlow::Node sink) { sink(_, sink.asExpr()) } - override predicate isBarrier(DataFlow::Node n) { - n.getType() instanceof BooleanType or isSource(n) - } + override predicate isBarrierIn(DataFlow::Node n) { isSource(n) } + + override predicate isBarrier(DataFlow::Node n) { n.getType() instanceof BooleanType } } predicate sink(ArithExpr exp, VarAccess use) { diff --git a/java/ql/src/semmle/code/java/dataflow/TaintTracking.qll b/java/ql/src/semmle/code/java/dataflow/TaintTracking.qll index b2ec74e5efc..d1829c43815 100644 --- a/java/ql/src/semmle/code/java/dataflow/TaintTracking.qll +++ b/java/ql/src/semmle/code/java/dataflow/TaintTracking.qll @@ -63,13 +63,23 @@ module TaintTracking { node.asExpr() instanceof ValidatedVariableAccess } - /** DEPRECATED: override `isSanitizer` instead. */ + /** DEPRECATED: override `isSanitizerIn` and `isSanitizerOut` instead. */ deprecated predicate isSanitizerEdge(DataFlow::Node node1, DataFlow::Node node2) { none() } deprecated final override predicate isBarrierEdge(DataFlow::Node node1, DataFlow::Node node2) { isSanitizerEdge(node1, node2) } + /** Holds if data flow into `node` is prohibited. */ + predicate isSanitizerIn(DataFlow::Node node) { none() } + + final override predicate isBarrierIn(DataFlow::Node node) { isSanitizerIn(node) } + + /** Holds if data flow out of `node` is prohibited. */ + predicate isSanitizerOut(DataFlow::Node node) { none() } + + final override predicate isBarrierOut(DataFlow::Node node) { isSanitizerOut(node) } + /** * Holds if the additional taint propagation step from `node1` to `node2` * must be taken into account in the analysis. @@ -135,13 +145,23 @@ module TaintTracking { node.asExpr() instanceof ValidatedVariableAccess } - /** DEPRECATED: override `isSanitizer` instead. */ + /** DEPRECATED: override `isSanitizerIn` and `isSanitizerOut` instead. */ deprecated predicate isSanitizerEdge(DataFlow::Node node1, DataFlow::Node node2) { none() } deprecated final override predicate isBarrierEdge(DataFlow::Node node1, DataFlow::Node node2) { isSanitizerEdge(node1, node2) } + /** Holds if data flow into `node` is prohibited. */ + predicate isSanitizerIn(DataFlow::Node node) { none() } + + final override predicate isBarrierIn(DataFlow::Node node) { isSanitizerIn(node) } + + /** Holds if data flow out of `node` is prohibited. */ + predicate isSanitizerOut(DataFlow::Node node) { none() } + + final override predicate isBarrierOut(DataFlow::Node node) { isSanitizerOut(node) } + /** * Holds if the additional taint propagation step from `node1` to `node2` * must be taken into account in the analysis. diff --git a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl.qll b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl.qll index cfe85663344..d6dccd45656 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl.qll @@ -57,9 +57,15 @@ abstract class Configuration extends string { /** Holds if data flow through `node` is prohibited. */ predicate isBarrier(Node node) { none() } - /** DEPRECATED: override `isBarrier` instead. */ + /** DEPRECATED: override `isBarrierIn` and `isBarrierOut` instead. */ deprecated predicate isBarrierEdge(Node node1, Node node2) { none() } + /** Holds if data flow into `node` is prohibited. */ + predicate isBarrierIn(Node node) { none() } + + /** Holds if data flow out of `node` is prohibited. */ + predicate isBarrierOut(Node node) { none() } + /** * Holds if the additional flow step from `node1` to `node2` must be taken * into account in the analysis. @@ -104,18 +110,22 @@ abstract class Configuration extends string { } private predicate inBarrier(Node node, Configuration config) { - config.isBarrier(node) and + config.isBarrierIn(node) and config.isSource(node) } private predicate outBarrier(Node node, Configuration config) { - config.isBarrier(node) and + config.isBarrierOut(node) and config.isSink(node) } private predicate fullBarrier(Node node, Configuration config) { - config.isBarrier(node) and - not config.isSource(node) and + config.isBarrier(node) + or + config.isBarrierIn(node) and + not config.isSource(node) + or + config.isBarrierOut(node) and not config.isSink(node) } diff --git a/java/ql/test/library-tests/dataflow/inoutbarriers/test.ql b/java/ql/test/library-tests/dataflow/inoutbarriers/test.ql index 1b21c9efb25..03c1290b172 100644 --- a/java/ql/test/library-tests/dataflow/inoutbarriers/test.ql +++ b/java/ql/test/library-tests/dataflow/inoutbarriers/test.ql @@ -29,7 +29,7 @@ class Conf2 extends Configuration { override predicate isSink(Node n) { sink0(n) } - override predicate isBarrier(Node n) { src0(n) } + override predicate isBarrierIn(Node n) { src0(n) } } class Conf3 extends Configuration { @@ -39,7 +39,7 @@ class Conf3 extends Configuration { override predicate isSink(Node n) { sink0(n) } - override predicate isBarrier(Node n) { sink0(n) } + override predicate isBarrierOut(Node n) { sink0(n) } } class Conf4 extends Configuration { @@ -49,7 +49,9 @@ class Conf4 extends Configuration { override predicate isSink(Node n) { sink0(n) } - override predicate isBarrier(Node n) { src0(n) or sink0(n) } + override predicate isBarrierIn(Node n) { src0(n) } + + override predicate isBarrierOut(Node n) { sink0(n) } } predicate flow(Node src, Node sink, string s) { From 2dc83c539c9406d036a2b69b61a120f1a6591cdc Mon Sep 17 00:00:00 2001 From: Anders Schack-Mulligen Date: Mon, 5 Aug 2019 12:07:32 +0200 Subject: [PATCH 5/7] Java/C++/C#: Sync dataflow. --- .../cpp/dataflow/internal/DataFlowImpl.qll | 20 ++++++++++++++----- .../cpp/dataflow/internal/DataFlowImpl2.qll | 20 ++++++++++++++----- .../cpp/dataflow/internal/DataFlowImpl3.qll | 20 ++++++++++++++----- .../cpp/dataflow/internal/DataFlowImpl4.qll | 20 ++++++++++++++----- .../cpp/ir/dataflow/internal/DataFlowImpl.qll | 20 ++++++++++++++----- .../ir/dataflow/internal/DataFlowImpl2.qll | 20 ++++++++++++++----- .../ir/dataflow/internal/DataFlowImpl3.qll | 20 ++++++++++++++----- .../ir/dataflow/internal/DataFlowImpl4.qll | 20 ++++++++++++++----- .../csharp/dataflow/internal/DataFlowImpl.qll | 20 ++++++++++++++----- .../java/dataflow/internal/DataFlowImpl2.qll | 20 ++++++++++++++----- .../java/dataflow/internal/DataFlowImpl3.qll | 20 ++++++++++++++----- .../java/dataflow/internal/DataFlowImpl4.qll | 20 ++++++++++++++----- .../java/dataflow/internal/DataFlowImpl5.qll | 20 ++++++++++++++----- 13 files changed, 195 insertions(+), 65 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl.qll b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl.qll index cfe85663344..d6dccd45656 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl.qll @@ -57,9 +57,15 @@ abstract class Configuration extends string { /** Holds if data flow through `node` is prohibited. */ predicate isBarrier(Node node) { none() } - /** DEPRECATED: override `isBarrier` instead. */ + /** DEPRECATED: override `isBarrierIn` and `isBarrierOut` instead. */ deprecated predicate isBarrierEdge(Node node1, Node node2) { none() } + /** Holds if data flow into `node` is prohibited. */ + predicate isBarrierIn(Node node) { none() } + + /** Holds if data flow out of `node` is prohibited. */ + predicate isBarrierOut(Node node) { none() } + /** * Holds if the additional flow step from `node1` to `node2` must be taken * into account in the analysis. @@ -104,18 +110,22 @@ abstract class Configuration extends string { } private predicate inBarrier(Node node, Configuration config) { - config.isBarrier(node) and + config.isBarrierIn(node) and config.isSource(node) } private predicate outBarrier(Node node, Configuration config) { - config.isBarrier(node) and + config.isBarrierOut(node) and config.isSink(node) } private predicate fullBarrier(Node node, Configuration config) { - config.isBarrier(node) and - not config.isSource(node) and + config.isBarrier(node) + or + config.isBarrierIn(node) and + not config.isSource(node) + or + config.isBarrierOut(node) and not config.isSink(node) } diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl2.qll b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl2.qll index cfe85663344..d6dccd45656 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl2.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl2.qll @@ -57,9 +57,15 @@ abstract class Configuration extends string { /** Holds if data flow through `node` is prohibited. */ predicate isBarrier(Node node) { none() } - /** DEPRECATED: override `isBarrier` instead. */ + /** DEPRECATED: override `isBarrierIn` and `isBarrierOut` instead. */ deprecated predicate isBarrierEdge(Node node1, Node node2) { none() } + /** Holds if data flow into `node` is prohibited. */ + predicate isBarrierIn(Node node) { none() } + + /** Holds if data flow out of `node` is prohibited. */ + predicate isBarrierOut(Node node) { none() } + /** * Holds if the additional flow step from `node1` to `node2` must be taken * into account in the analysis. @@ -104,18 +110,22 @@ abstract class Configuration extends string { } private predicate inBarrier(Node node, Configuration config) { - config.isBarrier(node) and + config.isBarrierIn(node) and config.isSource(node) } private predicate outBarrier(Node node, Configuration config) { - config.isBarrier(node) and + config.isBarrierOut(node) and config.isSink(node) } private predicate fullBarrier(Node node, Configuration config) { - config.isBarrier(node) and - not config.isSource(node) and + config.isBarrier(node) + or + config.isBarrierIn(node) and + not config.isSource(node) + or + config.isBarrierOut(node) and not config.isSink(node) } diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl3.qll b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl3.qll index cfe85663344..d6dccd45656 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl3.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl3.qll @@ -57,9 +57,15 @@ abstract class Configuration extends string { /** Holds if data flow through `node` is prohibited. */ predicate isBarrier(Node node) { none() } - /** DEPRECATED: override `isBarrier` instead. */ + /** DEPRECATED: override `isBarrierIn` and `isBarrierOut` instead. */ deprecated predicate isBarrierEdge(Node node1, Node node2) { none() } + /** Holds if data flow into `node` is prohibited. */ + predicate isBarrierIn(Node node) { none() } + + /** Holds if data flow out of `node` is prohibited. */ + predicate isBarrierOut(Node node) { none() } + /** * Holds if the additional flow step from `node1` to `node2` must be taken * into account in the analysis. @@ -104,18 +110,22 @@ abstract class Configuration extends string { } private predicate inBarrier(Node node, Configuration config) { - config.isBarrier(node) and + config.isBarrierIn(node) and config.isSource(node) } private predicate outBarrier(Node node, Configuration config) { - config.isBarrier(node) and + config.isBarrierOut(node) and config.isSink(node) } private predicate fullBarrier(Node node, Configuration config) { - config.isBarrier(node) and - not config.isSource(node) and + config.isBarrier(node) + or + config.isBarrierIn(node) and + not config.isSource(node) + or + config.isBarrierOut(node) and not config.isSink(node) } diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl4.qll b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl4.qll index cfe85663344..d6dccd45656 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl4.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl4.qll @@ -57,9 +57,15 @@ abstract class Configuration extends string { /** Holds if data flow through `node` is prohibited. */ predicate isBarrier(Node node) { none() } - /** DEPRECATED: override `isBarrier` instead. */ + /** DEPRECATED: override `isBarrierIn` and `isBarrierOut` instead. */ deprecated predicate isBarrierEdge(Node node1, Node node2) { none() } + /** Holds if data flow into `node` is prohibited. */ + predicate isBarrierIn(Node node) { none() } + + /** Holds if data flow out of `node` is prohibited. */ + predicate isBarrierOut(Node node) { none() } + /** * Holds if the additional flow step from `node1` to `node2` must be taken * into account in the analysis. @@ -104,18 +110,22 @@ abstract class Configuration extends string { } private predicate inBarrier(Node node, Configuration config) { - config.isBarrier(node) and + config.isBarrierIn(node) and config.isSource(node) } private predicate outBarrier(Node node, Configuration config) { - config.isBarrier(node) and + config.isBarrierOut(node) and config.isSink(node) } private predicate fullBarrier(Node node, Configuration config) { - config.isBarrier(node) and - not config.isSource(node) and + config.isBarrier(node) + or + config.isBarrierIn(node) and + not config.isSource(node) + or + config.isBarrierOut(node) and not config.isSink(node) } diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl.qll index cfe85663344..d6dccd45656 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl.qll @@ -57,9 +57,15 @@ abstract class Configuration extends string { /** Holds if data flow through `node` is prohibited. */ predicate isBarrier(Node node) { none() } - /** DEPRECATED: override `isBarrier` instead. */ + /** DEPRECATED: override `isBarrierIn` and `isBarrierOut` instead. */ deprecated predicate isBarrierEdge(Node node1, Node node2) { none() } + /** Holds if data flow into `node` is prohibited. */ + predicate isBarrierIn(Node node) { none() } + + /** Holds if data flow out of `node` is prohibited. */ + predicate isBarrierOut(Node node) { none() } + /** * Holds if the additional flow step from `node1` to `node2` must be taken * into account in the analysis. @@ -104,18 +110,22 @@ abstract class Configuration extends string { } private predicate inBarrier(Node node, Configuration config) { - config.isBarrier(node) and + config.isBarrierIn(node) and config.isSource(node) } private predicate outBarrier(Node node, Configuration config) { - config.isBarrier(node) and + config.isBarrierOut(node) and config.isSink(node) } private predicate fullBarrier(Node node, Configuration config) { - config.isBarrier(node) and - not config.isSource(node) and + config.isBarrier(node) + or + config.isBarrierIn(node) and + not config.isSource(node) + or + config.isBarrierOut(node) and not config.isSink(node) } diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl2.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl2.qll index cfe85663344..d6dccd45656 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl2.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl2.qll @@ -57,9 +57,15 @@ abstract class Configuration extends string { /** Holds if data flow through `node` is prohibited. */ predicate isBarrier(Node node) { none() } - /** DEPRECATED: override `isBarrier` instead. */ + /** DEPRECATED: override `isBarrierIn` and `isBarrierOut` instead. */ deprecated predicate isBarrierEdge(Node node1, Node node2) { none() } + /** Holds if data flow into `node` is prohibited. */ + predicate isBarrierIn(Node node) { none() } + + /** Holds if data flow out of `node` is prohibited. */ + predicate isBarrierOut(Node node) { none() } + /** * Holds if the additional flow step from `node1` to `node2` must be taken * into account in the analysis. @@ -104,18 +110,22 @@ abstract class Configuration extends string { } private predicate inBarrier(Node node, Configuration config) { - config.isBarrier(node) and + config.isBarrierIn(node) and config.isSource(node) } private predicate outBarrier(Node node, Configuration config) { - config.isBarrier(node) and + config.isBarrierOut(node) and config.isSink(node) } private predicate fullBarrier(Node node, Configuration config) { - config.isBarrier(node) and - not config.isSource(node) and + config.isBarrier(node) + or + config.isBarrierIn(node) and + not config.isSource(node) + or + config.isBarrierOut(node) and not config.isSink(node) } diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl3.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl3.qll index cfe85663344..d6dccd45656 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl3.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl3.qll @@ -57,9 +57,15 @@ abstract class Configuration extends string { /** Holds if data flow through `node` is prohibited. */ predicate isBarrier(Node node) { none() } - /** DEPRECATED: override `isBarrier` instead. */ + /** DEPRECATED: override `isBarrierIn` and `isBarrierOut` instead. */ deprecated predicate isBarrierEdge(Node node1, Node node2) { none() } + /** Holds if data flow into `node` is prohibited. */ + predicate isBarrierIn(Node node) { none() } + + /** Holds if data flow out of `node` is prohibited. */ + predicate isBarrierOut(Node node) { none() } + /** * Holds if the additional flow step from `node1` to `node2` must be taken * into account in the analysis. @@ -104,18 +110,22 @@ abstract class Configuration extends string { } private predicate inBarrier(Node node, Configuration config) { - config.isBarrier(node) and + config.isBarrierIn(node) and config.isSource(node) } private predicate outBarrier(Node node, Configuration config) { - config.isBarrier(node) and + config.isBarrierOut(node) and config.isSink(node) } private predicate fullBarrier(Node node, Configuration config) { - config.isBarrier(node) and - not config.isSource(node) and + config.isBarrier(node) + or + config.isBarrierIn(node) and + not config.isSource(node) + or + config.isBarrierOut(node) and not config.isSink(node) } diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl4.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl4.qll index cfe85663344..d6dccd45656 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl4.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl4.qll @@ -57,9 +57,15 @@ abstract class Configuration extends string { /** Holds if data flow through `node` is prohibited. */ predicate isBarrier(Node node) { none() } - /** DEPRECATED: override `isBarrier` instead. */ + /** DEPRECATED: override `isBarrierIn` and `isBarrierOut` instead. */ deprecated predicate isBarrierEdge(Node node1, Node node2) { none() } + /** Holds if data flow into `node` is prohibited. */ + predicate isBarrierIn(Node node) { none() } + + /** Holds if data flow out of `node` is prohibited. */ + predicate isBarrierOut(Node node) { none() } + /** * Holds if the additional flow step from `node1` to `node2` must be taken * into account in the analysis. @@ -104,18 +110,22 @@ abstract class Configuration extends string { } private predicate inBarrier(Node node, Configuration config) { - config.isBarrier(node) and + config.isBarrierIn(node) and config.isSource(node) } private predicate outBarrier(Node node, Configuration config) { - config.isBarrier(node) and + config.isBarrierOut(node) and config.isSink(node) } private predicate fullBarrier(Node node, Configuration config) { - config.isBarrier(node) and - not config.isSource(node) and + config.isBarrier(node) + or + config.isBarrierIn(node) and + not config.isSource(node) + or + config.isBarrierOut(node) and not config.isSink(node) } diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl.qll index cfe85663344..d6dccd45656 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl.qll @@ -57,9 +57,15 @@ abstract class Configuration extends string { /** Holds if data flow through `node` is prohibited. */ predicate isBarrier(Node node) { none() } - /** DEPRECATED: override `isBarrier` instead. */ + /** DEPRECATED: override `isBarrierIn` and `isBarrierOut` instead. */ deprecated predicate isBarrierEdge(Node node1, Node node2) { none() } + /** Holds if data flow into `node` is prohibited. */ + predicate isBarrierIn(Node node) { none() } + + /** Holds if data flow out of `node` is prohibited. */ + predicate isBarrierOut(Node node) { none() } + /** * Holds if the additional flow step from `node1` to `node2` must be taken * into account in the analysis. @@ -104,18 +110,22 @@ abstract class Configuration extends string { } private predicate inBarrier(Node node, Configuration config) { - config.isBarrier(node) and + config.isBarrierIn(node) and config.isSource(node) } private predicate outBarrier(Node node, Configuration config) { - config.isBarrier(node) and + config.isBarrierOut(node) and config.isSink(node) } private predicate fullBarrier(Node node, Configuration config) { - config.isBarrier(node) and - not config.isSource(node) and + config.isBarrier(node) + or + config.isBarrierIn(node) and + not config.isSource(node) + or + config.isBarrierOut(node) and not config.isSink(node) } diff --git a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl2.qll b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl2.qll index cfe85663344..d6dccd45656 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl2.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl2.qll @@ -57,9 +57,15 @@ abstract class Configuration extends string { /** Holds if data flow through `node` is prohibited. */ predicate isBarrier(Node node) { none() } - /** DEPRECATED: override `isBarrier` instead. */ + /** DEPRECATED: override `isBarrierIn` and `isBarrierOut` instead. */ deprecated predicate isBarrierEdge(Node node1, Node node2) { none() } + /** Holds if data flow into `node` is prohibited. */ + predicate isBarrierIn(Node node) { none() } + + /** Holds if data flow out of `node` is prohibited. */ + predicate isBarrierOut(Node node) { none() } + /** * Holds if the additional flow step from `node1` to `node2` must be taken * into account in the analysis. @@ -104,18 +110,22 @@ abstract class Configuration extends string { } private predicate inBarrier(Node node, Configuration config) { - config.isBarrier(node) and + config.isBarrierIn(node) and config.isSource(node) } private predicate outBarrier(Node node, Configuration config) { - config.isBarrier(node) and + config.isBarrierOut(node) and config.isSink(node) } private predicate fullBarrier(Node node, Configuration config) { - config.isBarrier(node) and - not config.isSource(node) and + config.isBarrier(node) + or + config.isBarrierIn(node) and + not config.isSource(node) + or + config.isBarrierOut(node) and not config.isSink(node) } diff --git a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl3.qll b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl3.qll index cfe85663344..d6dccd45656 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl3.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl3.qll @@ -57,9 +57,15 @@ abstract class Configuration extends string { /** Holds if data flow through `node` is prohibited. */ predicate isBarrier(Node node) { none() } - /** DEPRECATED: override `isBarrier` instead. */ + /** DEPRECATED: override `isBarrierIn` and `isBarrierOut` instead. */ deprecated predicate isBarrierEdge(Node node1, Node node2) { none() } + /** Holds if data flow into `node` is prohibited. */ + predicate isBarrierIn(Node node) { none() } + + /** Holds if data flow out of `node` is prohibited. */ + predicate isBarrierOut(Node node) { none() } + /** * Holds if the additional flow step from `node1` to `node2` must be taken * into account in the analysis. @@ -104,18 +110,22 @@ abstract class Configuration extends string { } private predicate inBarrier(Node node, Configuration config) { - config.isBarrier(node) and + config.isBarrierIn(node) and config.isSource(node) } private predicate outBarrier(Node node, Configuration config) { - config.isBarrier(node) and + config.isBarrierOut(node) and config.isSink(node) } private predicate fullBarrier(Node node, Configuration config) { - config.isBarrier(node) and - not config.isSource(node) and + config.isBarrier(node) + or + config.isBarrierIn(node) and + not config.isSource(node) + or + config.isBarrierOut(node) and not config.isSink(node) } diff --git a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl4.qll b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl4.qll index cfe85663344..d6dccd45656 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl4.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl4.qll @@ -57,9 +57,15 @@ abstract class Configuration extends string { /** Holds if data flow through `node` is prohibited. */ predicate isBarrier(Node node) { none() } - /** DEPRECATED: override `isBarrier` instead. */ + /** DEPRECATED: override `isBarrierIn` and `isBarrierOut` instead. */ deprecated predicate isBarrierEdge(Node node1, Node node2) { none() } + /** Holds if data flow into `node` is prohibited. */ + predicate isBarrierIn(Node node) { none() } + + /** Holds if data flow out of `node` is prohibited. */ + predicate isBarrierOut(Node node) { none() } + /** * Holds if the additional flow step from `node1` to `node2` must be taken * into account in the analysis. @@ -104,18 +110,22 @@ abstract class Configuration extends string { } private predicate inBarrier(Node node, Configuration config) { - config.isBarrier(node) and + config.isBarrierIn(node) and config.isSource(node) } private predicate outBarrier(Node node, Configuration config) { - config.isBarrier(node) and + config.isBarrierOut(node) and config.isSink(node) } private predicate fullBarrier(Node node, Configuration config) { - config.isBarrier(node) and - not config.isSource(node) and + config.isBarrier(node) + or + config.isBarrierIn(node) and + not config.isSource(node) + or + config.isBarrierOut(node) and not config.isSink(node) } diff --git a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl5.qll b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl5.qll index cfe85663344..d6dccd45656 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl5.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl5.qll @@ -57,9 +57,15 @@ abstract class Configuration extends string { /** Holds if data flow through `node` is prohibited. */ predicate isBarrier(Node node) { none() } - /** DEPRECATED: override `isBarrier` instead. */ + /** DEPRECATED: override `isBarrierIn` and `isBarrierOut` instead. */ deprecated predicate isBarrierEdge(Node node1, Node node2) { none() } + /** Holds if data flow into `node` is prohibited. */ + predicate isBarrierIn(Node node) { none() } + + /** Holds if data flow out of `node` is prohibited. */ + predicate isBarrierOut(Node node) { none() } + /** * Holds if the additional flow step from `node1` to `node2` must be taken * into account in the analysis. @@ -104,18 +110,22 @@ abstract class Configuration extends string { } private predicate inBarrier(Node node, Configuration config) { - config.isBarrier(node) and + config.isBarrierIn(node) and config.isSource(node) } private predicate outBarrier(Node node, Configuration config) { - config.isBarrier(node) and + config.isBarrierOut(node) and config.isSink(node) } private predicate fullBarrier(Node node, Configuration config) { - config.isBarrier(node) and - not config.isSource(node) and + config.isBarrier(node) + or + config.isBarrierIn(node) and + not config.isSource(node) + or + config.isBarrierOut(node) and not config.isSink(node) } From 9ebb83497d48607061583396ded1ca6cab4d9533 Mon Sep 17 00:00:00 2001 From: Anders Schack-Mulligen Date: Mon, 5 Aug 2019 15:34:12 +0200 Subject: [PATCH 6/7] Java/C++/C#: Fix small mistake. --- cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl.qll | 4 +++- .../src/semmle/code/cpp/dataflow/internal/DataFlowImpl2.qll | 4 +++- .../src/semmle/code/cpp/dataflow/internal/DataFlowImpl3.qll | 4 +++- .../src/semmle/code/cpp/dataflow/internal/DataFlowImpl4.qll | 4 +++- .../src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl.qll | 4 +++- .../semmle/code/cpp/ir/dataflow/internal/DataFlowImpl2.qll | 4 +++- .../semmle/code/cpp/ir/dataflow/internal/DataFlowImpl3.qll | 4 +++- .../semmle/code/cpp/ir/dataflow/internal/DataFlowImpl4.qll | 4 +++- .../src/semmle/code/csharp/dataflow/internal/DataFlowImpl.qll | 4 +++- .../src/semmle/code/java/dataflow/internal/DataFlowImpl.qll | 4 +++- .../src/semmle/code/java/dataflow/internal/DataFlowImpl2.qll | 4 +++- .../src/semmle/code/java/dataflow/internal/DataFlowImpl3.qll | 4 +++- .../src/semmle/code/java/dataflow/internal/DataFlowImpl4.qll | 4 +++- .../src/semmle/code/java/dataflow/internal/DataFlowImpl5.qll | 4 +++- 14 files changed, 42 insertions(+), 14 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl.qll b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl.qll index d6dccd45656..3a6cbd82bc9 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl.qll @@ -372,7 +372,9 @@ private predicate readCand1(Content f, Configuration config) { private predicate throughFlowNodeCand(Node node, Configuration config) { nodeCand1(node, false, config) and - not config.isBarrier(node) + not fullBarrier(node, config) and + not inBarrier(node, config) and + not outBarrier(node, config) } /** diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl2.qll b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl2.qll index d6dccd45656..3a6cbd82bc9 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl2.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl2.qll @@ -372,7 +372,9 @@ private predicate readCand1(Content f, Configuration config) { private predicate throughFlowNodeCand(Node node, Configuration config) { nodeCand1(node, false, config) and - not config.isBarrier(node) + not fullBarrier(node, config) and + not inBarrier(node, config) and + not outBarrier(node, config) } /** diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl3.qll b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl3.qll index d6dccd45656..3a6cbd82bc9 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl3.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl3.qll @@ -372,7 +372,9 @@ private predicate readCand1(Content f, Configuration config) { private predicate throughFlowNodeCand(Node node, Configuration config) { nodeCand1(node, false, config) and - not config.isBarrier(node) + not fullBarrier(node, config) and + not inBarrier(node, config) and + not outBarrier(node, config) } /** diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl4.qll b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl4.qll index d6dccd45656..3a6cbd82bc9 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl4.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl4.qll @@ -372,7 +372,9 @@ private predicate readCand1(Content f, Configuration config) { private predicate throughFlowNodeCand(Node node, Configuration config) { nodeCand1(node, false, config) and - not config.isBarrier(node) + not fullBarrier(node, config) and + not inBarrier(node, config) and + not outBarrier(node, config) } /** diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl.qll index d6dccd45656..3a6cbd82bc9 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl.qll @@ -372,7 +372,9 @@ private predicate readCand1(Content f, Configuration config) { private predicate throughFlowNodeCand(Node node, Configuration config) { nodeCand1(node, false, config) and - not config.isBarrier(node) + not fullBarrier(node, config) and + not inBarrier(node, config) and + not outBarrier(node, config) } /** diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl2.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl2.qll index d6dccd45656..3a6cbd82bc9 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl2.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl2.qll @@ -372,7 +372,9 @@ private predicate readCand1(Content f, Configuration config) { private predicate throughFlowNodeCand(Node node, Configuration config) { nodeCand1(node, false, config) and - not config.isBarrier(node) + not fullBarrier(node, config) and + not inBarrier(node, config) and + not outBarrier(node, config) } /** diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl3.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl3.qll index d6dccd45656..3a6cbd82bc9 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl3.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl3.qll @@ -372,7 +372,9 @@ private predicate readCand1(Content f, Configuration config) { private predicate throughFlowNodeCand(Node node, Configuration config) { nodeCand1(node, false, config) and - not config.isBarrier(node) + not fullBarrier(node, config) and + not inBarrier(node, config) and + not outBarrier(node, config) } /** diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl4.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl4.qll index d6dccd45656..3a6cbd82bc9 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl4.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl4.qll @@ -372,7 +372,9 @@ private predicate readCand1(Content f, Configuration config) { private predicate throughFlowNodeCand(Node node, Configuration config) { nodeCand1(node, false, config) and - not config.isBarrier(node) + not fullBarrier(node, config) and + not inBarrier(node, config) and + not outBarrier(node, config) } /** diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl.qll index d6dccd45656..3a6cbd82bc9 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl.qll @@ -372,7 +372,9 @@ private predicate readCand1(Content f, Configuration config) { private predicate throughFlowNodeCand(Node node, Configuration config) { nodeCand1(node, false, config) and - not config.isBarrier(node) + not fullBarrier(node, config) and + not inBarrier(node, config) and + not outBarrier(node, config) } /** diff --git a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl.qll b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl.qll index d6dccd45656..3a6cbd82bc9 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl.qll @@ -372,7 +372,9 @@ private predicate readCand1(Content f, Configuration config) { private predicate throughFlowNodeCand(Node node, Configuration config) { nodeCand1(node, false, config) and - not config.isBarrier(node) + not fullBarrier(node, config) and + not inBarrier(node, config) and + not outBarrier(node, config) } /** diff --git a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl2.qll b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl2.qll index d6dccd45656..3a6cbd82bc9 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl2.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl2.qll @@ -372,7 +372,9 @@ private predicate readCand1(Content f, Configuration config) { private predicate throughFlowNodeCand(Node node, Configuration config) { nodeCand1(node, false, config) and - not config.isBarrier(node) + not fullBarrier(node, config) and + not inBarrier(node, config) and + not outBarrier(node, config) } /** diff --git a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl3.qll b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl3.qll index d6dccd45656..3a6cbd82bc9 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl3.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl3.qll @@ -372,7 +372,9 @@ private predicate readCand1(Content f, Configuration config) { private predicate throughFlowNodeCand(Node node, Configuration config) { nodeCand1(node, false, config) and - not config.isBarrier(node) + not fullBarrier(node, config) and + not inBarrier(node, config) and + not outBarrier(node, config) } /** diff --git a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl4.qll b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl4.qll index d6dccd45656..3a6cbd82bc9 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl4.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl4.qll @@ -372,7 +372,9 @@ private predicate readCand1(Content f, Configuration config) { private predicate throughFlowNodeCand(Node node, Configuration config) { nodeCand1(node, false, config) and - not config.isBarrier(node) + not fullBarrier(node, config) and + not inBarrier(node, config) and + not outBarrier(node, config) } /** diff --git a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl5.qll b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl5.qll index d6dccd45656..3a6cbd82bc9 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl5.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl5.qll @@ -372,7 +372,9 @@ private predicate readCand1(Content f, Configuration config) { private predicate throughFlowNodeCand(Node node, Configuration config) { nodeCand1(node, false, config) and - not config.isBarrier(node) + not fullBarrier(node, config) and + not inBarrier(node, config) and + not outBarrier(node, config) } /** From a80cb262fc635cb3ad686fc691bdca96c550b035 Mon Sep 17 00:00:00 2001 From: Anders Schack-Mulligen Date: Mon, 5 Aug 2019 16:28:25 +0200 Subject: [PATCH 7/7] Java/C++/C#: Elaborate qldoc. --- .../code/cpp/dataflow/internal/DataFlowImpl.qll | 11 ++++++++++- .../code/cpp/dataflow/internal/DataFlowImpl2.qll | 11 ++++++++++- .../code/cpp/dataflow/internal/DataFlowImpl3.qll | 11 ++++++++++- .../code/cpp/dataflow/internal/DataFlowImpl4.qll | 11 ++++++++++- .../code/cpp/ir/dataflow/internal/DataFlowImpl.qll | 11 ++++++++++- .../code/cpp/ir/dataflow/internal/DataFlowImpl2.qll | 11 ++++++++++- .../code/cpp/ir/dataflow/internal/DataFlowImpl3.qll | 11 ++++++++++- .../code/cpp/ir/dataflow/internal/DataFlowImpl4.qll | 11 ++++++++++- .../code/csharp/dataflow/internal/DataFlowImpl.qll | 11 ++++++++++- .../code/java/dataflow/internal/DataFlowImpl.qll | 11 ++++++++++- .../code/java/dataflow/internal/DataFlowImpl2.qll | 11 ++++++++++- .../code/java/dataflow/internal/DataFlowImpl3.qll | 11 ++++++++++- .../code/java/dataflow/internal/DataFlowImpl4.qll | 11 ++++++++++- .../code/java/dataflow/internal/DataFlowImpl5.qll | 11 ++++++++++- 14 files changed, 140 insertions(+), 14 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl.qll b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl.qll index 3a6cbd82bc9..49686124c78 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl.qll @@ -27,6 +27,12 @@ import DataFlowImplSpecific::Public * // Optionally override `isAdditionalFlowStep`. * } * ``` + * Conceptually, this defines a graph where the nodes are `DataFlow::Node`s and + * the edges are those data-flow steps that preserve the value of the node + * along with any additional edges defined by `isAdditionalFlowStep`. + * Specifying nodes in `isBarrier` will remove those nodes from the graph, and + * specifying nodes in `isBarrierIn` and/or `isBarrierOut` will remove in-going + * and/or out-going edges from those nodes, respectively. * * Then, to query whether there is flow between some `source` and `sink`, * write @@ -54,7 +60,10 @@ abstract class Configuration extends string { */ abstract predicate isSink(Node sink); - /** Holds if data flow through `node` is prohibited. */ + /** + * Holds if data flow through `node` is prohibited. This completely removes + * `node` from the data flow graph. + */ predicate isBarrier(Node node) { none() } /** DEPRECATED: override `isBarrierIn` and `isBarrierOut` instead. */ diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl2.qll b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl2.qll index 3a6cbd82bc9..49686124c78 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl2.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl2.qll @@ -27,6 +27,12 @@ import DataFlowImplSpecific::Public * // Optionally override `isAdditionalFlowStep`. * } * ``` + * Conceptually, this defines a graph where the nodes are `DataFlow::Node`s and + * the edges are those data-flow steps that preserve the value of the node + * along with any additional edges defined by `isAdditionalFlowStep`. + * Specifying nodes in `isBarrier` will remove those nodes from the graph, and + * specifying nodes in `isBarrierIn` and/or `isBarrierOut` will remove in-going + * and/or out-going edges from those nodes, respectively. * * Then, to query whether there is flow between some `source` and `sink`, * write @@ -54,7 +60,10 @@ abstract class Configuration extends string { */ abstract predicate isSink(Node sink); - /** Holds if data flow through `node` is prohibited. */ + /** + * Holds if data flow through `node` is prohibited. This completely removes + * `node` from the data flow graph. + */ predicate isBarrier(Node node) { none() } /** DEPRECATED: override `isBarrierIn` and `isBarrierOut` instead. */ diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl3.qll b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl3.qll index 3a6cbd82bc9..49686124c78 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl3.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl3.qll @@ -27,6 +27,12 @@ import DataFlowImplSpecific::Public * // Optionally override `isAdditionalFlowStep`. * } * ``` + * Conceptually, this defines a graph where the nodes are `DataFlow::Node`s and + * the edges are those data-flow steps that preserve the value of the node + * along with any additional edges defined by `isAdditionalFlowStep`. + * Specifying nodes in `isBarrier` will remove those nodes from the graph, and + * specifying nodes in `isBarrierIn` and/or `isBarrierOut` will remove in-going + * and/or out-going edges from those nodes, respectively. * * Then, to query whether there is flow between some `source` and `sink`, * write @@ -54,7 +60,10 @@ abstract class Configuration extends string { */ abstract predicate isSink(Node sink); - /** Holds if data flow through `node` is prohibited. */ + /** + * Holds if data flow through `node` is prohibited. This completely removes + * `node` from the data flow graph. + */ predicate isBarrier(Node node) { none() } /** DEPRECATED: override `isBarrierIn` and `isBarrierOut` instead. */ diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl4.qll b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl4.qll index 3a6cbd82bc9..49686124c78 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl4.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl4.qll @@ -27,6 +27,12 @@ import DataFlowImplSpecific::Public * // Optionally override `isAdditionalFlowStep`. * } * ``` + * Conceptually, this defines a graph where the nodes are `DataFlow::Node`s and + * the edges are those data-flow steps that preserve the value of the node + * along with any additional edges defined by `isAdditionalFlowStep`. + * Specifying nodes in `isBarrier` will remove those nodes from the graph, and + * specifying nodes in `isBarrierIn` and/or `isBarrierOut` will remove in-going + * and/or out-going edges from those nodes, respectively. * * Then, to query whether there is flow between some `source` and `sink`, * write @@ -54,7 +60,10 @@ abstract class Configuration extends string { */ abstract predicate isSink(Node sink); - /** Holds if data flow through `node` is prohibited. */ + /** + * Holds if data flow through `node` is prohibited. This completely removes + * `node` from the data flow graph. + */ predicate isBarrier(Node node) { none() } /** DEPRECATED: override `isBarrierIn` and `isBarrierOut` instead. */ diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl.qll index 3a6cbd82bc9..49686124c78 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl.qll @@ -27,6 +27,12 @@ import DataFlowImplSpecific::Public * // Optionally override `isAdditionalFlowStep`. * } * ``` + * Conceptually, this defines a graph where the nodes are `DataFlow::Node`s and + * the edges are those data-flow steps that preserve the value of the node + * along with any additional edges defined by `isAdditionalFlowStep`. + * Specifying nodes in `isBarrier` will remove those nodes from the graph, and + * specifying nodes in `isBarrierIn` and/or `isBarrierOut` will remove in-going + * and/or out-going edges from those nodes, respectively. * * Then, to query whether there is flow between some `source` and `sink`, * write @@ -54,7 +60,10 @@ abstract class Configuration extends string { */ abstract predicate isSink(Node sink); - /** Holds if data flow through `node` is prohibited. */ + /** + * Holds if data flow through `node` is prohibited. This completely removes + * `node` from the data flow graph. + */ predicate isBarrier(Node node) { none() } /** DEPRECATED: override `isBarrierIn` and `isBarrierOut` instead. */ diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl2.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl2.qll index 3a6cbd82bc9..49686124c78 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl2.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl2.qll @@ -27,6 +27,12 @@ import DataFlowImplSpecific::Public * // Optionally override `isAdditionalFlowStep`. * } * ``` + * Conceptually, this defines a graph where the nodes are `DataFlow::Node`s and + * the edges are those data-flow steps that preserve the value of the node + * along with any additional edges defined by `isAdditionalFlowStep`. + * Specifying nodes in `isBarrier` will remove those nodes from the graph, and + * specifying nodes in `isBarrierIn` and/or `isBarrierOut` will remove in-going + * and/or out-going edges from those nodes, respectively. * * Then, to query whether there is flow between some `source` and `sink`, * write @@ -54,7 +60,10 @@ abstract class Configuration extends string { */ abstract predicate isSink(Node sink); - /** Holds if data flow through `node` is prohibited. */ + /** + * Holds if data flow through `node` is prohibited. This completely removes + * `node` from the data flow graph. + */ predicate isBarrier(Node node) { none() } /** DEPRECATED: override `isBarrierIn` and `isBarrierOut` instead. */ diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl3.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl3.qll index 3a6cbd82bc9..49686124c78 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl3.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl3.qll @@ -27,6 +27,12 @@ import DataFlowImplSpecific::Public * // Optionally override `isAdditionalFlowStep`. * } * ``` + * Conceptually, this defines a graph where the nodes are `DataFlow::Node`s and + * the edges are those data-flow steps that preserve the value of the node + * along with any additional edges defined by `isAdditionalFlowStep`. + * Specifying nodes in `isBarrier` will remove those nodes from the graph, and + * specifying nodes in `isBarrierIn` and/or `isBarrierOut` will remove in-going + * and/or out-going edges from those nodes, respectively. * * Then, to query whether there is flow between some `source` and `sink`, * write @@ -54,7 +60,10 @@ abstract class Configuration extends string { */ abstract predicate isSink(Node sink); - /** Holds if data flow through `node` is prohibited. */ + /** + * Holds if data flow through `node` is prohibited. This completely removes + * `node` from the data flow graph. + */ predicate isBarrier(Node node) { none() } /** DEPRECATED: override `isBarrierIn` and `isBarrierOut` instead. */ diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl4.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl4.qll index 3a6cbd82bc9..49686124c78 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl4.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl4.qll @@ -27,6 +27,12 @@ import DataFlowImplSpecific::Public * // Optionally override `isAdditionalFlowStep`. * } * ``` + * Conceptually, this defines a graph where the nodes are `DataFlow::Node`s and + * the edges are those data-flow steps that preserve the value of the node + * along with any additional edges defined by `isAdditionalFlowStep`. + * Specifying nodes in `isBarrier` will remove those nodes from the graph, and + * specifying nodes in `isBarrierIn` and/or `isBarrierOut` will remove in-going + * and/or out-going edges from those nodes, respectively. * * Then, to query whether there is flow between some `source` and `sink`, * write @@ -54,7 +60,10 @@ abstract class Configuration extends string { */ abstract predicate isSink(Node sink); - /** Holds if data flow through `node` is prohibited. */ + /** + * Holds if data flow through `node` is prohibited. This completely removes + * `node` from the data flow graph. + */ predicate isBarrier(Node node) { none() } /** DEPRECATED: override `isBarrierIn` and `isBarrierOut` instead. */ diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl.qll index 3a6cbd82bc9..49686124c78 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl.qll @@ -27,6 +27,12 @@ import DataFlowImplSpecific::Public * // Optionally override `isAdditionalFlowStep`. * } * ``` + * Conceptually, this defines a graph where the nodes are `DataFlow::Node`s and + * the edges are those data-flow steps that preserve the value of the node + * along with any additional edges defined by `isAdditionalFlowStep`. + * Specifying nodes in `isBarrier` will remove those nodes from the graph, and + * specifying nodes in `isBarrierIn` and/or `isBarrierOut` will remove in-going + * and/or out-going edges from those nodes, respectively. * * Then, to query whether there is flow between some `source` and `sink`, * write @@ -54,7 +60,10 @@ abstract class Configuration extends string { */ abstract predicate isSink(Node sink); - /** Holds if data flow through `node` is prohibited. */ + /** + * Holds if data flow through `node` is prohibited. This completely removes + * `node` from the data flow graph. + */ predicate isBarrier(Node node) { none() } /** DEPRECATED: override `isBarrierIn` and `isBarrierOut` instead. */ diff --git a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl.qll b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl.qll index 3a6cbd82bc9..49686124c78 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl.qll @@ -27,6 +27,12 @@ import DataFlowImplSpecific::Public * // Optionally override `isAdditionalFlowStep`. * } * ``` + * Conceptually, this defines a graph where the nodes are `DataFlow::Node`s and + * the edges are those data-flow steps that preserve the value of the node + * along with any additional edges defined by `isAdditionalFlowStep`. + * Specifying nodes in `isBarrier` will remove those nodes from the graph, and + * specifying nodes in `isBarrierIn` and/or `isBarrierOut` will remove in-going + * and/or out-going edges from those nodes, respectively. * * Then, to query whether there is flow between some `source` and `sink`, * write @@ -54,7 +60,10 @@ abstract class Configuration extends string { */ abstract predicate isSink(Node sink); - /** Holds if data flow through `node` is prohibited. */ + /** + * Holds if data flow through `node` is prohibited. This completely removes + * `node` from the data flow graph. + */ predicate isBarrier(Node node) { none() } /** DEPRECATED: override `isBarrierIn` and `isBarrierOut` instead. */ diff --git a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl2.qll b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl2.qll index 3a6cbd82bc9..49686124c78 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl2.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl2.qll @@ -27,6 +27,12 @@ import DataFlowImplSpecific::Public * // Optionally override `isAdditionalFlowStep`. * } * ``` + * Conceptually, this defines a graph where the nodes are `DataFlow::Node`s and + * the edges are those data-flow steps that preserve the value of the node + * along with any additional edges defined by `isAdditionalFlowStep`. + * Specifying nodes in `isBarrier` will remove those nodes from the graph, and + * specifying nodes in `isBarrierIn` and/or `isBarrierOut` will remove in-going + * and/or out-going edges from those nodes, respectively. * * Then, to query whether there is flow between some `source` and `sink`, * write @@ -54,7 +60,10 @@ abstract class Configuration extends string { */ abstract predicate isSink(Node sink); - /** Holds if data flow through `node` is prohibited. */ + /** + * Holds if data flow through `node` is prohibited. This completely removes + * `node` from the data flow graph. + */ predicate isBarrier(Node node) { none() } /** DEPRECATED: override `isBarrierIn` and `isBarrierOut` instead. */ diff --git a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl3.qll b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl3.qll index 3a6cbd82bc9..49686124c78 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl3.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl3.qll @@ -27,6 +27,12 @@ import DataFlowImplSpecific::Public * // Optionally override `isAdditionalFlowStep`. * } * ``` + * Conceptually, this defines a graph where the nodes are `DataFlow::Node`s and + * the edges are those data-flow steps that preserve the value of the node + * along with any additional edges defined by `isAdditionalFlowStep`. + * Specifying nodes in `isBarrier` will remove those nodes from the graph, and + * specifying nodes in `isBarrierIn` and/or `isBarrierOut` will remove in-going + * and/or out-going edges from those nodes, respectively. * * Then, to query whether there is flow between some `source` and `sink`, * write @@ -54,7 +60,10 @@ abstract class Configuration extends string { */ abstract predicate isSink(Node sink); - /** Holds if data flow through `node` is prohibited. */ + /** + * Holds if data flow through `node` is prohibited. This completely removes + * `node` from the data flow graph. + */ predicate isBarrier(Node node) { none() } /** DEPRECATED: override `isBarrierIn` and `isBarrierOut` instead. */ diff --git a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl4.qll b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl4.qll index 3a6cbd82bc9..49686124c78 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl4.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl4.qll @@ -27,6 +27,12 @@ import DataFlowImplSpecific::Public * // Optionally override `isAdditionalFlowStep`. * } * ``` + * Conceptually, this defines a graph where the nodes are `DataFlow::Node`s and + * the edges are those data-flow steps that preserve the value of the node + * along with any additional edges defined by `isAdditionalFlowStep`. + * Specifying nodes in `isBarrier` will remove those nodes from the graph, and + * specifying nodes in `isBarrierIn` and/or `isBarrierOut` will remove in-going + * and/or out-going edges from those nodes, respectively. * * Then, to query whether there is flow between some `source` and `sink`, * write @@ -54,7 +60,10 @@ abstract class Configuration extends string { */ abstract predicate isSink(Node sink); - /** Holds if data flow through `node` is prohibited. */ + /** + * Holds if data flow through `node` is prohibited. This completely removes + * `node` from the data flow graph. + */ predicate isBarrier(Node node) { none() } /** DEPRECATED: override `isBarrierIn` and `isBarrierOut` instead. */ diff --git a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl5.qll b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl5.qll index 3a6cbd82bc9..49686124c78 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl5.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl5.qll @@ -27,6 +27,12 @@ import DataFlowImplSpecific::Public * // Optionally override `isAdditionalFlowStep`. * } * ``` + * Conceptually, this defines a graph where the nodes are `DataFlow::Node`s and + * the edges are those data-flow steps that preserve the value of the node + * along with any additional edges defined by `isAdditionalFlowStep`. + * Specifying nodes in `isBarrier` will remove those nodes from the graph, and + * specifying nodes in `isBarrierIn` and/or `isBarrierOut` will remove in-going + * and/or out-going edges from those nodes, respectively. * * Then, to query whether there is flow between some `source` and `sink`, * write @@ -54,7 +60,10 @@ abstract class Configuration extends string { */ abstract predicate isSink(Node sink); - /** Holds if data flow through `node` is prohibited. */ + /** + * Holds if data flow through `node` is prohibited. This completely removes + * `node` from the data flow graph. + */ predicate isBarrier(Node node) { none() } /** DEPRECATED: override `isBarrierIn` and `isBarrierOut` instead. */