JS: Make separate type for back-tracking types

This commit is contained in:
Asger F
2019-03-06 12:50:50 +00:00
parent 0b2c94684d
commit e6a1374218
2 changed files with 78 additions and 7 deletions

View File

@@ -160,19 +160,24 @@ class SourceNode extends DataFlow::Node {
*
* See `TypeTracker` for more details about how to use this.
*/
DataFlow::SourceNode track(TypeTracker src, TypeTracker dst) {
DataFlow::SourceNode track(TypeTracker t2, TypeTracker t) {
exists(StepSummary summary |
StepSummary::step(this, result, summary) and
dst = StepSummary::append(src, summary)
t = StepSummary::append(t2, summary)
)
}
/**
* Gets a node that may flow into this one using one heap and/or interprocedural step.
*
* See `TypeTracker` for more details about how to use this.
* See `TypeBackTracker` for more details about how to use this.
*/
DataFlow::SourceNode backtrack(TypeTracker src, TypeTracker dst) { this = result.track(src, dst) }
DataFlow::SourceNode backtrack(TypeBackTracker t2, TypeBackTracker t) {
exists(StepSummary summary |
StepSummary::step(result, this, summary) and
t = StepSummary::prepend(summary, t2)
)
}
}
module SourceNode {

View File

@@ -118,6 +118,16 @@ module StepSummary {
not (type.hasCall() = true and summary.hasReturn() = true) and
result.hasCall() = type.hasCall().booleanOr(summary.hasCall())
}
/**
* INTERNAL. Do not use.
*
* Prepends a step summary before a backwards type-tracking summary.
*/
TypeBackTracker prepend(StepSummary summary, TypeBackTracker type) {
not (type.hasReturn() = true and summary.hasCall() = true) and
result.hasReturn() = type.hasReturn().booleanOr(summary.hasReturn())
}
}
private newtype TTypeTracker = MkTypeTracker(boolean hasCall) {
@@ -147,9 +157,8 @@ private newtype TTypeTracker = MkTypeTracker(boolean hasCall) {
* DataFlow::SourceNode myType() { result = myType(_) }
* ```
*
* This class can also be used to track values backwards, which can be useful for tracking
* the type of a callback. To do so, use the example above except with `.track`
* replaced with `.backtrack`.
* To track values backwards, which can be useful for tracking
* the type of a callback, use the `TypeBackTracker` class instead.
*/
class TypeTracker extends TTypeTracker {
Boolean hasCall;
@@ -178,3 +187,60 @@ class TypeTracker extends TTypeTracker {
result = hasCall
}
}
private newtype TTypeBackTracker = MkTypeBackTracker(boolean hasReturn) {
hasReturn = true or hasReturn = false
}
/**
* Summary of the steps needed to back-track a use of a value to a given dataflow node.
*
* This can be used to track callbacks that are passed to a certian API call, and are
* therefore expected to called with a certain type of value.
*
* Note that type back-tracking does not provide a source/sink relation, that is,
* it may determine that a node will be used in an API call somwwhere, but it won't
* determine exactly where that use was, or the path that led to the use.
*
* It is recommended that all uses of this type is written on the following form,
* for back-tracking some callback type `myCallback`:
* ```
* DataFlow::SourceNode myCallback(DataFlow::TypeBackTracker t) {
* t.start() and
* result = (< some API call >).getParameter(< n >).getALocalSource()
* or
* exists (DataFlow::TypeTracker t2 |
* result = myCallback(t2).backtrack(t2, t)
* )
* }
*
* DataFlow::SourceNode myCallback() { result = myCallback(_) }
* ```
*/
class TypeBackTracker extends TTypeBackTracker {
Boolean hasReturn;
TypeBackTracker() { this = MkTypeBackTracker(hasReturn) }
string toString() {
hasReturn = true and result = "type back-tracker with return steps"
or
hasReturn = false and result = "type back-tracker without return steps"
}
/**
* Holds if this is the starting point of type tracking.
*/
predicate start() {
hasReturn = false
}
/**
* INTERNAL. DO NOT USE.
*
* Holds if this type has been back-tracked into a call through return edge.
*/
boolean hasReturn() {
result = hasReturn
}
}