mirror of
https://github.com/github/codeql.git
synced 2026-04-26 17:25:19 +02:00
JS: Migrate TaintedObject to a CommonFlowState
This commit is contained in:
@@ -4,11 +4,13 @@
|
||||
|
||||
private import javascript
|
||||
private import TaintedUrlSuffixCustomizations
|
||||
private import TaintedObjectCustomizations
|
||||
|
||||
private newtype TFlowState =
|
||||
TTaint() or
|
||||
TTaintedUrlSuffix() or
|
||||
TTaintedPrefix()
|
||||
TTaintedPrefix() or
|
||||
TTaintedObject()
|
||||
|
||||
/**
|
||||
* A flow state indicating which part of a value is tainted.
|
||||
@@ -30,6 +32,12 @@ class FlowState extends TFlowState {
|
||||
*/
|
||||
predicate isTaintedPrefix() { this = TTaintedPrefix() }
|
||||
|
||||
/**
|
||||
* Holds if this represents a deeply tainted object, such as a JSON object
|
||||
* parsed from user-controlled data.
|
||||
*/
|
||||
predicate isTaintedObject() { this = TTaintedObject() }
|
||||
|
||||
/** Gets a string representation of this flow state. */
|
||||
string toString() {
|
||||
this.isTaint() and result = "taint"
|
||||
@@ -37,6 +45,8 @@ class FlowState extends TFlowState {
|
||||
this.isTaintedUrlSuffix() and result = "tainted-url-suffix"
|
||||
or
|
||||
this.isTaintedPrefix() and result = "tainted-prefix"
|
||||
or
|
||||
this.isTaintedObject() and result = "tainted-object"
|
||||
}
|
||||
|
||||
/** DEPRECATED. Gets the corresponding flow label. */
|
||||
@@ -46,6 +56,8 @@ class FlowState extends TFlowState {
|
||||
this.isTaintedUrlSuffix() and result = TaintedUrlSuffix::label()
|
||||
or
|
||||
this.isTaintedPrefix() and result = "PrefixString"
|
||||
or
|
||||
this.isTaintedObject() and result = TaintedObject::label()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -67,6 +79,12 @@ module FlowState {
|
||||
*/
|
||||
FlowState taintedPrefix() { result.isTaintedPrefix() }
|
||||
|
||||
/**
|
||||
* Gets the flow state representing a deeply tainted object, such as a JSON object
|
||||
* parsed from user-controlled data.
|
||||
*/
|
||||
FlowState taintedObject() { result.isTaintedObject() }
|
||||
|
||||
/** DEPRECATED. Gets the flow state corresponding to `label`. */
|
||||
deprecated FlowState fromFlowLabel(DataFlow::FlowLabel label) { result.toFlowLabel() = label }
|
||||
}
|
||||
|
||||
@@ -7,10 +7,10 @@
|
||||
*
|
||||
* To track deeply tainted objects, a flow-tracking configuration should generally include the following:
|
||||
*
|
||||
* 1. One or more sinks associated with the label `TaintedObject::label()`.
|
||||
* 2. The sources from `TaintedObject::isSource`.
|
||||
* 3. The flow steps from `TaintedObject::step`.
|
||||
* 4. The sanitizing guards `TaintedObject::SanitizerGuard`.
|
||||
* 1. One or more sinks associated with the flow state `FlowState::taintedObject()`.
|
||||
* 2. The sources from `TaintedObject::Source`.
|
||||
* 3. The flow steps from `TaintedObject::isAdditionalFlowStep`.
|
||||
* 4. The barriers from `TaintedObject::SanitizerGuard::getABarrierNode(state)`.
|
||||
*/
|
||||
|
||||
import javascript
|
||||
@@ -22,35 +22,39 @@ module TaintedObject {
|
||||
import TaintedObjectCustomizations::TaintedObject
|
||||
|
||||
// Materialize flow labels
|
||||
private class ConcreteTaintedObjectLabel extends TaintedObjectLabel {
|
||||
deprecated private class ConcreteTaintedObjectLabel extends TaintedObjectLabel {
|
||||
ConcreteTaintedObjectLabel() { this = this }
|
||||
}
|
||||
|
||||
deprecated predicate step(Node src, Node trg, FlowLabel inlbl, FlowLabel outlbl) {
|
||||
isAdditionalFlowStep(src, FlowState::fromFlowLabel(inlbl), trg, FlowState::fromFlowLabel(outlbl))
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds for the flows steps that are relevant for tracking user-controlled JSON objects.
|
||||
*/
|
||||
predicate step(Node src, Node trg, FlowLabel inlbl, FlowLabel outlbl) {
|
||||
predicate isAdditionalFlowStep(Node src, FlowState inlbl, Node trg, FlowState outlbl) {
|
||||
// JSON parsers map tainted inputs to tainted JSON
|
||||
inlbl.isDataOrTaint() and
|
||||
outlbl = label() and
|
||||
inlbl.isTaint() and
|
||||
outlbl.isTaintedObject() and
|
||||
exists(JsonParserCall parse |
|
||||
src = parse.getInput() and
|
||||
trg = parse.getOutput()
|
||||
)
|
||||
or
|
||||
// Property reads preserve deep object taint.
|
||||
inlbl = label() and
|
||||
outlbl = label() and
|
||||
inlbl.isTaintedObject() and
|
||||
outlbl.isTaintedObject() and
|
||||
trg.(PropRead).getBase() = src
|
||||
or
|
||||
// Property projection preserves deep object taint
|
||||
inlbl = label() and
|
||||
outlbl = label() and
|
||||
inlbl.isTaintedObject() and
|
||||
outlbl.isTaintedObject() and
|
||||
trg.(PropertyProjection).getObject() = src
|
||||
or
|
||||
// Extending objects preserves deep object taint
|
||||
inlbl = label() and
|
||||
outlbl = label() and
|
||||
inlbl.isTaintedObject() and
|
||||
outlbl.isTaintedObject() and
|
||||
exists(ExtendCall call |
|
||||
src = call.getAnOperand() and
|
||||
trg = call
|
||||
@@ -60,8 +64,8 @@ module TaintedObject {
|
||||
)
|
||||
or
|
||||
// Spreading into an object preserves deep object taint: `p -> { ...p }`
|
||||
inlbl = label() and
|
||||
outlbl = label() and
|
||||
inlbl.isTaintedObject() and
|
||||
outlbl.isTaintedObject() and
|
||||
exists(ObjectLiteralNode obj |
|
||||
src = obj.getASpreadProperty() and
|
||||
trg = obj
|
||||
@@ -69,9 +73,13 @@ module TaintedObject {
|
||||
}
|
||||
|
||||
/**
|
||||
* DEPRECATED. Use the `Source` class and `FlowState#isTaintedObject()` directly.
|
||||
*
|
||||
* Holds if `node` is a source of JSON taint and label is the JSON taint label.
|
||||
*/
|
||||
predicate isSource(Node source, FlowLabel label) { source instanceof Source and label = label() }
|
||||
deprecated predicate isSource(Node source, FlowLabel label) {
|
||||
source instanceof Source and label = label()
|
||||
}
|
||||
|
||||
/** Request input accesses as a JSON source. */
|
||||
private class RequestInputAsSource extends Source {
|
||||
@@ -86,11 +94,11 @@ module TaintedObject {
|
||||
predicate blocksExpr(boolean outcome, Expr e) { none() }
|
||||
|
||||
/** Holds if this node blocks flow of `label` through `e`, provided it evaluates to `outcome`. */
|
||||
predicate blocksExpr(boolean outcome, Expr e, FlowLabel label) { none() }
|
||||
predicate blocksExpr(boolean outcome, Expr e, FlowState label) { none() }
|
||||
|
||||
/** DEPRECATED. Use `blocksExpr` instead. */
|
||||
deprecated predicate sanitizes(boolean outcome, Expr e, FlowLabel label) {
|
||||
this.blocksExpr(outcome, e, label)
|
||||
this.blocksExpr(outcome, e, FlowState::fromFlowLabel(label))
|
||||
}
|
||||
|
||||
/** DEPRECATED. Use `blocksExpr` instead. */
|
||||
@@ -111,7 +119,7 @@ module TaintedObject {
|
||||
/**
|
||||
* A sanitizer guard that blocks deep object taint.
|
||||
*/
|
||||
module SanitizerGuard = DataFlow::MakeLabeledBarrierGuard<SanitizerGuard>;
|
||||
module SanitizerGuard = DataFlow::MakeStateBarrierGuard<FlowState, SanitizerGuard>;
|
||||
|
||||
/**
|
||||
* A test of form `typeof x === "something"`, preventing `x` from being an object in some cases.
|
||||
@@ -133,10 +141,10 @@ module TaintedObject {
|
||||
)
|
||||
}
|
||||
|
||||
override predicate blocksExpr(boolean outcome, Expr e, FlowLabel label) {
|
||||
override predicate blocksExpr(boolean outcome, Expr e, FlowState state) {
|
||||
polarity = outcome and
|
||||
e = operand and
|
||||
label = label()
|
||||
state.isTaintedObject()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -161,8 +169,8 @@ module TaintedObject {
|
||||
.getACall()
|
||||
}
|
||||
|
||||
override predicate blocksExpr(boolean outcome, Expr e, FlowLabel lbl) {
|
||||
e = super.getAnArgument().asExpr() and outcome = true and lbl = label()
|
||||
override predicate blocksExpr(boolean outcome, Expr e, FlowState state) {
|
||||
e = super.getAnArgument().asExpr() and outcome = true and state.isTaintedObject()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -175,10 +183,10 @@ module TaintedObject {
|
||||
|
||||
JsonSchemaValidationGuard() { this = call.getAValidationResultAccess(polarity) }
|
||||
|
||||
override predicate blocksExpr(boolean outcome, Expr e, FlowLabel label) {
|
||||
override predicate blocksExpr(boolean outcome, Expr e, FlowState state) {
|
||||
outcome = polarity and
|
||||
e = call.getInput().asExpr() and
|
||||
label = label()
|
||||
state.isTaintedObject()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,8 +7,10 @@ import javascript
|
||||
|
||||
/** Provides classes and predicates for reasoning about deeply tainted objects. */
|
||||
module TaintedObject {
|
||||
import CommonFlowState
|
||||
|
||||
/** A flow label representing a deeply tainted object. */
|
||||
abstract class TaintedObjectLabel extends DataFlow::FlowLabel {
|
||||
abstract deprecated class TaintedObjectLabel extends DataFlow::FlowLabel {
|
||||
TaintedObjectLabel() { this = "tainted-object" }
|
||||
}
|
||||
|
||||
@@ -19,7 +21,7 @@ module TaintedObject {
|
||||
*
|
||||
* Note that the presence of the this label generally implies the presence of the `taint` label as well.
|
||||
*/
|
||||
DataFlow::FlowLabel label() { result instanceof TaintedObjectLabel }
|
||||
deprecated DataFlow::FlowLabel label() { result instanceof TaintedObjectLabel }
|
||||
|
||||
/**
|
||||
* A source of a user-controlled deep object.
|
||||
|
||||
Reference in New Issue
Block a user