python: add reads of captured variables to

type tracking and the API graph.

- In `TypeTrackerSpecific.qll` we add a jump step
  - to every scope entry definition
  - from the value of any defining `DefinitionNode`
    (In our example, the definition is the class name, `Users`,
     while the assigned value is the class definition, and it is
     the latter which receives flow in this case.)
- In `LocalSources.qll` we allow scope entry definitions as local sources.
  - This feels natural enough, as they are a local source for the value, they represent.
    It is perhaps a bit funne to see an Ssa variable here,
    rather than a control flow node.
 - This is necessary in order for type tracking to see the local flow
    from the scope entry definition.
- In `ApiGraphs.qll` we no longer restrict the result of `trackUseNode`
  to be an `ExprNode`. To keep the positive formulation, we do not
  prohibit module variable nodes. Instead we restrict to the new
  `LocalSourceNodeNotModule` which avoids those cases.
This commit is contained in:
Rasmus Lerchedahl Petersen
2023-03-15 15:00:31 +01:00
parent 7e003f63b9
commit 2318752c14
8 changed files with 36 additions and 6 deletions

View File

@@ -987,7 +987,7 @@ module API {
DataFlow::LocalSourceNode trackUseNode(DataFlow::LocalSourceNode src) {
Stages::TypeTracking::ref() and
result = trackUseNode(src, DataFlow::TypeTracker::end()) and
result instanceof DataFlow::ExprNode
result instanceof DataFlow::LocalSourceNodeNotModule
}
/**

View File

@@ -51,6 +51,10 @@ class LocalSourceNode extends Node {
// We explicitly include any read of a global variable, as some of these may have local flow going
// into them.
this = any(ModuleVariableNode mvn).getARead()
or
// We include all scope entry definitions, as these act as the local source within the scope they
// enter.
this.asVar() instanceof ScopeEntryDefinition
}
/** Holds if this `LocalSourceNode` can flow to `nodeTo` in one or more local flow steps. */
@@ -133,6 +137,19 @@ class LocalSourceNode extends Node {
LocalSourceNode backtrack(TypeBackTracker t2, TypeBackTracker t) { t2 = t.step(result, this) }
}
/**
* A LocalSourceNode that is not a ModuleVariableNode
* This class provides a positive formulation of that in its charpred.
*/
class LocalSourceNodeNotModule extends LocalSourceNode {
cached
LocalSourceNodeNotModule() {
this instanceof ExprNode
or
this.asVar() instanceof ScopeEntryDefinition
}
}
/**
* A node that can be used for type tracking or type back-tracking.
*

View File

@@ -43,7 +43,19 @@ predicate compatibleContents(TypeTrackerContent storeContent, TypeTrackerContent
predicate simpleLocalFlowStep = DataFlowPrivate::simpleLocalFlowStepForTypetracking/2;
predicate jumpStep = DataFlowPrivate::jumpStepSharedWithTypeTracker/2;
predicate jumpStep(Node nodeFrom, Node nodeTo) {
DataFlowPrivate::jumpStepSharedWithTypeTracker(nodeFrom, nodeTo)
or
capturedJumpStep(nodeFrom, nodeTo)
}
predicate capturedJumpStep(Node nodeFrom, Node nodeTo) {
exists(SsaSourceVariable var, DefinitionNode def | var.hasDefiningNode(def) |
nodeTo.asVar().(ScopeEntryDefinition).getSourceVariable() = var and
nodeFrom.asCfgNode() = def.getValue() and
var.getScope().getScope*() = nodeFrom.getScope()
)
}
/** Holds if there is a level step from `nodeFrom` to `nodeTo`, which may depend on the call graph. */
predicate levelStepCall(Node nodeFrom, Node nodeTo) { none() }