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 1d51a88d13d..094a2530c31 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl.qll @@ -75,6 +75,9 @@ abstract class Configuration extends string { /** Holds if data flow out of `node` is prohibited. */ predicate isBarrierOut(Node node) { none() } + /** Holds if data flow through nodes guarded by `guard` is prohibited. */ + predicate isBarrierGuard(BarrierGuard guard) { none() } + /** * Holds if the additional flow step from `node1` to `node2` must be taken * into account in the analysis. @@ -136,6 +139,11 @@ private predicate fullBarrier(Node node, Configuration config) { or config.isBarrierOut(node) and not config.isSink(node) + or + exists(BarrierGuard g | + config.isBarrierGuard(g) and + node = g.getAGuardedNode() + ) } private class AdditionalFlowStepSource extends 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 1d51a88d13d..094a2530c31 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl2.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl2.qll @@ -75,6 +75,9 @@ abstract class Configuration extends string { /** Holds if data flow out of `node` is prohibited. */ predicate isBarrierOut(Node node) { none() } + /** Holds if data flow through nodes guarded by `guard` is prohibited. */ + predicate isBarrierGuard(BarrierGuard guard) { none() } + /** * Holds if the additional flow step from `node1` to `node2` must be taken * into account in the analysis. @@ -136,6 +139,11 @@ private predicate fullBarrier(Node node, Configuration config) { or config.isBarrierOut(node) and not config.isSink(node) + or + exists(BarrierGuard g | + config.isBarrierGuard(g) and + node = g.getAGuardedNode() + ) } private class AdditionalFlowStepSource extends 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 1d51a88d13d..094a2530c31 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl3.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl3.qll @@ -75,6 +75,9 @@ abstract class Configuration extends string { /** Holds if data flow out of `node` is prohibited. */ predicate isBarrierOut(Node node) { none() } + /** Holds if data flow through nodes guarded by `guard` is prohibited. */ + predicate isBarrierGuard(BarrierGuard guard) { none() } + /** * Holds if the additional flow step from `node1` to `node2` must be taken * into account in the analysis. @@ -136,6 +139,11 @@ private predicate fullBarrier(Node node, Configuration config) { or config.isBarrierOut(node) and not config.isSink(node) + or + exists(BarrierGuard g | + config.isBarrierGuard(g) and + node = g.getAGuardedNode() + ) } private class AdditionalFlowStepSource extends 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 1d51a88d13d..094a2530c31 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl4.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl4.qll @@ -75,6 +75,9 @@ abstract class Configuration extends string { /** Holds if data flow out of `node` is prohibited. */ predicate isBarrierOut(Node node) { none() } + /** Holds if data flow through nodes guarded by `guard` is prohibited. */ + predicate isBarrierGuard(BarrierGuard guard) { none() } + /** * Holds if the additional flow step from `node1` to `node2` must be taken * into account in the analysis. @@ -136,6 +139,11 @@ private predicate fullBarrier(Node node, Configuration config) { or config.isBarrierOut(node) and not config.isSink(node) + or + exists(BarrierGuard g | + config.isBarrierGuard(g) and + node = g.getAGuardedNode() + ) } private class AdditionalFlowStepSource extends Node { diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowUtil.qll b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowUtil.qll index e9b82a54e43..fe5518828ce 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowUtil.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowUtil.qll @@ -331,3 +331,14 @@ VariableAccess getAnAccessToAssignedVariable(Expr assign) { result = var.getAnAccess() ) } + +/** A guard that validates some expression. */ +class BarrierGuard extends Expr { + /** Holds if this guard validates `e` upon evaluating to `branch`. */ + abstract predicate checks(Expr e, boolean branch); + + /** Gets a node guarded by this. */ + final Node getAGuardedNode() { + none() // stub + } +} 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 1d51a88d13d..094a2530c31 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 @@ -75,6 +75,9 @@ abstract class Configuration extends string { /** Holds if data flow out of `node` is prohibited. */ predicate isBarrierOut(Node node) { none() } + /** Holds if data flow through nodes guarded by `guard` is prohibited. */ + predicate isBarrierGuard(BarrierGuard guard) { none() } + /** * Holds if the additional flow step from `node1` to `node2` must be taken * into account in the analysis. @@ -136,6 +139,11 @@ private predicate fullBarrier(Node node, Configuration config) { or config.isBarrierOut(node) and not config.isSink(node) + or + exists(BarrierGuard g | + config.isBarrierGuard(g) and + node = g.getAGuardedNode() + ) } private class AdditionalFlowStepSource extends 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 1d51a88d13d..094a2530c31 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 @@ -75,6 +75,9 @@ abstract class Configuration extends string { /** Holds if data flow out of `node` is prohibited. */ predicate isBarrierOut(Node node) { none() } + /** Holds if data flow through nodes guarded by `guard` is prohibited. */ + predicate isBarrierGuard(BarrierGuard guard) { none() } + /** * Holds if the additional flow step from `node1` to `node2` must be taken * into account in the analysis. @@ -136,6 +139,11 @@ private predicate fullBarrier(Node node, Configuration config) { or config.isBarrierOut(node) and not config.isSink(node) + or + exists(BarrierGuard g | + config.isBarrierGuard(g) and + node = g.getAGuardedNode() + ) } private class AdditionalFlowStepSource extends 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 1d51a88d13d..094a2530c31 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 @@ -75,6 +75,9 @@ abstract class Configuration extends string { /** Holds if data flow out of `node` is prohibited. */ predicate isBarrierOut(Node node) { none() } + /** Holds if data flow through nodes guarded by `guard` is prohibited. */ + predicate isBarrierGuard(BarrierGuard guard) { none() } + /** * Holds if the additional flow step from `node1` to `node2` must be taken * into account in the analysis. @@ -136,6 +139,11 @@ private predicate fullBarrier(Node node, Configuration config) { or config.isBarrierOut(node) and not config.isSink(node) + or + exists(BarrierGuard g | + config.isBarrierGuard(g) and + node = g.getAGuardedNode() + ) } private class AdditionalFlowStepSource extends 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 1d51a88d13d..094a2530c31 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 @@ -75,6 +75,9 @@ abstract class Configuration extends string { /** Holds if data flow out of `node` is prohibited. */ predicate isBarrierOut(Node node) { none() } + /** Holds if data flow through nodes guarded by `guard` is prohibited. */ + predicate isBarrierGuard(BarrierGuard guard) { none() } + /** * Holds if the additional flow step from `node1` to `node2` must be taken * into account in the analysis. @@ -136,6 +139,11 @@ private predicate fullBarrier(Node node, Configuration config) { or config.isBarrierOut(node) and not config.isSink(node) + or + exists(BarrierGuard g | + config.isBarrierGuard(g) and + node = g.getAGuardedNode() + ) } private class AdditionalFlowStepSource extends Node { diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll index d2101d09ab4..965d4c14b24 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll @@ -4,6 +4,7 @@ private import cpp private import semmle.code.cpp.ir.IR +private import semmle.code.cpp.controlflow.IRGuards /** * A node in a data flow graph. @@ -166,3 +167,14 @@ predicate localFlowStep(Node nodeFrom, Node nodeTo) { * (intra-procedural) steps. */ predicate localFlow(Node source, Node sink) { localFlowStep*(source, sink) } + +/** A guard that validates some expression. */ +class BarrierGuard extends IRGuardCondition { + /** Holds if this guard validates `e` upon evaluating to `b`. */ + abstract predicate checks(Instruction e, boolean b); + + /** Gets a node guarded by this. */ + final Node getAGuardedNode() { + none() // stub + } +} 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 1d51a88d13d..094a2530c31 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl.qll @@ -75,6 +75,9 @@ abstract class Configuration extends string { /** Holds if data flow out of `node` is prohibited. */ predicate isBarrierOut(Node node) { none() } + /** Holds if data flow through nodes guarded by `guard` is prohibited. */ + predicate isBarrierGuard(BarrierGuard guard) { none() } + /** * Holds if the additional flow step from `node1` to `node2` must be taken * into account in the analysis. @@ -136,6 +139,11 @@ private predicate fullBarrier(Node node, Configuration config) { or config.isBarrierOut(node) and not config.isSink(node) + or + exists(BarrierGuard g | + config.isBarrierGuard(g) and + node = g.getAGuardedNode() + ) } private class AdditionalFlowStepSource extends Node { diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl2.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl2.qll index 1d51a88d13d..094a2530c31 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl2.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl2.qll @@ -75,6 +75,9 @@ abstract class Configuration extends string { /** Holds if data flow out of `node` is prohibited. */ predicate isBarrierOut(Node node) { none() } + /** Holds if data flow through nodes guarded by `guard` is prohibited. */ + predicate isBarrierGuard(BarrierGuard guard) { none() } + /** * Holds if the additional flow step from `node1` to `node2` must be taken * into account in the analysis. @@ -136,6 +139,11 @@ private predicate fullBarrier(Node node, Configuration config) { or config.isBarrierOut(node) and not config.isSink(node) + or + exists(BarrierGuard g | + config.isBarrierGuard(g) and + node = g.getAGuardedNode() + ) } private class AdditionalFlowStepSource extends Node { diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl3.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl3.qll index 1d51a88d13d..094a2530c31 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl3.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl3.qll @@ -75,6 +75,9 @@ abstract class Configuration extends string { /** Holds if data flow out of `node` is prohibited. */ predicate isBarrierOut(Node node) { none() } + /** Holds if data flow through nodes guarded by `guard` is prohibited. */ + predicate isBarrierGuard(BarrierGuard guard) { none() } + /** * Holds if the additional flow step from `node1` to `node2` must be taken * into account in the analysis. @@ -136,6 +139,11 @@ private predicate fullBarrier(Node node, Configuration config) { or config.isBarrierOut(node) and not config.isSink(node) + or + exists(BarrierGuard g | + config.isBarrierGuard(g) and + node = g.getAGuardedNode() + ) } private class AdditionalFlowStepSource extends Node { diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl4.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl4.qll index 1d51a88d13d..094a2530c31 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl4.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl4.qll @@ -75,6 +75,9 @@ abstract class Configuration extends string { /** Holds if data flow out of `node` is prohibited. */ predicate isBarrierOut(Node node) { none() } + /** Holds if data flow through nodes guarded by `guard` is prohibited. */ + predicate isBarrierGuard(BarrierGuard guard) { none() } + /** * Holds if the additional flow step from `node1` to `node2` must be taken * into account in the analysis. @@ -136,6 +139,11 @@ private predicate fullBarrier(Node node, Configuration config) { or config.isBarrierOut(node) and not config.isSink(node) + or + exists(BarrierGuard g | + config.isBarrierGuard(g) and + node = g.getAGuardedNode() + ) } private class AdditionalFlowStepSource extends Node { diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl5.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl5.qll index 1d51a88d13d..094a2530c31 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl5.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl5.qll @@ -75,6 +75,9 @@ abstract class Configuration extends string { /** Holds if data flow out of `node` is prohibited. */ predicate isBarrierOut(Node node) { none() } + /** Holds if data flow through nodes guarded by `guard` is prohibited. */ + predicate isBarrierGuard(BarrierGuard guard) { none() } + /** * Holds if the additional flow step from `node1` to `node2` must be taken * into account in the analysis. @@ -136,6 +139,11 @@ private predicate fullBarrier(Node node, Configuration config) { or config.isBarrierOut(node) and not config.isSink(node) + or + exists(BarrierGuard g | + config.isBarrierGuard(g) and + node = g.getAGuardedNode() + ) } private class AdditionalFlowStepSource extends Node { diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowPublic.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowPublic.qll index 13fcb586395..545b0174269 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowPublic.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowPublic.qll @@ -3,6 +3,7 @@ private import cil private import dotnet private import DataFlowPrivate private import semmle.code.csharp.Caching +private import semmle.code.csharp.controlflow.Guards /** * An element, viewed as a node in a data flow graph. Either an expression @@ -162,3 +163,14 @@ abstract class NonLocalJumpNode extends Node { /** Gets a successor node that is potentially in another callable. */ abstract Node getAJumpSuccessor(boolean preservesValue); } + +/** A guard that validates some expression. */ +class BarrierGuard extends Internal::Guard { + /** Holds if this guard validates `e` upon evaluating to `v`. */ + abstract predicate checks(Expr e, AbstractValue v); + + /** Gets a node guarded by this. */ + final Node getAGuardedNode() { + none() // stub + } +} diff --git a/java/ql/src/Security/CWE/CWE-022/TaintedPath.ql b/java/ql/src/Security/CWE/CWE-022/TaintedPath.ql index 31fb0c5035c..2094207dc92 100644 --- a/java/ql/src/Security/CWE/CWE-022/TaintedPath.ql +++ b/java/ql/src/Security/CWE/CWE-022/TaintedPath.ql @@ -17,6 +17,17 @@ import semmle.code.java.dataflow.FlowSources import PathsCommon import DataFlow::PathGraph +class ContainsDotDotSanitizer extends DataFlow::BarrierGuard { + ContainsDotDotSanitizer() { + this.(MethodAccess).getMethod().hasName("contains") and + this.(MethodAccess).getAnArgument().(StringLiteral).getValue() = ".." + } + + override predicate checks(Expr e, boolean branch) { + e = this.(MethodAccess).getQualifier() and branch = false + } +} + class TaintedPathConfig extends TaintTracking::Configuration { TaintedPathConfig() { this = "TaintedPathConfig" } @@ -29,6 +40,10 @@ class TaintedPathConfig extends TaintTracking::Configuration { override predicate isSanitizer(DataFlow::Node node) { exists(Type t | t = node.getType() | t instanceof BoxedType or t instanceof PrimitiveType) } + + override predicate isSanitizerGuard(DataFlow::BarrierGuard guard) { + guard instanceof ContainsDotDotSanitizer + } } from DataFlow::PathNode source, DataFlow::PathNode sink, PathCreation p, TaintedPathConfig conf diff --git a/java/ql/src/semmle/code/java/dataflow/TaintTracking.qll b/java/ql/src/semmle/code/java/dataflow/TaintTracking.qll index c6dfc4e88ac..6d79359bb36 100644 --- a/java/ql/src/semmle/code/java/dataflow/TaintTracking.qll +++ b/java/ql/src/semmle/code/java/dataflow/TaintTracking.qll @@ -80,6 +80,11 @@ module TaintTracking { final override predicate isBarrierOut(DataFlow::Node node) { isSanitizerOut(node) } + /** Holds if data flow through nodes guarded by `guard` is prohibited. */ + predicate isSanitizerGuard(DataFlow::BarrierGuard guard) { none() } + + final override predicate isBarrierGuard(DataFlow::BarrierGuard guard) { isSanitizerGuard(guard) } + /** * Holds if the additional taint propagation step from `node1` to `node2` * must be taken into account in the analysis. @@ -162,6 +167,11 @@ module TaintTracking { final override predicate isBarrierOut(DataFlow::Node node) { isSanitizerOut(node) } + /** Holds if data flow through nodes guarded by `guard` is prohibited. */ + predicate isSanitizerGuard(DataFlow::BarrierGuard guard) { none() } + + final override predicate isBarrierGuard(DataFlow::BarrierGuard guard) { isSanitizerGuard(guard) } + /** * 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 1d51a88d13d..094a2530c31 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl.qll @@ -75,6 +75,9 @@ abstract class Configuration extends string { /** Holds if data flow out of `node` is prohibited. */ predicate isBarrierOut(Node node) { none() } + /** Holds if data flow through nodes guarded by `guard` is prohibited. */ + predicate isBarrierGuard(BarrierGuard guard) { none() } + /** * Holds if the additional flow step from `node1` to `node2` must be taken * into account in the analysis. @@ -136,6 +139,11 @@ private predicate fullBarrier(Node node, Configuration config) { or config.isBarrierOut(node) and not config.isSink(node) + or + exists(BarrierGuard g | + config.isBarrierGuard(g) and + node = g.getAGuardedNode() + ) } private class AdditionalFlowStepSource extends 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 1d51a88d13d..094a2530c31 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl2.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl2.qll @@ -75,6 +75,9 @@ abstract class Configuration extends string { /** Holds if data flow out of `node` is prohibited. */ predicate isBarrierOut(Node node) { none() } + /** Holds if data flow through nodes guarded by `guard` is prohibited. */ + predicate isBarrierGuard(BarrierGuard guard) { none() } + /** * Holds if the additional flow step from `node1` to `node2` must be taken * into account in the analysis. @@ -136,6 +139,11 @@ private predicate fullBarrier(Node node, Configuration config) { or config.isBarrierOut(node) and not config.isSink(node) + or + exists(BarrierGuard g | + config.isBarrierGuard(g) and + node = g.getAGuardedNode() + ) } private class AdditionalFlowStepSource extends 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 1d51a88d13d..094a2530c31 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl3.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl3.qll @@ -75,6 +75,9 @@ abstract class Configuration extends string { /** Holds if data flow out of `node` is prohibited. */ predicate isBarrierOut(Node node) { none() } + /** Holds if data flow through nodes guarded by `guard` is prohibited. */ + predicate isBarrierGuard(BarrierGuard guard) { none() } + /** * Holds if the additional flow step from `node1` to `node2` must be taken * into account in the analysis. @@ -136,6 +139,11 @@ private predicate fullBarrier(Node node, Configuration config) { or config.isBarrierOut(node) and not config.isSink(node) + or + exists(BarrierGuard g | + config.isBarrierGuard(g) and + node = g.getAGuardedNode() + ) } private class AdditionalFlowStepSource extends 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 1d51a88d13d..094a2530c31 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl4.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl4.qll @@ -75,6 +75,9 @@ abstract class Configuration extends string { /** Holds if data flow out of `node` is prohibited. */ predicate isBarrierOut(Node node) { none() } + /** Holds if data flow through nodes guarded by `guard` is prohibited. */ + predicate isBarrierGuard(BarrierGuard guard) { none() } + /** * Holds if the additional flow step from `node1` to `node2` must be taken * into account in the analysis. @@ -136,6 +139,11 @@ private predicate fullBarrier(Node node, Configuration config) { or config.isBarrierOut(node) and not config.isSink(node) + or + exists(BarrierGuard g | + config.isBarrierGuard(g) and + node = g.getAGuardedNode() + ) } private class AdditionalFlowStepSource extends 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 1d51a88d13d..094a2530c31 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl5.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl5.qll @@ -75,6 +75,9 @@ abstract class Configuration extends string { /** Holds if data flow out of `node` is prohibited. */ predicate isBarrierOut(Node node) { none() } + /** Holds if data flow through nodes guarded by `guard` is prohibited. */ + predicate isBarrierGuard(BarrierGuard guard) { none() } + /** * Holds if the additional flow step from `node1` to `node2` must be taken * into account in the analysis. @@ -136,6 +139,11 @@ private predicate fullBarrier(Node node, Configuration config) { or config.isBarrierOut(node) and not config.isSink(node) + or + exists(BarrierGuard g | + config.isBarrierGuard(g) and + node = g.getAGuardedNode() + ) } private class AdditionalFlowStepSource extends Node { diff --git a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowUtil.qll b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowUtil.qll index aae6f2ae2df..7657fea48eb 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowUtil.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowUtil.qll @@ -6,6 +6,7 @@ private import java private import DataFlowPrivate private import semmle.code.java.dataflow.SSA private import semmle.code.java.dataflow.TypeFlow +private import semmle.code.java.controlflow.Guards import semmle.code.java.dataflow.InstanceAccess cached @@ -416,3 +417,19 @@ Node getInstanceArgument(Call call) { explicitInstanceArgument(call, result.asExpr()) or implicitInstanceArgument(call, result.(ImplicitInstanceAccess).getInstanceAccess()) } + +/** A guard that validates some expression. */ +class BarrierGuard extends Guard { + /** Holds if this guard validates `e` upon evaluating to `branch`. */ + abstract predicate checks(Expr e, boolean branch); + + /** Gets a node guarded by this. */ + final Node getAGuardedNode() { + exists(SsaVariable v, boolean branch, RValue use | + this.checks(v.getAUse(), branch) and + use = v.getAUse() and + this.controls(use.getBasicBlock(), branch) and + result.asExpr() = use + ) + } +}