JS: Add withoutPropStep and model 'await' steps with it

This commit is contained in:
Asger F
2022-06-20 12:51:39 +02:00
parent 875776d91d
commit a0d3a6b5b1
3 changed files with 69 additions and 1 deletions

View File

@@ -189,6 +189,13 @@ module Promises {
* Gets the pseudo-field used to describe rejected values in a promise.
*/
string errorProp() { result = "$PromiseRejectField$" }
/** A property set containing the pseudo-properites of a promise object. */
class PromiseProps extends DataFlow::PropertySet {
PromiseProps() { this = "PromiseProps" }
override string getAProperty() { result = [valueProp(), errorProp()] }
}
}
/**
@@ -274,6 +281,24 @@ private class PromiseStep extends PreCallGraphStep {
}
}
/**
* A step from `p -> await p` for the case where `p` is not a promise.
*
* In this case, `await p` just returns `p` itself. We block flow of the promise-related
* pseudo properties through this edge.
*/
private class RawAwaitStep extends DataFlow::SharedTypeTrackingStep {
override predicate withoutPropStep(
DataFlow::Node pred, DataFlow::Node succ, DataFlow::PropertySet props
) {
exists(AwaitExpr await |
pred = await.getOperand().flow() and
succ = await.flow() and
props instanceof Promises::PromiseProps
)
}
}
/**
* This module defines how data-flow propagates into and out of a Promise.
* The data-flow is based on pseudo-properties rather than tainting the Promise object (which is what `PromiseTaintStep` does).

View File

@@ -70,6 +70,12 @@ class TypeTracker extends TTypeTracker {
step = LoadStep(prop) and result = MkTypeTracker(hasCall, "")
or
exists(string p | step = StoreStep(p) and prop = "" and result = MkTypeTracker(hasCall, p))
or
exists(PropertySet props |
step = WithoutPropStep(props) and
not prop = props.getAProperty() and
result = this
)
}
/** Gets a textual representation of this summary. */
@@ -373,6 +379,26 @@ class SharedTypeTrackingStep extends Unit {
) {
none()
}
/**
* Holds if type-tracking should step from `pred` to `succ` but block flow of `props` through here.
*
* This can be seen as taking a copy of the value in `pred` but without the properties in `props`.
*/
predicate withoutPropStep(DataFlow::Node pred, DataFlow::Node succ, PropertySet props) { none() }
}
/**
* A representative for a set of property names.
*
* Currently this is used to denote a set of properties in `withoutPropStep`.
*/
abstract class PropertySet extends string {
bindingset[this]
PropertySet() { any() }
/** Gets a property contained in this property set. */
abstract string getAProperty();
}
/** Provides access to the steps contributed by subclasses of `SharedTypeTrackingStep`. */
@@ -413,6 +439,15 @@ module SharedTypeTrackingStep {
) {
any(SharedTypeTrackingStep s).loadStoreStep(pred, succ, loadProp, storeProp)
}
/**
* Holds if type-tracking should step from `pred` to `succ` but block flow of `prop` through here.
*
* This can be seen as taking a copy of the value in `pred` but without the properties in `props`.
*/
predicate withoutPropStep(DataFlow::Node pred, DataFlow::Node succ, PropertySet props) {
any(SharedTypeTrackingStep s).withoutPropStep(pred, succ, props)
}
}
/**

View File

@@ -45,7 +45,8 @@ private module Cached {
CopyStep(PropertyName prop) or
LoadStoreStep(PropertyName fromProp, PropertyName toProp) {
SharedTypeTrackingStep::loadStoreStep(_, _, fromProp, toProp)
}
} or
WithoutPropStep(PropertySet props) { SharedTypeTrackingStep::withoutPropStep(_, _, props) }
}
/**
@@ -110,6 +111,11 @@ private module Cached {
summary = CopyStep(prop)
)
or
exists(PropertySet props |
SharedTypeTrackingStep::withoutPropStep(pred, succ, props) and
summary = WithoutPropStep(props)
)
or
exists(string fromProp, string toProp |
SharedTypeTrackingStep::loadStoreStep(pred, succ, fromProp, toProp) and
summary = LoadStoreStep(fromProp, toProp)
@@ -194,6 +200,8 @@ class StepSummary extends TStepSummary {
or
exists(string prop | this = CopyStep(prop) | result = "copy " + prop)
or
exists(string prop | this = WithoutPropStep(prop) | result = "without " + prop)
or
exists(string fromProp, string toProp | this = LoadStoreStep(fromProp, toProp) |
result = "load " + fromProp + " and store to " + toProp
)