mirror of
https://github.com/github/codeql.git
synced 2025-12-20 10:46:30 +01:00
Java: Deprecate BarrierGuard class.
This commit is contained in:
@@ -90,14 +90,20 @@ abstract class Configuration extends string {
|
|||||||
/** Holds if data flow out of `node` is prohibited. */
|
/** Holds if data flow out of `node` is prohibited. */
|
||||||
predicate isBarrierOut(Node node) { none() }
|
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
|
* Holds if data flow through nodes guarded by `guard` is prohibited when
|
||||||
* the flow state is `state`
|
* 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.
|
* 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]
|
pragma[nomagic]
|
||||||
private predicate fullBarrier(NodeEx node, Configuration config) {
|
private predicate fullBarrier(NodeEx node, Configuration config) {
|
||||||
exists(Node n | node.asNode() = n |
|
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) and
|
||||||
not config.isSink(n, _)
|
not config.isSink(n, _)
|
||||||
or
|
or
|
||||||
exists(BarrierGuard g |
|
any(BarrierGuardGuardedNodeBridge b).guardedNode(n, config)
|
||||||
config.isBarrierGuard(g) and
|
|
||||||
n = g.getAGuardedNode()
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -360,10 +386,7 @@ private predicate stateBarrier(NodeEx node, FlowState state, Configuration confi
|
|||||||
exists(Node n | node.asNode() = n |
|
exists(Node n | node.asNode() = n |
|
||||||
config.isBarrier(n, state)
|
config.isBarrier(n, state)
|
||||||
or
|
or
|
||||||
exists(BarrierGuard g |
|
any(BarrierGuardGuardedNodeBridge b).guardedNode(n, state, config)
|
||||||
config.isBarrierGuard(g, state) and
|
|
||||||
n = g.getAGuardedNode()
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -332,6 +332,8 @@ module BarrierGuard<guardChecksSig/3 guardChecks> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* DEPRECATED: Use `BarrierGuard` module instead.
|
||||||
|
*
|
||||||
* A guard that validates some expression.
|
* A guard that validates some expression.
|
||||||
*
|
*
|
||||||
* To use this in a configuration, extend the class and provide a
|
* 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.
|
* 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`. */
|
/** Holds if this guard validates `e` upon evaluating to `branch`. */
|
||||||
abstract predicate checks(Expr e, boolean branch);
|
abstract predicate checks(Expr e, boolean branch);
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
import Cached
|
||||||
|
|
||||||
private RefType getElementType(RefType container) {
|
private RefType getElementType(RefType container) {
|
||||||
|
|||||||
@@ -116,20 +116,30 @@ abstract class Configuration extends DataFlow::Configuration {
|
|||||||
|
|
||||||
final override predicate isBarrierOut(DataFlow::Node node) { this.isSanitizerOut(node) }
|
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) {
|
deprecated final override predicate isBarrierGuard(DataFlow::BarrierGuard guard) {
|
||||||
this.isSanitizerGuard(guard) or defaultTaintSanitizerGuard(guard)
|
this.isSanitizerGuard(guard)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* DEPRECATED: Use `isSanitizer` and `BarrierGuard` module instead.
|
||||||
|
*
|
||||||
* Holds if taint propagation through nodes guarded by `guard` is prohibited
|
* Holds if taint propagation through nodes guarded by `guard` is prohibited
|
||||||
* when the flow state is `state`.
|
* 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)
|
this.isSanitizerGuard(guard, state)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -116,20 +116,30 @@ abstract class Configuration extends DataFlow::Configuration {
|
|||||||
|
|
||||||
final override predicate isBarrierOut(DataFlow::Node node) { this.isSanitizerOut(node) }
|
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) {
|
deprecated final override predicate isBarrierGuard(DataFlow::BarrierGuard guard) {
|
||||||
this.isSanitizerGuard(guard) or defaultTaintSanitizerGuard(guard)
|
this.isSanitizerGuard(guard)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* DEPRECATED: Use `isSanitizer` and `BarrierGuard` module instead.
|
||||||
|
*
|
||||||
* Holds if taint propagation through nodes guarded by `guard` is prohibited
|
* Holds if taint propagation through nodes guarded by `guard` is prohibited
|
||||||
* when the flow state is `state`.
|
* 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)
|
this.isSanitizerGuard(guard, state)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -116,20 +116,30 @@ abstract class Configuration extends DataFlow::Configuration {
|
|||||||
|
|
||||||
final override predicate isBarrierOut(DataFlow::Node node) { this.isSanitizerOut(node) }
|
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) {
|
deprecated final override predicate isBarrierGuard(DataFlow::BarrierGuard guard) {
|
||||||
this.isSanitizerGuard(guard) or defaultTaintSanitizerGuard(guard)
|
this.isSanitizerGuard(guard)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* DEPRECATED: Use `isSanitizer` and `BarrierGuard` module instead.
|
||||||
|
*
|
||||||
* Holds if taint propagation through nodes guarded by `guard` is prohibited
|
* Holds if taint propagation through nodes guarded by `guard` is prohibited
|
||||||
* when the flow state is `state`.
|
* 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)
|
this.isSanitizerGuard(guard, state)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -24,12 +24,14 @@ abstract class IntentUriPermissionManipulationSink extends DataFlow::Node { }
|
|||||||
abstract class IntentUriPermissionManipulationSanitizer 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.
|
* 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
|
* Usually, this is done by checking that the Intent's data URI and/or its flags contain
|
||||||
* expected values.
|
* 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
|
* 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) {}
|
* intent.getFlags() & Intent.FLAG_GRANT_WRITE_URI_PERMISSION != 0) {}
|
||||||
* ```
|
* ```
|
||||||
*/
|
*/
|
||||||
private class IntentFlagsOrDataCheckedGuard extends IntentUriPermissionManipulationGuard {
|
private class IntentFlagsOrDataCheckedSanitizer extends IntentUriPermissionManipulationSanitizer {
|
||||||
IntentFlagsOrDataCheckedGuard() { intentFlagsOrDataChecked(this, _, _) }
|
IntentFlagsOrDataCheckedSanitizer() {
|
||||||
|
this = DataFlow::BarrierGuard<intentFlagsOrDataChecked/3>::getABarrierNode()
|
||||||
override predicate checks(Expr e, boolean branch) { intentFlagsOrDataChecked(this, e, branch) }
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ class IntentUriPermissionManipulationConf extends TaintTracking::Configuration {
|
|||||||
barrier instanceof IntentUriPermissionManipulationSanitizer
|
barrier instanceof IntentUriPermissionManipulationSanitizer
|
||||||
}
|
}
|
||||||
|
|
||||||
override predicate isSanitizerGuard(DataFlow::BarrierGuard guard) {
|
deprecated override predicate isSanitizerGuard(DataFlow::BarrierGuard guard) {
|
||||||
guard instanceof IntentUriPermissionManipulationGuard
|
guard instanceof IntentUriPermissionManipulationGuard
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -30,10 +30,8 @@ class InjectFilePathConfig extends TaintTracking::Configuration {
|
|||||||
|
|
||||||
override predicate isSanitizer(DataFlow::Node node) {
|
override predicate isSanitizer(DataFlow::Node node) {
|
||||||
exists(Type t | t = node.getType() | t instanceof BoxedType or t instanceof PrimitiveType)
|
exists(Type t | t = node.getType() | t instanceof BoxedType or t instanceof PrimitiveType)
|
||||||
}
|
or
|
||||||
|
node instanceof PathTraversalSanitizer
|
||||||
override predicate isSanitizerGuard(DataFlow::BarrierGuard guard) {
|
|
||||||
guard instanceof PathTraversalBarrierGuard
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -24,9 +24,7 @@ class InsecureWebResourceResponseConfig extends TaintTracking::Configuration {
|
|||||||
|
|
||||||
override predicate isSink(DataFlow::Node sink) { sink instanceof WebResourceResponseSink }
|
override predicate isSink(DataFlow::Node sink) { sink instanceof WebResourceResponseSink }
|
||||||
|
|
||||||
override predicate isSanitizerGuard(DataFlow::BarrierGuard guard) {
|
override predicate isSanitizer(DataFlow::Node node) { node instanceof PathTraversalSanitizer }
|
||||||
guard instanceof PathTraversalBarrierGuard
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
from DataFlow::PathNode source, DataFlow::PathNode sink, InsecureWebResourceResponseConfig conf
|
from DataFlow::PathNode source, DataFlow::PathNode sink, InsecureWebResourceResponseConfig conf
|
||||||
|
|||||||
@@ -15,17 +15,13 @@ import AndroidFileIntentSink
|
|||||||
import AndroidFileIntentSource
|
import AndroidFileIntentSource
|
||||||
import DataFlow::PathGraph
|
import DataFlow::PathGraph
|
||||||
|
|
||||||
private class StartsWithSanitizer extends DataFlow::BarrierGuard {
|
private predicate startsWithSanitizer(Guard g, Expr e, boolean branch) {
|
||||||
StartsWithSanitizer() { this.(MethodAccess).getMethod().hasName("startsWith") }
|
exists(MethodAccess ma |
|
||||||
|
g = ma and
|
||||||
override predicate checks(Expr e, boolean branch) {
|
ma.getMethod().hasName("startsWith") and
|
||||||
e =
|
e = [ma.getQualifier(), ma.getQualifier().(MethodAccess).getQualifier()] and
|
||||||
[
|
|
||||||
this.(MethodAccess).getQualifier(),
|
|
||||||
this.(MethodAccess).getQualifier().(MethodAccess).getQualifier()
|
|
||||||
] and
|
|
||||||
branch = false
|
branch = false
|
||||||
}
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
class AndroidFileLeakConfig extends TaintTracking::Configuration {
|
class AndroidFileLeakConfig extends TaintTracking::Configuration {
|
||||||
@@ -75,8 +71,8 @@ class AndroidFileLeakConfig extends TaintTracking::Configuration {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
override predicate isSanitizerGuard(DataFlow::BarrierGuard guard) {
|
override predicate isSanitizer(DataFlow::Node node) {
|
||||||
guard instanceof StartsWithSanitizer
|
node = DataFlow::BarrierGuard<startsWithSanitizer/3>::getABarrierNode()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -59,10 +59,8 @@ class ThreadResourceAbuse extends TaintTracking::Configuration {
|
|||||||
ma.getMethod().hasQualifiedName("java.lang", "Math", "min") and
|
ma.getMethod().hasQualifiedName("java.lang", "Math", "min") and
|
||||||
node.asExpr() = ma.getAnArgument()
|
node.asExpr() = ma.getAnArgument()
|
||||||
)
|
)
|
||||||
}
|
or
|
||||||
|
node instanceof LessThanSanitizer // if (sleepTime > 0 && sleepTime < 5000) { ... }
|
||||||
override predicate isSanitizerGuard(DataFlow::BarrierGuard guard) {
|
|
||||||
guard instanceof LessThanSanitizer // if (sleepTime > 0 && sleepTime < 5000) { ... }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -33,10 +33,8 @@ class ThreadResourceAbuse extends TaintTracking::Configuration {
|
|||||||
ma.getMethod().hasQualifiedName("java.lang", "Math", "min") and
|
ma.getMethod().hasQualifiedName("java.lang", "Math", "min") and
|
||||||
node.asExpr() = ma.getAnArgument()
|
node.asExpr() = ma.getAnArgument()
|
||||||
)
|
)
|
||||||
}
|
or
|
||||||
|
node instanceof LessThanSanitizer // if (sleepTime > 0 && sleepTime < 5000) { ... }
|
||||||
override predicate isSanitizerGuard(DataFlow::BarrierGuard guard) {
|
|
||||||
guard instanceof LessThanSanitizer // if (sleepTime > 0 && sleepTime < 5000) { ... }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import java
|
|||||||
import semmle.code.java.dataflow.DataFlow
|
import semmle.code.java.dataflow.DataFlow
|
||||||
private import semmle.code.java.dataflow.ExternalFlow
|
private import semmle.code.java.dataflow.ExternalFlow
|
||||||
import semmle.code.java.dataflow.FlowSteps
|
import semmle.code.java.dataflow.FlowSteps
|
||||||
|
import semmle.code.java.controlflow.Guards
|
||||||
|
|
||||||
/** `java.lang.Math` data model for value comparison in the new CSV format. */
|
/** `java.lang.Math` data model for value comparison in the new CSV format. */
|
||||||
private class MathCompDataModel extends SummaryModelCsv {
|
private class MathCompDataModel extends SummaryModelCsv {
|
||||||
@@ -32,15 +33,17 @@ class PauseThreadSink extends DataFlow::Node {
|
|||||||
PauseThreadSink() { sinkNode(this, "thread-pause") }
|
PauseThreadSink() { sinkNode(this, "thread-pause") }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private predicate lessThanGuard(Guard g, Expr e, boolean branch) {
|
||||||
|
e = g.(ComparisonExpr).getLesserOperand() and
|
||||||
|
branch = true
|
||||||
|
or
|
||||||
|
e = g.(ComparisonExpr).getGreaterOperand() and
|
||||||
|
branch = false
|
||||||
|
}
|
||||||
|
|
||||||
/** A sanitizer for lessThan check. */
|
/** A sanitizer for lessThan check. */
|
||||||
class LessThanSanitizer extends DataFlow::BarrierGuard instanceof ComparisonExpr {
|
class LessThanSanitizer extends DataFlow::Node {
|
||||||
override predicate checks(Expr e, boolean branch) {
|
LessThanSanitizer() { this = DataFlow::BarrierGuard<lessThanGuard/3>::getABarrierNode() }
|
||||||
e = super.getLesserOperand() and
|
|
||||||
branch = true
|
|
||||||
or
|
|
||||||
e = super.getGreaterOperand() and
|
|
||||||
branch = false
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Value step from the constructor call of a `Runnable` to the instance parameter (this) of `run`. */
|
/** Value step from the constructor call of a `Runnable` to the instance parameter (this) of `run`. */
|
||||||
|
|||||||
@@ -15,23 +15,19 @@ import DataFlow
|
|||||||
import UnsafeReflectionLib
|
import UnsafeReflectionLib
|
||||||
import semmle.code.java.dataflow.DataFlow
|
import semmle.code.java.dataflow.DataFlow
|
||||||
import semmle.code.java.dataflow.FlowSources
|
import semmle.code.java.dataflow.FlowSources
|
||||||
|
import semmle.code.java.controlflow.Guards
|
||||||
import DataFlow::PathGraph
|
import DataFlow::PathGraph
|
||||||
|
|
||||||
private class ContainsSanitizer extends DataFlow::BarrierGuard {
|
private predicate containsSanitizer(Guard g, Expr e, boolean branch) {
|
||||||
ContainsSanitizer() { this.(MethodAccess).getMethod().hasName("contains") }
|
g.(MethodAccess).getMethod().hasName("contains") and
|
||||||
|
e = g.(MethodAccess).getArgument(0) and
|
||||||
override predicate checks(Expr e, boolean branch) {
|
branch = true
|
||||||
e = this.(MethodAccess).getArgument(0) and branch = true
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private class EqualsSanitizer extends DataFlow::BarrierGuard {
|
private predicate equalsSanitizer(Guard g, Expr e, boolean branch) {
|
||||||
EqualsSanitizer() { this.(MethodAccess).getMethod().hasName("equals") }
|
g.(MethodAccess).getMethod().hasName("equals") and
|
||||||
|
e = [g.(MethodAccess).getArgument(0), g.(MethodAccess).getQualifier()] and
|
||||||
override predicate checks(Expr e, boolean branch) {
|
branch = true
|
||||||
e = [this.(MethodAccess).getArgument(0), this.(MethodAccess).getQualifier()] and
|
|
||||||
branch = true
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class UnsafeReflectionConfig extends TaintTracking::Configuration {
|
class UnsafeReflectionConfig extends TaintTracking::Configuration {
|
||||||
@@ -78,8 +74,9 @@ class UnsafeReflectionConfig extends TaintTracking::Configuration {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
override predicate isSanitizerGuard(DataFlow::BarrierGuard guard) {
|
override predicate isSanitizer(DataFlow::Node node) {
|
||||||
guard instanceof ContainsSanitizer or guard instanceof EqualsSanitizer
|
node = DataFlow::BarrierGuard<containsSanitizer/3>::getABarrierNode() or
|
||||||
|
node = DataFlow::BarrierGuard<equalsSanitizer/3>::getABarrierNode()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -35,10 +35,9 @@ class UnsafeUrlForwardFlowConfig extends TaintTracking::Configuration {
|
|||||||
|
|
||||||
override predicate isSink(DataFlow::Node sink) { sink instanceof UnsafeUrlForwardSink }
|
override predicate isSink(DataFlow::Node sink) { sink instanceof UnsafeUrlForwardSink }
|
||||||
|
|
||||||
override predicate isSanitizer(DataFlow::Node node) { node instanceof UnsafeUrlForwardSanitizer }
|
override predicate isSanitizer(DataFlow::Node node) {
|
||||||
|
node instanceof UnsafeUrlForwardSanitizer or
|
||||||
override predicate isSanitizerGuard(DataFlow::BarrierGuard guard) {
|
node instanceof PathTraversalSanitizer
|
||||||
guard instanceof PathTraversalBarrierGuard
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override DataFlow::FlowFeature getAFeature() {
|
override DataFlow::FlowFeature getAFeature() {
|
||||||
|
|||||||
@@ -13,18 +13,15 @@
|
|||||||
import java
|
import java
|
||||||
import SpringUrlRedirect
|
import SpringUrlRedirect
|
||||||
import semmle.code.java.dataflow.FlowSources
|
import semmle.code.java.dataflow.FlowSources
|
||||||
|
import semmle.code.java.controlflow.Guards
|
||||||
import DataFlow::PathGraph
|
import DataFlow::PathGraph
|
||||||
|
|
||||||
private class StartsWithSanitizer extends DataFlow::BarrierGuard {
|
private predicate startsWithSanitizer(Guard g, Expr e, boolean branch) {
|
||||||
StartsWithSanitizer() {
|
g.(MethodAccess).getMethod().hasName("startsWith") and
|
||||||
this.(MethodAccess).getMethod().hasName("startsWith") and
|
g.(MethodAccess).getMethod().getDeclaringType() instanceof TypeString and
|
||||||
this.(MethodAccess).getMethod().getDeclaringType() instanceof TypeString and
|
g.(MethodAccess).getMethod().getNumberOfParameters() = 1 and
|
||||||
this.(MethodAccess).getMethod().getNumberOfParameters() = 1
|
e = g.(MethodAccess).getQualifier() and
|
||||||
}
|
branch = true
|
||||||
|
|
||||||
override predicate checks(Expr e, boolean branch) {
|
|
||||||
e = this.(MethodAccess).getQualifier() and branch = true
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class SpringUrlRedirectFlowConfig extends TaintTracking::Configuration {
|
class SpringUrlRedirectFlowConfig extends TaintTracking::Configuration {
|
||||||
@@ -38,10 +35,6 @@ class SpringUrlRedirectFlowConfig extends TaintTracking::Configuration {
|
|||||||
springUrlRedirectTaintStep(fromNode, toNode)
|
springUrlRedirectTaintStep(fromNode, toNode)
|
||||||
}
|
}
|
||||||
|
|
||||||
override predicate isSanitizerGuard(DataFlow::BarrierGuard guard) {
|
|
||||||
guard instanceof StartsWithSanitizer
|
|
||||||
}
|
|
||||||
|
|
||||||
override predicate isSanitizer(DataFlow::Node node) {
|
override predicate isSanitizer(DataFlow::Node node) {
|
||||||
// Exclude the case where the left side of the concatenated string is not `redirect:`.
|
// Exclude the case where the left side of the concatenated string is not `redirect:`.
|
||||||
// E.g: `String url = "/path?token=" + request.getParameter("token");`
|
// E.g: `String url = "/path?token=" + request.getParameter("token");`
|
||||||
@@ -63,6 +56,8 @@ class SpringUrlRedirectFlowConfig extends TaintTracking::Configuration {
|
|||||||
)
|
)
|
||||||
or
|
or
|
||||||
nonLocationHeaderSanitizer(node)
|
nonLocationHeaderSanitizer(node)
|
||||||
|
or
|
||||||
|
node = DataFlow::BarrierGuard<startsWithSanitizer/3>::getABarrierNode()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,21 +3,32 @@ private import semmle.code.java.controlflow.Guards
|
|||||||
private import semmle.code.java.dataflow.FlowSources
|
private import semmle.code.java.dataflow.FlowSources
|
||||||
private import semmle.code.java.dataflow.ExternalFlow
|
private import semmle.code.java.dataflow.ExternalFlow
|
||||||
|
|
||||||
/** A barrier guard that protects against path traversal vulnerabilities. */
|
/**
|
||||||
abstract class PathTraversalBarrierGuard extends DataFlow::BarrierGuard { }
|
* DEPRECATED: Use `PathTraversalSanitizer` instead.
|
||||||
|
*
|
||||||
|
* A barrier guard that protects against path traversal vulnerabilities.
|
||||||
|
*/
|
||||||
|
abstract deprecated class PathTraversalBarrierGuard extends DataFlow::BarrierGuard { }
|
||||||
|
|
||||||
|
/** A sanitizer that protects against path traversal vulnerabilities. */
|
||||||
|
abstract class PathTraversalSanitizer extends DataFlow::Node { }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A guard that considers safe a string being exactly compared to a trusted value.
|
* Holds if `g` is guard that compares a string to a trusted value.
|
||||||
*/
|
*/
|
||||||
private class ExactStringPathMatchGuard extends PathTraversalBarrierGuard instanceof MethodAccess {
|
private predicate exactStringPathMatchGuard(Guard g, Expr e, boolean branch) {
|
||||||
ExactStringPathMatchGuard() {
|
exists(MethodAccess ma |
|
||||||
super.getMethod().getDeclaringType() instanceof TypeString and
|
ma = g and
|
||||||
super.getMethod().getName() = ["equals", "equalsIgnoreCase"]
|
ma.getMethod().getDeclaringType() instanceof TypeString and
|
||||||
}
|
ma.getMethod().getName() = ["equals", "equalsIgnoreCase"] and
|
||||||
|
e = ma.getQualifier() and
|
||||||
override predicate checks(Expr e, boolean branch) {
|
|
||||||
e = super.getQualifier() and
|
|
||||||
branch = true
|
branch = true
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private class ExactStringPathMatchSanitizer extends PathTraversalSanitizer {
|
||||||
|
ExactStringPathMatchSanitizer() {
|
||||||
|
this = DataFlow::BarrierGuard<exactStringPathMatchGuard/3>::getABarrierNode()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -42,41 +53,45 @@ private class AllowListGuard extends Guard instanceof MethodAccess {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A guard that considers a path safe because it is checked against an allowlist of partial trusted values.
|
* Holds if `g` is a guard that considers a path safe because it is checked against an allowlist of partial trusted values.
|
||||||
* This requires additional protection against path traversal, either another guard (`PathTraversalGuard`)
|
* This requires additional protection against path traversal, either another guard (`PathTraversalGuard`)
|
||||||
* or a sanitizer (`PathNormalizeSanitizer`), to ensure any internal `..` components are removed from the path.
|
* or a sanitizer (`PathNormalizeSanitizer`), to ensure any internal `..` components are removed from the path.
|
||||||
*/
|
*/
|
||||||
private class AllowListBarrierGuard extends PathTraversalBarrierGuard instanceof AllowListGuard {
|
private predicate allowListGuard(Guard g, Expr e, boolean branch) {
|
||||||
override predicate checks(Expr e, boolean branch) {
|
e = g.(AllowListGuard).getCheckedExpr() and
|
||||||
e = super.getCheckedExpr() and
|
branch = true and
|
||||||
branch = true and
|
(
|
||||||
(
|
// Either a path normalization sanitizer comes before the guard,
|
||||||
// Either a path normalization sanitizer comes before the guard,
|
exists(PathNormalizeSanitizer sanitizer | DataFlow::localExprFlow(sanitizer, e))
|
||||||
exists(PathNormalizeSanitizer sanitizer | DataFlow::localExprFlow(sanitizer, e))
|
or
|
||||||
or
|
// or a check like `!path.contains("..")` comes before the guard
|
||||||
// or a check like `!path.contains("..")` comes before the guard
|
exists(PathTraversalGuard previousGuard |
|
||||||
exists(PathTraversalGuard previousGuard |
|
DataFlow::localExprFlow(previousGuard.getCheckedExpr(), e) and
|
||||||
DataFlow::localExprFlow(previousGuard.getCheckedExpr(), e) and
|
previousGuard.controls(g.getBasicBlock().(ConditionBlock), false)
|
||||||
previousGuard.controls(this.getBasicBlock().(ConditionBlock), false)
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
}
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private class AllowListSanitizer extends PathTraversalSanitizer {
|
||||||
|
AllowListSanitizer() { this = DataFlow::BarrierGuard<allowListGuard/3>::getABarrierNode() }
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A guard that considers a path safe because it is checked for `..` components, having previously
|
* Holds if `g` is a guard that considers a path safe because it is checked for `..` components, having previously
|
||||||
* been checked for a trusted prefix.
|
* been checked for a trusted prefix.
|
||||||
*/
|
*/
|
||||||
private class DotDotCheckBarrierGuard extends PathTraversalBarrierGuard instanceof PathTraversalGuard {
|
private predicate dotDotCheckGuard(Guard g, Expr e, boolean branch) {
|
||||||
override predicate checks(Expr e, boolean branch) {
|
e = g.(PathTraversalGuard).getCheckedExpr() and
|
||||||
e = super.getCheckedExpr() and
|
branch = false and
|
||||||
branch = false and
|
// The same value has previously been checked against a list of allowed prefixes:
|
||||||
// The same value has previously been checked against a list of allowed prefixes:
|
exists(AllowListGuard previousGuard |
|
||||||
exists(AllowListGuard previousGuard |
|
DataFlow::localExprFlow(previousGuard.getCheckedExpr(), e) and
|
||||||
DataFlow::localExprFlow(previousGuard.getCheckedExpr(), e) and
|
previousGuard.controls(g.getBasicBlock().(ConditionBlock), true)
|
||||||
previousGuard.controls(this.getBasicBlock().(ConditionBlock), true)
|
)
|
||||||
)
|
}
|
||||||
}
|
|
||||||
|
private class DotDotCheckSanitizer extends PathTraversalSanitizer {
|
||||||
|
DotDotCheckSanitizer() { this = DataFlow::BarrierGuard<dotDotCheckGuard/3>::getABarrierNode() }
|
||||||
}
|
}
|
||||||
|
|
||||||
private class BlockListGuard extends Guard instanceof MethodAccess {
|
private class BlockListGuard extends Guard instanceof MethodAccess {
|
||||||
@@ -89,40 +104,44 @@ private class BlockListGuard extends Guard instanceof MethodAccess {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A guard that considers a string safe because it is checked against a blocklist of known dangerous values.
|
* Holds if `g` is a guard that considers a string safe because it is checked against a blocklist of known dangerous values.
|
||||||
* This requires a prior check for URL encoding concealing a forbidden value, either a guard (`UrlEncodingGuard`)
|
* This requires a prior check for URL encoding concealing a forbidden value, either a guard (`UrlEncodingGuard`)
|
||||||
* or a sanitizer (`UrlDecodeSanitizer`).
|
* or a sanitizer (`UrlDecodeSanitizer`).
|
||||||
*/
|
*/
|
||||||
private class BlockListBarrierGuard extends PathTraversalBarrierGuard instanceof BlockListGuard {
|
private predicate blockListGuard(Guard g, Expr e, boolean branch) {
|
||||||
override predicate checks(Expr e, boolean branch) {
|
e = g.(BlockListGuard).getCheckedExpr() and
|
||||||
e = super.getCheckedExpr() and
|
branch = false and
|
||||||
branch = false and
|
(
|
||||||
(
|
// Either `e` has been URL decoded:
|
||||||
// Either `e` has been URL decoded:
|
exists(UrlDecodeSanitizer sanitizer | DataFlow::localExprFlow(sanitizer, e))
|
||||||
exists(UrlDecodeSanitizer sanitizer | DataFlow::localExprFlow(sanitizer, e))
|
or
|
||||||
or
|
// or `e` has previously been checked for URL encoding sequences:
|
||||||
// or `e` has previously been checked for URL encoding sequences:
|
exists(UrlEncodingGuard previousGuard |
|
||||||
exists(UrlEncodingGuard previousGuard |
|
DataFlow::localExprFlow(previousGuard.getCheckedExpr(), e) and
|
||||||
DataFlow::localExprFlow(previousGuard.getCheckedExpr(), e) and
|
previousGuard.controls(g.getBasicBlock(), false)
|
||||||
previousGuard.controls(this.getBasicBlock(), false)
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
}
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private class BlockListSanitizer extends PathTraversalSanitizer {
|
||||||
|
BlockListSanitizer() { this = DataFlow::BarrierGuard<blockListGuard/3>::getABarrierNode() }
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A guard that considers a string safe because it is checked for URL encoding sequences,
|
* Holds if `g` is a guard that considers a string safe because it is checked for URL encoding sequences,
|
||||||
* having previously been checked against a block-list of forbidden values.
|
* having previously been checked against a block-list of forbidden values.
|
||||||
*/
|
*/
|
||||||
private class UrlEncodingBarrierGuard extends PathTraversalBarrierGuard instanceof UrlEncodingGuard {
|
private predicate urlEncodingGuard(Guard g, Expr e, boolean branch) {
|
||||||
override predicate checks(Expr e, boolean branch) {
|
e = g.(UrlEncodingGuard).getCheckedExpr() and
|
||||||
e = super.getCheckedExpr() and
|
branch = false and
|
||||||
branch = false and
|
exists(BlockListGuard previousGuard |
|
||||||
exists(BlockListGuard previousGuard |
|
DataFlow::localExprFlow(previousGuard.getCheckedExpr(), e) and
|
||||||
DataFlow::localExprFlow(previousGuard.getCheckedExpr(), e) and
|
previousGuard.controls(g.getBasicBlock(), false)
|
||||||
previousGuard.controls(this.getBasicBlock(), false)
|
)
|
||||||
)
|
}
|
||||||
}
|
|
||||||
|
private class UrlEncodingSanitizer extends PathTraversalSanitizer {
|
||||||
|
UrlEncodingSanitizer() { this = DataFlow::BarrierGuard<urlEncodingGuard/3>::getABarrierNode() }
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
Reference in New Issue
Block a user