mirror of
https://github.com/github/codeql.git
synced 2026-04-27 17:55:19 +02:00
Merge pull request #5554 from asgerf/js/non-recursive-propref
Approved by esbena
This commit is contained in:
@@ -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()
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -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() }
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user