JS: add two-prop version of loadStoreStep and infer pseudo properties

Initial step towards migrating CollectionFlowStep to PreCallGraphStep
This commit is contained in:
Asger Feldthaus
2021-03-18 12:40:34 +00:00
parent 67ec5d325c
commit 98398a9efd
6 changed files with 64 additions and 31 deletions

View File

@@ -10,18 +10,12 @@ private import DataFlow::PseudoProperties
/**
* A pseudo-property used in a data-flow/type-tracking step for collections.
*
* By extending `TypeTrackingPseudoProperty` the class enables the use of the collection related pseudo-properties in type-tracking predicates.
*/
private class PseudoProperty extends TypeTrackingPseudoProperty {
private class PseudoProperty extends string {
PseudoProperty() {
this = [arrayLikeElement(), "1"] or // the "1" is required for the `ForOfStep`.
this = any(CollectionDataFlow::MapSet step).getAPseudoProperty()
}
override PseudoProperty getLoadStoreToProp() {
exists(CollectionFlowStep step | step.loadStore(_, _, this, result))
}
}
/**

View File

@@ -214,13 +214,6 @@ module PromiseTypeTracking {
result = PromiseTypeTracking::promiseStep(mid, summary)
)
}
/**
* A class enabling the use of the `resolveField` as a pseudo-property in type-tracking predicates.
*/
private class ResolveFieldAsTypeTrackingProperty extends TypeTrackingPseudoProperty {
ResolveFieldAsTypeTrackingProperty() { this = Promises::valueProp() }
}
}
private import semmle.javascript.dataflow.internal.PreCallGraphStep

View File

@@ -358,6 +358,15 @@ class SharedTypeTrackingStep extends Unit {
* Holds if type-tracking should step from the `prop` property of `pred` to the same property in `succ`.
*/
predicate loadStoreStep(DataFlow::Node pred, DataFlow::SourceNode succ, string prop) { none() }
/**
* Holds if type-tracking should step from the `loadProp` property of `pred` to the `storeProp` property in `succ`.
*/
predicate loadStoreStep(
DataFlow::Node pred, DataFlow::SourceNode succ, string loadProp, string storeProp
) {
none()
}
}
/** Provides access to the steps contributed by subclasses of `SharedTypeTrackingStep`. */
@@ -389,6 +398,15 @@ module SharedTypeTrackingStep {
predicate loadStoreStep(DataFlow::Node pred, DataFlow::SourceNode succ, string prop) {
any(SharedTypeTrackingStep s).loadStoreStep(pred, succ, prop)
}
/**
* Holds if type-tracking should step from the `loadProp` property of `pred` to the `storeProp` property in `succ`.
*/
predicate loadStoreStep(
DataFlow::Node pred, DataFlow::SourceNode succ, string loadProp, string storeProp
) {
any(SharedTypeTrackingStep s).loadStoreStep(pred, succ, loadProp, storeProp)
}
}
/**

View File

@@ -40,6 +40,15 @@ class PreCallGraphStep extends Unit {
* Holds if there is a step from the `prop` property of `pred` to the same property in `succ`.
*/
predicate loadStoreStep(DataFlow::Node pred, DataFlow::SourceNode succ, string prop) { none() }
/**
* Holds if there is a step from the `loadProp` property of `pred` to the `storeProp` property in `succ`.
*/
predicate loadStoreStep(
DataFlow::Node pred, DataFlow::SourceNode succ, string loadProp, string storeProp
) {
none()
}
}
module PreCallGraphStep {
@@ -75,6 +84,15 @@ module PreCallGraphStep {
predicate loadStoreStep(DataFlow::Node pred, DataFlow::SourceNode succ, string prop) {
any(PreCallGraphStep s).loadStoreStep(pred, succ, prop)
}
/**
* Holds if there is a step from the `loadProp` property of `pred` to the `storeProp` property in `succ`.
*/
predicate loadStoreStep(
DataFlow::Node pred, DataFlow::SourceNode succ, string loadProp, string storeProp
) {
any(PreCallGraphStep s).loadStoreStep(pred, succ, loadProp, storeProp)
}
}
private class SharedFlowStepFromPreCallGraph extends DataFlow::SharedFlowStep {
@@ -93,6 +111,12 @@ private class SharedFlowStepFromPreCallGraph extends DataFlow::SharedFlowStep {
override predicate loadStoreStep(DataFlow::Node pred, DataFlow::Node succ, string prop) {
PreCallGraphStep::loadStoreStep(pred, succ, prop)
}
override predicate loadStoreStep(
DataFlow::Node pred, DataFlow::Node succ, string loadProp, string storeProp
) {
PreCallGraphStep::loadStoreStep(pred, succ, loadProp, storeProp)
}
}
private class SharedTypeTrackingStepFromPreCallGraph extends DataFlow::SharedTypeTrackingStep {
@@ -111,4 +135,10 @@ private class SharedTypeTrackingStepFromPreCallGraph extends DataFlow::SharedTyp
override predicate loadStoreStep(DataFlow::Node pred, DataFlow::SourceNode succ, string prop) {
PreCallGraphStep::loadStoreStep(pred, succ, prop)
}
override predicate loadStoreStep(
DataFlow::Node pred, DataFlow::SourceNode succ, string loadProp, string storeProp
) {
PreCallGraphStep::loadStoreStep(pred, succ, loadProp, storeProp)
}
}

View File

@@ -10,7 +10,13 @@ class PropertyName extends string {
or
exists(AccessPath::getAnAssignmentTo(_, this))
or
this instanceof TypeTrackingPseudoProperty
SharedTypeTrackingStep::loadStep(_, _, this)
or
SharedTypeTrackingStep::storeStep(_, _, this)
or
SharedTypeTrackingStep::loadStoreStep(_, _, this, _)
or
SharedTypeTrackingStep::loadStoreStep(_, _, _, this)
}
}
@@ -18,19 +24,6 @@ class OptionalPropertyName extends string {
OptionalPropertyName() { this instanceof PropertyName or this = "" }
}
/**
* A pseudo-property that can be used in type-tracking.
*/
abstract class TypeTrackingPseudoProperty extends string {
bindingset[this]
TypeTrackingPseudoProperty() { any() }
/**
* Gets a property name that `this` can be copied to in a `LoadStoreStep(this, result)`.
*/
string getLoadStoreToProp() { none() }
}
/**
* A description of a step on an inter-procedural data flow path.
*/
@@ -42,7 +35,7 @@ newtype TStepSummary =
LoadStep(PropertyName prop) or
CopyStep(PropertyName prop) or
LoadStoreStep(PropertyName fromProp, PropertyName toProp) {
exists(TypeTrackingPseudoProperty prop | fromProp = prop and toProp = prop.getLoadStoreToProp())
SharedTypeTrackingStep::loadStoreStep(_, _, fromProp, toProp)
}
/**
@@ -121,6 +114,11 @@ module StepSummary {
summary = CopyStep(prop)
)
or
exists(string fromProp, string toProp |
SharedTypeTrackingStep::loadStoreStep(pred, succ, fromProp, toProp) and
summary = LoadStoreStep(fromProp, toProp)
)
or
SharedTypeTrackingStep::step(pred, succ) and
summary = LevelStep()
or

View File

@@ -708,8 +708,8 @@ module HTTP {
override DataFlow::SourceNode getRouteHandler(DataFlow::SourceNode access) {
result instanceof RouteHandlerCandidate and
exists(
DataFlow::Node input, TypeTrackingPseudoProperty key, CollectionFlowStep store,
CollectionFlowStep load, DataFlow::Node storeTo, DataFlow::Node loadFrom
DataFlow::Node input, string key, CollectionFlowStep store, CollectionFlowStep load,
DataFlow::Node storeTo, DataFlow::Node loadFrom
|
this.flowsTo(storeTo) and
store.store(input, storeTo, key) and