mirror of
https://github.com/github/codeql.git
synced 2026-04-03 14:18:17 +02:00
162 lines
7.8 KiB
Plaintext
162 lines
7.8 KiB
Plaintext
/**
|
|
* INTERNAL: Do not use outside the data flow library.
|
|
*
|
|
* Contains the raw data type underlying `DataFlow::Node`.
|
|
*/
|
|
overlay[local?]
|
|
module;
|
|
|
|
private import javascript
|
|
private import codeql.util.Boolean
|
|
private import semmle.javascript.dataflow.internal.AdditionalFlowInternal
|
|
private import semmle.javascript.dataflow.internal.Contents::Private
|
|
private import semmle.javascript.dataflow.internal.sharedlib.DataFlowImplCommon as DataFlowImplCommon
|
|
private import semmle.javascript.dataflow.internal.sharedlib.Ssa as Ssa2
|
|
private import semmle.javascript.dataflow.internal.DataFlowPrivate as DataFlowPrivate
|
|
private import semmle.javascript.dataflow.internal.sharedlib.FlowSummaryImpl as FlowSummaryImpl
|
|
private import semmle.javascript.dataflow.internal.FlowSummaryPrivate as FlowSummaryPrivate
|
|
private import semmle.javascript.dataflow.internal.VariableCapture as VariableCapture
|
|
private import semmle.javascript.dataflow.internal.VariableOrThis
|
|
|
|
cached
|
|
private module Cached {
|
|
private Content dynamicArgumentsContent() {
|
|
result.asArrayIndex() = [0 .. 10]
|
|
or
|
|
result.isUnknownArrayElement()
|
|
}
|
|
|
|
/**
|
|
* The raw data type underlying `DataFlow::Node`.
|
|
*/
|
|
cached
|
|
newtype TNode =
|
|
TValueNode(AST::ValueNode nd) or
|
|
/** An SSA node from the legacy SSA library */
|
|
TSsaDefNode(SsaDefinition d) or
|
|
/** Use of a variable or 'this', with flow from a post-update node (from an earlier use) */
|
|
TSsaUseNode(ControlFlowNode use) { use = any(Ssa2::SsaConfig::SourceVariable v).getAUse() } or
|
|
/** A synthesized variable read (new SSA library). Definitions are represented by TSsaDefNode. */
|
|
TSsaSynthReadNode(Ssa2::SsaSynthReadNode read) or
|
|
TCapturedVariableNode(LocalVariable v) { v.isCaptured() } or
|
|
TPropNode(@property p) or
|
|
TRestPatternNode(DestructuringPattern dp, Expr rest) { rest = dp.getRest() } or
|
|
TElementPatternNode(ArrayPattern ap, Expr p) { p = ap.getElement(_) } or
|
|
TElementNode(ArrayExpr arr, Expr e) { e = arr.getAnElement() } or
|
|
TReflectiveCallNode(MethodCallExpr ce, string kind) {
|
|
ce.getMethodName() = kind and
|
|
(kind = "call" or kind = "apply")
|
|
} or
|
|
TThisNode(StmtContainer f) { f.(Function).getThisBinder() = f or f instanceof TopLevel } or
|
|
TFunctionSelfReferenceNode(Function f) or
|
|
TStaticArgumentArrayNode(InvokeExpr node) or
|
|
TDynamicArgumentArrayNode(InvokeExpr node) { node.isSpreadArgument(_) } or
|
|
TStaticParameterArrayNode(Function f) {
|
|
f.getAParameter().isRestParameter() or f.usesArgumentsObject()
|
|
} or
|
|
TDynamicParameterArrayNode(Function f) or
|
|
/** Data about to be stored in the rest parameter object. Needed for shifting array indices. */
|
|
TRestParameterStoreNode(Function f, Content storeContent) {
|
|
f.getRestParameter().getIndex() > 0 and
|
|
storeContent = dynamicArgumentsContent()
|
|
} or
|
|
/** Data about to be stored in the dynamic argument array of an invocation. Needed for shifting array indices. */
|
|
TDynamicArgumentStoreNode(InvokeExpr invoke, Content storeContent) {
|
|
invoke.isSpreadArgument(_) and
|
|
storeContent = dynamicArgumentsContent()
|
|
} or
|
|
TApplyCallTaintNode(MethodCallExpr node) {
|
|
node.getMethodName() = "apply" and exists(node.getArgument(1))
|
|
} or
|
|
TDestructuredModuleImportNode(ImportDeclaration decl) {
|
|
exists(decl.getASpecifier().getImportedName())
|
|
} or
|
|
THtmlAttributeNode(HTML::Attribute attr) or
|
|
TXmlAttributeNode(XmlAttribute attr) or
|
|
TFunctionReturnNode(Function f) or
|
|
TExceptionalFunctionReturnNode(Function f) or
|
|
TExceptionalInvocationReturnNode(InvokeExpr e) or
|
|
TGlobalAccessPathRoot() or
|
|
TTemplatePlaceholderTag(Templating::TemplatePlaceholderTag tag) or
|
|
TReflectiveParametersNode(Function f) { f.usesArgumentsObject() } or
|
|
TExprPostUpdateNode(AST::ValueNode e) {
|
|
e = any(InvokeExpr invoke).getAnArgument() or
|
|
e = any(PropAccess access).getBase() or
|
|
e = any(DestructuringPattern pattern) or
|
|
e = any(InvokeExpr invoke).getCallee() or
|
|
// We have read steps out of the await operand, so it technically needs a post-update
|
|
e = any(AwaitExpr a).getOperand() or
|
|
e = any(Function f) or // functions are passed as their own self-reference argument
|
|
// The RHS of an assignment can be an argument to a setter-call, so it needs a post-update node
|
|
e = any(Assignment asn | asn.getTarget() instanceof PropAccess).getRhs()
|
|
} or
|
|
TNewCallThisArgument(NewExpr e) or
|
|
TImplicitThisUse(ImplicitThisUse use, Boolean isPost) or
|
|
TFlowSummaryNode(FlowSummaryImpl::Private::SummaryNode sn) or
|
|
TFlowSummaryDynamicParameterArrayNode(FlowSummaryImpl::Public::SummarizedCallable callable) or
|
|
TFlowSummaryIntermediateAwaitStoreNode(FlowSummaryImpl::Private::SummaryNode sn) {
|
|
// NOTE: This dependency goes through the 'Steps' module whose instantiation depends on the call graph,
|
|
// but the specific predicate we're referering to does not use that information.
|
|
// So it doesn't cause negative recursion but it might look a bit surprising.
|
|
FlowSummaryPrivate::Steps::summaryStoreStep(sn, MkAwaited(), _)
|
|
} or
|
|
TFlowSummaryDefaultExceptionalReturn(FlowSummaryImpl::Public::SummarizedCallable callable) {
|
|
not DataFlowPrivate::mentionsExceptionalReturn(callable)
|
|
} or
|
|
TSynthCaptureNode(VariableCapture::VariableCaptureOutput::SynthesizedCaptureNode node) or
|
|
TGenericSynthesizedNode(AstNode node, string tag, DataFlowPrivate::DataFlowCallable container) {
|
|
any(AdditionalFlowInternal flow).needsSynthesizedNode(node, tag, container)
|
|
} or
|
|
TForbiddenRecursionGuard() {
|
|
none() and
|
|
// We want to prune irrelevant models before materialising data flow nodes, so types contributed
|
|
// directly from CodeQL must expose their pruning info without depending on data flow nodes.
|
|
(any(ModelInput::TypeModel tm).isTypeUsed("") implies any())
|
|
}
|
|
|
|
cached
|
|
private module Backref {
|
|
cached
|
|
predicate backref() {
|
|
DataFlowImplCommon::forceCachingInSameStage() or
|
|
exists(any(DataFlow::Node node).toString()) or
|
|
exists(any(DataFlow::Node node).getContainer()) or
|
|
any(DataFlow::Node node).hasLocationInfo(_, _, _, _, _) or
|
|
exists(any(Content c).toString())
|
|
}
|
|
}
|
|
}
|
|
|
|
import Cached
|
|
|
|
private class TEarlyStageNode =
|
|
TValueNode or TSsaDefNode or TCapturedVariableNode or TPropNode or TRestPatternNode or
|
|
TElementPatternNode or TElementNode or TReflectiveCallNode or TThisNode or
|
|
TFunctionSelfReferenceNode or TDestructuredModuleImportNode or THtmlAttributeNode or
|
|
TFunctionReturnNode or TExceptionalFunctionReturnNode or TExceptionalInvocationReturnNode or
|
|
TGlobalAccessPathRoot or TTemplatePlaceholderTag or TReflectiveParametersNode or
|
|
TExprPostUpdateNode or TNewCallThisArgument or TStaticArgumentArrayNode or
|
|
TDynamicArgumentArrayNode or TStaticParameterArrayNode or TDynamicParameterArrayNode or
|
|
TImplicitThisUse;
|
|
|
|
/**
|
|
* A data-flow node that is not a flow summary node.
|
|
*
|
|
* This node exists to avoid an unwanted dependency on flow summaries in some parts of the codebase
|
|
* that should not depend on them.
|
|
*
|
|
* In particular, this dependency chain must not result in negative recursion:
|
|
* - Flow summaries can only be created after pruning irrelevant flow summaries
|
|
* - To prune irrelevant flow summaries, we must know which packages are imported
|
|
* - To know which packages are imported, module systems must be evaluated
|
|
* - The AMD and NodeJS module systems rely on data flow to find calls to `require` and similar.
|
|
* These module systems must therefore use `EarlyStageNode` instead of `DataFlow::Node`.
|
|
*/
|
|
class EarlyStageNode extends TEarlyStageNode {
|
|
/** Gets a string representation of this data flow node. */
|
|
string toString() { result = this.(DataFlow::Node).toString() }
|
|
|
|
/** Gets the location of this data flow node. */
|
|
Location getLocation() { result = this.(DataFlow::Node).getLocation() }
|
|
}
|