Merge pull request #5554 from asgerf/js/non-recursive-propref

Approved by esbena
This commit is contained in:
CodeQL CI
2021-03-30 11:29:32 +01:00
committed by GitHub
6 changed files with 76 additions and 14 deletions

View File

@@ -202,6 +202,42 @@ private class RequireVariable extends Variable {
*/
private predicate moduleInFile(Module m, File f) { m.getFile() = f }
private predicate isModuleModule(DataFlow::Node nd) {
exists(ImportDeclaration imp |
imp.getImportedPath().getValue() = "module" and
nd =
[
DataFlow::destructuredModuleImportNode(imp),
DataFlow::valueNode(imp.getASpecifier().(ImportNamespaceSpecifier))
]
)
or
isModuleModule(nd.getAPredecessor())
}
private predicate isCreateRequire(DataFlow::Node nd) {
exists(PropAccess prop |
isModuleModule(prop.getBase().flow()) and
prop.getPropertyName() = "createRequire" and
nd = prop.flow()
)
or
exists(PropertyPattern prop |
isModuleModule(prop.getObjectPattern().flow()) and
prop.getName() = "createRequire" and
nd = prop.getValuePattern().flow()
)
or
exists(ImportDeclaration decl, NamedImportSpecifier spec |
decl.getImportedPath().getValue() = "module" and
spec = decl.getASpecifier() and
spec.getImportedName() = "createRequire" and
nd = spec.flow()
)
or
isCreateRequire(nd.getAPredecessor())
}
/**
* Holds if `nd` may refer to `require`, either directly or modulo local data flow.
*/
@@ -215,16 +251,11 @@ private predicate isRequire(DataFlow::Node nd) {
or
// `import { createRequire } from 'module';`.
// specialized to ES2015 modules to avoid recursion in the `DataFlow::moduleImport()` predicate and to avoid
// negative recursion between `Import.getImportedModuleNode()` and `Import.getImportedModule()`.
exists(ImportDeclaration imp, DataFlow::SourceNode baseObj |
imp.getImportedPath().getValue() = "module"
|
baseObj =
[
DataFlow::destructuredModuleImportNode(imp),
DataFlow::valueNode(imp.getASpecifier().(ImportNamespaceSpecifier))
] and
nd = baseObj.getAPropertyRead("createRequire").getACall()
// negative recursion between `Import.getImportedModuleNode()` and `Import.getImportedModule()`, and
// to avoid depending on `SourceNode` as this would make `SourceNode::Range` recursive.
exists(CallExpr call |
isCreateRequire(call.getCallee().flow()) and
nd = call.flow()
)
}

View File

@@ -492,6 +492,7 @@ module DataFlow {
* Gets the data flow node corresponding to the base object
* whose property is read from or written to.
*/
cached
abstract Node getBase();
/**
@@ -595,7 +596,10 @@ module DataFlow {
PropLValueAsPropWrite() { astNode instanceof LValue }
override Node getBase() { result = valueNode(astNode.getBase()) }
override Node getBase() {
result = valueNode(astNode.getBase()) and
Stages::DataFlowStage::ref()
}
override Expr getPropertyNameExpr() { result = astNode.getPropertyNameExpr() }
@@ -724,7 +728,7 @@ module DataFlow {
override ParameterField prop;
override Node getBase() {
result = thisNode(prop.getDeclaringClass().getConstructor().getBody())
thisNode(result, prop.getDeclaringClass().getConstructor().getBody())
}
override Expr getPropertyNameExpr() {
@@ -758,7 +762,7 @@ module DataFlow {
}
override Node getBase() {
result = thisNode(prop.getDeclaringClass().getConstructor().getBody())
thisNode(result, prop.getDeclaringClass().getConstructor().getBody())
}
override Expr getPropertyNameExpr() { result = prop.getNameExpr() }

View File

@@ -34,7 +34,11 @@ private import semmle.javascript.internal.CachedStages
* ```
*/
class SourceNode extends DataFlow::Node {
SourceNode() { this instanceof SourceNode::Range }
SourceNode() {
this instanceof SourceNode::Range
or
none() and this instanceof SourceNode::Internal::RecursionGuard
}
/**
* Holds if this node flows into `sink` in zero or more local (that is,
@@ -329,6 +333,12 @@ module SourceNode {
DataFlow::functionReturnNode(this, _)
}
}
/** INTERNAL. DO NOT USE. */
module Internal {
/** An empty class that some tests are using to enforce that SourceNode is non-recursive. */
abstract class RecursionGuard extends DataFlow::Node { }
}
}
deprecated class DefaultSourceNode extends SourceNode {

View File

@@ -133,6 +133,8 @@ module Stages {
exists(any(DataFlow::Node node).toString())
or
exists(any(AccessPath a).getAnInstanceIn(_))
or
exists(any(DataFlow::PropRef ref).getBase())
}
}