mirror of
https://github.com/github/codeql.git
synced 2026-05-01 03:35:13 +02:00
JavaScript: Autoformat new libraries.
This commit is contained in:
@@ -3,7 +3,6 @@
|
||||
*/
|
||||
|
||||
import javascript
|
||||
|
||||
import semmle.javascript.security.dataflow.BrokenCryptoAlgorithm
|
||||
import semmle.javascript.security.dataflow.CleartextLogging
|
||||
import semmle.javascript.security.dataflow.CleartextStorage
|
||||
|
||||
@@ -13,20 +13,20 @@ import AllConfigurations
|
||||
import PortalExitSource
|
||||
import PortalEntrySink
|
||||
|
||||
from TaintTracking::Configuration cfg, DataFlow::PathNode source, DataFlow::PathNode sink,
|
||||
Portal p1, Portal p2, DataFlow::FlowLabel lbl1, DataFlow::FlowLabel lbl2
|
||||
where cfg.hasFlowPath(source, sink) and
|
||||
p1 = source.getNode().(PortalExitSource).getPortal() and
|
||||
p2 = sink.getNode().(PortalEntrySink).getPortal() and
|
||||
lbl1 = sink.getPathSummary().getStartLabel() and
|
||||
lbl2 = sink.getPathSummary().getEndLabel() and
|
||||
// avoid constructing infeasible paths
|
||||
sink.getPathSummary().hasCall() = false and
|
||||
sink.getPathSummary().hasReturn() = false and
|
||||
// restrict to steps flow function parameters to returns
|
||||
p1.(ParameterPortal).getBasePortal() = p2.(ReturnPortal).getBasePortal() and
|
||||
// restrict to data/taint flow
|
||||
lbl1 instanceof DataFlow::StandardFlowLabel
|
||||
select p1.toString(), lbl1.toString(),
|
||||
p2.toString(), lbl2.toString(),
|
||||
cfg.toString()
|
||||
from
|
||||
TaintTracking::Configuration cfg, DataFlow::PathNode source, DataFlow::PathNode sink, Portal p1,
|
||||
Portal p2, DataFlow::FlowLabel lbl1, DataFlow::FlowLabel lbl2
|
||||
where
|
||||
cfg.hasFlowPath(source, sink) and
|
||||
p1 = source.getNode().(PortalExitSource).getPortal() and
|
||||
p2 = sink.getNode().(PortalEntrySink).getPortal() and
|
||||
lbl1 = sink.getPathSummary().getStartLabel() and
|
||||
lbl2 = sink.getPathSummary().getEndLabel() and
|
||||
// avoid constructing infeasible paths
|
||||
sink.getPathSummary().hasCall() = false and
|
||||
sink.getPathSummary().hasReturn() = false and
|
||||
// restrict to steps flow function parameters to returns
|
||||
p1.(ParameterPortal).getBasePortal() = p2.(ReturnPortal).getBasePortal() and
|
||||
// restrict to data/taint flow
|
||||
lbl1 instanceof DataFlow::StandardFlowLabel
|
||||
select p1.toString(), lbl1.toString(), p2.toString(), lbl2.toString(), cfg.toString()
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/**
|
||||
* @name Extract sink summaries
|
||||
* @description Extracts sink summaries, that is, tuples `(p, lbl, cfg)` representing the fact
|
||||
* @description Extracts sink summaries, that is, tuples `(p, lbl, cfg)` representing the fact
|
||||
* that data with flow label `lbl` may flow from a user-controlled exit node of portal
|
||||
* `p` to a known sink for configuration `cfg`.
|
||||
* @kind sink-summary
|
||||
@@ -11,10 +11,10 @@ import AllConfigurations
|
||||
import PortalExitSource
|
||||
import SinkFromAnnotation
|
||||
|
||||
from TaintTracking::Configuration cfg, DataFlow::PathNode source, DataFlow::PathNode sink,
|
||||
Portal p
|
||||
where cfg.hasFlowPath(source, sink) and
|
||||
p = source.getNode().(PortalExitSource).getPortal() and
|
||||
// avoid constructing infeasible paths
|
||||
sink.getPathSummary().hasReturn() = false
|
||||
from TaintTracking::Configuration cfg, DataFlow::PathNode source, DataFlow::PathNode sink, Portal p
|
||||
where
|
||||
cfg.hasFlowPath(source, sink) and
|
||||
p = source.getNode().(PortalExitSource).getPortal() and
|
||||
// avoid constructing infeasible paths
|
||||
sink.getPathSummary().hasReturn() = false
|
||||
select p.toString(), source.getPathSummary().getStartLabel().toString(), cfg.toString()
|
||||
|
||||
@@ -11,10 +11,10 @@ import AllConfigurations
|
||||
import PortalEntrySink
|
||||
import SourceFromAnnotation
|
||||
|
||||
from TaintTracking::Configuration cfg, DataFlow::PathNode source, DataFlow::PathNode sink,
|
||||
Portal p
|
||||
where cfg.hasFlowPath(source, sink) and
|
||||
p = sink.getNode().(PortalEntrySink).getPortal() and
|
||||
// avoid constructing infeasible paths
|
||||
sink.getPathSummary().hasCall() = false
|
||||
from TaintTracking::Configuration cfg, DataFlow::PathNode source, DataFlow::PathNode sink, Portal p
|
||||
where
|
||||
cfg.hasFlowPath(source, sink) and
|
||||
p = sink.getNode().(PortalEntrySink).getPortal() and
|
||||
// avoid constructing infeasible paths
|
||||
sink.getPathSummary().hasCall() = false
|
||||
select p.toString(), sink.getPathSummary().getEndLabel().toString(), cfg.toString()
|
||||
|
||||
@@ -12,38 +12,28 @@ private import Shared
|
||||
* An additional source specified in an `additional-sources.csv` file.
|
||||
*/
|
||||
class AdditionalSourceSpec extends ExternalData {
|
||||
AdditionalSourceSpec() {
|
||||
this.getDataPath() = "additional-sources.csv"
|
||||
}
|
||||
AdditionalSourceSpec() { this.getDataPath() = "additional-sources.csv" }
|
||||
|
||||
/**
|
||||
* Gets the portal of this additional source.
|
||||
*/
|
||||
Portal getPortal() {
|
||||
result.toString() = getField(0)
|
||||
}
|
||||
Portal getPortal() { result.toString() = getField(0) }
|
||||
|
||||
/**
|
||||
* Gets the flow label of this source.
|
||||
*/
|
||||
DataFlow::FlowLabel getFlowLabel() {
|
||||
sourceFlowLabelSpec(result, getField(1))
|
||||
}
|
||||
DataFlow::FlowLabel getFlowLabel() { sourceFlowLabelSpec(result, getField(1)) }
|
||||
|
||||
/**
|
||||
* Gets the configuration for which this is a source, or any
|
||||
* configuration if this source does not specify a configuration.
|
||||
*/
|
||||
DataFlow::Configuration getConfiguration() {
|
||||
configSpec(result, getField(2))
|
||||
}
|
||||
DataFlow::Configuration getConfiguration() { configSpec(result, getField(2)) }
|
||||
|
||||
override string toString() {
|
||||
exists (string config |
|
||||
if getField(2) = "" then
|
||||
config = "any configuration"
|
||||
else
|
||||
config = getConfiguration() |
|
||||
exists(string config |
|
||||
if getField(2) = "" then config = "any configuration" else config = getConfiguration()
|
||||
|
|
||||
result = getPortal() + " as " + getFlowLabel() + " source for " + config
|
||||
)
|
||||
}
|
||||
@@ -52,9 +42,7 @@ class AdditionalSourceSpec extends ExternalData {
|
||||
private class AdditionalSourceFromSpec extends DataFlow::AdditionalSource {
|
||||
AdditionalSourceSpec spec;
|
||||
|
||||
AdditionalSourceFromSpec() {
|
||||
this = spec.getPortal().getAnExitNode(_)
|
||||
}
|
||||
AdditionalSourceFromSpec() { this = spec.getPortal().getAnExitNode(_) }
|
||||
|
||||
override predicate isSourceFor(DataFlow::Configuration cfg, DataFlow::FlowLabel lbl) {
|
||||
cfg = spec.getConfiguration() and lbl = spec.getFlowLabel()
|
||||
@@ -65,40 +53,30 @@ private class AdditionalSourceFromSpec extends DataFlow::AdditionalSource {
|
||||
* An additional sink specified in an `additional-sinks.csv` file.
|
||||
*/
|
||||
class AdditionalSinkSpec extends ExternalData {
|
||||
AdditionalSinkSpec() {
|
||||
this.getDataPath() = "additional-sinks.csv"
|
||||
}
|
||||
AdditionalSinkSpec() { this.getDataPath() = "additional-sinks.csv" }
|
||||
|
||||
/**
|
||||
* Gets the portal specification of this additional sink.
|
||||
*/
|
||||
Portal getPortal() {
|
||||
result.toString() = getField(0)
|
||||
}
|
||||
Portal getPortal() { result.toString() = getField(0) }
|
||||
|
||||
/**
|
||||
* Gets the flow label of this sink, or any standard flow label if this sink
|
||||
* does not specify a flow label.
|
||||
*/
|
||||
DataFlow::FlowLabel getFlowLabel() {
|
||||
sinkFlowLabelSpec(result, getField(1))
|
||||
}
|
||||
DataFlow::FlowLabel getFlowLabel() { sinkFlowLabelSpec(result, getField(1)) }
|
||||
|
||||
/**
|
||||
* Gets the configuration for which this is a sink, or any configuration if
|
||||
* this sink does not specify a configuration.
|
||||
*/
|
||||
DataFlow::Configuration getConfiguration() {
|
||||
configSpec(result, getField(2))
|
||||
}
|
||||
DataFlow::Configuration getConfiguration() { configSpec(result, getField(2)) }
|
||||
|
||||
override string toString() {
|
||||
exists (string labels, string config |
|
||||
exists(string labels, string config |
|
||||
labels = strictconcat(getFlowLabel(), " or ") and
|
||||
if getField(2) = "" then
|
||||
config = "any configuration"
|
||||
else
|
||||
config = getConfiguration() |
|
||||
if getField(2) = "" then config = "any configuration" else config = getConfiguration()
|
||||
|
|
||||
result = getPortal() + " as " + labels + " sink for " + config
|
||||
)
|
||||
}
|
||||
@@ -107,73 +85,59 @@ class AdditionalSinkSpec extends ExternalData {
|
||||
private class AdditionalSinkFromSpec extends DataFlow::AdditionalSink {
|
||||
AdditionalSinkSpec spec;
|
||||
|
||||
AdditionalSinkFromSpec() {
|
||||
this = spec.getPortal().getAnEntryNode(_)
|
||||
}
|
||||
AdditionalSinkFromSpec() { this = spec.getPortal().getAnEntryNode(_) }
|
||||
|
||||
override predicate isSinkFor(DataFlow::Configuration cfg, DataFlow::FlowLabel lbl) {
|
||||
cfg = spec.getConfiguration() and lbl = spec.getFlowLabel()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An additional flow step specified in an `additional-steps.csv` file.
|
||||
*/
|
||||
class AdditionalStepSpec extends ExternalData {
|
||||
AdditionalStepSpec() {
|
||||
this.getDataPath() = "additional-steps.csv"
|
||||
}
|
||||
AdditionalStepSpec() { this.getDataPath() = "additional-steps.csv" }
|
||||
|
||||
/**
|
||||
* Gets the start portal of this additional step.
|
||||
*/
|
||||
Portal getStartPortal() {
|
||||
result.toString() = getField(0)
|
||||
}
|
||||
Portal getStartPortal() { result.toString() = getField(0) }
|
||||
|
||||
/**
|
||||
* Gets the start flow label of this additional step.
|
||||
*/
|
||||
DataFlow::FlowLabel getStartFlowLabel() {
|
||||
result.toString() = getField(1)
|
||||
}
|
||||
DataFlow::FlowLabel getStartFlowLabel() { result.toString() = getField(1) }
|
||||
|
||||
/**
|
||||
* Gets the end portal of this additional step.
|
||||
*/
|
||||
Portal getEndPortal() {
|
||||
result.toString() = getField(2)
|
||||
}
|
||||
Portal getEndPortal() { result.toString() = getField(2) }
|
||||
|
||||
/**
|
||||
* Gets the end flow label of this additional step.
|
||||
*/
|
||||
DataFlow::FlowLabel getEndFlowLabel() {
|
||||
result.toString() = getField(3)
|
||||
}
|
||||
DataFlow::FlowLabel getEndFlowLabel() { result.toString() = getField(3) }
|
||||
|
||||
/**
|
||||
* Gets the configuration to which this step should be added.
|
||||
*/
|
||||
DataFlow::Configuration getConfiguration() {
|
||||
configSpec(result, getField(4))
|
||||
}
|
||||
DataFlow::Configuration getConfiguration() { configSpec(result, getField(4)) }
|
||||
|
||||
override string toString() {
|
||||
exists (string config |
|
||||
if getField(4) = "" then
|
||||
config = "any configuration"
|
||||
else
|
||||
config = getConfiguration() |
|
||||
result = "edge from " + getStartPortal() + " to " + getEndPortal() +
|
||||
", transforming " + getStartFlowLabel() + " into " + getEndFlowLabel() +
|
||||
" for " + config
|
||||
exists(string config |
|
||||
if getField(4) = "" then config = "any configuration" else config = getConfiguration()
|
||||
|
|
||||
result = "edge from " + getStartPortal() + " to " + getEndPortal() + ", transforming " +
|
||||
getStartFlowLabel() + " into " + getEndFlowLabel() + " for " + config
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private class AdditionalFlowStepFromSpec extends DataFlow::Configuration {
|
||||
AdditionalStepSpec spec;
|
||||
|
||||
DataFlow::Node entry;
|
||||
|
||||
DataFlow::Node exit;
|
||||
|
||||
AdditionalFlowStepFromSpec() {
|
||||
@@ -182,8 +146,10 @@ private class AdditionalFlowStepFromSpec extends DataFlow::Configuration {
|
||||
exit = spec.getEndPortal().getAnExitNode(_)
|
||||
}
|
||||
|
||||
override predicate isAdditionalFlowStep(DataFlow::Node pred, DataFlow::Node succ,
|
||||
DataFlow::FlowLabel predlbl, DataFlow::FlowLabel succlbl) {
|
||||
override predicate isAdditionalFlowStep(
|
||||
DataFlow::Node pred, DataFlow::Node succ, DataFlow::FlowLabel predlbl,
|
||||
DataFlow::FlowLabel succlbl
|
||||
) {
|
||||
pred = entry and
|
||||
succ = exit and
|
||||
predlbl = spec.getStartFlowLabel() and
|
||||
|
||||
@@ -27,14 +27,18 @@ external predicate additionalSinks(string portal, string flowLabel, string confi
|
||||
*
|
||||
* This predicate can be populated from the output of the `ExtractFlowStepSummaries` query.
|
||||
*/
|
||||
external predicate additionalSteps(string startPortal, string startFlowLabel, string endPortal, string endFlowLabel, string config);
|
||||
external predicate additionalSteps(
|
||||
string startPortal, string startFlowLabel, string endPortal, string endFlowLabel, string config
|
||||
);
|
||||
|
||||
/**
|
||||
* An additional source specified through the `additionalSources` predicate.
|
||||
*/
|
||||
private class AdditionalSourceFromSpec extends DataFlow::AdditionalSource {
|
||||
Portal portal;
|
||||
|
||||
string flowLabel;
|
||||
|
||||
string config;
|
||||
|
||||
AdditionalSourceFromSpec() {
|
||||
@@ -52,7 +56,9 @@ private class AdditionalSourceFromSpec extends DataFlow::AdditionalSource {
|
||||
*/
|
||||
private class AdditionalSinkFromSpec extends DataFlow::AdditionalSink {
|
||||
Portal portal;
|
||||
|
||||
string flowLabel;
|
||||
|
||||
string config;
|
||||
|
||||
AdditionalSinkFromSpec() {
|
||||
@@ -64,26 +70,33 @@ private class AdditionalSinkFromSpec extends DataFlow::AdditionalSink {
|
||||
configSpec(cfg, config) and sinkFlowLabelSpec(lbl, flowLabel)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An additional flow step specified through the `additionalSteps` predicate.
|
||||
*/
|
||||
private class AdditionalFlowStepFromSpec extends DataFlow::Configuration {
|
||||
DataFlow::Node entry;
|
||||
|
||||
string startFlowLabel;
|
||||
|
||||
DataFlow::Node exit;
|
||||
|
||||
string endFlowLabel;
|
||||
|
||||
AdditionalFlowStepFromSpec() {
|
||||
exists (Portal startPortal, Portal endPortal, string config |
|
||||
additionalSteps(startPortal.toString(), startFlowLabel, endPortal.toString(), endFlowLabel, config) and
|
||||
exists(Portal startPortal, Portal endPortal, string config |
|
||||
additionalSteps(startPortal.toString(), startFlowLabel, endPortal.toString(), endFlowLabel,
|
||||
config) and
|
||||
configSpec(this, config) and
|
||||
entry = startPortal.getAnEntryNode(_) and
|
||||
exit = endPortal.getAnExitNode(_)
|
||||
)
|
||||
}
|
||||
|
||||
override predicate isAdditionalFlowStep(DataFlow::Node pred, DataFlow::Node succ,
|
||||
DataFlow::FlowLabel predlbl, DataFlow::FlowLabel succlbl) {
|
||||
override predicate isAdditionalFlowStep(
|
||||
DataFlow::Node pred, DataFlow::Node succ, DataFlow::FlowLabel predlbl,
|
||||
DataFlow::FlowLabel succlbl
|
||||
) {
|
||||
pred = entry and
|
||||
succ = exit and
|
||||
predlbl = startFlowLabel and
|
||||
|
||||
@@ -8,9 +8,7 @@ import semmle.javascript.dataflow.Portals
|
||||
class PortalEntrySink extends DataFlow::AdditionalSink {
|
||||
Portal p;
|
||||
|
||||
PortalEntrySink() {
|
||||
this = p.getAnEntryNode(true)
|
||||
}
|
||||
PortalEntrySink() { this = p.getAnEntryNode(true) }
|
||||
|
||||
override predicate isSinkFor(DataFlow::Configuration cfg, DataFlow::FlowLabel lbl) {
|
||||
cfg instanceof TaintTracking::Configuration and
|
||||
@@ -18,7 +16,5 @@ class PortalEntrySink extends DataFlow::AdditionalSink {
|
||||
}
|
||||
|
||||
/** Gets the portal of which this is an entry node. */
|
||||
Portal getPortal() {
|
||||
result = p
|
||||
}
|
||||
Portal getPortal() { result = p }
|
||||
}
|
||||
|
||||
@@ -8,9 +8,7 @@ import semmle.javascript.dataflow.Portals
|
||||
class PortalExitSource extends DataFlow::AdditionalSource {
|
||||
Portal p;
|
||||
|
||||
PortalExitSource() {
|
||||
this = p.getAnExitNode(true)
|
||||
}
|
||||
PortalExitSource() { this = p.getAnExitNode(true) }
|
||||
|
||||
override predicate isSourceFor(DataFlow::Configuration cfg, DataFlow::FlowLabel lbl) {
|
||||
cfg instanceof TaintTracking::Configuration and
|
||||
@@ -18,7 +16,5 @@ class PortalExitSource extends DataFlow::AdditionalSource {
|
||||
}
|
||||
|
||||
/** Gets the portal of which this is an exit node. */
|
||||
Portal getPortal() {
|
||||
result = p
|
||||
}
|
||||
Portal getPortal() { result = p }
|
||||
}
|
||||
|
||||
@@ -50,16 +50,14 @@ predicate sinkFlowLabelSpec(DataFlow::FlowLabel lbl, string spec) {
|
||||
class AnnotationComment extends Comment {
|
||||
string ann;
|
||||
|
||||
AnnotationComment() {
|
||||
ann = getText().regexpCapture("(?s)\\s*Semmle:(.*)", 1)
|
||||
}
|
||||
AnnotationComment() { ann = getText().regexpCapture("(?s)\\s*Semmle:(.*)", 1) }
|
||||
|
||||
/**
|
||||
* Holds if this comment applies to `nd`, that is, it starts on the same line on
|
||||
* which `nd` ends.
|
||||
*/
|
||||
predicate appliesTo(DataFlow::Node nd) {
|
||||
exists (string file, int line |
|
||||
exists(string file, int line |
|
||||
getLocation().hasLocationInfo(file, line, _, _, _) and
|
||||
nd.hasLocationInfo(file, _, _, line, _)
|
||||
)
|
||||
@@ -71,7 +69,7 @@ class AnnotationComment extends Comment {
|
||||
* any configuration.
|
||||
*/
|
||||
predicate specifiesSource(DataFlow::FlowLabel label, DataFlow::Configuration config) {
|
||||
exists (string spec |
|
||||
exists(string spec |
|
||||
spec = ann.regexpFind("(?<=\\bsource:)\\s*[^\\s,]+(\\s*,\\s*[^\\s,])?", _, _) and
|
||||
sourceFlowLabelSpec(label, spec.splitAt(",", 0).trim()) and
|
||||
configSpec(config, spec.splitAt(",", 1).trim())
|
||||
@@ -84,7 +82,7 @@ class AnnotationComment extends Comment {
|
||||
* any configuration.
|
||||
*/
|
||||
predicate specifiesSink(string label, string config) {
|
||||
exists (string spec |
|
||||
exists(string spec |
|
||||
spec = ann.regexpFind("(?<=\\bsink:)\\s*[^\\s,]+(\\s*,\\s*[^\\s,]+)?", _, _) and
|
||||
sinkFlowLabelSpec(label, spec.splitAt(",", 0).trim()) and
|
||||
configSpec(config, spec.splitAt(",", 1).trim())
|
||||
|
||||
@@ -20,29 +20,25 @@ private newtype TPortal =
|
||||
NpmPackagePortal::imports(_, pkgName, _) or
|
||||
NpmPackagePortal::exports(pkgName, _) or
|
||||
MemberPortal::exports(pkgName, _, _)
|
||||
}
|
||||
or
|
||||
} or
|
||||
MkMemberPortal(Portal base, string prop) {
|
||||
(
|
||||
MemberPortal::reads(base, prop, _, _) or
|
||||
MemberPortal::writes(base, prop, _, _)
|
||||
MemberPortal::reads(base, prop, _, _) or
|
||||
MemberPortal::writes(base, prop, _, _)
|
||||
) and
|
||||
// only consider alpha-numeric properties, excluding special properties
|
||||
// and properties whose names look like they are meant to be internal
|
||||
prop.regexpMatch("(?!prototype$|__)[a-zA-Z_]\\w*")
|
||||
}
|
||||
or
|
||||
} or
|
||||
MkInstancePortal(Portal base) {
|
||||
InstancePortal::instanceUse(base, _, _) or
|
||||
InstancePortal::instanceDef(base, _, _) or
|
||||
InstancePortal::instanceMemberDef(base, _, _, _)
|
||||
}
|
||||
or
|
||||
} or
|
||||
MkParameterPortal(Portal base, int i) {
|
||||
ParameterPortal::parameter(base, i, _, _) or
|
||||
ParameterPortal::argument(base, i, _, _)
|
||||
}
|
||||
or
|
||||
} or
|
||||
MkReturnPortal(Portal base) {
|
||||
ReturnPortal::calls(_, base, _) or
|
||||
ReturnPortal::returns(base, _, _)
|
||||
@@ -51,26 +47,30 @@ private newtype TPortal =
|
||||
/**
|
||||
* A portal, that is, an interface point between different npm packages.
|
||||
*/
|
||||
cached class Portal extends TPortal {
|
||||
cached
|
||||
class Portal extends TPortal {
|
||||
/**
|
||||
* Gets an exit node for this portal, that is, a node from which data
|
||||
* that comes through the portal emerges. The flag `isRemote`
|
||||
* indicates whether data read from this node may come from a different
|
||||
* package.
|
||||
*/
|
||||
abstract cached DataFlow::SourceNode getAnExitNode(boolean isRemote);
|
||||
cached
|
||||
abstract DataFlow::SourceNode getAnExitNode(boolean isRemote);
|
||||
|
||||
/**
|
||||
* Gets an entry node for this portal, that is, a node through which data
|
||||
* enters the portal. The flag `escapes` indicates whether data written to
|
||||
* the node may escape to a different package.
|
||||
*/
|
||||
abstract cached DataFlow::Node getAnEntryNode(boolean escapes);
|
||||
cached
|
||||
abstract DataFlow::Node getAnEntryNode(boolean escapes);
|
||||
|
||||
/**
|
||||
* Gets the member portal with the given `name` of this portal, if any.
|
||||
*/
|
||||
cached MemberPortal getMember(string name) {
|
||||
cached
|
||||
MemberPortal getMember(string name) {
|
||||
result.getName() = name and
|
||||
result.getBasePortal() = this
|
||||
}
|
||||
@@ -78,14 +78,14 @@ cached class Portal extends TPortal {
|
||||
/**
|
||||
* Gets the instance portal of this portal, if any.
|
||||
*/
|
||||
cached InstancePortal getInstance() {
|
||||
result.getBasePortal() = this
|
||||
}
|
||||
cached
|
||||
InstancePortal getInstance() { result.getBasePortal() = this }
|
||||
|
||||
/**
|
||||
* Gets the portal of parameter `idx` of this portal, if any.
|
||||
*/
|
||||
cached ParameterPortal getParameter(int idx) {
|
||||
cached
|
||||
ParameterPortal getParameter(int idx) {
|
||||
result.getIndex() = idx and
|
||||
result.getBasePortal() = this
|
||||
}
|
||||
@@ -93,9 +93,8 @@ cached class Portal extends TPortal {
|
||||
/**
|
||||
* Gets the return value portal of this portal, if any.
|
||||
*/
|
||||
cached ReturnPortal getReturn() {
|
||||
result.getBasePortal() = this
|
||||
}
|
||||
cached
|
||||
ReturnPortal getReturn() { result.getBasePortal() = this }
|
||||
|
||||
/**
|
||||
* Gets a textual representation of this portal.
|
||||
@@ -103,7 +102,8 @@ cached class Portal extends TPortal {
|
||||
* Different portals must have different `toString`s, so the result of
|
||||
* this predicate can be used to uniquely identify a portal.
|
||||
*/
|
||||
cached abstract string toString();
|
||||
cached
|
||||
abstract string toString();
|
||||
|
||||
/**
|
||||
* INTERNAL: Do not use outside this library.
|
||||
@@ -111,7 +111,8 @@ cached class Portal extends TPortal {
|
||||
* The constructor depth of this portal, used to limit the number of
|
||||
* portals.
|
||||
*/
|
||||
cached abstract int depth();
|
||||
cached
|
||||
abstract int depth();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -125,14 +126,10 @@ cached class Portal extends TPortal {
|
||||
private class NpmPackagePortal extends Portal, MkNpmPackagePortal {
|
||||
string pkgName;
|
||||
|
||||
NpmPackagePortal() {
|
||||
this = MkNpmPackagePortal(pkgName)
|
||||
}
|
||||
NpmPackagePortal() { this = MkNpmPackagePortal(pkgName) }
|
||||
|
||||
/** Gets the name of the npm package. */
|
||||
string getName() {
|
||||
result = pkgName
|
||||
}
|
||||
string getName() { result = pkgName }
|
||||
|
||||
override DataFlow::SourceNode getAnExitNode(boolean isRemote) {
|
||||
NpmPackagePortal::imports(result, pkgName) and
|
||||
@@ -159,14 +156,16 @@ private module NpmPackagePortal {
|
||||
|
||||
/** Gets an import of `member` from `imported` inside package `importer`. */
|
||||
pragma[noinline]
|
||||
private DataFlow::SourceNode getAModuleMemberImport(NPMPackage importer, string imported, string member) {
|
||||
private DataFlow::SourceNode getAModuleMemberImport(
|
||||
NPMPackage importer, string imported, string member
|
||||
) {
|
||||
result = DataFlow::moduleMember(imported, member) and
|
||||
result.getTopLevel() = importer.getAModule()
|
||||
}
|
||||
|
||||
/** Holds if `imp` is an import of package `pkgName`. */
|
||||
predicate imports(DataFlow::SourceNode imp, string pkgName) {
|
||||
exists (NPMPackage pkg |
|
||||
exists(NPMPackage pkg |
|
||||
imp = getAModuleImport(pkg, pkgName) and
|
||||
pkg.declaresDependency(pkgName, _)
|
||||
)
|
||||
@@ -174,7 +173,7 @@ private module NpmPackagePortal {
|
||||
|
||||
/** Holds if `imp` imports `member` from package `pkgName`. */
|
||||
predicate imports(DataFlow::SourceNode imp, string pkgName, string member) {
|
||||
exists (NPMPackage pkg |
|
||||
exists(NPMPackage pkg |
|
||||
imp = getAModuleMemberImport(pkg, pkgName, member) and
|
||||
pkg.declaresDependency(pkgName, _)
|
||||
)
|
||||
@@ -182,11 +181,11 @@ private module NpmPackagePortal {
|
||||
|
||||
/** Gets the main module of package `pkgName`. */
|
||||
Module packageMain(string pkgName) {
|
||||
exists (PackageJSON pkg |
|
||||
exists(PackageJSON pkg |
|
||||
// don't construct portals for private packages
|
||||
not pkg.isPrivate() and
|
||||
// don't construct portals for vendored-in packages
|
||||
exists (Folder pkgDir | pkgDir = pkg.getFile().getParentContainer() |
|
||||
exists(Folder pkgDir | pkgDir = pkg.getFile().getParentContainer() |
|
||||
pkgDir.getRelativePath() = ""
|
||||
or
|
||||
not pkgDir.getParentContainer().getBaseName() = "node_modules"
|
||||
@@ -198,8 +197,8 @@ private module NpmPackagePortal {
|
||||
|
||||
/** Holds if the main module of package `pkgName` exports `exp`. */
|
||||
predicate exports(string pkgName, DataFlow::Node exp) {
|
||||
exists (Module m | m = packageMain(pkgName) |
|
||||
exists (AnalyzedPropertyWrite apw |
|
||||
exists(Module m | m = packageMain(pkgName) |
|
||||
exists(AnalyzedPropertyWrite apw |
|
||||
apw.writes(m.(AnalyzedModule).getModuleObject(), "exports", exp)
|
||||
)
|
||||
or
|
||||
@@ -213,14 +212,12 @@ private module NpmPackagePortal {
|
||||
*
|
||||
* This is a somewhat crude way of preventing us from constructing infinitely many portals.
|
||||
*/
|
||||
private int maxdepth() {
|
||||
result = 10
|
||||
}
|
||||
private int maxdepth() { result = 10 }
|
||||
|
||||
/**
|
||||
* A portal that is constructed over some base portal.
|
||||
*/
|
||||
private abstract class CompoundPortal extends Portal {
|
||||
abstract private class CompoundPortal extends Portal {
|
||||
Portal base;
|
||||
|
||||
bindingset[this]
|
||||
@@ -230,9 +227,7 @@ private abstract class CompoundPortal extends Portal {
|
||||
}
|
||||
|
||||
/** Gets the base portal over which this portal is constructed. */
|
||||
Portal getBasePortal() {
|
||||
result = base
|
||||
}
|
||||
Portal getBasePortal() { result = base }
|
||||
|
||||
override int depth() { result = base.depth() + 1 }
|
||||
}
|
||||
@@ -249,9 +244,7 @@ private class MemberPortal extends CompoundPortal, MkMemberPortal {
|
||||
MemberPortal() { this = MkMemberPortal(base, prop) }
|
||||
|
||||
/** Gets the name of this member. */
|
||||
string getName() {
|
||||
result = prop
|
||||
}
|
||||
string getName() { result = prop }
|
||||
|
||||
override DataFlow::SourceNode getAnExitNode(boolean isRemote) {
|
||||
MemberPortal::reads(base, prop, result, isRemote)
|
||||
@@ -277,7 +270,7 @@ private module MemberPortal {
|
||||
read = portalBaseRef(base, isRemote).getAPropertyRead(prop)
|
||||
or
|
||||
// imports are a kind of property read
|
||||
exists (string pkg |
|
||||
exists(string pkg |
|
||||
NpmPackagePortal::imports(read, pkg, prop) and
|
||||
base = MkNpmPackagePortal(pkg) and
|
||||
isRemote = false
|
||||
@@ -286,7 +279,7 @@ private module MemberPortal {
|
||||
|
||||
/** Holds if the main module of `pkgName` exports `rhs` under the name `prop`. */
|
||||
predicate exports(string pkgName, string prop, DataFlow::Node rhs) {
|
||||
exists (AnalyzedModule m, AnalyzedPropertyWrite apw |
|
||||
exists(AnalyzedModule m, AnalyzedPropertyWrite apw |
|
||||
m = NpmPackagePortal::packageMain(pkgName) and
|
||||
apw.writes(m.getAnExportsValue(), prop, rhs)
|
||||
)
|
||||
@@ -302,7 +295,7 @@ private module MemberPortal {
|
||||
InstancePortal::instanceMemberDef(base.(InstancePortal).getBasePortal(), prop, rhs, escapes)
|
||||
or
|
||||
// exports are a kind of property write.
|
||||
exists (string pkgName |
|
||||
exists(string pkgName |
|
||||
exports(pkgName, prop, rhs) and
|
||||
base = MkNpmPackagePortal(pkgName) and
|
||||
escapes = true
|
||||
@@ -341,11 +334,13 @@ private module InstancePortal {
|
||||
private predicate instantiable(DataFlow::Node ctor) {
|
||||
ctor.getAstNode() instanceof ClassDefinition
|
||||
or
|
||||
exists (ThisExpr thiz | ctor = thiz.getBinder().flow())
|
||||
exists(ThisExpr thiz | ctor = thiz.getBinder().flow())
|
||||
}
|
||||
|
||||
/** Holds if `i` represents instances of `ctor`, which flows into `base`. */
|
||||
private predicate isInstance(Portal base, DataFlow::SourceNode ctor, AbstractInstance i, boolean escapes) {
|
||||
private predicate isInstance(
|
||||
Portal base, DataFlow::SourceNode ctor, AbstractInstance i, boolean escapes
|
||||
) {
|
||||
ctor = DataFlow::valueNode(i.getConstructor().getDefinition()) and
|
||||
ctor.flowsTo(base.getAnEntryNode(escapes)) and
|
||||
instantiable(ctor)
|
||||
@@ -363,17 +358,19 @@ private module InstancePortal {
|
||||
* right-hand side of that definition.
|
||||
*/
|
||||
predicate instanceMemberDef(Portal base, string name, DataFlow::Node rhs, boolean escapes) {
|
||||
exists (AbstractInstance i, DataFlow::SourceNode ctor | isInstance(base, ctor, i, escapes) |
|
||||
exists(AbstractInstance i, DataFlow::SourceNode ctor | isInstance(base, ctor, i, escapes) |
|
||||
// ES2015 instance method
|
||||
exists (MemberDefinition mem |
|
||||
exists(MemberDefinition mem |
|
||||
mem = ctor.getAstNode().(ClassDefinition).getAMember() and
|
||||
not mem.isStatic() and not mem instanceof ConstructorDefinition |
|
||||
not mem.isStatic() and
|
||||
not mem instanceof ConstructorDefinition
|
||||
|
|
||||
name = mem.getName() and
|
||||
rhs = DataFlow::valueNode(mem.getInit())
|
||||
)
|
||||
or
|
||||
// ES5 instance method
|
||||
exists (DataFlow::PropWrite pw |
|
||||
exists(DataFlow::PropWrite pw |
|
||||
pw = ctor.getAPropertyRead("prototype").getAPropertyWrite(name) and
|
||||
rhs = pw.getRhs()
|
||||
)
|
||||
@@ -382,7 +379,7 @@ private module InstancePortal {
|
||||
|
||||
/** Holds if `nd` is a return node of a function flowing into `base`. */
|
||||
predicate instanceDef(Portal base, DataFlow::Node nd, boolean escapes) {
|
||||
exists (DataFlow::FunctionNode fn |
|
||||
exists(DataFlow::FunctionNode fn |
|
||||
isInstance(base, fn, _, escapes) and
|
||||
nd = fn.getAReturn() and
|
||||
instantiable(fn)
|
||||
@@ -402,9 +399,7 @@ class ParameterPortal extends CompoundPortal, MkParameterPortal {
|
||||
ParameterPortal() { this = MkParameterPortal(base, i) }
|
||||
|
||||
/** Gets the index of the parameterb represented by this portal. */
|
||||
int getIndex() {
|
||||
result = i
|
||||
}
|
||||
int getIndex() { result = i }
|
||||
|
||||
override DataFlow::SourceNode getAnExitNode(boolean isRemote) {
|
||||
ParameterPortal::parameter(base, i, result, isRemote)
|
||||
@@ -425,7 +420,7 @@ private module ParameterPortal {
|
||||
|
||||
/** Holds if `arg` is the `i`th argument passed to an invocation of a function flowing through `base`. */
|
||||
predicate argument(Portal base, int i, DataFlow::Node arg, boolean escapes) {
|
||||
exists (DataFlow::InvokeNode invk |
|
||||
exists(DataFlow::InvokeNode invk |
|
||||
invk = base.getAnExitNode(escapes).getAnInvocation() and
|
||||
arg = invk.getArgument(i)
|
||||
)
|
||||
|
||||
@@ -286,9 +286,7 @@ class PathSummary extends TPathSummary {
|
||||
boolean hasCall() { result = hasCall }
|
||||
|
||||
/** Gets the flow label describing the value at the start of this flow path. */
|
||||
FlowLabel getStartLabel() {
|
||||
result = start
|
||||
}
|
||||
FlowLabel getStartLabel() { result = start }
|
||||
|
||||
/** Gets the flow label describing the value at the end of this flow path. */
|
||||
FlowLabel getEndLabel() { result = end }
|
||||
|
||||
Reference in New Issue
Block a user