Merge pull request #9618 from aschackmull/dataflow/deprecate-barrierguard-class

Dataflow: Deprecate BarrierGuard class
This commit is contained in:
Anders Schack-Mulligen
2022-06-22 10:44:08 +02:00
committed by GitHub
195 changed files with 2584 additions and 1294 deletions

View File

@@ -0,0 +1,4 @@
---
category: deprecated
---
* The `BarrierGuard` class has been deprecated. Such barriers and sanitizers can now instead be created using the new `BarrierGuard` parameterized module.

View File

@@ -90,14 +90,20 @@ 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() }
/**
* DEPRECATED: Use `isBarrier` and `BarrierGuard` module instead.
*
* Holds if data flow through nodes guarded by `guard` is prohibited.
*/
deprecated predicate isBarrierGuard(BarrierGuard guard) { none() }
/**
* DEPRECATED: Use `isBarrier` and `BarrierGuard` module instead.
*
* Holds if data flow through nodes guarded by `guard` is prohibited when
* the flow state is `state`
*/
predicate isBarrierGuard(BarrierGuard guard, FlowState state) { none() }
deprecated predicate isBarrierGuard(BarrierGuard guard, FlowState state) { none() }
/**
* Holds if data may flow from `node1` to `node2` in addition to the normal data-flow steps.
@@ -335,6 +341,29 @@ private predicate outBarrier(NodeEx node, Configuration config) {
)
}
/** A bridge class to access the deprecated `isBarrierGuard`. */
private class BarrierGuardGuardedNodeBridge extends Unit {
abstract predicate guardedNode(Node n, Configuration config);
abstract predicate guardedNode(Node n, FlowState state, Configuration config);
}
private class BarrierGuardGuardedNode extends BarrierGuardGuardedNodeBridge {
deprecated override predicate guardedNode(Node n, Configuration config) {
exists(BarrierGuard g |
config.isBarrierGuard(g) and
n = g.getAGuardedNode()
)
}
deprecated override predicate guardedNode(Node n, FlowState state, Configuration config) {
exists(BarrierGuard g |
config.isBarrierGuard(g, state) and
n = g.getAGuardedNode()
)
}
}
pragma[nomagic]
private predicate fullBarrier(NodeEx node, Configuration config) {
exists(Node n | node.asNode() = n |
@@ -348,10 +377,7 @@ private predicate fullBarrier(NodeEx node, Configuration config) {
not config.isSink(n) and
not config.isSink(n, _)
or
exists(BarrierGuard g |
config.isBarrierGuard(g) and
n = g.getAGuardedNode()
)
any(BarrierGuardGuardedNodeBridge b).guardedNode(n, config)
)
}
@@ -360,10 +386,7 @@ private predicate stateBarrier(NodeEx node, FlowState state, Configuration confi
exists(Node n | node.asNode() = n |
config.isBarrier(n, state)
or
exists(BarrierGuard g |
config.isBarrierGuard(g, state) and
n = g.getAGuardedNode()
)
any(BarrierGuardGuardedNodeBridge b).guardedNode(n, state, config)
)
}

View File

@@ -90,14 +90,20 @@ 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() }
/**
* DEPRECATED: Use `isBarrier` and `BarrierGuard` module instead.
*
* Holds if data flow through nodes guarded by `guard` is prohibited.
*/
deprecated predicate isBarrierGuard(BarrierGuard guard) { none() }
/**
* DEPRECATED: Use `isBarrier` and `BarrierGuard` module instead.
*
* Holds if data flow through nodes guarded by `guard` is prohibited when
* the flow state is `state`
*/
predicate isBarrierGuard(BarrierGuard guard, FlowState state) { none() }
deprecated predicate isBarrierGuard(BarrierGuard guard, FlowState state) { none() }
/**
* Holds if data may flow from `node1` to `node2` in addition to the normal data-flow steps.
@@ -335,6 +341,29 @@ private predicate outBarrier(NodeEx node, Configuration config) {
)
}
/** A bridge class to access the deprecated `isBarrierGuard`. */
private class BarrierGuardGuardedNodeBridge extends Unit {
abstract predicate guardedNode(Node n, Configuration config);
abstract predicate guardedNode(Node n, FlowState state, Configuration config);
}
private class BarrierGuardGuardedNode extends BarrierGuardGuardedNodeBridge {
deprecated override predicate guardedNode(Node n, Configuration config) {
exists(BarrierGuard g |
config.isBarrierGuard(g) and
n = g.getAGuardedNode()
)
}
deprecated override predicate guardedNode(Node n, FlowState state, Configuration config) {
exists(BarrierGuard g |
config.isBarrierGuard(g, state) and
n = g.getAGuardedNode()
)
}
}
pragma[nomagic]
private predicate fullBarrier(NodeEx node, Configuration config) {
exists(Node n | node.asNode() = n |
@@ -348,10 +377,7 @@ private predicate fullBarrier(NodeEx node, Configuration config) {
not config.isSink(n) and
not config.isSink(n, _)
or
exists(BarrierGuard g |
config.isBarrierGuard(g) and
n = g.getAGuardedNode()
)
any(BarrierGuardGuardedNodeBridge b).guardedNode(n, config)
)
}
@@ -360,10 +386,7 @@ private predicate stateBarrier(NodeEx node, FlowState state, Configuration confi
exists(Node n | node.asNode() = n |
config.isBarrier(n, state)
or
exists(BarrierGuard g |
config.isBarrierGuard(g, state) and
n = g.getAGuardedNode()
)
any(BarrierGuardGuardedNodeBridge b).guardedNode(n, state, config)
)
}

View File

@@ -90,14 +90,20 @@ 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() }
/**
* DEPRECATED: Use `isBarrier` and `BarrierGuard` module instead.
*
* Holds if data flow through nodes guarded by `guard` is prohibited.
*/
deprecated predicate isBarrierGuard(BarrierGuard guard) { none() }
/**
* DEPRECATED: Use `isBarrier` and `BarrierGuard` module instead.
*
* Holds if data flow through nodes guarded by `guard` is prohibited when
* the flow state is `state`
*/
predicate isBarrierGuard(BarrierGuard guard, FlowState state) { none() }
deprecated predicate isBarrierGuard(BarrierGuard guard, FlowState state) { none() }
/**
* Holds if data may flow from `node1` to `node2` in addition to the normal data-flow steps.
@@ -335,6 +341,29 @@ private predicate outBarrier(NodeEx node, Configuration config) {
)
}
/** A bridge class to access the deprecated `isBarrierGuard`. */
private class BarrierGuardGuardedNodeBridge extends Unit {
abstract predicate guardedNode(Node n, Configuration config);
abstract predicate guardedNode(Node n, FlowState state, Configuration config);
}
private class BarrierGuardGuardedNode extends BarrierGuardGuardedNodeBridge {
deprecated override predicate guardedNode(Node n, Configuration config) {
exists(BarrierGuard g |
config.isBarrierGuard(g) and
n = g.getAGuardedNode()
)
}
deprecated override predicate guardedNode(Node n, FlowState state, Configuration config) {
exists(BarrierGuard g |
config.isBarrierGuard(g, state) and
n = g.getAGuardedNode()
)
}
}
pragma[nomagic]
private predicate fullBarrier(NodeEx node, Configuration config) {
exists(Node n | node.asNode() = n |
@@ -348,10 +377,7 @@ private predicate fullBarrier(NodeEx node, Configuration config) {
not config.isSink(n) and
not config.isSink(n, _)
or
exists(BarrierGuard g |
config.isBarrierGuard(g) and
n = g.getAGuardedNode()
)
any(BarrierGuardGuardedNodeBridge b).guardedNode(n, config)
)
}
@@ -360,10 +386,7 @@ private predicate stateBarrier(NodeEx node, FlowState state, Configuration confi
exists(Node n | node.asNode() = n |
config.isBarrier(n, state)
or
exists(BarrierGuard g |
config.isBarrierGuard(g, state) and
n = g.getAGuardedNode()
)
any(BarrierGuardGuardedNodeBridge b).guardedNode(n, state, config)
)
}

View File

@@ -90,14 +90,20 @@ 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() }
/**
* DEPRECATED: Use `isBarrier` and `BarrierGuard` module instead.
*
* Holds if data flow through nodes guarded by `guard` is prohibited.
*/
deprecated predicate isBarrierGuard(BarrierGuard guard) { none() }
/**
* DEPRECATED: Use `isBarrier` and `BarrierGuard` module instead.
*
* Holds if data flow through nodes guarded by `guard` is prohibited when
* the flow state is `state`
*/
predicate isBarrierGuard(BarrierGuard guard, FlowState state) { none() }
deprecated predicate isBarrierGuard(BarrierGuard guard, FlowState state) { none() }
/**
* Holds if data may flow from `node1` to `node2` in addition to the normal data-flow steps.
@@ -335,6 +341,29 @@ private predicate outBarrier(NodeEx node, Configuration config) {
)
}
/** A bridge class to access the deprecated `isBarrierGuard`. */
private class BarrierGuardGuardedNodeBridge extends Unit {
abstract predicate guardedNode(Node n, Configuration config);
abstract predicate guardedNode(Node n, FlowState state, Configuration config);
}
private class BarrierGuardGuardedNode extends BarrierGuardGuardedNodeBridge {
deprecated override predicate guardedNode(Node n, Configuration config) {
exists(BarrierGuard g |
config.isBarrierGuard(g) and
n = g.getAGuardedNode()
)
}
deprecated override predicate guardedNode(Node n, FlowState state, Configuration config) {
exists(BarrierGuard g |
config.isBarrierGuard(g, state) and
n = g.getAGuardedNode()
)
}
}
pragma[nomagic]
private predicate fullBarrier(NodeEx node, Configuration config) {
exists(Node n | node.asNode() = n |
@@ -348,10 +377,7 @@ private predicate fullBarrier(NodeEx node, Configuration config) {
not config.isSink(n) and
not config.isSink(n, _)
or
exists(BarrierGuard g |
config.isBarrierGuard(g) and
n = g.getAGuardedNode()
)
any(BarrierGuardGuardedNodeBridge b).guardedNode(n, config)
)
}
@@ -360,10 +386,7 @@ private predicate stateBarrier(NodeEx node, FlowState state, Configuration confi
exists(Node n | node.asNode() = n |
config.isBarrier(n, state)
or
exists(BarrierGuard g |
config.isBarrierGuard(g, state) and
n = g.getAGuardedNode()
)
any(BarrierGuardGuardedNodeBridge b).guardedNode(n, state, config)
)
}

View File

@@ -90,14 +90,20 @@ 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() }
/**
* DEPRECATED: Use `isBarrier` and `BarrierGuard` module instead.
*
* Holds if data flow through nodes guarded by `guard` is prohibited.
*/
deprecated predicate isBarrierGuard(BarrierGuard guard) { none() }
/**
* DEPRECATED: Use `isBarrier` and `BarrierGuard` module instead.
*
* Holds if data flow through nodes guarded by `guard` is prohibited when
* the flow state is `state`
*/
predicate isBarrierGuard(BarrierGuard guard, FlowState state) { none() }
deprecated predicate isBarrierGuard(BarrierGuard guard, FlowState state) { none() }
/**
* Holds if data may flow from `node1` to `node2` in addition to the normal data-flow steps.
@@ -335,6 +341,29 @@ private predicate outBarrier(NodeEx node, Configuration config) {
)
}
/** A bridge class to access the deprecated `isBarrierGuard`. */
private class BarrierGuardGuardedNodeBridge extends Unit {
abstract predicate guardedNode(Node n, Configuration config);
abstract predicate guardedNode(Node n, FlowState state, Configuration config);
}
private class BarrierGuardGuardedNode extends BarrierGuardGuardedNodeBridge {
deprecated override predicate guardedNode(Node n, Configuration config) {
exists(BarrierGuard g |
config.isBarrierGuard(g) and
n = g.getAGuardedNode()
)
}
deprecated override predicate guardedNode(Node n, FlowState state, Configuration config) {
exists(BarrierGuard g |
config.isBarrierGuard(g, state) and
n = g.getAGuardedNode()
)
}
}
pragma[nomagic]
private predicate fullBarrier(NodeEx node, Configuration config) {
exists(Node n | node.asNode() = n |
@@ -348,10 +377,7 @@ private predicate fullBarrier(NodeEx node, Configuration config) {
not config.isSink(n) and
not config.isSink(n, _)
or
exists(BarrierGuard g |
config.isBarrierGuard(g) and
n = g.getAGuardedNode()
)
any(BarrierGuardGuardedNodeBridge b).guardedNode(n, config)
)
}
@@ -360,10 +386,7 @@ private predicate stateBarrier(NodeEx node, FlowState state, Configuration confi
exists(Node n | node.asNode() = n |
config.isBarrier(n, state)
or
exists(BarrierGuard g |
config.isBarrierGuard(g, state) and
n = g.getAGuardedNode()
)
any(BarrierGuardGuardedNodeBridge b).guardedNode(n, state, config)
)
}

View File

@@ -850,6 +850,34 @@ class ContentSet instanceof Content {
}
/**
* Holds if the guard `g` validates the expression `e` upon evaluating to `branch`.
*
* The expression `e` is expected to be a syntactic part of the guard `g`.
* For example, the guard `g` might be a call `isSafe(x)` and the expression `e`
* the argument `x`.
*/
signature predicate guardChecksSig(GuardCondition g, Expr e, boolean branch);
/**
* Provides a set of barrier nodes for a guard that validates an expression.
*
* This is expected to be used in `isBarrier`/`isSanitizer` definitions
* in data flow and taint tracking.
*/
module BarrierGuard<guardChecksSig/3 guardChecks> {
/** Gets a node that is safely guarded by the given guard check. */
ExprNode getABarrierNode() {
exists(GuardCondition g, SsaDefinition def, Variable v, boolean branch |
result.getExpr() = def.getAUse(v) and
guardChecks(g, def.getAUse(v), branch) and
g.controls(result.getExpr().getBasicBlock(), branch)
)
}
}
/**
* DEPRECATED: Use `BarrierGuard` module instead.
*
* A guard that validates some expression.
*
* To use this in a configuration, extend the class and provide a
@@ -858,7 +886,7 @@ class ContentSet instanceof Content {
*
* It is important that all extending classes in scope are disjoint.
*/
class BarrierGuard extends GuardCondition {
deprecated class BarrierGuard extends GuardCondition {
/** Override this predicate to hold if this guard validates `e` upon evaluating to `b`. */
abstract predicate checks(Expr e, boolean b);

View File

@@ -47,12 +47,6 @@ predicate defaultImplicitTaintRead(DataFlow::Node node, DataFlow::Content c) { n
*/
predicate defaultTaintSanitizer(DataFlow::Node node) { none() }
/**
* Holds if `guard` should be a sanitizer guard in all global taint flow configurations
* but not in local taint.
*/
predicate defaultTaintSanitizerGuard(DataFlow::BarrierGuard guard) { none() }
/**
* Holds if taint can flow in one local step from `nodeFrom` to `nodeTo` excluding
* local data flow steps. That is, `nodeFrom` and `nodeTo` are likely to represent

View File

@@ -116,20 +116,30 @@ abstract class Configuration extends DataFlow::Configuration {
final override predicate isBarrierOut(DataFlow::Node node) { this.isSanitizerOut(node) }
/** Holds if taint propagation through nodes guarded by `guard` is prohibited. */
predicate isSanitizerGuard(DataFlow::BarrierGuard guard) { none() }
/**
* DEPRECATED: Use `isSanitizer` and `BarrierGuard` module instead.
*
* Holds if taint propagation through nodes guarded by `guard` is prohibited.
*/
deprecated predicate isSanitizerGuard(DataFlow::BarrierGuard guard) { none() }
final override predicate isBarrierGuard(DataFlow::BarrierGuard guard) {
this.isSanitizerGuard(guard) or defaultTaintSanitizerGuard(guard)
deprecated final override predicate isBarrierGuard(DataFlow::BarrierGuard guard) {
this.isSanitizerGuard(guard)
}
/**
* DEPRECATED: Use `isSanitizer` and `BarrierGuard` module instead.
*
* Holds if taint propagation through nodes guarded by `guard` is prohibited
* when the flow state is `state`.
*/
predicate isSanitizerGuard(DataFlow::BarrierGuard guard, DataFlow::FlowState state) { none() }
deprecated predicate isSanitizerGuard(DataFlow::BarrierGuard guard, DataFlow::FlowState state) {
none()
}
final override predicate isBarrierGuard(DataFlow::BarrierGuard guard, DataFlow::FlowState state) {
deprecated final override predicate isBarrierGuard(
DataFlow::BarrierGuard guard, DataFlow::FlowState state
) {
this.isSanitizerGuard(guard, state)
}

View File

@@ -116,20 +116,30 @@ abstract class Configuration extends DataFlow::Configuration {
final override predicate isBarrierOut(DataFlow::Node node) { this.isSanitizerOut(node) }
/** Holds if taint propagation through nodes guarded by `guard` is prohibited. */
predicate isSanitizerGuard(DataFlow::BarrierGuard guard) { none() }
/**
* DEPRECATED: Use `isSanitizer` and `BarrierGuard` module instead.
*
* Holds if taint propagation through nodes guarded by `guard` is prohibited.
*/
deprecated predicate isSanitizerGuard(DataFlow::BarrierGuard guard) { none() }
final override predicate isBarrierGuard(DataFlow::BarrierGuard guard) {
this.isSanitizerGuard(guard) or defaultTaintSanitizerGuard(guard)
deprecated final override predicate isBarrierGuard(DataFlow::BarrierGuard guard) {
this.isSanitizerGuard(guard)
}
/**
* DEPRECATED: Use `isSanitizer` and `BarrierGuard` module instead.
*
* Holds if taint propagation through nodes guarded by `guard` is prohibited
* when the flow state is `state`.
*/
predicate isSanitizerGuard(DataFlow::BarrierGuard guard, DataFlow::FlowState state) { none() }
deprecated predicate isSanitizerGuard(DataFlow::BarrierGuard guard, DataFlow::FlowState state) {
none()
}
final override predicate isBarrierGuard(DataFlow::BarrierGuard guard, DataFlow::FlowState state) {
deprecated final override predicate isBarrierGuard(
DataFlow::BarrierGuard guard, DataFlow::FlowState state
) {
this.isSanitizerGuard(guard, state)
}

View File

@@ -90,14 +90,20 @@ 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() }
/**
* DEPRECATED: Use `isBarrier` and `BarrierGuard` module instead.
*
* Holds if data flow through nodes guarded by `guard` is prohibited.
*/
deprecated predicate isBarrierGuard(BarrierGuard guard) { none() }
/**
* DEPRECATED: Use `isBarrier` and `BarrierGuard` module instead.
*
* Holds if data flow through nodes guarded by `guard` is prohibited when
* the flow state is `state`
*/
predicate isBarrierGuard(BarrierGuard guard, FlowState state) { none() }
deprecated predicate isBarrierGuard(BarrierGuard guard, FlowState state) { none() }
/**
* Holds if data may flow from `node1` to `node2` in addition to the normal data-flow steps.
@@ -335,6 +341,29 @@ private predicate outBarrier(NodeEx node, Configuration config) {
)
}
/** A bridge class to access the deprecated `isBarrierGuard`. */
private class BarrierGuardGuardedNodeBridge extends Unit {
abstract predicate guardedNode(Node n, Configuration config);
abstract predicate guardedNode(Node n, FlowState state, Configuration config);
}
private class BarrierGuardGuardedNode extends BarrierGuardGuardedNodeBridge {
deprecated override predicate guardedNode(Node n, Configuration config) {
exists(BarrierGuard g |
config.isBarrierGuard(g) and
n = g.getAGuardedNode()
)
}
deprecated override predicate guardedNode(Node n, FlowState state, Configuration config) {
exists(BarrierGuard g |
config.isBarrierGuard(g, state) and
n = g.getAGuardedNode()
)
}
}
pragma[nomagic]
private predicate fullBarrier(NodeEx node, Configuration config) {
exists(Node n | node.asNode() = n |
@@ -348,10 +377,7 @@ private predicate fullBarrier(NodeEx node, Configuration config) {
not config.isSink(n) and
not config.isSink(n, _)
or
exists(BarrierGuard g |
config.isBarrierGuard(g) and
n = g.getAGuardedNode()
)
any(BarrierGuardGuardedNodeBridge b).guardedNode(n, config)
)
}
@@ -360,10 +386,7 @@ private predicate stateBarrier(NodeEx node, FlowState state, Configuration confi
exists(Node n | node.asNode() = n |
config.isBarrier(n, state)
or
exists(BarrierGuard g |
config.isBarrierGuard(g, state) and
n = g.getAGuardedNode()
)
any(BarrierGuardGuardedNodeBridge b).guardedNode(n, state, config)
)
}

View File

@@ -90,14 +90,20 @@ 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() }
/**
* DEPRECATED: Use `isBarrier` and `BarrierGuard` module instead.
*
* Holds if data flow through nodes guarded by `guard` is prohibited.
*/
deprecated predicate isBarrierGuard(BarrierGuard guard) { none() }
/**
* DEPRECATED: Use `isBarrier` and `BarrierGuard` module instead.
*
* Holds if data flow through nodes guarded by `guard` is prohibited when
* the flow state is `state`
*/
predicate isBarrierGuard(BarrierGuard guard, FlowState state) { none() }
deprecated predicate isBarrierGuard(BarrierGuard guard, FlowState state) { none() }
/**
* Holds if data may flow from `node1` to `node2` in addition to the normal data-flow steps.
@@ -335,6 +341,29 @@ private predicate outBarrier(NodeEx node, Configuration config) {
)
}
/** A bridge class to access the deprecated `isBarrierGuard`. */
private class BarrierGuardGuardedNodeBridge extends Unit {
abstract predicate guardedNode(Node n, Configuration config);
abstract predicate guardedNode(Node n, FlowState state, Configuration config);
}
private class BarrierGuardGuardedNode extends BarrierGuardGuardedNodeBridge {
deprecated override predicate guardedNode(Node n, Configuration config) {
exists(BarrierGuard g |
config.isBarrierGuard(g) and
n = g.getAGuardedNode()
)
}
deprecated override predicate guardedNode(Node n, FlowState state, Configuration config) {
exists(BarrierGuard g |
config.isBarrierGuard(g, state) and
n = g.getAGuardedNode()
)
}
}
pragma[nomagic]
private predicate fullBarrier(NodeEx node, Configuration config) {
exists(Node n | node.asNode() = n |
@@ -348,10 +377,7 @@ private predicate fullBarrier(NodeEx node, Configuration config) {
not config.isSink(n) and
not config.isSink(n, _)
or
exists(BarrierGuard g |
config.isBarrierGuard(g) and
n = g.getAGuardedNode()
)
any(BarrierGuardGuardedNodeBridge b).guardedNode(n, config)
)
}
@@ -360,10 +386,7 @@ private predicate stateBarrier(NodeEx node, FlowState state, Configuration confi
exists(Node n | node.asNode() = n |
config.isBarrier(n, state)
or
exists(BarrierGuard g |
config.isBarrierGuard(g, state) and
n = g.getAGuardedNode()
)
any(BarrierGuardGuardedNodeBridge b).guardedNode(n, state, config)
)
}

View File

@@ -90,14 +90,20 @@ 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() }
/**
* DEPRECATED: Use `isBarrier` and `BarrierGuard` module instead.
*
* Holds if data flow through nodes guarded by `guard` is prohibited.
*/
deprecated predicate isBarrierGuard(BarrierGuard guard) { none() }
/**
* DEPRECATED: Use `isBarrier` and `BarrierGuard` module instead.
*
* Holds if data flow through nodes guarded by `guard` is prohibited when
* the flow state is `state`
*/
predicate isBarrierGuard(BarrierGuard guard, FlowState state) { none() }
deprecated predicate isBarrierGuard(BarrierGuard guard, FlowState state) { none() }
/**
* Holds if data may flow from `node1` to `node2` in addition to the normal data-flow steps.
@@ -335,6 +341,29 @@ private predicate outBarrier(NodeEx node, Configuration config) {
)
}
/** A bridge class to access the deprecated `isBarrierGuard`. */
private class BarrierGuardGuardedNodeBridge extends Unit {
abstract predicate guardedNode(Node n, Configuration config);
abstract predicate guardedNode(Node n, FlowState state, Configuration config);
}
private class BarrierGuardGuardedNode extends BarrierGuardGuardedNodeBridge {
deprecated override predicate guardedNode(Node n, Configuration config) {
exists(BarrierGuard g |
config.isBarrierGuard(g) and
n = g.getAGuardedNode()
)
}
deprecated override predicate guardedNode(Node n, FlowState state, Configuration config) {
exists(BarrierGuard g |
config.isBarrierGuard(g, state) and
n = g.getAGuardedNode()
)
}
}
pragma[nomagic]
private predicate fullBarrier(NodeEx node, Configuration config) {
exists(Node n | node.asNode() = n |
@@ -348,10 +377,7 @@ private predicate fullBarrier(NodeEx node, Configuration config) {
not config.isSink(n) and
not config.isSink(n, _)
or
exists(BarrierGuard g |
config.isBarrierGuard(g) and
n = g.getAGuardedNode()
)
any(BarrierGuardGuardedNodeBridge b).guardedNode(n, config)
)
}
@@ -360,10 +386,7 @@ private predicate stateBarrier(NodeEx node, FlowState state, Configuration confi
exists(Node n | node.asNode() = n |
config.isBarrier(n, state)
or
exists(BarrierGuard g |
config.isBarrierGuard(g, state) and
n = g.getAGuardedNode()
)
any(BarrierGuardGuardedNodeBridge b).guardedNode(n, state, config)
)
}

View File

@@ -90,14 +90,20 @@ 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() }
/**
* DEPRECATED: Use `isBarrier` and `BarrierGuard` module instead.
*
* Holds if data flow through nodes guarded by `guard` is prohibited.
*/
deprecated predicate isBarrierGuard(BarrierGuard guard) { none() }
/**
* DEPRECATED: Use `isBarrier` and `BarrierGuard` module instead.
*
* Holds if data flow through nodes guarded by `guard` is prohibited when
* the flow state is `state`
*/
predicate isBarrierGuard(BarrierGuard guard, FlowState state) { none() }
deprecated predicate isBarrierGuard(BarrierGuard guard, FlowState state) { none() }
/**
* Holds if data may flow from `node1` to `node2` in addition to the normal data-flow steps.
@@ -335,6 +341,29 @@ private predicate outBarrier(NodeEx node, Configuration config) {
)
}
/** A bridge class to access the deprecated `isBarrierGuard`. */
private class BarrierGuardGuardedNodeBridge extends Unit {
abstract predicate guardedNode(Node n, Configuration config);
abstract predicate guardedNode(Node n, FlowState state, Configuration config);
}
private class BarrierGuardGuardedNode extends BarrierGuardGuardedNodeBridge {
deprecated override predicate guardedNode(Node n, Configuration config) {
exists(BarrierGuard g |
config.isBarrierGuard(g) and
n = g.getAGuardedNode()
)
}
deprecated override predicate guardedNode(Node n, FlowState state, Configuration config) {
exists(BarrierGuard g |
config.isBarrierGuard(g, state) and
n = g.getAGuardedNode()
)
}
}
pragma[nomagic]
private predicate fullBarrier(NodeEx node, Configuration config) {
exists(Node n | node.asNode() = n |
@@ -348,10 +377,7 @@ private predicate fullBarrier(NodeEx node, Configuration config) {
not config.isSink(n) and
not config.isSink(n, _)
or
exists(BarrierGuard g |
config.isBarrierGuard(g) and
n = g.getAGuardedNode()
)
any(BarrierGuardGuardedNodeBridge b).guardedNode(n, config)
)
}
@@ -360,10 +386,7 @@ private predicate stateBarrier(NodeEx node, FlowState state, Configuration confi
exists(Node n | node.asNode() = n |
config.isBarrier(n, state)
or
exists(BarrierGuard g |
config.isBarrierGuard(g, state) and
n = g.getAGuardedNode()
)
any(BarrierGuardGuardedNodeBridge b).guardedNode(n, state, config)
)
}

View File

@@ -1092,6 +1092,56 @@ class ContentSet instanceof Content {
}
/**
* Holds if the guard `g` validates the expression `e` upon evaluating to `branch`.
*
* The expression `e` is expected to be a syntactic part of the guard `g`.
* For example, the guard `g` might be a call `isSafe(x)` and the expression `e`
* the argument `x`.
*/
signature predicate guardChecksSig(IRGuardCondition g, Expr e, boolean branch);
/**
* Provides a set of barrier nodes for a guard that validates an expression.
*
* This is expected to be used in `isBarrier`/`isSanitizer` definitions
* in data flow and taint tracking.
*/
module BarrierGuard<guardChecksSig/3 guardChecks> {
/** Gets a node that is safely guarded by the given guard check. */
ExprNode getABarrierNode() {
exists(IRGuardCondition g, ValueNumber value, boolean edge |
guardChecks(g, value.getAnInstruction().getConvertedResultExpression(), edge) and
result.asInstruction() = value.getAnInstruction() and
g.controls(result.asInstruction().getBlock(), edge)
)
}
}
/**
* Holds if the guard `g` validates the instruction `instr` upon evaluating to `branch`.
*/
signature predicate instructionGuardChecksSig(IRGuardCondition g, Instruction instr, boolean branch);
/**
* Provides a set of barrier nodes for a guard that validates an instruction.
*
* This is expected to be used in `isBarrier`/`isSanitizer` definitions
* in data flow and taint tracking.
*/
module InstructionBarrierGuard<instructionGuardChecksSig/3 instructionGuardChecks> {
/** Gets a node that is safely guarded by the given guard check. */
ExprNode getABarrierNode() {
exists(IRGuardCondition g, ValueNumber value, boolean edge |
instructionGuardChecks(g, value.getAnInstruction(), edge) and
result.asInstruction() = value.getAnInstruction() and
g.controls(result.asInstruction().getBlock(), edge)
)
}
}
/**
* DEPRECATED: Use `BarrierGuard` module instead.
*
* A guard that validates some instruction.
*
* To use this in a configuration, extend the class and provide a
@@ -1100,7 +1150,7 @@ class ContentSet instanceof Content {
*
* It is important that all extending classes in scope are disjoint.
*/
class BarrierGuard extends IRGuardCondition {
deprecated class BarrierGuard extends IRGuardCondition {
/** Override this predicate to hold if this guard validates `instr` upon evaluating to `b`. */
predicate checksInstr(Instruction instr, boolean b) { none() }

View File

@@ -94,12 +94,6 @@ private string getNodeProperty(DataFlow::Node node, string key) {
any(DataFlow::Configuration cfg).isBarrierIn(node) and kind = "in"
or
any(DataFlow::Configuration cfg).isBarrierOut(node) and kind = "out"
or
exists(DataFlow::BarrierGuard guard |
any(DataFlow::Configuration cfg).isBarrierGuard(guard) and
node = guard.getAGuardedNode() and
kind = "guard(" + guard.getResultId() + ")"
)
|
kind, ", "
)

View File

@@ -163,12 +163,6 @@ predicate defaultImplicitTaintRead(DataFlow::Node node, DataFlow::Content c) { n
*/
predicate defaultTaintSanitizer(DataFlow::Node node) { none() }
/**
* Holds if `guard` should be a sanitizer guard in all global taint flow configurations
* but not in local taint.
*/
predicate defaultTaintSanitizerGuard(DataFlow::BarrierGuard guard) { none() }
/**
* Holds if taint can flow from `instrIn` to `instrOut` through a call to a
* modeled function.

View File

@@ -116,20 +116,30 @@ abstract class Configuration extends DataFlow::Configuration {
final override predicate isBarrierOut(DataFlow::Node node) { this.isSanitizerOut(node) }
/** Holds if taint propagation through nodes guarded by `guard` is prohibited. */
predicate isSanitizerGuard(DataFlow::BarrierGuard guard) { none() }
/**
* DEPRECATED: Use `isSanitizer` and `BarrierGuard` module instead.
*
* Holds if taint propagation through nodes guarded by `guard` is prohibited.
*/
deprecated predicate isSanitizerGuard(DataFlow::BarrierGuard guard) { none() }
final override predicate isBarrierGuard(DataFlow::BarrierGuard guard) {
this.isSanitizerGuard(guard) or defaultTaintSanitizerGuard(guard)
deprecated final override predicate isBarrierGuard(DataFlow::BarrierGuard guard) {
this.isSanitizerGuard(guard)
}
/**
* DEPRECATED: Use `isSanitizer` and `BarrierGuard` module instead.
*
* Holds if taint propagation through nodes guarded by `guard` is prohibited
* when the flow state is `state`.
*/
predicate isSanitizerGuard(DataFlow::BarrierGuard guard, DataFlow::FlowState state) { none() }
deprecated predicate isSanitizerGuard(DataFlow::BarrierGuard guard, DataFlow::FlowState state) {
none()
}
final override predicate isBarrierGuard(DataFlow::BarrierGuard guard, DataFlow::FlowState state) {
deprecated final override predicate isBarrierGuard(
DataFlow::BarrierGuard guard, DataFlow::FlowState state
) {
this.isSanitizerGuard(guard, state)
}

View File

@@ -116,20 +116,30 @@ abstract class Configuration extends DataFlow::Configuration {
final override predicate isBarrierOut(DataFlow::Node node) { this.isSanitizerOut(node) }
/** Holds if taint propagation through nodes guarded by `guard` is prohibited. */
predicate isSanitizerGuard(DataFlow::BarrierGuard guard) { none() }
/**
* DEPRECATED: Use `isSanitizer` and `BarrierGuard` module instead.
*
* Holds if taint propagation through nodes guarded by `guard` is prohibited.
*/
deprecated predicate isSanitizerGuard(DataFlow::BarrierGuard guard) { none() }
final override predicate isBarrierGuard(DataFlow::BarrierGuard guard) {
this.isSanitizerGuard(guard) or defaultTaintSanitizerGuard(guard)
deprecated final override predicate isBarrierGuard(DataFlow::BarrierGuard guard) {
this.isSanitizerGuard(guard)
}
/**
* DEPRECATED: Use `isSanitizer` and `BarrierGuard` module instead.
*
* Holds if taint propagation through nodes guarded by `guard` is prohibited
* when the flow state is `state`.
*/
predicate isSanitizerGuard(DataFlow::BarrierGuard guard, DataFlow::FlowState state) { none() }
deprecated predicate isSanitizerGuard(DataFlow::BarrierGuard guard, DataFlow::FlowState state) {
none()
}
final override predicate isBarrierGuard(DataFlow::BarrierGuard guard, DataFlow::FlowState state) {
deprecated final override predicate isBarrierGuard(
DataFlow::BarrierGuard guard, DataFlow::FlowState state
) {
this.isSanitizerGuard(guard, state)
}

View File

@@ -116,20 +116,30 @@ abstract class Configuration extends DataFlow::Configuration {
final override predicate isBarrierOut(DataFlow::Node node) { this.isSanitizerOut(node) }
/** Holds if taint propagation through nodes guarded by `guard` is prohibited. */
predicate isSanitizerGuard(DataFlow::BarrierGuard guard) { none() }
/**
* DEPRECATED: Use `isSanitizer` and `BarrierGuard` module instead.
*
* Holds if taint propagation through nodes guarded by `guard` is prohibited.
*/
deprecated predicate isSanitizerGuard(DataFlow::BarrierGuard guard) { none() }
final override predicate isBarrierGuard(DataFlow::BarrierGuard guard) {
this.isSanitizerGuard(guard) or defaultTaintSanitizerGuard(guard)
deprecated final override predicate isBarrierGuard(DataFlow::BarrierGuard guard) {
this.isSanitizerGuard(guard)
}
/**
* DEPRECATED: Use `isSanitizer` and `BarrierGuard` module instead.
*
* Holds if taint propagation through nodes guarded by `guard` is prohibited
* when the flow state is `state`.
*/
predicate isSanitizerGuard(DataFlow::BarrierGuard guard, DataFlow::FlowState state) { none() }
deprecated predicate isSanitizerGuard(DataFlow::BarrierGuard guard, DataFlow::FlowState state) {
none()
}
final override predicate isBarrierGuard(DataFlow::BarrierGuard guard, DataFlow::FlowState state) {
deprecated final override predicate isBarrierGuard(
DataFlow::BarrierGuard guard, DataFlow::FlowState state
) {
this.isSanitizerGuard(guard, state)
}

View File

@@ -2,19 +2,17 @@ import TestUtilities.dataflow.FlowTestCommon
module AstTest {
private import semmle.code.cpp.dataflow.DataFlow
private import semmle.code.cpp.controlflow.Guards
/**
* A `BarrierGuard` that stops flow to all occurrences of `x` within statement
* S in `if (guarded(x)) S`.
*/
// This is tested in `BarrierGuard.cpp`.
class TestBarrierGuard extends DataFlow::BarrierGuard {
TestBarrierGuard() { this.(FunctionCall).getTarget().getName() = "guarded" }
override predicate checks(Expr checked, boolean isTrue) {
checked = this.(FunctionCall).getArgument(0) and
isTrue = true
}
predicate testBarrierGuard(GuardCondition g, Expr checked, boolean isTrue) {
g.(FunctionCall).getTarget().getName() = "guarded" and
checked = g.(FunctionCall).getArgument(0) and
isTrue = true
}
/** Common data flow configuration to be used by tests. */
@@ -40,29 +38,26 @@ module AstTest {
}
override predicate isBarrier(DataFlow::Node barrier) {
barrier.asExpr().(VariableAccess).getTarget().hasName("barrier")
barrier.asExpr().(VariableAccess).getTarget().hasName("barrier") or
barrier = DataFlow::BarrierGuard<testBarrierGuard/3>::getABarrierNode()
}
override predicate isBarrierGuard(DataFlow::BarrierGuard bg) { bg instanceof TestBarrierGuard }
}
}
module IRTest {
private import semmle.code.cpp.ir.dataflow.DataFlow
private import semmle.code.cpp.ir.IR
private import semmle.code.cpp.controlflow.IRGuards
/**
* A `BarrierGuard` that stops flow to all occurrences of `x` within statement
* S in `if (guarded(x)) S`.
*/
// This is tested in `BarrierGuard.cpp`.
class TestBarrierGuard extends DataFlow::BarrierGuard {
TestBarrierGuard() { this.(CallInstruction).getStaticCallTarget().getName() = "guarded" }
override predicate checksInstr(Instruction checked, boolean isTrue) {
checked = this.(CallInstruction).getPositionalArgument(0) and
isTrue = true
}
predicate testBarrierGuard(IRGuardCondition g, Instruction checked, boolean isTrue) {
g.(CallInstruction).getStaticCallTarget().getName() = "guarded" and
checked = g.(CallInstruction).getPositionalArgument(0) and
isTrue = true
}
/** Common data flow configuration to be used by tests. */
@@ -93,10 +88,9 @@ module IRTest {
}
override predicate isBarrier(DataFlow::Node barrier) {
barrier.asExpr().(VariableAccess).getTarget().hasName("barrier")
barrier.asExpr().(VariableAccess).getTarget().hasName("barrier") or
barrier = DataFlow::InstructionBarrierGuard<testBarrierGuard/3>::getABarrierNode()
}
override predicate isBarrierGuard(DataFlow::BarrierGuard bg) { bg instanceof TestBarrierGuard }
}
private predicate readsVariable(LoadInstruction load, Variable var) {

View File

@@ -0,0 +1,4 @@
---
category: deprecated
---
* The `BarrierGuard` class has been deprecated. Such barriers and sanitizers can now instead be created using the new `BarrierGuard` parameterized module.

View File

@@ -90,14 +90,20 @@ 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() }
/**
* DEPRECATED: Use `isBarrier` and `BarrierGuard` module instead.
*
* Holds if data flow through nodes guarded by `guard` is prohibited.
*/
deprecated predicate isBarrierGuard(BarrierGuard guard) { none() }
/**
* DEPRECATED: Use `isBarrier` and `BarrierGuard` module instead.
*
* Holds if data flow through nodes guarded by `guard` is prohibited when
* the flow state is `state`
*/
predicate isBarrierGuard(BarrierGuard guard, FlowState state) { none() }
deprecated predicate isBarrierGuard(BarrierGuard guard, FlowState state) { none() }
/**
* Holds if data may flow from `node1` to `node2` in addition to the normal data-flow steps.
@@ -335,6 +341,29 @@ private predicate outBarrier(NodeEx node, Configuration config) {
)
}
/** A bridge class to access the deprecated `isBarrierGuard`. */
private class BarrierGuardGuardedNodeBridge extends Unit {
abstract predicate guardedNode(Node n, Configuration config);
abstract predicate guardedNode(Node n, FlowState state, Configuration config);
}
private class BarrierGuardGuardedNode extends BarrierGuardGuardedNodeBridge {
deprecated override predicate guardedNode(Node n, Configuration config) {
exists(BarrierGuard g |
config.isBarrierGuard(g) and
n = g.getAGuardedNode()
)
}
deprecated override predicate guardedNode(Node n, FlowState state, Configuration config) {
exists(BarrierGuard g |
config.isBarrierGuard(g, state) and
n = g.getAGuardedNode()
)
}
}
pragma[nomagic]
private predicate fullBarrier(NodeEx node, Configuration config) {
exists(Node n | node.asNode() = n |
@@ -348,10 +377,7 @@ private predicate fullBarrier(NodeEx node, Configuration config) {
not config.isSink(n) and
not config.isSink(n, _)
or
exists(BarrierGuard g |
config.isBarrierGuard(g) and
n = g.getAGuardedNode()
)
any(BarrierGuardGuardedNodeBridge b).guardedNode(n, config)
)
}
@@ -360,10 +386,7 @@ private predicate stateBarrier(NodeEx node, FlowState state, Configuration confi
exists(Node n | node.asNode() = n |
config.isBarrier(n, state)
or
exists(BarrierGuard g |
config.isBarrierGuard(g, state) and
n = g.getAGuardedNode()
)
any(BarrierGuardGuardedNodeBridge b).guardedNode(n, state, config)
)
}

View File

@@ -90,14 +90,20 @@ 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() }
/**
* DEPRECATED: Use `isBarrier` and `BarrierGuard` module instead.
*
* Holds if data flow through nodes guarded by `guard` is prohibited.
*/
deprecated predicate isBarrierGuard(BarrierGuard guard) { none() }
/**
* DEPRECATED: Use `isBarrier` and `BarrierGuard` module instead.
*
* Holds if data flow through nodes guarded by `guard` is prohibited when
* the flow state is `state`
*/
predicate isBarrierGuard(BarrierGuard guard, FlowState state) { none() }
deprecated predicate isBarrierGuard(BarrierGuard guard, FlowState state) { none() }
/**
* Holds if data may flow from `node1` to `node2` in addition to the normal data-flow steps.
@@ -335,6 +341,29 @@ private predicate outBarrier(NodeEx node, Configuration config) {
)
}
/** A bridge class to access the deprecated `isBarrierGuard`. */
private class BarrierGuardGuardedNodeBridge extends Unit {
abstract predicate guardedNode(Node n, Configuration config);
abstract predicate guardedNode(Node n, FlowState state, Configuration config);
}
private class BarrierGuardGuardedNode extends BarrierGuardGuardedNodeBridge {
deprecated override predicate guardedNode(Node n, Configuration config) {
exists(BarrierGuard g |
config.isBarrierGuard(g) and
n = g.getAGuardedNode()
)
}
deprecated override predicate guardedNode(Node n, FlowState state, Configuration config) {
exists(BarrierGuard g |
config.isBarrierGuard(g, state) and
n = g.getAGuardedNode()
)
}
}
pragma[nomagic]
private predicate fullBarrier(NodeEx node, Configuration config) {
exists(Node n | node.asNode() = n |
@@ -348,10 +377,7 @@ private predicate fullBarrier(NodeEx node, Configuration config) {
not config.isSink(n) and
not config.isSink(n, _)
or
exists(BarrierGuard g |
config.isBarrierGuard(g) and
n = g.getAGuardedNode()
)
any(BarrierGuardGuardedNodeBridge b).guardedNode(n, config)
)
}
@@ -360,10 +386,7 @@ private predicate stateBarrier(NodeEx node, FlowState state, Configuration confi
exists(Node n | node.asNode() = n |
config.isBarrier(n, state)
or
exists(BarrierGuard g |
config.isBarrierGuard(g, state) and
n = g.getAGuardedNode()
)
any(BarrierGuardGuardedNodeBridge b).guardedNode(n, state, config)
)
}

View File

@@ -90,14 +90,20 @@ 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() }
/**
* DEPRECATED: Use `isBarrier` and `BarrierGuard` module instead.
*
* Holds if data flow through nodes guarded by `guard` is prohibited.
*/
deprecated predicate isBarrierGuard(BarrierGuard guard) { none() }
/**
* DEPRECATED: Use `isBarrier` and `BarrierGuard` module instead.
*
* Holds if data flow through nodes guarded by `guard` is prohibited when
* the flow state is `state`
*/
predicate isBarrierGuard(BarrierGuard guard, FlowState state) { none() }
deprecated predicate isBarrierGuard(BarrierGuard guard, FlowState state) { none() }
/**
* Holds if data may flow from `node1` to `node2` in addition to the normal data-flow steps.
@@ -335,6 +341,29 @@ private predicate outBarrier(NodeEx node, Configuration config) {
)
}
/** A bridge class to access the deprecated `isBarrierGuard`. */
private class BarrierGuardGuardedNodeBridge extends Unit {
abstract predicate guardedNode(Node n, Configuration config);
abstract predicate guardedNode(Node n, FlowState state, Configuration config);
}
private class BarrierGuardGuardedNode extends BarrierGuardGuardedNodeBridge {
deprecated override predicate guardedNode(Node n, Configuration config) {
exists(BarrierGuard g |
config.isBarrierGuard(g) and
n = g.getAGuardedNode()
)
}
deprecated override predicate guardedNode(Node n, FlowState state, Configuration config) {
exists(BarrierGuard g |
config.isBarrierGuard(g, state) and
n = g.getAGuardedNode()
)
}
}
pragma[nomagic]
private predicate fullBarrier(NodeEx node, Configuration config) {
exists(Node n | node.asNode() = n |
@@ -348,10 +377,7 @@ private predicate fullBarrier(NodeEx node, Configuration config) {
not config.isSink(n) and
not config.isSink(n, _)
or
exists(BarrierGuard g |
config.isBarrierGuard(g) and
n = g.getAGuardedNode()
)
any(BarrierGuardGuardedNodeBridge b).guardedNode(n, config)
)
}
@@ -360,10 +386,7 @@ private predicate stateBarrier(NodeEx node, FlowState state, Configuration confi
exists(Node n | node.asNode() = n |
config.isBarrier(n, state)
or
exists(BarrierGuard g |
config.isBarrierGuard(g, state) and
n = g.getAGuardedNode()
)
any(BarrierGuardGuardedNodeBridge b).guardedNode(n, state, config)
)
}

View File

@@ -90,14 +90,20 @@ 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() }
/**
* DEPRECATED: Use `isBarrier` and `BarrierGuard` module instead.
*
* Holds if data flow through nodes guarded by `guard` is prohibited.
*/
deprecated predicate isBarrierGuard(BarrierGuard guard) { none() }
/**
* DEPRECATED: Use `isBarrier` and `BarrierGuard` module instead.
*
* Holds if data flow through nodes guarded by `guard` is prohibited when
* the flow state is `state`
*/
predicate isBarrierGuard(BarrierGuard guard, FlowState state) { none() }
deprecated predicate isBarrierGuard(BarrierGuard guard, FlowState state) { none() }
/**
* Holds if data may flow from `node1` to `node2` in addition to the normal data-flow steps.
@@ -335,6 +341,29 @@ private predicate outBarrier(NodeEx node, Configuration config) {
)
}
/** A bridge class to access the deprecated `isBarrierGuard`. */
private class BarrierGuardGuardedNodeBridge extends Unit {
abstract predicate guardedNode(Node n, Configuration config);
abstract predicate guardedNode(Node n, FlowState state, Configuration config);
}
private class BarrierGuardGuardedNode extends BarrierGuardGuardedNodeBridge {
deprecated override predicate guardedNode(Node n, Configuration config) {
exists(BarrierGuard g |
config.isBarrierGuard(g) and
n = g.getAGuardedNode()
)
}
deprecated override predicate guardedNode(Node n, FlowState state, Configuration config) {
exists(BarrierGuard g |
config.isBarrierGuard(g, state) and
n = g.getAGuardedNode()
)
}
}
pragma[nomagic]
private predicate fullBarrier(NodeEx node, Configuration config) {
exists(Node n | node.asNode() = n |
@@ -348,10 +377,7 @@ private predicate fullBarrier(NodeEx node, Configuration config) {
not config.isSink(n) and
not config.isSink(n, _)
or
exists(BarrierGuard g |
config.isBarrierGuard(g) and
n = g.getAGuardedNode()
)
any(BarrierGuardGuardedNodeBridge b).guardedNode(n, config)
)
}
@@ -360,10 +386,7 @@ private predicate stateBarrier(NodeEx node, FlowState state, Configuration confi
exists(Node n | node.asNode() = n |
config.isBarrier(n, state)
or
exists(BarrierGuard g |
config.isBarrierGuard(g, state) and
n = g.getAGuardedNode()
)
any(BarrierGuardGuardedNodeBridge b).guardedNode(n, state, config)
)
}

View File

@@ -90,14 +90,20 @@ 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() }
/**
* DEPRECATED: Use `isBarrier` and `BarrierGuard` module instead.
*
* Holds if data flow through nodes guarded by `guard` is prohibited.
*/
deprecated predicate isBarrierGuard(BarrierGuard guard) { none() }
/**
* DEPRECATED: Use `isBarrier` and `BarrierGuard` module instead.
*
* Holds if data flow through nodes guarded by `guard` is prohibited when
* the flow state is `state`
*/
predicate isBarrierGuard(BarrierGuard guard, FlowState state) { none() }
deprecated predicate isBarrierGuard(BarrierGuard guard, FlowState state) { none() }
/**
* Holds if data may flow from `node1` to `node2` in addition to the normal data-flow steps.
@@ -335,6 +341,29 @@ private predicate outBarrier(NodeEx node, Configuration config) {
)
}
/** A bridge class to access the deprecated `isBarrierGuard`. */
private class BarrierGuardGuardedNodeBridge extends Unit {
abstract predicate guardedNode(Node n, Configuration config);
abstract predicate guardedNode(Node n, FlowState state, Configuration config);
}
private class BarrierGuardGuardedNode extends BarrierGuardGuardedNodeBridge {
deprecated override predicate guardedNode(Node n, Configuration config) {
exists(BarrierGuard g |
config.isBarrierGuard(g) and
n = g.getAGuardedNode()
)
}
deprecated override predicate guardedNode(Node n, FlowState state, Configuration config) {
exists(BarrierGuard g |
config.isBarrierGuard(g, state) and
n = g.getAGuardedNode()
)
}
}
pragma[nomagic]
private predicate fullBarrier(NodeEx node, Configuration config) {
exists(Node n | node.asNode() = n |
@@ -348,10 +377,7 @@ private predicate fullBarrier(NodeEx node, Configuration config) {
not config.isSink(n) and
not config.isSink(n, _)
or
exists(BarrierGuard g |
config.isBarrierGuard(g) and
n = g.getAGuardedNode()
)
any(BarrierGuardGuardedNodeBridge b).guardedNode(n, config)
)
}
@@ -360,10 +386,7 @@ private predicate stateBarrier(NodeEx node, FlowState state, Configuration confi
exists(Node n | node.asNode() = n |
config.isBarrier(n, state)
or
exists(BarrierGuard g |
config.isBarrierGuard(g, state) and
n = g.getAGuardedNode()
)
any(BarrierGuardGuardedNodeBridge b).guardedNode(n, state, config)
)
}

View File

@@ -90,14 +90,20 @@ 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() }
/**
* DEPRECATED: Use `isBarrier` and `BarrierGuard` module instead.
*
* Holds if data flow through nodes guarded by `guard` is prohibited.
*/
deprecated predicate isBarrierGuard(BarrierGuard guard) { none() }
/**
* DEPRECATED: Use `isBarrier` and `BarrierGuard` module instead.
*
* Holds if data flow through nodes guarded by `guard` is prohibited when
* the flow state is `state`
*/
predicate isBarrierGuard(BarrierGuard guard, FlowState state) { none() }
deprecated predicate isBarrierGuard(BarrierGuard guard, FlowState state) { none() }
/**
* Holds if data may flow from `node1` to `node2` in addition to the normal data-flow steps.
@@ -335,6 +341,29 @@ private predicate outBarrier(NodeEx node, Configuration config) {
)
}
/** A bridge class to access the deprecated `isBarrierGuard`. */
private class BarrierGuardGuardedNodeBridge extends Unit {
abstract predicate guardedNode(Node n, Configuration config);
abstract predicate guardedNode(Node n, FlowState state, Configuration config);
}
private class BarrierGuardGuardedNode extends BarrierGuardGuardedNodeBridge {
deprecated override predicate guardedNode(Node n, Configuration config) {
exists(BarrierGuard g |
config.isBarrierGuard(g) and
n = g.getAGuardedNode()
)
}
deprecated override predicate guardedNode(Node n, FlowState state, Configuration config) {
exists(BarrierGuard g |
config.isBarrierGuard(g, state) and
n = g.getAGuardedNode()
)
}
}
pragma[nomagic]
private predicate fullBarrier(NodeEx node, Configuration config) {
exists(Node n | node.asNode() = n |
@@ -348,10 +377,7 @@ private predicate fullBarrier(NodeEx node, Configuration config) {
not config.isSink(n) and
not config.isSink(n, _)
or
exists(BarrierGuard g |
config.isBarrierGuard(g) and
n = g.getAGuardedNode()
)
any(BarrierGuardGuardedNodeBridge b).guardedNode(n, config)
)
}
@@ -360,10 +386,7 @@ private predicate stateBarrier(NodeEx node, FlowState state, Configuration confi
exists(Node n | node.asNode() = n |
config.isBarrier(n, state)
or
exists(BarrierGuard g |
config.isBarrierGuard(g, state) and
n = g.getAGuardedNode()
)
any(BarrierGuardGuardedNodeBridge b).guardedNode(n, state, config)
)
}

View File

@@ -173,6 +173,33 @@ abstract class NonLocalJumpNode extends Node {
}
/**
* Holds if the guard `g` validates the expression `e` upon evaluating to `v`.
*
* The expression `e` is expected to be a syntactic part of the guard `g`.
* For example, the guard `g` might be a call `isSafe(x)` and the expression `e`
* the argument `x`.
*/
signature predicate guardChecksSig(Guard g, Expr e, AbstractValue v);
/**
* Provides a set of barrier nodes for a guard that validates an expression.
*
* This is expected to be used in `isBarrier`/`isSanitizer` definitions
* in data flow and taint tracking.
*/
module BarrierGuard<guardChecksSig/3 guardChecks> {
/** Gets a node that is safely guarded by the given guard check. */
ExprNode getABarrierNode() {
exists(Guard g, Expr e, AbstractValue v |
guardChecks(g, e, v) and
g.controlsNode(result.getControlFlowNode(), e, v)
)
}
}
/**
* DEPRECATED: Use `BarrierGuard` module instead.
*
* A guard that validates some expression.
*
* To use this in a configuration, extend the class and provide a
@@ -181,7 +208,7 @@ abstract class NonLocalJumpNode extends Node {
*
* It is important that all extending classes in scope are disjoint.
*/
class BarrierGuard extends Guard {
deprecated class BarrierGuard extends Guard {
/** Holds if this guard validates `e` upon evaluating to `v`. */
abstract predicate checks(Expr e, AbstractValue v);

View File

@@ -19,12 +19,6 @@ private import semmle.code.csharp.frameworks.WCF
*/
predicate defaultTaintSanitizer(DataFlow::Node node) { none() }
/**
* Holds if `guard` should be a sanitizer guard in all global taint flow configurations
* but not in local taint.
*/
predicate defaultTaintSanitizerGuard(DataFlow::BarrierGuard guard) { none() }
/**
* Holds if default `TaintTracking::Configuration`s should allow implicit reads
* of `c` at sinks and inputs to additional taint steps.

View File

@@ -116,20 +116,30 @@ abstract class Configuration extends DataFlow::Configuration {
final override predicate isBarrierOut(DataFlow::Node node) { this.isSanitizerOut(node) }
/** Holds if taint propagation through nodes guarded by `guard` is prohibited. */
predicate isSanitizerGuard(DataFlow::BarrierGuard guard) { none() }
/**
* DEPRECATED: Use `isSanitizer` and `BarrierGuard` module instead.
*
* Holds if taint propagation through nodes guarded by `guard` is prohibited.
*/
deprecated predicate isSanitizerGuard(DataFlow::BarrierGuard guard) { none() }
final override predicate isBarrierGuard(DataFlow::BarrierGuard guard) {
this.isSanitizerGuard(guard) or defaultTaintSanitizerGuard(guard)
deprecated final override predicate isBarrierGuard(DataFlow::BarrierGuard guard) {
this.isSanitizerGuard(guard)
}
/**
* DEPRECATED: Use `isSanitizer` and `BarrierGuard` module instead.
*
* Holds if taint propagation through nodes guarded by `guard` is prohibited
* when the flow state is `state`.
*/
predicate isSanitizerGuard(DataFlow::BarrierGuard guard, DataFlow::FlowState state) { none() }
deprecated predicate isSanitizerGuard(DataFlow::BarrierGuard guard, DataFlow::FlowState state) {
none()
}
final override predicate isBarrierGuard(DataFlow::BarrierGuard guard, DataFlow::FlowState state) {
deprecated final override predicate isBarrierGuard(
DataFlow::BarrierGuard guard, DataFlow::FlowState state
) {
this.isSanitizerGuard(guard, state)
}

View File

@@ -116,20 +116,30 @@ abstract class Configuration extends DataFlow::Configuration {
final override predicate isBarrierOut(DataFlow::Node node) { this.isSanitizerOut(node) }
/** Holds if taint propagation through nodes guarded by `guard` is prohibited. */
predicate isSanitizerGuard(DataFlow::BarrierGuard guard) { none() }
/**
* DEPRECATED: Use `isSanitizer` and `BarrierGuard` module instead.
*
* Holds if taint propagation through nodes guarded by `guard` is prohibited.
*/
deprecated predicate isSanitizerGuard(DataFlow::BarrierGuard guard) { none() }
final override predicate isBarrierGuard(DataFlow::BarrierGuard guard) {
this.isSanitizerGuard(guard) or defaultTaintSanitizerGuard(guard)
deprecated final override predicate isBarrierGuard(DataFlow::BarrierGuard guard) {
this.isSanitizerGuard(guard)
}
/**
* DEPRECATED: Use `isSanitizer` and `BarrierGuard` module instead.
*
* Holds if taint propagation through nodes guarded by `guard` is prohibited
* when the flow state is `state`.
*/
predicate isSanitizerGuard(DataFlow::BarrierGuard guard, DataFlow::FlowState state) { none() }
deprecated predicate isSanitizerGuard(DataFlow::BarrierGuard guard, DataFlow::FlowState state) {
none()
}
final override predicate isBarrierGuard(DataFlow::BarrierGuard guard, DataFlow::FlowState state) {
deprecated final override predicate isBarrierGuard(
DataFlow::BarrierGuard guard, DataFlow::FlowState state
) {
this.isSanitizerGuard(guard, state)
}

View File

@@ -116,20 +116,30 @@ abstract class Configuration extends DataFlow::Configuration {
final override predicate isBarrierOut(DataFlow::Node node) { this.isSanitizerOut(node) }
/** Holds if taint propagation through nodes guarded by `guard` is prohibited. */
predicate isSanitizerGuard(DataFlow::BarrierGuard guard) { none() }
/**
* DEPRECATED: Use `isSanitizer` and `BarrierGuard` module instead.
*
* Holds if taint propagation through nodes guarded by `guard` is prohibited.
*/
deprecated predicate isSanitizerGuard(DataFlow::BarrierGuard guard) { none() }
final override predicate isBarrierGuard(DataFlow::BarrierGuard guard) {
this.isSanitizerGuard(guard) or defaultTaintSanitizerGuard(guard)
deprecated final override predicate isBarrierGuard(DataFlow::BarrierGuard guard) {
this.isSanitizerGuard(guard)
}
/**
* DEPRECATED: Use `isSanitizer` and `BarrierGuard` module instead.
*
* Holds if taint propagation through nodes guarded by `guard` is prohibited
* when the flow state is `state`.
*/
predicate isSanitizerGuard(DataFlow::BarrierGuard guard, DataFlow::FlowState state) { none() }
deprecated predicate isSanitizerGuard(DataFlow::BarrierGuard guard, DataFlow::FlowState state) {
none()
}
final override predicate isBarrierGuard(DataFlow::BarrierGuard guard, DataFlow::FlowState state) {
deprecated final override predicate isBarrierGuard(
DataFlow::BarrierGuard guard, DataFlow::FlowState state
) {
this.isSanitizerGuard(guard, state)
}

View File

@@ -116,20 +116,30 @@ abstract class Configuration extends DataFlow::Configuration {
final override predicate isBarrierOut(DataFlow::Node node) { this.isSanitizerOut(node) }
/** Holds if taint propagation through nodes guarded by `guard` is prohibited. */
predicate isSanitizerGuard(DataFlow::BarrierGuard guard) { none() }
/**
* DEPRECATED: Use `isSanitizer` and `BarrierGuard` module instead.
*
* Holds if taint propagation through nodes guarded by `guard` is prohibited.
*/
deprecated predicate isSanitizerGuard(DataFlow::BarrierGuard guard) { none() }
final override predicate isBarrierGuard(DataFlow::BarrierGuard guard) {
this.isSanitizerGuard(guard) or defaultTaintSanitizerGuard(guard)
deprecated final override predicate isBarrierGuard(DataFlow::BarrierGuard guard) {
this.isSanitizerGuard(guard)
}
/**
* DEPRECATED: Use `isSanitizer` and `BarrierGuard` module instead.
*
* Holds if taint propagation through nodes guarded by `guard` is prohibited
* when the flow state is `state`.
*/
predicate isSanitizerGuard(DataFlow::BarrierGuard guard, DataFlow::FlowState state) { none() }
deprecated predicate isSanitizerGuard(DataFlow::BarrierGuard guard, DataFlow::FlowState state) {
none()
}
final override predicate isBarrierGuard(DataFlow::BarrierGuard guard, DataFlow::FlowState state) {
deprecated final override predicate isBarrierGuard(
DataFlow::BarrierGuard guard, DataFlow::FlowState state
) {
this.isSanitizerGuard(guard, state)
}

View File

@@ -116,20 +116,30 @@ abstract class Configuration extends DataFlow::Configuration {
final override predicate isBarrierOut(DataFlow::Node node) { this.isSanitizerOut(node) }
/** Holds if taint propagation through nodes guarded by `guard` is prohibited. */
predicate isSanitizerGuard(DataFlow::BarrierGuard guard) { none() }
/**
* DEPRECATED: Use `isSanitizer` and `BarrierGuard` module instead.
*
* Holds if taint propagation through nodes guarded by `guard` is prohibited.
*/
deprecated predicate isSanitizerGuard(DataFlow::BarrierGuard guard) { none() }
final override predicate isBarrierGuard(DataFlow::BarrierGuard guard) {
this.isSanitizerGuard(guard) or defaultTaintSanitizerGuard(guard)
deprecated final override predicate isBarrierGuard(DataFlow::BarrierGuard guard) {
this.isSanitizerGuard(guard)
}
/**
* DEPRECATED: Use `isSanitizer` and `BarrierGuard` module instead.
*
* Holds if taint propagation through nodes guarded by `guard` is prohibited
* when the flow state is `state`.
*/
predicate isSanitizerGuard(DataFlow::BarrierGuard guard, DataFlow::FlowState state) { none() }
deprecated predicate isSanitizerGuard(DataFlow::BarrierGuard guard, DataFlow::FlowState state) {
none()
}
final override predicate isBarrierGuard(DataFlow::BarrierGuard guard, DataFlow::FlowState state) {
deprecated final override predicate isBarrierGuard(
DataFlow::BarrierGuard guard, DataFlow::FlowState state
) {
this.isSanitizerGuard(guard, state)
}

View File

@@ -26,9 +26,11 @@ abstract class Sink extends DataFlow::ExprNode { }
abstract class Sanitizer extends DataFlow::ExprNode { }
/**
* DEPRECATED: Use `Sanitizer` instead.
*
* A guard for unvalidated URL redirect vulnerabilities.
*/
abstract class SanitizerGuard extends DataFlow::BarrierGuard { }
abstract deprecated class SanitizerGuard extends DataFlow::BarrierGuard { }
/**
* A taint-tracking configuration for reasoning about unvalidated URL redirect vulnerabilities.
@@ -42,7 +44,7 @@ class TaintTrackingConfiguration extends TaintTracking::Configuration {
override predicate isSanitizer(DataFlow::Node node) { node instanceof Sanitizer }
override predicate isSanitizerGuard(DataFlow::BarrierGuard guard) {
deprecated override predicate isSanitizerGuard(DataFlow::BarrierGuard guard) {
guard instanceof SanitizerGuard
}
}
@@ -102,16 +104,17 @@ class HttpServerTransferSink extends Sink {
}
}
private predicate isLocalUrlSanitizer(Guard g, Expr e, AbstractValue v) {
g.(MethodCall).getTarget().hasName("IsLocalUrl") and
e = g.(MethodCall).getArgument(0) and
v.(AbstractValues::BooleanValue).getValue() = true
}
/**
* A URL argument to a call to `UrlHelper.isLocalUrl()` that is a sanitizer for URL redirects.
*/
class IsLocalUrlSanitizer extends SanitizerGuard, MethodCall {
IsLocalUrlSanitizer() { this.getTarget().hasName("IsLocalUrl") }
override predicate checks(Expr e, AbstractValue v) {
e = this.getArgument(0) and
v.(AbstractValues::BooleanValue).getValue() = true
}
class LocalUrlSanitizer extends Sanitizer {
LocalUrlSanitizer() { this = DataFlow::BarrierGuard<isLocalUrlSanitizer/3>::getABarrierNode() }
}
/**

View File

@@ -21,9 +21,11 @@ abstract class Sink extends DataFlow::ExprNode { }
abstract class Sanitizer extends DataFlow::ExprNode { }
/**
* DEPRECATED: Use `Sanitizer` instead.
*
* A guard for unsafe zip extraction.
*/
abstract class SanitizerGuard extends DataFlow::BarrierGuard { }
abstract deprecated class SanitizerGuard extends DataFlow::BarrierGuard { }
/** A taint tracking configuration for Zip Slip */
class TaintTrackingConfiguration extends TaintTracking::Configuration {
@@ -35,7 +37,7 @@ class TaintTrackingConfiguration extends TaintTracking::Configuration {
override predicate isSanitizer(DataFlow::Node node) { node instanceof Sanitizer }
override predicate isSanitizerGuard(DataFlow::BarrierGuard guard) {
deprecated override predicate isSanitizerGuard(DataFlow::BarrierGuard guard) {
guard instanceof SanitizerGuard
}
}
@@ -126,26 +128,22 @@ class SubstringSanitizer extends Sanitizer {
}
}
private predicate stringCheckGuard(Guard g, Expr e, AbstractValue v) {
g.(MethodCall).getTarget().hasQualifiedName("System.String", "StartsWith") and
g.(MethodCall).getQualifier() = e and
// A StartsWith check against Path.Combine is not sufficient, because the ".." elements have
// not yet been resolved.
not exists(MethodCall combineCall |
combineCall.getTarget().hasQualifiedName("System.IO.Path", "Combine") and
DataFlow::localExprFlow(combineCall, e)
) and
v.(AbstractValues::BooleanValue).getValue() = true
}
/**
* A call to `String.StartsWith()` that indicates that the tainted path value is being
* validated to ensure that it occurs within a permitted output path.
*/
class StringCheckGuard extends SanitizerGuard, MethodCall {
private Expr q;
StringCheckGuard() {
this.getTarget().hasQualifiedName("System.String", "StartsWith") and
this.getQualifier() = q and
// A StartsWith check against Path.Combine is not sufficient, because the ".." elements have
// not yet been resolved.
not exists(MethodCall combineCall |
combineCall.getTarget().hasQualifiedName("System.IO.Path", "Combine") and
DataFlow::localExprFlow(combineCall, q)
)
}
override predicate checks(Expr e, AbstractValue v) {
e = q and
v.(AbstractValues::BooleanValue).getValue() = true
}
class StringCheckSanitizer extends Sanitizer {
StringCheckSanitizer() { this = DataFlow::BarrierGuard<stringCheckGuard/3>::getABarrierNode() }
}

View File

@@ -18,10 +18,10 @@ module RequestForgery {
abstract private class Sink extends DataFlow::ExprNode { }
/**
* A data flow BarrierGuard which blocks the flow of taint for
* A data flow Barrier that blocks the flow of taint for
* server side request forgery vulnerabilities.
*/
abstract private class BarrierGuard extends DataFlow::BarrierGuard { }
abstract private class Barrier extends DataFlow::Node { }
/**
* A data flow configuration for detecting server side request forgery vulnerabilities.
@@ -51,9 +51,7 @@ module RequestForgery {
pathCombineStep(prev, succ)
}
override predicate isBarrierGuard(DataFlow::BarrierGuard guard) {
guard instanceof BarrierGuard
}
override predicate isBarrier(DataFlow::Node node) { node instanceof Barrier }
}
/**
@@ -129,17 +127,18 @@ module RequestForgery {
* to be a guard for Server Side Request Forgery(SSRF) Vulnerabilities.
* This guard considers all checks as valid.
*/
private class BaseUriGuard extends BarrierGuard, MethodCall {
BaseUriGuard() { this.getTarget().hasQualifiedName("System.Uri", "IsBaseOf") }
private predicate baseUriGuard(Guard g, Expr e, AbstractValue v) {
g.(MethodCall).getTarget().hasQualifiedName("System.Uri", "IsBaseOf") and
// we consider any checks against the tainted value to sainitize the taint.
// This implies any check such as shown below block the taint flow.
// Uri url = new Uri("whitelist.com")
// if (url.isBaseOf(`taint1))
(e = g.(MethodCall).getArgument(0) or e = g.(MethodCall).getQualifier()) and
v.(AbstractValues::BooleanValue).getValue() = true
}
override predicate checks(Expr e, AbstractValue v) {
// we consider any checks against the tainted value to sainitize the taint.
// This implies any check such as shown below block the taint flow.
// Uri url = new Uri("whitelist.com")
// if (url.isBaseOf(`taint1))
(e = this.getArgument(0) or e = this.getQualifier()) and
v.(AbstractValues::BooleanValue).getValue() = true
}
private class BaseUriBarrier extends Barrier {
BaseUriBarrier() { this = DataFlow::BarrierGuard<baseUriGuard/3>::getABarrierNode() }
}
/**
@@ -147,18 +146,19 @@ module RequestForgery {
* to be a guard for Server Side Request Forgery(SSRF) Vulnerabilities.
* This guard considers all checks as valid.
*/
private class StringStartsWithBarrierGuard extends BarrierGuard, MethodCall {
StringStartsWithBarrierGuard() {
this.getTarget().hasQualifiedName("System.String", "StartsWith")
}
private predicate stringStartsWithGuard(Guard g, Expr e, AbstractValue v) {
g.(MethodCall).getTarget().hasQualifiedName("System.String", "StartsWith") and
// Any check such as the ones shown below
// "https://myurl.com/".startsWith(`taint`)
// `taint`.startsWith("https://myurl.com/")
// are assumed to sainitize the taint
(e = g.(MethodCall).getQualifier() or g.(MethodCall).getArgument(0) = e) and
v.(AbstractValues::BooleanValue).getValue() = true
}
override predicate checks(Expr e, AbstractValue v) {
// Any check such as the ones shown below
// "https://myurl.com/".startsWith(`taint`)
// `taint`.startsWith("https://myurl.com/")
// are assumed to sainitize the taint
(e = this.getQualifier() or this.getArgument(0) = e) and
v.(AbstractValues::BooleanValue).getValue() = true
private class StringStartsWithBarrier extends Barrier {
StringStartsWithBarrier() {
this = DataFlow::BarrierGuard<stringStartsWithGuard/3>::getABarrierNode()
}
}

View File

@@ -0,0 +1,4 @@
---
category: deprecated
---
* The `BarrierGuard` class has been deprecated. Such barriers and sanitizers can now instead be created using the new `BarrierGuard` parameterized module.

View File

@@ -4,11 +4,30 @@
import go
private predicate redirectCheckGuard(DataFlow::Node g, Expr e, boolean outcome) {
g.(DataFlow::CallNode)
.getCalleeName()
.regexpMatch("(?i)(is_?)?(local_?url|valid_?redir(ect)?)(ur[li])?") and
// `isLocalUrl(e)` is a barrier for `e` if it evaluates to `true`
g.(DataFlow::CallNode).getAnArgument().asExpr() = e and
outcome = true
}
/**
* A call to a function called `isLocalUrl`, `isValidRedirect`, or similar, which is
* considered a barrier guard for sanitizing untrusted URLs.
*/
class RedirectCheckBarrierGuard extends DataFlow::BarrierGuard, DataFlow::CallNode {
class RedirectCheckBarrier extends DataFlow::Node {
RedirectCheckBarrier() { this = DataFlow::BarrierGuard<redirectCheckGuard/3>::getABarrierNode() }
}
/**
* DEPRECATED: Use `RedirectCheckBarrier` instead.
*
* A call to a function called `isLocalUrl`, `isValidRedirect`, or similar, which is
* considered a barrier guard for sanitizing untrusted URLs.
*/
deprecated class RedirectCheckBarrierGuard extends DataFlow::BarrierGuard, DataFlow::CallNode {
RedirectCheckBarrierGuard() {
this.getCalleeName().regexpMatch("(?i)(is_?)?(local_?url|valid_?redir(ect)?)(ur[li])?")
}

View File

@@ -10,7 +10,7 @@ import go
* This is overapproximate: we do not attempt to reason about the correctness of the regexp.
*
* Use this if you want to define a derived `DataFlow::BarrierGuard` without
* make the type recursive. Otherwise use `RegexpCheck`.
* make the type recursive. Otherwise use `RegexpCheckBarrier`.
*/
predicate regexpFunctionChecksExpr(DataFlow::Node resultNode, Expr checked, boolean branch) {
exists(RegexpMatchFunction matchfn, DataFlow::CallNode call |
@@ -26,7 +26,20 @@ predicate regexpFunctionChecksExpr(DataFlow::Node resultNode, Expr checked, bool
*
* This is overapproximate: we do not attempt to reason about the correctness of the regexp.
*/
class RegexpCheck extends DataFlow::BarrierGuard {
class RegexpCheckBarrier extends DataFlow::Node {
RegexpCheckBarrier() {
this = DataFlow::BarrierGuard<regexpFunctionChecksExpr/3>::getABarrierNode()
}
}
/**
* DEPRECATED: Use `RegexpCheckBarrier` instead.
*
* A call to a regexp match function, considered as a barrier guard for sanitizing untrusted URLs.
*
* This is overapproximate: we do not attempt to reason about the correctness of the regexp.
*/
deprecated class RegexpCheck extends DataFlow::BarrierGuard {
RegexpCheck() { regexpFunctionChecksExpr(this, _, _) }
override predicate checks(Expr e, boolean branch) { regexpFunctionChecksExpr(this, e, branch) }

View File

@@ -4,6 +4,23 @@
import go
private predicate urlCheck(DataFlow::Node g, Expr e, boolean outcome) {
exists(DataFlow::Node url, DataFlow::EqualityTestNode eq |
g = eq and
exists(eq.getAnOperand().getStringValue()) and
(
url = eq.getAnOperand()
or
exists(DataFlow::MethodCallNode mc | mc = eq.getAnOperand() |
mc.getTarget().getName() = "Hostname" and
url = mc.getReceiver()
)
) and
e = url.asExpr() and
outcome = eq.getPolarity()
)
}
/**
* An equality check comparing a data-flow node against a constant string, considered as
* a barrier guard for sanitizing untrusted URLs.
@@ -11,7 +28,20 @@ import go
* Additionally, a check comparing `url.Hostname()` against a constant string is also
* considered a barrier guard for `url`.
*/
class UrlCheck extends DataFlow::BarrierGuard, DataFlow::EqualityTestNode {
class UrlCheckBarrier extends DataFlow::Node {
UrlCheckBarrier() { this = DataFlow::BarrierGuard<urlCheck/3>::getABarrierNode() }
}
/**
* DEPRECATED: Use `UrlCheckBarrier` instead.
*
* An equality check comparing a data-flow node against a constant string, considered as
* a barrier guard for sanitizing untrusted URLs.
*
* Additionally, a check comparing `url.Hostname()` against a constant string is also
* considered a barrier guard for `url`.
*/
deprecated class UrlCheck extends DataFlow::BarrierGuard, DataFlow::EqualityTestNode {
DataFlow::Node url;
UrlCheck() {

View File

@@ -73,8 +73,12 @@ 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() }
/**
* DEPRECATED: Use `isBarrier` and `BarrierGuard` module instead.
*
* Holds if data flow through nodes guarded by `guard` is prohibited.
*/
deprecated predicate isBarrierGuard(BarrierGuard guard) { none() }
/**
* Holds if the additional flow step from `node1` to `node2` must be taken
@@ -289,6 +293,20 @@ private predicate outBarrier(NodeEx node, Configuration config) {
)
}
/** A bridge class to access the deprecated `isBarrierGuard`. */
private class BarrierGuardGuardedNodeBridge extends Unit {
abstract predicate guardedNode(Node n, Configuration config);
}
private class BarrierGuardGuardedNode extends BarrierGuardGuardedNodeBridge {
deprecated override predicate guardedNode(Node n, Configuration config) {
exists(BarrierGuard g |
config.isBarrierGuard(g) and
n = g.getAGuardedNode()
)
}
}
pragma[nomagic]
private predicate fullBarrier(NodeEx node, Configuration config) {
exists(Node n | node.asNode() = n |
@@ -300,10 +318,7 @@ private predicate fullBarrier(NodeEx node, Configuration config) {
config.isBarrierOut(n) and
not config.isSink(n)
or
exists(BarrierGuard g |
config.isBarrierGuard(g) and
n = g.getAGuardedNode()
)
any(BarrierGuardGuardedNodeBridge b).guardedNode(n, config)
)
}

View File

@@ -73,8 +73,12 @@ 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() }
/**
* DEPRECATED: Use `isBarrier` and `BarrierGuard` module instead.
*
* Holds if data flow through nodes guarded by `guard` is prohibited.
*/
deprecated predicate isBarrierGuard(BarrierGuard guard) { none() }
/**
* Holds if the additional flow step from `node1` to `node2` must be taken
@@ -289,6 +293,20 @@ private predicate outBarrier(NodeEx node, Configuration config) {
)
}
/** A bridge class to access the deprecated `isBarrierGuard`. */
private class BarrierGuardGuardedNodeBridge extends Unit {
abstract predicate guardedNode(Node n, Configuration config);
}
private class BarrierGuardGuardedNode extends BarrierGuardGuardedNodeBridge {
deprecated override predicate guardedNode(Node n, Configuration config) {
exists(BarrierGuard g |
config.isBarrierGuard(g) and
n = g.getAGuardedNode()
)
}
}
pragma[nomagic]
private predicate fullBarrier(NodeEx node, Configuration config) {
exists(Node n | node.asNode() = n |
@@ -300,10 +318,7 @@ private predicate fullBarrier(NodeEx node, Configuration config) {
config.isBarrierOut(n) and
not config.isSink(n)
or
exists(BarrierGuard g |
config.isBarrierGuard(g) and
n = g.getAGuardedNode()
)
any(BarrierGuardGuardedNodeBridge b).guardedNode(n, config)
)
}

View File

@@ -231,27 +231,39 @@ class SyntheticFieldContent extends Content, TSyntheticFieldContent {
}
/**
* A guard that validates some expression.
* Holds if the guard `g` validates the expression `e` upon evaluating to `branch`.
*
* To use this in a configuration, extend the class and provide a
* characteristic predicate precisely specifying the guard, and override
* `checks` to specify what is being validated and in which branch.
*
* When using a data-flow or taint-flow configuration `cfg`, it is important
* that any classes extending BarrierGuard in scope which are not used in `cfg`
* are disjoint from any classes extending BarrierGuard in scope which are used
* in `cfg`.
* The expression `e` is expected to be a syntactic part of the guard `g`.
* For example, the guard `g` might be a call `isSafe(x)` and the expression `e`
* the argument `x`.
*/
abstract class BarrierGuard extends Node {
/** Holds if this guard validates `e` upon evaluating to `branch`. */
abstract predicate checks(Expr e, boolean branch);
signature predicate guardChecksSig(Node g, Expr e, boolean branch);
/** Gets a node guarded by this guard. */
final Node getAGuardedNode() {
/**
* Provides a set of barrier nodes for a guard that validates an expression.
*
* This is expected to be used in `isBarrier`/`isSanitizer` definitions
* in data flow and taint tracking.
*/
module BarrierGuard<guardChecksSig/3 guardChecks> {
/** Gets a node that is safely guarded by the given guard check. */
Node getABarrierNode() {
exists(Node g, ControlFlow::ConditionGuardNode guard, Node nd, SsaWithFields var |
result = var.getAUse()
|
guards(g, guard, nd, var) and
guard.dominates(result.getBasicBlock())
)
}
/**
* Gets a node that is safely guarded by the given guard check.
*/
Node getABarrierNodeForGuard(Node guardCheck) {
exists(ControlFlow::ConditionGuardNode guard, Node nd, SsaWithFields var |
result = var.getAUse()
|
this.guards(guard, nd, var) and
guards(guardCheck, guard, nd, var) and
guard.dominates(result.getBasicBlock())
)
}
@@ -263,25 +275,25 @@ abstract class BarrierGuard extends Node {
* This predicate exists to enforce a good join order in `getAGuardedNode`.
*/
pragma[noinline]
private predicate guards(ControlFlow::ConditionGuardNode guard, Node nd, SsaWithFields ap) {
this.guards(guard, nd) and nd = ap.getAUse()
private predicate guards(Node g, ControlFlow::ConditionGuardNode guard, Node nd, SsaWithFields ap) {
guards(g, guard, nd) and nd = ap.getAUse()
}
/**
* Holds if `guard` markes a point in the control-flow graph where this node
* is known to validate `nd`.
*/
private predicate guards(ControlFlow::ConditionGuardNode guard, Node nd) {
private predicate guards(Node g, ControlFlow::ConditionGuardNode guard, Node nd) {
exists(boolean branch |
this.checks(nd.asExpr(), branch) and
guard.ensures(this, branch)
guardChecks(g, nd.asExpr(), branch) and
guard.ensures(g, branch)
)
or
exists(
Function f, FunctionInput inp, FunctionOutput outp, DataFlow::Property p, CallNode c,
Node resNode, Node check, boolean outcome
|
this.guardingCall(f, inp, outp, p, c, nd, resNode) and
guardingCall(g, f, inp, outp, p, c, nd, resNode) and
p.checkOn(check, outcome, resNode) and
guard.ensures(pragma[only_bind_into](check), outcome)
)
@@ -289,10 +301,10 @@ abstract class BarrierGuard extends Node {
pragma[noinline]
private predicate guardingCall(
Function f, FunctionInput inp, FunctionOutput outp, DataFlow::Property p, CallNode c, Node nd,
Node resNode
Node g, Function f, FunctionInput inp, FunctionOutput outp, DataFlow::Property p, CallNode c,
Node nd, Node resNode
) {
this.guardingFunction(f, inp, outp, p) and
guardingFunction(g, f, inp, outp, p) and
c = f.getACall() and
nd = inp.getNode(c) and
localFlow(pragma[only_bind_out](outp.getNode(c)), resNode)
@@ -308,7 +320,7 @@ abstract class BarrierGuard extends Node {
* `false`, `nil` or a non-`nil` value.)
*/
private predicate guardingFunction(
Function f, FunctionInput inp, FunctionOutput outp, DataFlow::Property p
Node g, Function f, FunctionInput inp, FunctionOutput outp, DataFlow::Property p
) {
exists(FuncDecl fd, Node arg, Node ret |
fd.getFunction() = f and
@@ -317,7 +329,7 @@ abstract class BarrierGuard extends Node {
(
// Case: a function like "if someBarrierGuard(arg) { return true } else { return false }"
exists(ControlFlow::ConditionGuardNode guard |
this.guards(guard, arg) and
guards(g, guard, arg) and
guard.dominates(ret.getBasicBlock())
|
exists(boolean b |
@@ -336,12 +348,12 @@ abstract class BarrierGuard extends Node {
// or "return !someBarrierGuard(arg) && otherCond(...)"
exists(boolean outcome |
ret = getUniqueOutputNode(fd, outp) and
this.checks(arg.asExpr(), outcome) and
guardChecks(g, arg.asExpr(), outcome) and
// This predicate's contract is (p holds of ret ==> arg is checked),
// (and we have (this has outcome ==> arg is checked))
// but p.checkOn(ret, outcome, this) gives us (ret has outcome ==> p holds of this),
// so we need to swap outcome and (specifically boolean) p:
DataFlow::booleanProperty(outcome).checkOn(ret, p.asBoolean(), this)
DataFlow::booleanProperty(outcome).checkOn(ret, p.asBoolean(), g)
)
or
// Case: a function like "return guardProxy(arg)"
@@ -351,7 +363,7 @@ abstract class BarrierGuard extends Node {
DataFlow::Property outpProp
|
ret = getUniqueOutputNode(fd, outp) and
this.guardingFunction(f2, inp2, outp2, outpProp) and
guardingFunction(g, f2, inp2, outp2, outpProp) and
c = f2.getACall() and
arg = inp2.getNode(c) and
(
@@ -368,6 +380,34 @@ abstract class BarrierGuard extends Node {
}
}
/**
* DEPRECATED: Use `BarrierGuard` module instead.
*
* A guard that validates some expression.
*
* To use this in a configuration, extend the class and provide a
* characteristic predicate precisely specifying the guard, and override
* `checks` to specify what is being validated and in which branch.
*
* When using a data-flow or taint-flow configuration `cfg`, it is important
* that any classes extending BarrierGuard in scope which are not used in `cfg`
* are disjoint from any classes extending BarrierGuard in scope which are used
* in `cfg`.
*/
abstract deprecated class BarrierGuard extends Node {
/** Holds if this guard validates `e` upon evaluating to `branch`. */
abstract predicate checks(Expr e, boolean branch);
/** Gets a node guarded by this guard. */
final Node getAGuardedNode() {
result = BarrierGuard<barrierGuardChecks/3>::getABarrierNodeForGuard(this)
}
}
deprecated private predicate barrierGuardChecks(Node g, Expr e, boolean branch) {
g.(BarrierGuard).checks(e, branch)
}
DataFlow::Node getUniqueOutputNode(FuncDecl fd, FunctionOutput outp) {
result = unique(DataFlow::Node n | n = outp.getEntryNode(fd) | n)
}

View File

@@ -228,16 +228,22 @@ abstract class DefaultTaintSanitizer extends DataFlow::Node { }
predicate defaultTaintSanitizer(DataFlow::Node node) { node instanceof DefaultTaintSanitizer }
/**
* DEPRECATED: Use `DefaultTaintSanitizer` instead.
*
* A sanitizer guard in all global taint flow configurations but not in local taint.
*/
abstract class DefaultTaintSanitizerGuard extends DataFlow::BarrierGuard { }
abstract deprecated class DefaultTaintSanitizerGuard extends DataFlow::BarrierGuard { }
/**
* Holds if `guard` should be a sanitizer guard in all global taint flow configurations
* but not in local taint.
*/
predicate defaultTaintSanitizerGuard(DataFlow::BarrierGuard guard) {
guard instanceof DefaultTaintSanitizerGuard
private predicate equalityTestGuard(DataFlow::Node g, Expr e, boolean outcome) {
exists(DataFlow::EqualityTestNode eq, DataFlow::Node nonConstNode |
eq = g and
eq.getAnOperand().isConst() and
nonConstNode = eq.getAnOperand() and
not nonConstNode.isConst() and
not eq.getAnOperand() = Builtin::nil().getARead() and
e = nonConstNode.asExpr() and
outcome = eq.getPolarity()
)
}
/**
@@ -247,20 +253,8 @@ predicate defaultTaintSanitizerGuard(DataFlow::BarrierGuard guard) {
* Note that comparisons to `nil` are excluded. This is needed for performance
* reasons.
*/
class EqualityTestGuard extends DefaultTaintSanitizerGuard, DataFlow::EqualityTestNode {
DataFlow::Node nonConstNode;
EqualityTestGuard() {
this.getAnOperand().isConst() and
nonConstNode = this.getAnOperand() and
not nonConstNode.isConst() and
not this.getAnOperand() = Builtin::nil().getARead()
}
override predicate checks(Expr e, boolean outcome) {
e = nonConstNode.asExpr() and
outcome = this.getPolarity()
}
class EqualityTestBarrier extends DefaultTaintSanitizer {
EqualityTestBarrier() { this = DataFlow::BarrierGuard<equalityTestGuard/3>::getABarrierNode() }
}
/**
@@ -398,6 +392,16 @@ predicate inputIsConstantIfOutputHasProperty(
)
}
private predicate listOfConstantsComparisonSanitizerGuard(DataFlow::Node g, Expr e, boolean outcome) {
exists(DataFlow::Node guardedExpr |
exists(DataFlow::Node outputNode, DataFlow::Property p |
inputIsConstantIfOutputHasProperty(guardedExpr, outputNode, p) and
p.checkOn(g, outcome, outputNode)
) and
e = guardedExpr.asExpr()
)
}
/**
* A comparison against a list of constants, acting as a sanitizer guard for
* `guardedExpr` by restricting it to a known value.
@@ -406,18 +410,8 @@ predicate inputIsConstantIfOutputHasProperty(
* it could equally look for a check for membership of a constant map or
* constant array, which does not need to be in its own function.
*/
class ListOfConstantsComparisonSanitizerGuard extends TaintTracking::DefaultTaintSanitizerGuard {
DataFlow::Node guardedExpr;
boolean outcome;
class ListOfConstantsComparisonSanitizerGuard extends TaintTracking::DefaultTaintSanitizer {
ListOfConstantsComparisonSanitizerGuard() {
exists(DataFlow::Node outputNode, DataFlow::Property p |
inputIsConstantIfOutputHasProperty(guardedExpr, outputNode, p) and
p.checkOn(this, outcome, outputNode)
)
}
override predicate checks(Expr e, boolean branch) {
e = guardedExpr.asExpr() and branch = outcome
this = DataFlow::BarrierGuard<listOfConstantsComparisonSanitizerGuard/3>::getABarrierNode()
}
}

View File

@@ -89,11 +89,15 @@ abstract class Configuration extends DataFlow::Configuration {
final override predicate isBarrierOut(DataFlow::Node node) { this.isSanitizerOut(node) }
/** Holds if taint propagation through nodes guarded by `guard` is prohibited. */
predicate isSanitizerGuard(DataFlow::BarrierGuard guard) { none() }
/**
* DEPRECATED: Use `isSanitizer` and `BarrierGuard` module instead.
*
* Holds if taint propagation through nodes guarded by `guard` is prohibited.
*/
deprecated predicate isSanitizerGuard(DataFlow::BarrierGuard guard) { none() }
final override predicate isBarrierGuard(DataFlow::BarrierGuard guard) {
this.isSanitizerGuard(guard) or defaultTaintSanitizerGuard(guard)
deprecated final override predicate isBarrierGuard(DataFlow::BarrierGuard guard) {
this.isSanitizerGuard(guard)
}
/**

View File

@@ -89,11 +89,15 @@ abstract class Configuration extends DataFlow::Configuration {
final override predicate isBarrierOut(DataFlow::Node node) { this.isSanitizerOut(node) }
/** Holds if taint propagation through nodes guarded by `guard` is prohibited. */
predicate isSanitizerGuard(DataFlow::BarrierGuard guard) { none() }
/**
* DEPRECATED: Use `isSanitizer` and `BarrierGuard` module instead.
*
* Holds if taint propagation through nodes guarded by `guard` is prohibited.
*/
deprecated predicate isSanitizerGuard(DataFlow::BarrierGuard guard) { none() }
final override predicate isBarrierGuard(DataFlow::BarrierGuard guard) {
this.isSanitizerGuard(guard) or defaultTaintSanitizerGuard(guard)
deprecated final override predicate isBarrierGuard(DataFlow::BarrierGuard guard) {
this.isSanitizerGuard(guard)
}
/**

View File

@@ -23,7 +23,7 @@ module AllocationSizeOverflow {
override predicate isSink(DataFlow::Node nd) { nd = Builtin::len().getACall().getArgument(0) }
override predicate isSanitizerGuard(DataFlow::BarrierGuard guard) {
deprecated override predicate isSanitizerGuard(DataFlow::BarrierGuard guard) {
guard instanceof SanitizerGuard
}
@@ -64,7 +64,7 @@ module AllocationSizeOverflow {
)
}
override predicate isSanitizerGuard(DataFlow::BarrierGuard guard) {
deprecated override predicate isSanitizerGuard(DataFlow::BarrierGuard guard) {
guard instanceof SanitizerGuard
}

View File

@@ -25,9 +25,11 @@ module AllocationSizeOverflow {
}
/**
* DEPRECATED: Use `Sanitizer` instead.
*
* A guard node that prevents allocation-size overflow.
*/
abstract class SanitizerGuard extends DataFlow::BarrierGuard { }
abstract deprecated class SanitizerGuard extends DataFlow::BarrierGuard { }
/**
* A sanitizer node that prevents allocation-size overflow.
@@ -73,12 +75,18 @@ module AllocationSizeOverflow {
}
}
private predicate allocationSizeCheck(DataFlow::Node g, Expr e, boolean branch) {
exists(DataFlow::Node lesser |
g.(DataFlow::RelationalComparisonNode).leq(branch, lesser, _, _) and
not lesser.isConst() and
globalValueNumber(DataFlow::exprNode(e)) = globalValueNumber(lesser)
)
}
/** A check of the allocation size, acting as a guard to prevent allocation-size overflow. */
class AllocationSizeCheck extends DataFlow::BarrierGuard, DataFlow::RelationalComparisonNode {
override predicate checks(Expr e, boolean branch) {
exists(DataFlow::Node lesser | this.leq(branch, lesser, _, _) and not lesser.isConst() |
globalValueNumber(DataFlow::exprNode(e)) = globalValueNumber(lesser)
)
class AllocationSizeCheckBarrier extends DataFlow::Node {
AllocationSizeCheckBarrier() {
this = DataFlow::BarrierGuard<allocationSizeCheck/3>::getABarrierNode()
}
}
@@ -92,20 +100,24 @@ module AllocationSizeOverflow {
DefaultSink() {
this instanceof OverflowProneOperand and
localStep*(this, allocsz) and
not exists(AllocationSizeCheck g | allocsz = g.getAGuardedNode())
not allocsz instanceof AllocationSizeCheckBarrier
}
override DataFlow::Node getAllocationSize() { result = allocsz }
}
private predicate lengthCheck(DataFlow::Node g, Expr e, boolean branch) {
exists(DataFlow::CallNode lesser |
g.(DataFlow::RelationalComparisonNode).leq(branch, lesser, _, _)
|
lesser = Builtin::len().getACall() and
globalValueNumber(DataFlow::exprNode(e)) = globalValueNumber(lesser.getArgument(0))
)
}
/** A length check, acting as a guard to prevent allocation-size overflow. */
class LengthCheck extends SanitizerGuard, DataFlow::RelationalComparisonNode {
override predicate checks(Expr e, boolean branch) {
exists(DataFlow::CallNode lesser | this.leq(branch, lesser, _, _) |
lesser = Builtin::len().getACall() and
globalValueNumber(DataFlow::exprNode(e)) = globalValueNumber(lesser.getArgument(0))
)
}
class LengthCheckSanitizer extends Sanitizer {
LengthCheckSanitizer() { this = DataFlow::BarrierGuard<lengthCheck/3>::getABarrierNode() }
}
/**

View File

@@ -34,7 +34,7 @@ module CommandInjection {
node instanceof Sanitizer
}
override predicate isSanitizerGuard(DataFlow::BarrierGuard guard) {
deprecated override predicate isSanitizerGuard(DataFlow::BarrierGuard guard) {
guard instanceof SanitizerGuard
}
}
@@ -97,7 +97,7 @@ module CommandInjection {
node = any(ArgumentArrayWithDoubleDash array).getASanitizedElement()
}
override predicate isSanitizerGuard(DataFlow::BarrierGuard guard) {
deprecated override predicate isSanitizerGuard(DataFlow::BarrierGuard guard) {
guard instanceof SanitizerGuard
}
}

View File

@@ -30,9 +30,11 @@ module CommandInjection {
abstract class Sanitizer extends DataFlow::Node { }
/**
* DEPRECATED: Use `Sanitizer` instead.
*
* A sanitizer guard for command-injection vulnerabilities.
*/
abstract class SanitizerGuard extends DataFlow::BarrierGuard { }
abstract deprecated class SanitizerGuard extends DataFlow::BarrierGuard { }
/** A source of untrusted data, considered as a taint source for command injection. */
class UntrustedFlowAsSource extends Source {

View File

@@ -127,11 +127,14 @@ class ConversionWithoutBoundsCheckConfig extends TaintTracking::Configuration {
override predicate isSink(DataFlow::Node sink) { this.isSink(sink, sinkBitSize) }
override predicate isSanitizerGuard(DataFlow::BarrierGuard guard) {
override predicate isSanitizer(DataFlow::Node node) {
// To catch flows that only happen on 32-bit architectures we
// consider an architecture-dependent sink bit size to be 32.
exists(int bitSize | if sinkBitSize != 0 then bitSize = sinkBitSize else bitSize = 32 |
guard.(UpperBoundCheckGuard).isBoundFor(bitSize, sourceIsSigned)
exists(UpperBoundCheckGuard g, int bitSize |
if sinkBitSize != 0 then bitSize = sinkBitSize else bitSize = 32
|
node = DataFlow::BarrierGuard<upperBoundCheckGuard/3>::getABarrierNodeForGuard(g) and
g.isBoundFor(bitSize, sourceIsSigned)
)
}
@@ -142,8 +145,12 @@ class ConversionWithoutBoundsCheckConfig extends TaintTracking::Configuration {
}
}
private predicate upperBoundCheckGuard(DataFlow::Node g, Expr e, boolean branch) {
g.(UpperBoundCheckGuard).checks(e, branch)
}
/** An upper bound check that compares a variable to a constant value. */
class UpperBoundCheckGuard extends DataFlow::BarrierGuard, DataFlow::RelationalComparisonNode {
class UpperBoundCheckGuard extends DataFlow::RelationalComparisonNode {
UpperBoundCheckGuard() {
count(expr.getAnOperand().getExactValue()) = 1 and
expr.getAnOperand().getType().getUnderlyingType() instanceof IntegerType
@@ -180,7 +187,8 @@ class UpperBoundCheckGuard extends DataFlow::BarrierGuard, DataFlow::RelationalC
)
}
override predicate checks(Expr e, boolean branch) {
/** Holds if this guard validates `e` upon evaluating to `branch`. */
predicate checks(Expr e, boolean branch) {
this.leq(branch, DataFlow::exprNode(e), _, _) and
not e.isConst()
}

View File

@@ -26,7 +26,7 @@ module LogInjection {
override predicate isSanitizer(DataFlow::Node sanitizer) { sanitizer instanceof Sanitizer }
override predicate isSanitizerGuard(DataFlow::BarrierGuard guard) {
deprecated override predicate isSanitizerGuard(DataFlow::BarrierGuard guard) {
guard instanceof SanitizerGuard
}
}

View File

@@ -27,9 +27,11 @@ module LogInjection {
abstract class Sanitizer extends DataFlow::Node { }
/**
* DEPRECATED: Use `Sanitizer` instead.
*
* A sanitizer guard for log injection vulnerabilities.
*/
abstract class SanitizerGuard extends DataFlow::BarrierGuard { }
abstract deprecated class SanitizerGuard extends DataFlow::BarrierGuard { }
/** A source of untrusted data, considered as a taint source for log injection. */
class UntrustedFlowAsSource extends Source {

View File

@@ -59,7 +59,7 @@ module OpenUrlRedirect {
hostnameSanitizingPrefixEdge(node, _)
}
override predicate isBarrierGuard(DataFlow::BarrierGuard guard) {
deprecated override predicate isBarrierGuard(DataFlow::BarrierGuard guard) {
guard instanceof BarrierGuard
}
}

View File

@@ -32,9 +32,11 @@ module OpenUrlRedirect {
abstract class Barrier extends DataFlow::Node { }
/**
* DEPRECATED: Use `Barrier` instead.
*
* A barrier guard for unvalidated URL redirect vulnerabilities.
*/
abstract class BarrierGuard extends DataFlow::BarrierGuard { }
abstract deprecated class BarrierGuard extends DataFlow::BarrierGuard { }
/**
* An additional taint propagation step specific to this query.
@@ -98,20 +100,20 @@ module OpenUrlRedirect {
* A call to a function called `isLocalUrl`, `isValidRedirect`, or similar, which is
* considered a barrier guard for sanitizing untrusted URLs.
*/
class RedirectCheckBarrierGuardAsBarrierGuard extends RedirectCheckBarrierGuard, BarrierGuard { }
class RedirectCheckBarrierGuardAsBarrierGuard extends RedirectCheckBarrier, Barrier { }
/**
* A call to a regexp match function, considered as a barrier guard for sanitizing untrusted URLs.
*
* This is overapproximate: we do not attempt to reason about the correctness of the regexp.
*/
class RegexpCheckAsBarrierGuard extends RegexpCheck, BarrierGuard { }
class RegexpCheckAsBarrierGuard extends RegexpCheckBarrier, Barrier { }
/**
* A check against a constant value or the `Hostname` function,
* considered a barrier guard for url flow.
*/
class UrlCheckAsBarrierGuard extends UrlCheck, BarrierGuard { }
class UrlCheckAsBarrierGuard extends UrlCheckBarrier, Barrier { }
}
/** A sink for an open redirect, considered as a sink for safe URL flow. */

View File

@@ -31,7 +31,7 @@ module ReflectedXss {
node instanceof Sanitizer
}
override predicate isSanitizerGuard(DataFlow::BarrierGuard guard) {
deprecated override predicate isSanitizerGuard(DataFlow::BarrierGuard guard) {
guard instanceof SanitizerGuard
}
}

View File

@@ -20,9 +20,11 @@ module ReflectedXss {
abstract class Sanitizer extends DataFlow::Node { }
/**
* DEPRECATED: Use `Sanitizer` instead.
*
* A sanitizer guard for reflected XSS vulnerabilities.
*/
abstract class SanitizerGuard extends DataFlow::BarrierGuard { }
abstract deprecated class SanitizerGuard extends DataFlow::BarrierGuard { }
/** A shared XSS sanitizer as a sanitizer for reflected XSS. */
private class SharedXssSanitizer extends Sanitizer {
@@ -30,7 +32,7 @@ module ReflectedXss {
}
/** A shared XSS sanitizer guard as a sanitizer guard for reflected XSS. */
private class SharedXssSanitizerGuard extends SanitizerGuard {
deprecated private class SharedXssSanitizerGuard extends SanitizerGuard {
SharedXss::SanitizerGuard self;
SharedXssSanitizerGuard() { this = self }

View File

@@ -43,7 +43,7 @@ module RequestForgery {
node instanceof SanitizerEdge
}
override predicate isSanitizerGuard(DataFlow::BarrierGuard guard) {
deprecated override predicate isSanitizerGuard(DataFlow::BarrierGuard guard) {
super.isSanitizerGuard(guard) or guard instanceof SanitizerGuard
}
}

View File

@@ -33,9 +33,11 @@ module RequestForgery {
abstract class SanitizerEdge extends DataFlow::Node { }
/**
* DEPRECATED: Use `Sanitizer` instead.
*
* A sanitizer guard for request forgery vulnerabilities.
*/
abstract class SanitizerGuard extends DataFlow::BarrierGuard { }
abstract deprecated class SanitizerGuard extends DataFlow::BarrierGuard { }
/**
* A third-party controllable input, considered as a flow source for request forgery.
@@ -80,15 +82,14 @@ module RequestForgery {
* A call to a function called `isLocalUrl`, `isValidRedirect`, or similar, which is
* considered a barrier guard.
*/
class RedirectCheckBarrierGuardAsBarrierGuard extends RedirectCheckBarrierGuard, SanitizerGuard {
}
class RedirectCheckBarrierGuardAsBarrierGuard extends RedirectCheckBarrier, Sanitizer { }
/**
* A call to a regexp match function, considered as a barrier guard for sanitizing untrusted URLs.
*
* This is overapproximate: we do not attempt to reason about the correctness of the regexp.
*/
class RegexpCheckAsBarrierGuard extends RegexpCheck, SanitizerGuard { }
class RegexpCheckAsBarrierGuard extends RegexpCheckBarrier, Sanitizer { }
/**
* An equality check comparing a data-flow node against a constant string, considered as
@@ -97,7 +98,7 @@ module RequestForgery {
* Additionally, a check comparing `url.Hostname()` against a constant string is also
* considered a barrier guard for `url`.
*/
class UrlCheckAsBarrierGuard extends UrlCheck, SanitizerGuard { }
class UrlCheckAsBarrierGuard extends UrlCheckBarrier, Sanitizer { }
}
/** A sink for request forgery, considered as a sink for safe URL flow. */

View File

@@ -32,7 +32,7 @@ module SqlInjection {
node instanceof Sanitizer
}
override predicate isSanitizerGuard(DataFlow::BarrierGuard guard) {
deprecated override predicate isSanitizerGuard(DataFlow::BarrierGuard guard) {
guard instanceof SanitizerGuard
}
}

View File

@@ -26,9 +26,11 @@ module SqlInjection {
abstract class Sanitizer extends DataFlow::Node { }
/**
* DEPRECATED: Use `Sanitizer` instead.
*
* A sanitizer guard for SQL-injection vulnerabilities.
*/
abstract class SanitizerGuard extends DataFlow::BarrierGuard { }
abstract deprecated class SanitizerGuard extends DataFlow::BarrierGuard { }
/** A source of untrusted data, considered as a taint source for SQL injection. */
class UntrustedFlowAsSource extends Source {

View File

@@ -35,7 +35,7 @@ module StoredCommand {
node instanceof CommandInjection::Sanitizer
}
override predicate isSanitizerGuard(DataFlow::BarrierGuard guard) {
deprecated override predicate isSanitizerGuard(DataFlow::BarrierGuard guard) {
guard instanceof CommandInjection::SanitizerGuard
}
}

View File

@@ -31,7 +31,7 @@ module StoredXss {
node instanceof Sanitizer
}
override predicate isSanitizerGuard(DataFlow::BarrierGuard guard) {
deprecated override predicate isSanitizerGuard(DataFlow::BarrierGuard guard) {
guard instanceof SanitizerGuard
}
}

View File

@@ -16,8 +16,12 @@ module StoredXss {
/** A sanitizer for stored XSS vulnerabilities. */
abstract class Sanitizer extends DataFlow::Node { }
/** A sanitizer guard for stored XSS vulnerabilities. */
abstract class SanitizerGuard extends DataFlow::BarrierGuard { }
/**
* DEPRECATED: Use `Sanitizer` instead.
*
* A sanitizer guard for stored XSS vulnerabilities.
*/
abstract deprecated class SanitizerGuard extends DataFlow::BarrierGuard { }
/** A shared XSS sanitizer as a sanitizer for stored XSS. */
private class SharedXssSanitizer extends Sanitizer {
@@ -25,7 +29,7 @@ module StoredXss {
}
/** A shared XSS sanitizer guard as a sanitizer guard for stored XSS. */
private class SharedXssSanitizerGuard extends SanitizerGuard {
deprecated private class SharedXssSanitizerGuard extends SanitizerGuard {
SharedXss::SanitizerGuard self;
SharedXssSanitizerGuard() { this = self }

View File

@@ -40,9 +40,11 @@ module StringBreak {
}
/**
* DEPRECATED: Use `Sanitizer` instead.
*
* A sanitizer guard for unsafe-quoting vulnerabilities.
*/
abstract class SanitizerGuard extends DataFlow::BarrierGuard { }
abstract deprecated class SanitizerGuard extends DataFlow::BarrierGuard { }
/** Holds if `l` contains a `quote` (either single or double). */
private predicate containsQuote(StringOps::ConcatenationLeaf l, Quote quote) {

View File

@@ -25,9 +25,5 @@ module TaintedPath {
super.isSanitizer(node) or
node instanceof Sanitizer
}
override predicate isSanitizerGuard(DataFlow::BarrierGuard guard) {
guard instanceof SanitizerGuardAsBarrierGuard
}
}
}

View File

@@ -28,24 +28,31 @@ module TaintedPath {
/**
* A sanitizer guard for path-traversal vulnerabilities.
*
* Note this class should be extended to define more taint-path sanitizer guards, but isn't itself a
* `DataFlow::BarrierGuard` so that other queries can use this to define `BarrierGuard`s without
* introducing recursion. The class `SanitizerGuardAsBarrierGuard` plugs all instances of this class
* into the `DataFlow::BarrierGuard` type hierarchy.
*/
abstract class SanitizerGuard extends DataFlow::Node {
abstract predicate checks(Expr e, boolean branch);
}
private predicate sanitizerGuard(DataFlow::Node g, Expr e, boolean branch) {
g.(SanitizerGuard).checks(e, branch)
}
private class SanitizerGuardAsSanitizer extends Sanitizer {
SanitizerGuardAsSanitizer() {
this = DataFlow::BarrierGuard<sanitizerGuard/3>::getABarrierNode()
}
}
/**
* DEPRECATED: Use `Sanitizer` instead.
*
* A sanitizer guard for path-traversal vulnerabilities, as a `DataFlow::BarrierGuard`.
*
* Use this class if you want all `TaintedPath::SanitizerGuard`s as a `DataFlow::BarrierGuard`,
* e.g. to use directly in a `DataFlow::Configuration::isSanitizerGuard` method. If you want to
* provide a new instance of a tainted path sanitizer, extend `TaintedPath::SanitizerGuard` instead.
*/
class SanitizerGuardAsBarrierGuard extends DataFlow::BarrierGuard {
deprecated class SanitizerGuardAsBarrierGuard extends DataFlow::BarrierGuard {
SanitizerGuard guardImpl;
SanitizerGuardAsBarrierGuard() { this = guardImpl }

View File

@@ -28,7 +28,7 @@ module UnsafeUnzipSymlink {
node instanceof EvalSymlinksInvalidator
}
override predicate isSanitizerGuard(DataFlow::BarrierGuard guard) {
deprecated override predicate isSanitizerGuard(DataFlow::BarrierGuard guard) {
guard instanceof EvalSymlinksInvalidatorGuard
}
}
@@ -59,7 +59,7 @@ module UnsafeUnzipSymlink {
node instanceof SymlinkSanitizer
}
override predicate isSanitizerGuard(DataFlow::BarrierGuard guard) {
deprecated override predicate isSanitizerGuard(DataFlow::BarrierGuard guard) {
guard instanceof SymlinkSanitizerGuard
}
}

View File

@@ -37,12 +37,14 @@ module UnsafeUnzipSymlink {
abstract class EvalSymlinksInvalidator extends DataFlow::Node { }
/**
* DEPRECATED: Use `EvalSymlinksInvalidator` instead.
*
* A sanitizer guard that prevents reaching an `EvalSymlinksSink`.
*
* This is called an invalidator instead of a sanitizer because reaching a EvalSymlinksSink
* is a good thing from a security perspective.
*/
abstract class EvalSymlinksInvalidatorGuard extends DataFlow::BarrierGuard { }
abstract deprecated class EvalSymlinksInvalidatorGuard extends DataFlow::BarrierGuard { }
/**
* A sanitizer for an unsafe symbolic-link unzip vulnerability.
@@ -54,13 +56,15 @@ module UnsafeUnzipSymlink {
abstract class SymlinkSanitizer extends DataFlow::Node { }
/**
* DEPRECATED: Use `SymlinkSanitizer` instead.
*
* A sanitizer guard for an unsafe symbolic-link unzip vulnerability.
*
* Extend this to mark a particular path as safe for use in an `os.Symlink` or similar call.
* To exclude a source from the query entirely if it reaches a particular node, extend
* `EvalSymlinksSink` instead.
*/
abstract class SymlinkSanitizerGuard extends DataFlow::BarrierGuard { }
abstract deprecated class SymlinkSanitizerGuard extends DataFlow::BarrierGuard { }
/** A file name from a zip or tar entry, as a source for unsafe unzipping of symlinks. */
class FileNameSource extends FilenameWithSymlinks, DataFlow::FieldReadNode {

View File

@@ -28,7 +28,7 @@ module XPathInjection {
node instanceof Sanitizer
}
override predicate isSanitizerGuard(DataFlow::BarrierGuard guard) {
deprecated override predicate isSanitizerGuard(DataFlow::BarrierGuard guard) {
guard instanceof SanitizerGuard
}
}

View File

@@ -25,9 +25,11 @@ module XPathInjection {
abstract class Sanitizer extends DataFlow::ExprNode { }
/**
* DEPRECATED: Use `Sanitizer` instead.
*
* A sanitizer guard for untrusted user input used in an XPath expression.
*/
abstract class SanitizerGuard extends DataFlow::BarrierGuard { }
abstract deprecated class SanitizerGuard extends DataFlow::BarrierGuard { }
/** A source of untrusted data, used in an XPath expression. */
class UntrustedFlowAsSource extends Source {

View File

@@ -31,8 +31,12 @@ module SharedXss {
/** A sanitizer for XSS vulnerabilities. */
abstract class Sanitizer extends DataFlow::Node { }
/** A sanitizer guard for XSS vulnerabilities. */
abstract class SanitizerGuard extends DataFlow::BarrierGuard { }
/**
* DEPRECATED: Use `Sanitizer` instead.
*
* A sanitizer guard for XSS vulnerabilities.
*/
abstract deprecated class SanitizerGuard extends DataFlow::BarrierGuard { }
/**
* An expression that is sent as part of an HTTP response body, considered as an

View File

@@ -26,7 +26,7 @@ module ZipSlip {
node instanceof Sanitizer
}
override predicate isSanitizerGuard(DataFlow::BarrierGuard guard) {
deprecated override predicate isSanitizerGuard(DataFlow::BarrierGuard guard) {
guard instanceof SanitizerGuard
}
}

View File

@@ -28,9 +28,11 @@ module ZipSlip {
abstract class Sanitizer extends DataFlow::Node { }
/**
* DEPRECATED: Use `Sanitizer` instead.
*
* A sanitizer guard for zip-slip vulnerabilities.
*/
abstract class SanitizerGuard extends DataFlow::BarrierGuard { }
abstract deprecated class SanitizerGuard extends DataFlow::BarrierGuard { }
/**
* A tar file header, as a source for zip slip.
@@ -107,6 +109,17 @@ module ZipSlip {
)
}
private predicate taintedPathSanitizerGuardAsBacktrackingSanitizerGuard(
DataFlow::Node g, Expr e, boolean branch
) {
exists(DataFlow::Node source, DataFlow::Node checked |
taintedPathGuardChecks(g, checked, branch) and
taintFlowsToCheckedNode(source, checked)
|
e = source.asExpr()
)
}
/**
* A sanitizer guard for zip-slip vulnerabilities which backtracks to sanitize expressions
* that locally flow into a guarded expression. For example, an ordinary sanitizer guard
@@ -120,18 +133,10 @@ module ZipSlip {
* (e.g. `hdr.Filename` to `hdr`), increasing the chances that a future reference to `hdr.Filename`
* will also be regarded as clean (though SSA catches some cases of this).
*/
class TaintedPathSanitizerGuardAsBacktrackingSanitizerGuard extends SanitizerGuard {
TaintedPath::SanitizerGuard taintedPathGuard;
TaintedPathSanitizerGuardAsBacktrackingSanitizerGuard() { this = taintedPathGuard }
override predicate checks(Expr e, boolean branch) {
exists(DataFlow::Node source, DataFlow::Node checked |
taintedPathGuardChecks(taintedPathGuard, checked, branch) and
taintFlowsToCheckedNode(source, checked)
|
e = source.asExpr()
)
class TaintedPathSanitizerGuardAsBacktrackingSanitizerGuard extends Sanitizer {
TaintedPathSanitizerGuardAsBacktrackingSanitizerGuard() {
this =
DataFlow::BarrierGuard<taintedPathSanitizerGuardAsBacktrackingSanitizerGuard/3>::getABarrierNode()
}
}
}

View File

@@ -18,19 +18,15 @@ string packagePath() { result = package("github.com/pkg/errors", "") }
/**
* An equality test which guarantees that an expression is always `nil`.
*/
class NilTestGuard extends DataFlow::BarrierGuard, DataFlow::EqualityTestNode {
DataFlow::Node otherNode;
NilTestGuard() {
this.getAnOperand() = Builtin::nil().getARead() and
otherNode = this.getAnOperand() and
not otherNode = Builtin::nil().getARead()
}
override predicate checks(Expr e, boolean outcome) {
predicate nilTestGuard(DataFlow::Node g, Expr e, boolean outcome) {
exists(DataFlow::EqualityTestNode eq, DataFlow::Node otherNode |
g = eq and
eq.getAnOperand() = Builtin::nil().getARead() and
otherNode = eq.getAnOperand() and
not otherNode = Builtin::nil().getARead() and
e = otherNode.asExpr() and
outcome = this.getPolarity()
}
outcome = eq.getPolarity()
)
}
/** Gets a use of a local variable that has the value `nil`. */
@@ -63,6 +59,6 @@ where
// if ok2, _ := f2(input); !ok2 {
// return errors.Wrap(err, "")
// }
n = any(NilTestGuard ntg).getAGuardedNode()
n = DataFlow::BarrierGuard<nilTestGuard/3>::getABarrierNode()
)
select n, "The first argument to 'errors.Wrap' is always nil"

View File

@@ -28,27 +28,25 @@ class RsaKeyTrackingConfiguration extends DataFlow::Configuration {
)
}
override predicate isBarrierGuard(DataFlow::BarrierGuard guard) {
guard instanceof ComparisonBarrierGuard
override predicate isBarrier(DataFlow::Node node) {
node = DataFlow::BarrierGuard<comparisonBarrierGuard/3>::getABarrierNode()
}
}
/**
* A comparison which guarantees that an expression is at least 2048,
* Holds if `g` is a comparison which guarantees that `e` is at least 2048 on `branch`,
* considered as a barrier guard for key sizes.
*/
class ComparisonBarrierGuard extends DataFlow::BarrierGuard instanceof DataFlow::RelationalComparisonNode {
override predicate checks(Expr e, boolean branch) {
exists(DataFlow::Node lesser, DataFlow::Node greater, int bias |
super.leq(branch, lesser, greater, bias)
|
// Force join order: find comparisons checking x >= 2048, then take the global value
// number of x. Otherwise this can be realised by starting from all pairs of matching value
// numbers, which can be huge.
pragma[only_bind_into](globalValueNumber(DataFlow::exprNode(e))) = globalValueNumber(greater) and
lesser.getIntValue() - bias >= 2048
)
}
predicate comparisonBarrierGuard(DataFlow::Node g, Expr e, boolean branch) {
exists(DataFlow::Node lesser, DataFlow::Node greater, int bias |
g.(DataFlow::RelationalComparisonNode).leq(branch, lesser, greater, bias)
|
// Force join order: find comparisons checking x >= 2048, then take the global value
// number of x. Otherwise this can be realised by starting from all pairs of matching value
// numbers, which can be huge.
pragma[only_bind_into](globalValueNumber(DataFlow::exprNode(e))) = globalValueNumber(greater) and
lesser.getIntValue() - bias >= 2048
)
}
from RsaKeyTrackingConfiguration cfg, DataFlow::PathNode source, DataFlow::PathNode sink

View File

@@ -29,11 +29,6 @@ module HardcodedKeys {
*/
abstract class Sanitizer extends DataFlow::Node { }
/**
* A sanitizer guard for JWT token signing vulnerabilities.
*/
abstract class SanitizerGuard extends DataFlow::BarrierGuard { }
private predicate isTestCode(Expr e) {
e.getFile().getAbsolutePath().toLowerCase().matches("%test%") and
not e.getFile().getAbsolutePath().toLowerCase().matches("%ql/test%")
@@ -315,9 +310,5 @@ module HardcodedKeys {
override predicate isSink(DataFlow::Node sink) { sink instanceof Sink }
override predicate isSanitizer(DataFlow::Node sanitizer) { sanitizer instanceof Sanitizer }
override predicate isSanitizerGuard(DataFlow::BarrierGuard guard) {
guard instanceof SanitizerGuard
}
}
}

View File

@@ -13,25 +13,18 @@ import DataFlow::PathGraph
import semmle.go.dataflow.internal.TaintTrackingUtil
/**
* A barrier-guard, which represents comparison and equality with zero.
* Holds if `g` is a barrier-guard which checks `e` is nonzero on `branch`.
*/
class DivideByZeroSanitizerGuard extends DataFlow::BarrierGuard {
DivideByZeroSanitizerGuard() {
this.(DataFlow::EqualityTestNode).getAnOperand().getNumericValue() = 0 or
this.(DataFlow::RelationalComparisonNode).getAnOperand().getNumericValue() = 0
}
override predicate checks(Expr e, boolean branch) {
exists(DataFlow::Node zero, DataFlow::Node checked |
zero.getNumericValue() = 0 and
e = checked.asExpr() and
checked.getType().getUnderlyingType() instanceof IntegerType and
(
this.(DataFlow::EqualityTestNode).eq(branch.booleanNot(), checked, zero) or
this.(DataFlow::RelationalComparisonNode).leq(branch.booleanNot(), checked, zero, 0)
)
predicate divideByZeroSanitizerGuard(DataFlow::Node g, Expr e, boolean branch) {
exists(DataFlow::Node zero, DataFlow::Node checked |
zero.getNumericValue() = 0 and
e = checked.asExpr() and
checked.getType().getUnderlyingType() instanceof IntegerType and
(
g.(DataFlow::EqualityTestNode).eq(branch.booleanNot(), checked, zero) or
g.(DataFlow::RelationalComparisonNode).leq(branch.booleanNot(), checked, zero, 0)
)
}
)
}
/**
@@ -50,8 +43,8 @@ class DivideByZeroCheckConfig extends TaintTracking::Configuration {
)
}
override predicate isSanitizerGuard(DataFlow::BarrierGuard guard) {
guard instanceof DivideByZeroSanitizerGuard
override predicate isSanitizer(DataFlow::Node node) {
node = DataFlow::BarrierGuard<divideByZeroSanitizerGuard/3>::getABarrierNode()
}
override predicate isSink(DataFlow::Node sink) {

View File

@@ -42,10 +42,6 @@ module ServerSideRequestForgery {
super.isSanitizerOut(node) or
node instanceof SanitizerEdge
}
override predicate isSanitizerGuard(DataFlow::BarrierGuard guard) {
super.isSanitizerGuard(guard) or guard instanceof SanitizerGuard
}
}
/** A data flow source for request forgery vulnerabilities. */
@@ -69,11 +65,6 @@ module ServerSideRequestForgery {
/** An outgoing sanitizer edge for request forgery vulnerabilities. */
abstract class SanitizerEdge extends DataFlow::Node { }
/**
* A sanitizer guard for request forgery vulnerabilities.
*/
abstract class SanitizerGuard extends DataFlow::BarrierGuard { }
/**
* An user controlled input, considered as a flow source for request forgery.
*/
@@ -118,22 +109,25 @@ module ServerSideRequestForgery {
*
* This is overapproximate: we do not attempt to reason about the correctness of the regexp.
*/
class RegexpCheckAsBarrierGuard extends RegexpCheck, SanitizerGuard { }
class RegexpCheckAsBarrierGuard extends RegexpCheckBarrier, Sanitizer { }
private predicate equalityAsSanitizerGuard(DataFlow::Node g, Expr e, boolean outcome) {
exists(DataFlow::Node url, DataFlow::EqualityTestNode eq |
g = eq and
exists(eq.getAnOperand().getStringValue()) and
url = eq.getAnOperand() and
e = url.asExpr() and
outcome = eq.getPolarity()
)
}
/**
* An equality check comparing a data-flow node against a constant string, considered as
* a barrier guard for sanitizing untrusted URLs.
*/
class EqualityAsSanitizerGuard extends SanitizerGuard, DataFlow::EqualityTestNode {
DataFlow::Node url;
class EqualityAsSanitizerGuard extends Sanitizer {
EqualityAsSanitizerGuard() {
exists(this.getAnOperand().getStringValue()) and
url = this.getAnOperand()
}
override predicate checks(Expr e, boolean outcome) {
e = url.asExpr() and outcome = this.getPolarity()
this = DataFlow::BarrierGuard<equalityAsSanitizerGuard/3>::getABarrierNode()
}
}
@@ -158,7 +152,5 @@ module ServerSideRequestForgery {
* The method Var of package validator is a sanitizer guard only if the check
* of the error binding exists, and the tag to check is one of "alpha", "alphanum", "alphaunicode", "alphanumunicode", "number", "numeric".
*/
class ValidatorAsSanitizer extends SanitizerGuard instanceof ValidatorVarCheck {
override predicate checks(Expr e, boolean branch) { this.checks(e, branch) }
}
class ValidatorAsSanitizer extends Sanitizer, ValidatorVarCheckBarrier { }
}

View File

@@ -69,20 +69,25 @@ class AlphanumericStructFieldRead extends DataFlow::Node {
class CheckedAlphanumericStructFieldRead extends AlphanumericStructFieldRead {
CheckedAlphanumericStructFieldRead() {
exists(StructValidationFunction guard, SelectorExpr selector |
guard.getAGuardedNode().asExpr() = selector.getBase() and
DataFlow::BarrierGuard<structValidationFunction/3>::getABarrierNodeForGuard(guard).asExpr() =
selector.getBase() and
selector = this.asExpr() and
this.getKey() = guard.getValidationKindKey()
)
}
}
private predicate structValidationFunction(DataFlow::Node g, Expr e, boolean branch) {
g.(StructValidationFunction).checks(e, branch)
}
/**
* A function that validates a struct, checking that fields conform to restrictions given as a tag.
*
* The Gin `Context.Bind` family of functions apply checks according to a `binding:` tag, and the
* Go-Playground Validator checks fields that have a `validate:` tag.
*/
private class StructValidationFunction extends DataFlow::BarrierGuard, DataFlow::EqualityTestNode {
private class StructValidationFunction extends DataFlow::EqualityTestNode {
Expr checked;
boolean safeOutcome;
string validationKindKey;
@@ -113,7 +118,7 @@ private class StructValidationFunction extends DataFlow::BarrierGuard, DataFlow:
)
}
override predicate checks(Expr e, boolean branch) { e = checked and branch = safeOutcome }
predicate checks(Expr e, boolean branch) { e = checked and branch = safeOutcome }
/**
* Returns the struct tag key from which this validation function draws its validation kind.
@@ -133,27 +138,25 @@ private Expr dereference(DataFlow::Node nd) {
nd.asExpr() = result
}
private predicate validatorVarCheck(DataFlow::Node g, Expr e, boolean outcome) {
exists(DataFlow::CallNode callToValidator, Method validatorMethod, DataFlow::Node resultErr |
g instanceof DataFlow::EqualityTestNode and
validatorMethod.hasQualifiedName("github.com/go-playground/validator", "Validate", "Var") and
callToValidator = validatorMethod.getACall() and
isAlphanumericValidationKind(callToValidator.getArgument(1).getStringValue()) and
resultErr = callToValidator.getResult().getASuccessor*() and
nilProperty().checkOn(g, outcome, resultErr) and
callToValidator.getArgument(0).asExpr() = e
)
}
/**
* A validation performed by package `validator`'s method `Var` to check that an expression is
* alphanumeric (see `isAlphanumericValidationKind` for more information) sanitizes guarded uses
* of the same variable.
*/
class ValidatorVarCheck extends DataFlow::BarrierGuard, DataFlow::EqualityTestNode {
DataFlow::CallNode callToValidator;
boolean outcome;
ValidatorVarCheck() {
exists(Method validatorMethod, DataFlow::Node resultErr |
validatorMethod.hasQualifiedName("github.com/go-playground/validator", "Validate", "Var") and
callToValidator = validatorMethod.getACall() and
isAlphanumericValidationKind(callToValidator.getArgument(1).getStringValue()) and
resultErr = callToValidator.getResult().getASuccessor*() and
nilProperty().checkOn(this, outcome, resultErr)
)
}
override predicate checks(Expr e, boolean branch) {
callToValidator.getArgument(0).asExpr() = e and
branch = outcome
class ValidatorVarCheckBarrier extends DataFlow::Node {
ValidatorVarCheckBarrier() {
this = DataFlow::BarrierGuard<validatorVarCheck/3>::getABarrierNode()
}
}

View File

@@ -1,12 +1,10 @@
import go
import TestUtilities.InlineExpectationsTest
class IsBad extends DataFlow::BarrierGuard, DataFlow::CallNode {
IsBad() { this.getTarget().getName() = "isBad" }
override predicate checks(Expr e, boolean branch) {
e = this.getAnArgument().asExpr() and branch = false
}
predicate isBad(DataFlow::Node g, Expr e, boolean branch) {
g.(DataFlow::CallNode).getTarget().getName() = "isBad" and
e = g.(DataFlow::CallNode).getAnArgument().asExpr() and
branch = false
}
class TestConfig extends DataFlow::Configuration {
@@ -20,7 +18,9 @@ class TestConfig extends DataFlow::Configuration {
sink = any(DataFlow::CallNode c | c.getTarget().getName() = "sink").getAnArgument()
}
override predicate isBarrierGuard(DataFlow::BarrierGuard bg) { bg instanceof IsBad }
override predicate isBarrier(DataFlow::Node node) {
node = DataFlow::BarrierGuard<isBad/3>::getABarrierNode()
}
}
class DataFlowTest extends InlineExpectationsTest {

View File

@@ -0,0 +1,4 @@
---
category: deprecated
---
* The `BarrierGuard` class has been deprecated. Such barriers and sanitizers can now instead be created using the new `BarrierGuard` parameterized module.

View File

@@ -90,14 +90,20 @@ 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() }
/**
* DEPRECATED: Use `isBarrier` and `BarrierGuard` module instead.
*
* Holds if data flow through nodes guarded by `guard` is prohibited.
*/
deprecated predicate isBarrierGuard(BarrierGuard guard) { none() }
/**
* DEPRECATED: Use `isBarrier` and `BarrierGuard` module instead.
*
* Holds if data flow through nodes guarded by `guard` is prohibited when
* the flow state is `state`
*/
predicate isBarrierGuard(BarrierGuard guard, FlowState state) { none() }
deprecated predicate isBarrierGuard(BarrierGuard guard, FlowState state) { none() }
/**
* Holds if data may flow from `node1` to `node2` in addition to the normal data-flow steps.
@@ -335,6 +341,29 @@ private predicate outBarrier(NodeEx node, Configuration config) {
)
}
/** A bridge class to access the deprecated `isBarrierGuard`. */
private class BarrierGuardGuardedNodeBridge extends Unit {
abstract predicate guardedNode(Node n, Configuration config);
abstract predicate guardedNode(Node n, FlowState state, Configuration config);
}
private class BarrierGuardGuardedNode extends BarrierGuardGuardedNodeBridge {
deprecated override predicate guardedNode(Node n, Configuration config) {
exists(BarrierGuard g |
config.isBarrierGuard(g) and
n = g.getAGuardedNode()
)
}
deprecated override predicate guardedNode(Node n, FlowState state, Configuration config) {
exists(BarrierGuard g |
config.isBarrierGuard(g, state) and
n = g.getAGuardedNode()
)
}
}
pragma[nomagic]
private predicate fullBarrier(NodeEx node, Configuration config) {
exists(Node n | node.asNode() = n |
@@ -348,10 +377,7 @@ private predicate fullBarrier(NodeEx node, Configuration config) {
not config.isSink(n) and
not config.isSink(n, _)
or
exists(BarrierGuard g |
config.isBarrierGuard(g) and
n = g.getAGuardedNode()
)
any(BarrierGuardGuardedNodeBridge b).guardedNode(n, config)
)
}
@@ -360,10 +386,7 @@ private predicate stateBarrier(NodeEx node, FlowState state, Configuration confi
exists(Node n | node.asNode() = n |
config.isBarrier(n, state)
or
exists(BarrierGuard g |
config.isBarrierGuard(g, state) and
n = g.getAGuardedNode()
)
any(BarrierGuardGuardedNodeBridge b).guardedNode(n, state, config)
)
}

View File

@@ -90,14 +90,20 @@ 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() }
/**
* DEPRECATED: Use `isBarrier` and `BarrierGuard` module instead.
*
* Holds if data flow through nodes guarded by `guard` is prohibited.
*/
deprecated predicate isBarrierGuard(BarrierGuard guard) { none() }
/**
* DEPRECATED: Use `isBarrier` and `BarrierGuard` module instead.
*
* Holds if data flow through nodes guarded by `guard` is prohibited when
* the flow state is `state`
*/
predicate isBarrierGuard(BarrierGuard guard, FlowState state) { none() }
deprecated predicate isBarrierGuard(BarrierGuard guard, FlowState state) { none() }
/**
* Holds if data may flow from `node1` to `node2` in addition to the normal data-flow steps.
@@ -335,6 +341,29 @@ private predicate outBarrier(NodeEx node, Configuration config) {
)
}
/** A bridge class to access the deprecated `isBarrierGuard`. */
private class BarrierGuardGuardedNodeBridge extends Unit {
abstract predicate guardedNode(Node n, Configuration config);
abstract predicate guardedNode(Node n, FlowState state, Configuration config);
}
private class BarrierGuardGuardedNode extends BarrierGuardGuardedNodeBridge {
deprecated override predicate guardedNode(Node n, Configuration config) {
exists(BarrierGuard g |
config.isBarrierGuard(g) and
n = g.getAGuardedNode()
)
}
deprecated override predicate guardedNode(Node n, FlowState state, Configuration config) {
exists(BarrierGuard g |
config.isBarrierGuard(g, state) and
n = g.getAGuardedNode()
)
}
}
pragma[nomagic]
private predicate fullBarrier(NodeEx node, Configuration config) {
exists(Node n | node.asNode() = n |
@@ -348,10 +377,7 @@ private predicate fullBarrier(NodeEx node, Configuration config) {
not config.isSink(n) and
not config.isSink(n, _)
or
exists(BarrierGuard g |
config.isBarrierGuard(g) and
n = g.getAGuardedNode()
)
any(BarrierGuardGuardedNodeBridge b).guardedNode(n, config)
)
}
@@ -360,10 +386,7 @@ private predicate stateBarrier(NodeEx node, FlowState state, Configuration confi
exists(Node n | node.asNode() = n |
config.isBarrier(n, state)
or
exists(BarrierGuard g |
config.isBarrierGuard(g, state) and
n = g.getAGuardedNode()
)
any(BarrierGuardGuardedNodeBridge b).guardedNode(n, state, config)
)
}

View File

@@ -90,14 +90,20 @@ 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() }
/**
* DEPRECATED: Use `isBarrier` and `BarrierGuard` module instead.
*
* Holds if data flow through nodes guarded by `guard` is prohibited.
*/
deprecated predicate isBarrierGuard(BarrierGuard guard) { none() }
/**
* DEPRECATED: Use `isBarrier` and `BarrierGuard` module instead.
*
* Holds if data flow through nodes guarded by `guard` is prohibited when
* the flow state is `state`
*/
predicate isBarrierGuard(BarrierGuard guard, FlowState state) { none() }
deprecated predicate isBarrierGuard(BarrierGuard guard, FlowState state) { none() }
/**
* Holds if data may flow from `node1` to `node2` in addition to the normal data-flow steps.
@@ -335,6 +341,29 @@ private predicate outBarrier(NodeEx node, Configuration config) {
)
}
/** A bridge class to access the deprecated `isBarrierGuard`. */
private class BarrierGuardGuardedNodeBridge extends Unit {
abstract predicate guardedNode(Node n, Configuration config);
abstract predicate guardedNode(Node n, FlowState state, Configuration config);
}
private class BarrierGuardGuardedNode extends BarrierGuardGuardedNodeBridge {
deprecated override predicate guardedNode(Node n, Configuration config) {
exists(BarrierGuard g |
config.isBarrierGuard(g) and
n = g.getAGuardedNode()
)
}
deprecated override predicate guardedNode(Node n, FlowState state, Configuration config) {
exists(BarrierGuard g |
config.isBarrierGuard(g, state) and
n = g.getAGuardedNode()
)
}
}
pragma[nomagic]
private predicate fullBarrier(NodeEx node, Configuration config) {
exists(Node n | node.asNode() = n |
@@ -348,10 +377,7 @@ private predicate fullBarrier(NodeEx node, Configuration config) {
not config.isSink(n) and
not config.isSink(n, _)
or
exists(BarrierGuard g |
config.isBarrierGuard(g) and
n = g.getAGuardedNode()
)
any(BarrierGuardGuardedNodeBridge b).guardedNode(n, config)
)
}
@@ -360,10 +386,7 @@ private predicate stateBarrier(NodeEx node, FlowState state, Configuration confi
exists(Node n | node.asNode() = n |
config.isBarrier(n, state)
or
exists(BarrierGuard g |
config.isBarrierGuard(g, state) and
n = g.getAGuardedNode()
)
any(BarrierGuardGuardedNodeBridge b).guardedNode(n, state, config)
)
}

View File

@@ -90,14 +90,20 @@ 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() }
/**
* DEPRECATED: Use `isBarrier` and `BarrierGuard` module instead.
*
* Holds if data flow through nodes guarded by `guard` is prohibited.
*/
deprecated predicate isBarrierGuard(BarrierGuard guard) { none() }
/**
* DEPRECATED: Use `isBarrier` and `BarrierGuard` module instead.
*
* Holds if data flow through nodes guarded by `guard` is prohibited when
* the flow state is `state`
*/
predicate isBarrierGuard(BarrierGuard guard, FlowState state) { none() }
deprecated predicate isBarrierGuard(BarrierGuard guard, FlowState state) { none() }
/**
* Holds if data may flow from `node1` to `node2` in addition to the normal data-flow steps.
@@ -335,6 +341,29 @@ private predicate outBarrier(NodeEx node, Configuration config) {
)
}
/** A bridge class to access the deprecated `isBarrierGuard`. */
private class BarrierGuardGuardedNodeBridge extends Unit {
abstract predicate guardedNode(Node n, Configuration config);
abstract predicate guardedNode(Node n, FlowState state, Configuration config);
}
private class BarrierGuardGuardedNode extends BarrierGuardGuardedNodeBridge {
deprecated override predicate guardedNode(Node n, Configuration config) {
exists(BarrierGuard g |
config.isBarrierGuard(g) and
n = g.getAGuardedNode()
)
}
deprecated override predicate guardedNode(Node n, FlowState state, Configuration config) {
exists(BarrierGuard g |
config.isBarrierGuard(g, state) and
n = g.getAGuardedNode()
)
}
}
pragma[nomagic]
private predicate fullBarrier(NodeEx node, Configuration config) {
exists(Node n | node.asNode() = n |
@@ -348,10 +377,7 @@ private predicate fullBarrier(NodeEx node, Configuration config) {
not config.isSink(n) and
not config.isSink(n, _)
or
exists(BarrierGuard g |
config.isBarrierGuard(g) and
n = g.getAGuardedNode()
)
any(BarrierGuardGuardedNodeBridge b).guardedNode(n, config)
)
}
@@ -360,10 +386,7 @@ private predicate stateBarrier(NodeEx node, FlowState state, Configuration confi
exists(Node n | node.asNode() = n |
config.isBarrier(n, state)
or
exists(BarrierGuard g |
config.isBarrierGuard(g, state) and
n = g.getAGuardedNode()
)
any(BarrierGuardGuardedNodeBridge b).guardedNode(n, state, config)
)
}

View File

@@ -90,14 +90,20 @@ 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() }
/**
* DEPRECATED: Use `isBarrier` and `BarrierGuard` module instead.
*
* Holds if data flow through nodes guarded by `guard` is prohibited.
*/
deprecated predicate isBarrierGuard(BarrierGuard guard) { none() }
/**
* DEPRECATED: Use `isBarrier` and `BarrierGuard` module instead.
*
* Holds if data flow through nodes guarded by `guard` is prohibited when
* the flow state is `state`
*/
predicate isBarrierGuard(BarrierGuard guard, FlowState state) { none() }
deprecated predicate isBarrierGuard(BarrierGuard guard, FlowState state) { none() }
/**
* Holds if data may flow from `node1` to `node2` in addition to the normal data-flow steps.
@@ -335,6 +341,29 @@ private predicate outBarrier(NodeEx node, Configuration config) {
)
}
/** A bridge class to access the deprecated `isBarrierGuard`. */
private class BarrierGuardGuardedNodeBridge extends Unit {
abstract predicate guardedNode(Node n, Configuration config);
abstract predicate guardedNode(Node n, FlowState state, Configuration config);
}
private class BarrierGuardGuardedNode extends BarrierGuardGuardedNodeBridge {
deprecated override predicate guardedNode(Node n, Configuration config) {
exists(BarrierGuard g |
config.isBarrierGuard(g) and
n = g.getAGuardedNode()
)
}
deprecated override predicate guardedNode(Node n, FlowState state, Configuration config) {
exists(BarrierGuard g |
config.isBarrierGuard(g, state) and
n = g.getAGuardedNode()
)
}
}
pragma[nomagic]
private predicate fullBarrier(NodeEx node, Configuration config) {
exists(Node n | node.asNode() = n |
@@ -348,10 +377,7 @@ private predicate fullBarrier(NodeEx node, Configuration config) {
not config.isSink(n) and
not config.isSink(n, _)
or
exists(BarrierGuard g |
config.isBarrierGuard(g) and
n = g.getAGuardedNode()
)
any(BarrierGuardGuardedNodeBridge b).guardedNode(n, config)
)
}
@@ -360,10 +386,7 @@ private predicate stateBarrier(NodeEx node, FlowState state, Configuration confi
exists(Node n | node.asNode() = n |
config.isBarrier(n, state)
or
exists(BarrierGuard g |
config.isBarrierGuard(g, state) and
n = g.getAGuardedNode()
)
any(BarrierGuardGuardedNodeBridge b).guardedNode(n, state, config)
)
}

View File

@@ -90,14 +90,20 @@ 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() }
/**
* DEPRECATED: Use `isBarrier` and `BarrierGuard` module instead.
*
* Holds if data flow through nodes guarded by `guard` is prohibited.
*/
deprecated predicate isBarrierGuard(BarrierGuard guard) { none() }
/**
* DEPRECATED: Use `isBarrier` and `BarrierGuard` module instead.
*
* Holds if data flow through nodes guarded by `guard` is prohibited when
* the flow state is `state`
*/
predicate isBarrierGuard(BarrierGuard guard, FlowState state) { none() }
deprecated predicate isBarrierGuard(BarrierGuard guard, FlowState state) { none() }
/**
* Holds if data may flow from `node1` to `node2` in addition to the normal data-flow steps.
@@ -335,6 +341,29 @@ private predicate outBarrier(NodeEx node, Configuration config) {
)
}
/** A bridge class to access the deprecated `isBarrierGuard`. */
private class BarrierGuardGuardedNodeBridge extends Unit {
abstract predicate guardedNode(Node n, Configuration config);
abstract predicate guardedNode(Node n, FlowState state, Configuration config);
}
private class BarrierGuardGuardedNode extends BarrierGuardGuardedNodeBridge {
deprecated override predicate guardedNode(Node n, Configuration config) {
exists(BarrierGuard g |
config.isBarrierGuard(g) and
n = g.getAGuardedNode()
)
}
deprecated override predicate guardedNode(Node n, FlowState state, Configuration config) {
exists(BarrierGuard g |
config.isBarrierGuard(g, state) and
n = g.getAGuardedNode()
)
}
}
pragma[nomagic]
private predicate fullBarrier(NodeEx node, Configuration config) {
exists(Node n | node.asNode() = n |
@@ -348,10 +377,7 @@ private predicate fullBarrier(NodeEx node, Configuration config) {
not config.isSink(n) and
not config.isSink(n, _)
or
exists(BarrierGuard g |
config.isBarrierGuard(g) and
n = g.getAGuardedNode()
)
any(BarrierGuardGuardedNodeBridge b).guardedNode(n, config)
)
}
@@ -360,10 +386,7 @@ private predicate stateBarrier(NodeEx node, FlowState state, Configuration confi
exists(Node n | node.asNode() = n |
config.isBarrier(n, state)
or
exists(BarrierGuard g |
config.isBarrierGuard(g, state) and
n = g.getAGuardedNode()
)
any(BarrierGuardGuardedNodeBridge b).guardedNode(n, state, config)
)
}

View File

@@ -90,14 +90,20 @@ 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() }
/**
* DEPRECATED: Use `isBarrier` and `BarrierGuard` module instead.
*
* Holds if data flow through nodes guarded by `guard` is prohibited.
*/
deprecated predicate isBarrierGuard(BarrierGuard guard) { none() }
/**
* DEPRECATED: Use `isBarrier` and `BarrierGuard` module instead.
*
* Holds if data flow through nodes guarded by `guard` is prohibited when
* the flow state is `state`
*/
predicate isBarrierGuard(BarrierGuard guard, FlowState state) { none() }
deprecated predicate isBarrierGuard(BarrierGuard guard, FlowState state) { none() }
/**
* Holds if data may flow from `node1` to `node2` in addition to the normal data-flow steps.
@@ -335,6 +341,29 @@ private predicate outBarrier(NodeEx node, Configuration config) {
)
}
/** A bridge class to access the deprecated `isBarrierGuard`. */
private class BarrierGuardGuardedNodeBridge extends Unit {
abstract predicate guardedNode(Node n, Configuration config);
abstract predicate guardedNode(Node n, FlowState state, Configuration config);
}
private class BarrierGuardGuardedNode extends BarrierGuardGuardedNodeBridge {
deprecated override predicate guardedNode(Node n, Configuration config) {
exists(BarrierGuard g |
config.isBarrierGuard(g) and
n = g.getAGuardedNode()
)
}
deprecated override predicate guardedNode(Node n, FlowState state, Configuration config) {
exists(BarrierGuard g |
config.isBarrierGuard(g, state) and
n = g.getAGuardedNode()
)
}
}
pragma[nomagic]
private predicate fullBarrier(NodeEx node, Configuration config) {
exists(Node n | node.asNode() = n |
@@ -348,10 +377,7 @@ private predicate fullBarrier(NodeEx node, Configuration config) {
not config.isSink(n) and
not config.isSink(n, _)
or
exists(BarrierGuard g |
config.isBarrierGuard(g) and
n = g.getAGuardedNode()
)
any(BarrierGuardGuardedNodeBridge b).guardedNode(n, config)
)
}
@@ -360,10 +386,7 @@ private predicate stateBarrier(NodeEx node, FlowState state, Configuration confi
exists(Node n | node.asNode() = n |
config.isBarrier(n, state)
or
exists(BarrierGuard g |
config.isBarrierGuard(g, state) and
n = g.getAGuardedNode()
)
any(BarrierGuardGuardedNodeBridge b).guardedNode(n, state, config)
)
}

View File

@@ -90,14 +90,20 @@ 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() }
/**
* DEPRECATED: Use `isBarrier` and `BarrierGuard` module instead.
*
* Holds if data flow through nodes guarded by `guard` is prohibited.
*/
deprecated predicate isBarrierGuard(BarrierGuard guard) { none() }
/**
* DEPRECATED: Use `isBarrier` and `BarrierGuard` module instead.
*
* Holds if data flow through nodes guarded by `guard` is prohibited when
* the flow state is `state`
*/
predicate isBarrierGuard(BarrierGuard guard, FlowState state) { none() }
deprecated predicate isBarrierGuard(BarrierGuard guard, FlowState state) { none() }
/**
* Holds if data may flow from `node1` to `node2` in addition to the normal data-flow steps.
@@ -335,6 +341,29 @@ private predicate outBarrier(NodeEx node, Configuration config) {
)
}
/** A bridge class to access the deprecated `isBarrierGuard`. */
private class BarrierGuardGuardedNodeBridge extends Unit {
abstract predicate guardedNode(Node n, Configuration config);
abstract predicate guardedNode(Node n, FlowState state, Configuration config);
}
private class BarrierGuardGuardedNode extends BarrierGuardGuardedNodeBridge {
deprecated override predicate guardedNode(Node n, Configuration config) {
exists(BarrierGuard g |
config.isBarrierGuard(g) and
n = g.getAGuardedNode()
)
}
deprecated override predicate guardedNode(Node n, FlowState state, Configuration config) {
exists(BarrierGuard g |
config.isBarrierGuard(g, state) and
n = g.getAGuardedNode()
)
}
}
pragma[nomagic]
private predicate fullBarrier(NodeEx node, Configuration config) {
exists(Node n | node.asNode() = n |
@@ -348,10 +377,7 @@ private predicate fullBarrier(NodeEx node, Configuration config) {
not config.isSink(n) and
not config.isSink(n, _)
or
exists(BarrierGuard g |
config.isBarrierGuard(g) and
n = g.getAGuardedNode()
)
any(BarrierGuardGuardedNodeBridge b).guardedNode(n, config)
)
}
@@ -360,10 +386,7 @@ private predicate stateBarrier(NodeEx node, FlowState state, Configuration confi
exists(Node n | node.asNode() = n |
config.isBarrier(n, state)
or
exists(BarrierGuard g |
config.isBarrierGuard(g, state) and
n = g.getAGuardedNode()
)
any(BarrierGuardGuardedNodeBridge b).guardedNode(n, state, config)
)
}

View File

@@ -332,6 +332,8 @@ module BarrierGuard<guardChecksSig/3 guardChecks> {
}
/**
* DEPRECATED: Use `BarrierGuard` module instead.
*
* A guard that validates some expression.
*
* To use this in a configuration, extend the class and provide a
@@ -340,7 +342,7 @@ module BarrierGuard<guardChecksSig/3 guardChecks> {
*
* It is important that all extending classes in scope are disjoint.
*/
class BarrierGuard extends Guard {
deprecated class BarrierGuard extends Guard {
/** Holds if this guard validates `e` upon evaluating to `branch`. */
abstract predicate checks(Expr e, boolean branch);

View File

@@ -112,12 +112,6 @@ private module Cached {
}
}
/**
* Holds if `guard` should be a sanitizer guard in all global taint flow configurations
* but not in local taint.
*/
predicate defaultTaintSanitizerGuard(DataFlow::BarrierGuard guard) { none() }
import Cached
private RefType getElementType(RefType container) {

View File

@@ -116,20 +116,30 @@ abstract class Configuration extends DataFlow::Configuration {
final override predicate isBarrierOut(DataFlow::Node node) { this.isSanitizerOut(node) }
/** Holds if taint propagation through nodes guarded by `guard` is prohibited. */
predicate isSanitizerGuard(DataFlow::BarrierGuard guard) { none() }
/**
* DEPRECATED: Use `isSanitizer` and `BarrierGuard` module instead.
*
* Holds if taint propagation through nodes guarded by `guard` is prohibited.
*/
deprecated predicate isSanitizerGuard(DataFlow::BarrierGuard guard) { none() }
final override predicate isBarrierGuard(DataFlow::BarrierGuard guard) {
this.isSanitizerGuard(guard) or defaultTaintSanitizerGuard(guard)
deprecated final override predicate isBarrierGuard(DataFlow::BarrierGuard guard) {
this.isSanitizerGuard(guard)
}
/**
* DEPRECATED: Use `isSanitizer` and `BarrierGuard` module instead.
*
* Holds if taint propagation through nodes guarded by `guard` is prohibited
* when the flow state is `state`.
*/
predicate isSanitizerGuard(DataFlow::BarrierGuard guard, DataFlow::FlowState state) { none() }
deprecated predicate isSanitizerGuard(DataFlow::BarrierGuard guard, DataFlow::FlowState state) {
none()
}
final override predicate isBarrierGuard(DataFlow::BarrierGuard guard, DataFlow::FlowState state) {
deprecated final override predicate isBarrierGuard(
DataFlow::BarrierGuard guard, DataFlow::FlowState state
) {
this.isSanitizerGuard(guard, state)
}

View File

@@ -116,20 +116,30 @@ abstract class Configuration extends DataFlow::Configuration {
final override predicate isBarrierOut(DataFlow::Node node) { this.isSanitizerOut(node) }
/** Holds if taint propagation through nodes guarded by `guard` is prohibited. */
predicate isSanitizerGuard(DataFlow::BarrierGuard guard) { none() }
/**
* DEPRECATED: Use `isSanitizer` and `BarrierGuard` module instead.
*
* Holds if taint propagation through nodes guarded by `guard` is prohibited.
*/
deprecated predicate isSanitizerGuard(DataFlow::BarrierGuard guard) { none() }
final override predicate isBarrierGuard(DataFlow::BarrierGuard guard) {
this.isSanitizerGuard(guard) or defaultTaintSanitizerGuard(guard)
deprecated final override predicate isBarrierGuard(DataFlow::BarrierGuard guard) {
this.isSanitizerGuard(guard)
}
/**
* DEPRECATED: Use `isSanitizer` and `BarrierGuard` module instead.
*
* Holds if taint propagation through nodes guarded by `guard` is prohibited
* when the flow state is `state`.
*/
predicate isSanitizerGuard(DataFlow::BarrierGuard guard, DataFlow::FlowState state) { none() }
deprecated predicate isSanitizerGuard(DataFlow::BarrierGuard guard, DataFlow::FlowState state) {
none()
}
final override predicate isBarrierGuard(DataFlow::BarrierGuard guard, DataFlow::FlowState state) {
deprecated final override predicate isBarrierGuard(
DataFlow::BarrierGuard guard, DataFlow::FlowState state
) {
this.isSanitizerGuard(guard, state)
}

View File

@@ -116,20 +116,30 @@ abstract class Configuration extends DataFlow::Configuration {
final override predicate isBarrierOut(DataFlow::Node node) { this.isSanitizerOut(node) }
/** Holds if taint propagation through nodes guarded by `guard` is prohibited. */
predicate isSanitizerGuard(DataFlow::BarrierGuard guard) { none() }
/**
* DEPRECATED: Use `isSanitizer` and `BarrierGuard` module instead.
*
* Holds if taint propagation through nodes guarded by `guard` is prohibited.
*/
deprecated predicate isSanitizerGuard(DataFlow::BarrierGuard guard) { none() }
final override predicate isBarrierGuard(DataFlow::BarrierGuard guard) {
this.isSanitizerGuard(guard) or defaultTaintSanitizerGuard(guard)
deprecated final override predicate isBarrierGuard(DataFlow::BarrierGuard guard) {
this.isSanitizerGuard(guard)
}
/**
* DEPRECATED: Use `isSanitizer` and `BarrierGuard` module instead.
*
* Holds if taint propagation through nodes guarded by `guard` is prohibited
* when the flow state is `state`.
*/
predicate isSanitizerGuard(DataFlow::BarrierGuard guard, DataFlow::FlowState state) { none() }
deprecated predicate isSanitizerGuard(DataFlow::BarrierGuard guard, DataFlow::FlowState state) {
none()
}
final override predicate isBarrierGuard(DataFlow::BarrierGuard guard, DataFlow::FlowState state) {
deprecated final override predicate isBarrierGuard(
DataFlow::BarrierGuard guard, DataFlow::FlowState state
) {
this.isSanitizerGuard(guard, state)
}

View File

@@ -24,12 +24,14 @@ abstract class IntentUriPermissionManipulationSink extends DataFlow::Node { }
abstract class IntentUriPermissionManipulationSanitizer extends DataFlow::Node { }
/**
* DEPRECATED: Use `IntentUriPermissionManipulationSanitizer` instead.
*
* A guard that makes sure that an Intent is safe to be returned to another Activity.
*
* Usually, this is done by checking that the Intent's data URI and/or its flags contain
* expected values.
*/
abstract class IntentUriPermissionManipulationGuard extends DataFlow::BarrierGuard { }
abstract deprecated class IntentUriPermissionManipulationGuard extends DataFlow::BarrierGuard { }
/**
* An additional taint step for flows related to Intent URI permission manipulation
@@ -95,10 +97,10 @@ private class IntentFlagsOrDataChangedSanitizer extends IntentUriPermissionManip
* intent.getFlags() & Intent.FLAG_GRANT_WRITE_URI_PERMISSION != 0) {}
* ```
*/
private class IntentFlagsOrDataCheckedGuard extends IntentUriPermissionManipulationGuard {
IntentFlagsOrDataCheckedGuard() { intentFlagsOrDataChecked(this, _, _) }
override predicate checks(Expr e, boolean branch) { intentFlagsOrDataChecked(this, e, branch) }
private class IntentFlagsOrDataCheckedSanitizer extends IntentUriPermissionManipulationSanitizer {
IntentFlagsOrDataCheckedSanitizer() {
this = DataFlow::BarrierGuard<intentFlagsOrDataChecked/3>::getABarrierNode()
}
}
/**

View File

@@ -24,7 +24,7 @@ class IntentUriPermissionManipulationConf extends TaintTracking::Configuration {
barrier instanceof IntentUriPermissionManipulationSanitizer
}
override predicate isSanitizerGuard(DataFlow::BarrierGuard guard) {
deprecated override predicate isSanitizerGuard(DataFlow::BarrierGuard guard) {
guard instanceof IntentUriPermissionManipulationGuard
}

View File

@@ -30,10 +30,8 @@ class InjectFilePathConfig 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 PathTraversalBarrierGuard
or
node instanceof PathTraversalSanitizer
}
}

Some files were not shown because too many files have changed in this diff Show More