diff --git a/javascript/ql/src/Security/Summaries/ImportFromCsv.qll b/javascript/ql/src/Security/Summaries/ImportFromCsv.qll index 9be65514323..88be9c2d851 100644 --- a/javascript/ql/src/Security/Summaries/ImportFromCsv.qll +++ b/javascript/ql/src/Security/Summaries/ImportFromCsv.qll @@ -6,6 +6,7 @@ import javascript import semmle.javascript.dataflow.Portals import external.ExternalArtifact +private import Shared /** * An additional source specified in an `additional-sources.csv` file. @@ -26,18 +27,25 @@ class AdditionalSourceSpec extends ExternalData { * Gets the flow label of this source. */ DataFlow::FlowLabel getFlowLabel() { - result.toString() = getField(1) + sourceFlowLabelSpec(result, getField(1)) } /** - * Gets the configuration for which this is a source. + * Gets the configuration for which this is a source, or any + * configuration if this source does not specify a configuration. */ DataFlow::Configuration getConfiguration() { - result.toString() = getField(2) + configSpec(result, getField(2)) } override string toString() { - result = getPortal() + " as " + getFlowLabel() + " source for " + getConfiguration() + exists (string config | + if getField(2) = "" then + config = "any configuration" + else + config = getConfiguration() | + result = getPortal() + " as " + getFlowLabel() + " source for " + config + ) } } @@ -69,21 +77,30 @@ class AdditionalSinkSpec extends ExternalData { } /** - * Gets the flow label of this sink. + * Gets the flow label of this sink, or any standard flow label if this sink + * does not specify a flow label. */ DataFlow::FlowLabel getFlowLabel() { - result.toString() = getField(1) + sinkFlowLabelSpec(result, getField(1)) } /** - * Gets the configuration for which this is a sink. + * Gets the configuration for which this is a sink, or any configuration if + * this sink does not specify a configuration. */ DataFlow::Configuration getConfiguration() { - result.toString() = getField(2) + configSpec(result, getField(2)) } override string toString() { - result = getPortal() + " as " + getFlowLabel() + " sink for " + getConfiguration() + exists (string labels, string config | + labels = strictconcat(getFlowLabel(), " or ") and + if getField(2) = "" then + config = "any configuration" + else + config = getConfiguration() | + result = getPortal() + " as " + labels + " sink for " + config + ) } } @@ -138,13 +155,19 @@ class AdditionalStepSpec extends ExternalData { * Gets the configuration to which this step should be added. */ DataFlow::Configuration getConfiguration() { - result.toString() = getField(4) + configSpec(result, getField(4)) } override string toString() { - result = "edge from " + getStartPortal() + " to " + getEndPortal() + - ", transforming " + getStartFlowLabel() + " into " + getEndFlowLabel() + - " for " + getConfiguration() + 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 + ) } } diff --git a/javascript/ql/src/Security/Summaries/ImportFromExternalPredicates.qll b/javascript/ql/src/Security/Summaries/ImportFromExternalPredicates.qll index cc6a4d50f2d..c976708c6c6 100644 --- a/javascript/ql/src/Security/Summaries/ImportFromExternalPredicates.qll +++ b/javascript/ql/src/Security/Summaries/ImportFromExternalPredicates.qll @@ -6,6 +6,7 @@ import javascript import semmle.javascript.dataflow.Portals import external.ExternalArtifact +import Shared /** * An external predicate providing information about additional sources. @@ -42,8 +43,7 @@ private class AdditionalSourceFromSpec extends DataFlow::AdditionalSource { } override predicate isSourceFor(DataFlow::Configuration cfg, DataFlow::FlowLabel lbl) { - cfg.toString() = config and - lbl = flowLabel + configSpec(cfg, config) and sourceFlowLabelSpec(lbl, flowLabel) } } @@ -61,8 +61,7 @@ private class AdditionalSinkFromSpec extends DataFlow::AdditionalSink { } override predicate isSinkFor(DataFlow::Configuration cfg, DataFlow::FlowLabel lbl) { - cfg.toString() = config and - lbl = flowLabel + configSpec(cfg, config) and sinkFlowLabelSpec(lbl, flowLabel) } } /** @@ -75,8 +74,9 @@ private class AdditionalFlowStepFromSpec extends DataFlow::Configuration { string endFlowLabel; AdditionalFlowStepFromSpec() { - exists (Portal startPortal, Portal endPortal | - additionalSteps(startPortal.toString(), startFlowLabel, endPortal.toString(), endFlowLabel, this) 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(_) ) diff --git a/javascript/ql/src/Security/Summaries/Shared.qll b/javascript/ql/src/Security/Summaries/Shared.qll new file mode 100644 index 00000000000..d34e68e6a30 --- /dev/null +++ b/javascript/ql/src/Security/Summaries/Shared.qll @@ -0,0 +1,37 @@ +/** + * Provides utility predicates for working with flow summary specifications. + */ + +import javascript + +/** + * Holds if `config` matches `spec`, that is, either `spec` is the name of `config` + * or `spec` is the empty string and `config` is an arbitrary configuration. + */ +predicate configSpec(DataFlow::Configuration config, string spec) { + config.toString() = spec + or + spec = "" +} + +/** + * Holds if `lbl` matches `spec`, that is, either `spec` is the name of `config` + * or `spec` is the empty string and `lbl` is the built-in flow label `data`. + */ +predicate sourceFlowLabelSpec(DataFlow::FlowLabel lbl, string spec) { + lbl.toString() = spec + or + spec = "" and + lbl = DataFlow::FlowLabel::data() +} + +/** + * Holds if `lbl` matches `spec`, that is, either `spec` is the name of `config` + * or `spec` is the empty string and `lbl` is an arbitrary standard flow label. + */ +predicate sinkFlowLabelSpec(DataFlow::FlowLabel lbl, string spec) { + lbl.toString() = spec + or + spec = "" and + lbl instanceof DataFlow::StandardFlowLabel +}