mirror of
https://github.com/github/codeql.git
synced 2026-04-26 09:15:12 +02:00
JS: Port ConditionalBypass
This commit is contained in:
@@ -13,7 +13,28 @@ import ConditionalBypassCustomizations::ConditionalBypass
|
||||
/**
|
||||
* A taint tracking configuration for bypass of sensitive action guards.
|
||||
*/
|
||||
class Configuration extends TaintTracking::Configuration {
|
||||
module ConditionalBypassConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) { source instanceof Source }
|
||||
|
||||
predicate isSink(DataFlow::Node sink) { sink instanceof Sink }
|
||||
|
||||
predicate isBarrier(DataFlow::Node node) { node instanceof Sanitizer }
|
||||
|
||||
predicate isAdditionalFlowStep(DataFlow::Node src, DataFlow::Node dst) {
|
||||
// comparing a tainted expression against a constant gives a tainted result
|
||||
dst.asExpr().(Comparison).hasOperands(src.asExpr(), any(ConstantExpr c))
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Taint tracking flow for bypass of sensitive action guards.
|
||||
*/
|
||||
module ConditionalBypassFlow = TaintTracking::Global<ConditionalBypassConfig>;
|
||||
|
||||
/**
|
||||
* DEPRECATED. Use the `ConditionalBypassFlow` module instead.
|
||||
*/
|
||||
deprecated class Configuration extends TaintTracking::Configuration {
|
||||
Configuration() { this = "ConditionalBypass" }
|
||||
|
||||
override predicate isSource(DataFlow::Node source) { source instanceof Source }
|
||||
@@ -26,8 +47,7 @@ class Configuration extends TaintTracking::Configuration {
|
||||
}
|
||||
|
||||
override predicate isAdditionalTaintStep(DataFlow::Node src, DataFlow::Node dst) {
|
||||
// comparing a tainted expression against a constant gives a tainted result
|
||||
dst.asExpr().(Comparison).hasOperands(src.asExpr(), any(ConstantExpr c))
|
||||
ConditionalBypassConfig::isAdditionalFlowStep(src, dst)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -72,7 +92,67 @@ class SensitiveActionGuardComparisonOperand extends Sink {
|
||||
* If flow from `source` taints `sink`, then an attacker can
|
||||
* control if `action` should be executed or not.
|
||||
*/
|
||||
predicate isTaintedGuardForSensitiveAction(
|
||||
predicate isTaintedGuardNodeForSensitiveAction(
|
||||
ConditionalBypassFlow::PathNode sink, ConditionalBypassFlow::PathNode source,
|
||||
SensitiveAction action
|
||||
) {
|
||||
action = sink.getNode().(Sink).getAction() and
|
||||
// exclude the intermediary sink
|
||||
not sink.getNode() instanceof SensitiveActionGuardComparisonOperand and
|
||||
(
|
||||
// ordinary taint tracking to a guard
|
||||
ConditionalBypassFlow::flowPath(source, sink)
|
||||
or
|
||||
// taint tracking to both operands of a guard comparison
|
||||
exists(
|
||||
SensitiveActionGuardComparison cmp, ConditionalBypassFlow::PathNode lSource,
|
||||
ConditionalBypassFlow::PathNode rSource, ConditionalBypassFlow::PathNode lSink,
|
||||
ConditionalBypassFlow::PathNode rSink
|
||||
|
|
||||
sink.getNode() = cmp.getGuard() and
|
||||
ConditionalBypassFlow::flowPath(lSource, lSink) and
|
||||
lSink.getNode() = DataFlow::valueNode(cmp.getLeftOperand()) and
|
||||
ConditionalBypassFlow::flowPath(rSource, rSink) and
|
||||
rSink.getNode() = DataFlow::valueNode(cmp.getRightOperand())
|
||||
|
|
||||
source = lSource or
|
||||
source = rSource
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `e` effectively guards access to `action` by returning or throwing early.
|
||||
*
|
||||
* Example: `if (e) return; action(x)`.
|
||||
*/
|
||||
predicate isEarlyAbortGuardNode(ConditionalBypassFlow::PathNode e, SensitiveAction action) {
|
||||
exists(IfStmt guard |
|
||||
// `e` is in the condition of an if-statement ...
|
||||
e.getNode().(Sink).asExpr().getParentExpr*() = guard.getCondition() and
|
||||
// ... where the then-branch always throws or returns
|
||||
exists(Stmt abort |
|
||||
abort instanceof ThrowStmt or
|
||||
abort instanceof ReturnStmt
|
||||
|
|
||||
abort.nestedIn(guard) and
|
||||
abort.getBasicBlock().(ReachableBasicBlock).postDominates(guard.getThen().getBasicBlock())
|
||||
) and
|
||||
// ... and the else-branch does not exist
|
||||
not exists(guard.getElse())
|
||||
|
|
||||
// ... and `action` is outside the if-statement
|
||||
not action.asExpr().getEnclosingStmt().nestedIn(guard)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `sink` guards `action`, and `source` taints `sink`.
|
||||
*
|
||||
* If flow from `source` taints `sink`, then an attacker can
|
||||
* control if `action` should be executed or not.
|
||||
*/
|
||||
deprecated predicate isTaintedGuardForSensitiveAction(
|
||||
DataFlow::PathNode sink, DataFlow::PathNode source, SensitiveAction action
|
||||
) {
|
||||
action = sink.getNode().(Sink).getAction() and
|
||||
@@ -104,7 +184,7 @@ predicate isTaintedGuardForSensitiveAction(
|
||||
*
|
||||
* Example: `if (e) return; action(x)`.
|
||||
*/
|
||||
predicate isEarlyAbortGuard(DataFlow::PathNode e, SensitiveAction action) {
|
||||
deprecated predicate isEarlyAbortGuard(DataFlow::PathNode e, SensitiveAction action) {
|
||||
exists(IfStmt guard |
|
||||
// `e` is in the condition of an if-statement ...
|
||||
e.getNode().(Sink).asExpr().getParentExpr*() = guard.getCondition() and
|
||||
|
||||
Reference in New Issue
Block a user