diff --git a/javascript/ql/src/semmle/javascript/PackageExports.qll b/javascript/ql/src/semmle/javascript/PackageExports.qll index c66585344599..c225e5a733be 100644 --- a/javascript/ql/src/semmle/javascript/PackageExports.qll +++ b/javascript/ql/src/semmle/javascript/PackageExports.qll @@ -5,11 +5,14 @@ */ import javascript +private import semmle.javascript.internal.CachedStages /** * Gets a parameter that is a library input to a top-level package. */ +cached DataFlow::ParameterNode getALibraryInputParameter() { + Stages::Taint::ref() and exists(int bound, DataFlow::FunctionNode func | func = getAValueExportedByPackage().getABoundFunctionValue(bound) and result = func.getParameter(any(int arg | arg >= bound)) diff --git a/javascript/ql/src/semmle/javascript/dataflow/DataFlow.qll b/javascript/ql/src/semmle/javascript/dataflow/DataFlow.qll index 2bcee954cbc0..c73c894ca4b5 100644 --- a/javascript/ql/src/semmle/javascript/dataflow/DataFlow.qll +++ b/javascript/ql/src/semmle/javascript/dataflow/DataFlow.qll @@ -255,7 +255,9 @@ module DataFlow { * Holds if this node is annotated with the given named type, * or is declared as a subtype thereof, or is a union or intersection containing such a type. */ + cached predicate hasUnderlyingType(string globalName) { + Stages::TypeTracking::ref() and getType().hasUnderlyingType(globalName) or getFallbackTypeAnnotation().getAnUnderlyingType().hasQualifiedName(globalName) @@ -265,7 +267,9 @@ module DataFlow { * Holds if this node is annotated with the given named type, * or is declared as a subtype thereof, or is a union or intersection containing such a type. */ + cached predicate hasUnderlyingType(string moduleName, string typeName) { + Stages::TypeTracking::ref() and getType().hasUnderlyingType(moduleName, typeName) or getFallbackTypeAnnotation().getAnUnderlyingType().hasQualifiedName(moduleName, typeName) diff --git a/javascript/ql/src/semmle/javascript/dataflow/internal/StepSummary.qll b/javascript/ql/src/semmle/javascript/dataflow/internal/StepSummary.qll index 5869444053fb..2c1362c871d1 100644 --- a/javascript/ql/src/semmle/javascript/dataflow/internal/StepSummary.qll +++ b/javascript/ql/src/semmle/javascript/dataflow/internal/StepSummary.qll @@ -53,49 +53,11 @@ private module Cached { predicate step(DataFlow::SourceNode pred, DataFlow::SourceNode succ, StepSummary summary) { exists(DataFlow::Node mid | pred.flowsTo(mid) | StepSummary::smallstep(mid, succ, summary)) } -} - -import Cached::Public - -class OptionalPropertyName extends string { - OptionalPropertyName() { this instanceof PropertyName or this = "" } -} - -/** - * INTERNAL: Use `TypeTracker` or `TypeBackTracker` instead. - * - * A description of a step on an inter-procedural data flow path. - */ -class StepSummary extends TStepSummary { - /** Gets a textual representation of this step summary. */ - string toString() { - this instanceof LevelStep and result = "level" - or - this instanceof CallStep and result = "call" - or - this instanceof ReturnStep and result = "return" - or - exists(string prop | this = StoreStep(prop) | result = "store " + prop) - or - exists(string prop | this = LoadStep(prop) | result = "load " + prop) - or - exists(string prop | this = CopyStep(prop) | result = "copy " + prop) - or - exists(string fromProp, string toProp | this = LoadStoreStep(fromProp, toProp) | - result = "load " + fromProp + " and store to " + toProp - ) - } -} - -module StepSummary { - /** - * INTERNAL: Use `SourceNode.track()` or `SourceNode.backtrack()` instead. - */ - predicate step = Cached::step/3; /** * INTERNAL: Use `TypeBackTracker.smallstep()` instead. */ + cached predicate smallstep(DataFlow::Node pred, DataFlow::Node succ, StepSummary summary) { // Flow through properties of objects propertyFlowStep(pred, succ) and @@ -194,3 +156,47 @@ module StepSummary { ) } } + +import Cached::Public + +class OptionalPropertyName extends string { + OptionalPropertyName() { this instanceof PropertyName or this = "" } +} + +/** + * INTERNAL: Use `TypeTracker` or `TypeBackTracker` instead. + * + * A description of a step on an inter-procedural data flow path. + */ +class StepSummary extends TStepSummary { + /** Gets a textual representation of this step summary. */ + string toString() { + this instanceof LevelStep and result = "level" + or + this instanceof CallStep and result = "call" + or + this instanceof ReturnStep and result = "return" + or + exists(string prop | this = StoreStep(prop) | result = "store " + prop) + or + exists(string prop | this = LoadStep(prop) | result = "load " + prop) + or + exists(string prop | this = CopyStep(prop) | result = "copy " + prop) + or + exists(string fromProp, string toProp | this = LoadStoreStep(fromProp, toProp) | + result = "load " + fromProp + " and store to " + toProp + ) + } +} + +module StepSummary { + /** + * INTERNAL: Use `SourceNode.track()` or `SourceNode.backtrack()` instead. + */ + predicate step = Cached::step/3; + + /** + * INTERNAL: Use `TypeBackTracker.smallstep()` instead. + */ + predicate smallstep = Cached::smallstep/3; +} diff --git a/javascript/ql/src/semmle/javascript/internal/CachedStages.qll b/javascript/ql/src/semmle/javascript/internal/CachedStages.qll index a48cb8ed5e03..40b5e5ba6267 100644 --- a/javascript/ql/src/semmle/javascript/internal/CachedStages.qll +++ b/javascript/ql/src/semmle/javascript/internal/CachedStages.qll @@ -198,6 +198,10 @@ module Stages { exists(any(DataFlow::TypeBackTracker t).prepend(_)) or DataFlow::functionForwardingStep(_, _) + or + any(DataFlow::Node node).hasUnderlyingType(_) + or + any(DataFlow::Node node).hasUnderlyingType(_, _) } } @@ -232,6 +236,8 @@ module Stages { */ cached module Taint { + private import semmle.javascript.PackageExports as Exports + /** * Always holds. * Ensures that a predicate is evaluated as part of the Taint stage. @@ -250,6 +256,8 @@ module Stages { TaintTracking::heapStep(_, _) or exists(RemoteFlowSource r) + or + exists(Exports::getALibraryInputParameter()) } } }