mirror of
https://github.com/github/codeql.git
synced 2025-12-21 11:16:30 +01:00
JS: Support for dynamic args to flow summaries
This commit is contained in:
@@ -24,6 +24,8 @@ private module ConsistencyConfig implements InputSig<Location, JSDataFlow> {
|
|||||||
or
|
or
|
||||||
n instanceof FlowSummaryIntermediateAwaitStoreNode
|
n instanceof FlowSummaryIntermediateAwaitStoreNode
|
||||||
or
|
or
|
||||||
|
n instanceof FlowSummaryDynamicParameterArrayNode
|
||||||
|
or
|
||||||
n instanceof GenericSynthesizedNode
|
n instanceof GenericSynthesizedNode
|
||||||
or
|
or
|
||||||
n = DataFlow::globalAccessPathRootPseudoNode()
|
n = DataFlow::globalAccessPathRootPseudoNode()
|
||||||
@@ -43,6 +45,10 @@ private module ConsistencyConfig implements InputSig<Location, JSDataFlow> {
|
|||||||
node instanceof TStaticArgumentArrayNode or
|
node instanceof TStaticArgumentArrayNode or
|
||||||
node instanceof TDynamicArgumentArrayNode
|
node instanceof TDynamicArgumentArrayNode
|
||||||
}
|
}
|
||||||
|
|
||||||
|
predicate reverseReadExclude(DataFlow::Node node) {
|
||||||
|
node instanceof FlowSummaryDynamicParameterArrayNode
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module Consistency = MakeConsistency<Location, JSDataFlow, JSTaintFlow, ConsistencyConfig>;
|
module Consistency = MakeConsistency<Location, JSDataFlow, JSTaintFlow, ConsistencyConfig>;
|
||||||
|
|||||||
@@ -80,6 +80,7 @@ private module Cached {
|
|||||||
TConstructorThisArgumentNode(InvokeExpr e) { e instanceof NewExpr or e instanceof SuperCall } or
|
TConstructorThisArgumentNode(InvokeExpr e) { e instanceof NewExpr or e instanceof SuperCall } or
|
||||||
TConstructorThisPostUpdate(Constructor ctor) or
|
TConstructorThisPostUpdate(Constructor ctor) or
|
||||||
TFlowSummaryNode(FlowSummaryImpl::Private::SummaryNode sn) or
|
TFlowSummaryNode(FlowSummaryImpl::Private::SummaryNode sn) or
|
||||||
|
TFlowSummaryDynamicParameterArrayNode(FlowSummaryImpl::Public::SummarizedCallable callable) or
|
||||||
TFlowSummaryIntermediateAwaitStoreNode(FlowSummaryImpl::Private::SummaryNode sn) {
|
TFlowSummaryIntermediateAwaitStoreNode(FlowSummaryImpl::Private::SummaryNode sn) {
|
||||||
// NOTE: This dependency goes through the 'Steps' module whose instantiation depends on the call graph,
|
// 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.
|
// but the specific predicate we're referering to does not use that information.
|
||||||
|
|||||||
@@ -30,6 +30,19 @@ class FlowSummaryNode extends DataFlow::Node, TFlowSummaryNode {
|
|||||||
override string toString() { result = this.getSummaryNode().toString() }
|
override string toString() { result = this.getSummaryNode().toString() }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class FlowSummaryDynamicParameterArrayNode extends DataFlow::Node,
|
||||||
|
TFlowSummaryDynamicParameterArrayNode
|
||||||
|
{
|
||||||
|
private FlowSummaryImpl::Public::SummarizedCallable callable;
|
||||||
|
|
||||||
|
FlowSummaryDynamicParameterArrayNode() { this = TFlowSummaryDynamicParameterArrayNode(callable) }
|
||||||
|
|
||||||
|
FlowSummaryImpl::Public::SummarizedCallable getSummarizedCallable() { result = callable }
|
||||||
|
|
||||||
|
cached
|
||||||
|
override string toString() { result = "[dynamic parameter array] " + callable }
|
||||||
|
}
|
||||||
|
|
||||||
class FlowSummaryIntermediateAwaitStoreNode extends DataFlow::Node,
|
class FlowSummaryIntermediateAwaitStoreNode extends DataFlow::Node,
|
||||||
TFlowSummaryIntermediateAwaitStoreNode
|
TFlowSummaryIntermediateAwaitStoreNode
|
||||||
{
|
{
|
||||||
@@ -342,6 +355,12 @@ private predicate isParameterNodeImpl(Node p, DataFlowCallable c, ParameterPosit
|
|||||||
FlowSummaryImpl::Private::summaryParameterNode(summaryNode.getSummaryNode(), pos) and
|
FlowSummaryImpl::Private::summaryParameterNode(summaryNode.getSummaryNode(), pos) and
|
||||||
c.asLibraryCallable() = summaryNode.getSummarizedCallable()
|
c.asLibraryCallable() = summaryNode.getSummarizedCallable()
|
||||||
)
|
)
|
||||||
|
or
|
||||||
|
exists(FlowSummaryImpl::Public::SummarizedCallable callable |
|
||||||
|
c.asLibraryCallable() = callable and
|
||||||
|
pos.isDynamicArgumentArray() and
|
||||||
|
p = TFlowSummaryDynamicParameterArrayNode(callable)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
predicate isParameterNode(ParameterNode p, DataFlowCallable c, ParameterPosition pos) {
|
predicate isParameterNode(ParameterNode p, DataFlowCallable c, ParameterPosition pos) {
|
||||||
@@ -410,6 +429,8 @@ DataFlowCallable nodeGetEnclosingCallable(Node node) {
|
|||||||
or
|
or
|
||||||
result.asLibraryCallable() = node.(FlowSummaryNode).getSummarizedCallable()
|
result.asLibraryCallable() = node.(FlowSummaryNode).getSummarizedCallable()
|
||||||
or
|
or
|
||||||
|
result.asLibraryCallable() = node.(FlowSummaryDynamicParameterArrayNode).getSummarizedCallable()
|
||||||
|
or
|
||||||
result.asLibraryCallable() = node.(FlowSummaryIntermediateAwaitStoreNode).getSummarizedCallable()
|
result.asLibraryCallable() = node.(FlowSummaryIntermediateAwaitStoreNode).getSummarizedCallable()
|
||||||
or
|
or
|
||||||
node = TGenericSynthesizedNode(_, _, result)
|
node = TGenericSynthesizedNode(_, _, result)
|
||||||
@@ -1118,6 +1139,17 @@ predicate readStep(Node node1, ContentSet c, Node node2) {
|
|||||||
storeContent.isUnknownArrayElement()
|
storeContent.isUnknownArrayElement()
|
||||||
else storeContent.asArrayIndex() = n + c.asArrayIndex()
|
else storeContent.asArrayIndex() = n + c.asArrayIndex()
|
||||||
)
|
)
|
||||||
|
or
|
||||||
|
exists(FlowSummaryNode parameter, ParameterPosition pos |
|
||||||
|
FlowSummaryImpl::Private::summaryParameterNode(parameter.getSummaryNode(), pos) and
|
||||||
|
node1 = TFlowSummaryDynamicParameterArrayNode(parameter.getSummarizedCallable()) and
|
||||||
|
node2 = parameter and
|
||||||
|
(
|
||||||
|
c.asArrayIndex() = pos.asPositional()
|
||||||
|
or
|
||||||
|
c = ContentSet::arrayElementLowerBound(pos.asPositionalLowerBound())
|
||||||
|
)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Gets the post-update node for which `node` is the corresponding pre-update node. */
|
/** Gets the post-update node for which `node` is the corresponding pre-update node. */
|
||||||
|
|||||||
@@ -35,8 +35,6 @@ private predicate positionName(ParameterPosition pos, string operand) {
|
|||||||
or
|
or
|
||||||
pos.isFunctionSelfReference() and operand = "function"
|
pos.isFunctionSelfReference() and operand = "function"
|
||||||
or
|
or
|
||||||
pos.isDynamicArgumentArray() and operand = "arguments-array" // TODO: remove and handle automatically
|
|
||||||
or
|
|
||||||
operand = pos.asPositionalLowerBound() + ".."
|
operand = pos.asPositionalLowerBound() + ".."
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -101,17 +101,11 @@ class ArrayConstructorSummary extends SummarizedCallable {
|
|||||||
|
|
||||||
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
|
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
|
||||||
preservesValue = true and
|
preservesValue = true and
|
||||||
(
|
input = "Argument[0..]" and
|
||||||
input = "Argument[0..]" and
|
output = "ReturnValue.ArrayElement"
|
||||||
output = "ReturnValue.ArrayElement"
|
|
||||||
or
|
|
||||||
input = "Argument[arguments-array].WithArrayElement" and
|
|
||||||
output = "ReturnValue"
|
|
||||||
)
|
|
||||||
or
|
or
|
||||||
// TODO: workaround for WithArrayElement not being converted to a taint step
|
|
||||||
preservesValue = false and
|
preservesValue = false and
|
||||||
input = "Argument[arguments-array]" and
|
input = "Argument[0..]" and
|
||||||
output = "ReturnValue"
|
output = "ReturnValue"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -437,8 +431,7 @@ class PushLike extends SummarizedCallable {
|
|||||||
|
|
||||||
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
|
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
|
||||||
preservesValue = true and
|
preservesValue = true and
|
||||||
// TODO: make it so `arguments-array` is handled without needing to reference it explicitly in every flow-summary
|
input = "Argument[0..]" and
|
||||||
input = ["Argument[0..]", "Argument[arguments-array].ArrayElement"] and
|
|
||||||
output = "Argument[this].ArrayElement"
|
output = "Argument[this].ArrayElement"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +0,0 @@
|
|||||||
| library-tests/FlowSummary/tst.js:278 | expected an alert, but found none | NOT OK | ConsistencyConfig |
|
|
||||||
| library-tests/FlowSummary/tst.js:282 | expected an alert, but found none | NOT OK | ConsistencyConfig |
|
|
||||||
| library-tests/FlowSummary/tst.js:283 | expected an alert, but found none | NOT OK | ConsistencyConfig |
|
|
||||||
| library-tests/FlowSummary/tst.js:286 | expected an alert, but found none | NOT OK | ConsistencyConfig |
|
|
||||||
| library-tests/FlowSummary/tst.js:287 | expected an alert, but found none | NOT OK | ConsistencyConfig |
|
|
||||||
| library-tests/FlowSummary/tst.js:290 | expected an alert, but found none | NOT OK | ConsistencyConfig |
|
|
||||||
| library-tests/FlowSummary/tst.js:291 | expected an alert, but found none | NOT OK | ConsistencyConfig |
|
|
||||||
|
|||||||
@@ -275,19 +275,27 @@ function m18() {
|
|||||||
const dynamicParam0 = mkSummary("Argument[0..]", "ReturnValue");
|
const dynamicParam0 = mkSummary("Argument[0..]", "ReturnValue");
|
||||||
const dynamicParam1 = mkSummary("Argument[1..]", "ReturnValue");
|
const dynamicParam1 = mkSummary("Argument[1..]", "ReturnValue");
|
||||||
|
|
||||||
sink(staticParam0(...source())); // NOT OK
|
sink(staticParam0(...[source()])); // NOT OK
|
||||||
sink(staticParam0("safe", ...source())); // OK
|
sink(staticParam0(...["safe", source()])); // OK
|
||||||
|
sink(staticParam0(...[source(), "safe", ])); // NOT OK
|
||||||
|
sink(staticParam0("safe", ...[source()])); // OK
|
||||||
sink(staticParam0(source(), ...["safe"])); // NOT OK
|
sink(staticParam0(source(), ...["safe"])); // NOT OK
|
||||||
|
|
||||||
sink(staticParam1(...source())); // NOT OK
|
sink(staticParam1(...[source()])); // OK
|
||||||
sink(staticParam1("safe", ...source())); // NOT OK
|
sink(staticParam1(...["safe", source()])); // NOT OK
|
||||||
|
sink(staticParam1(...[source(), "safe", ])); // OK
|
||||||
|
sink(staticParam1("safe", ...[source()])); // NOT OK
|
||||||
sink(staticParam1(source(), ...["safe"])); // OK
|
sink(staticParam1(source(), ...["safe"])); // OK
|
||||||
|
|
||||||
sink(dynamicParam0(...source())); // NOT OK
|
sink(dynamicParam0(...[source()])); // NOT OK
|
||||||
sink(dynamicParam0("safe", ...source())); // NOT OK
|
sink(dynamicParam0(...["safe", source()])); // NOT OK
|
||||||
|
sink(dynamicParam0(...[source(), "safe", ])); // NOT OK
|
||||||
|
sink(dynamicParam0("safe", ...[source()])); // NOT OK
|
||||||
sink(dynamicParam0(source(), ...["safe"])); // NOT OK
|
sink(dynamicParam0(source(), ...["safe"])); // NOT OK
|
||||||
|
|
||||||
sink(dynamicParam1(...source())); // NOT OK
|
sink(dynamicParam1(...[source()])); // OK
|
||||||
sink(dynamicParam1("safe", ...source())); // NOT OK
|
sink(dynamicParam1(...["safe", source()])); // NOT OK
|
||||||
|
sink(dynamicParam1(...[source(), "safe", ])); // OK
|
||||||
|
sink(dynamicParam1("safe", ...[source()])); // NOT OK
|
||||||
sink(dynamicParam1(source(), ...["safe"])); // OK
|
sink(dynamicParam1(source(), ...["safe"])); // OK
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user