Skip to content

Commit 094112c

Browse files
authored
Merge pull request #17213 from asgerf/jss/spread-argument
JS: Improve handling of spread arguments and rest parameters [shared data flow branch]
2 parents 2adaf0f + fb9732a commit 094112c

File tree

52 files changed

+1257
-330
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

52 files changed

+1257
-330
lines changed

javascript/ql/lib/semmle/javascript/dataflow/DataFlow.qll

+2-3
Original file line numberDiff line numberDiff line change
@@ -1780,8 +1780,7 @@ module DataFlow {
17801780
)
17811781
}
17821782

1783-
/** A load step from a reflective parameter node to each parameter. */
1784-
private class ReflectiveParamsStep extends PreCallGraphStep {
1783+
private class ReflectiveParamsStep extends LegacyPreCallGraphStep {
17851784
override predicate loadStep(DataFlow::Node obj, DataFlow::Node element, string prop) {
17861785
exists(DataFlow::ReflectiveParametersNode params, DataFlow::FunctionNode f, int i |
17871786
f.getFunction() = params.getFunction() and
@@ -1793,7 +1792,7 @@ module DataFlow {
17931792
}
17941793

17951794
/** A taint step from the reflective parameters node to any parameter. */
1796-
private class ReflectiveParamsTaintStep extends TaintTracking::SharedTaintStep {
1795+
private class ReflectiveParamsTaintStep extends TaintTracking::LegacyTaintStep {
17971796
override predicate step(DataFlow::Node obj, DataFlow::Node element) {
17981797
exists(DataFlow::ReflectiveParametersNode params, DataFlow::FunctionNode f |
17991798
f.getFunction() = params.getFunction() and

javascript/ql/lib/semmle/javascript/dataflow/TaintTracking.qll

+8-4
Original file line numberDiff line numberDiff line change
@@ -260,6 +260,14 @@ module TaintTracking {
260260
)
261261
}
262262

263+
private class HeapLegacyTaintStep extends LegacyTaintStep {
264+
override predicate heapStep(DataFlow::Node pred, DataFlow::Node succ) {
265+
// arrays with tainted elements are tainted (in old data flow)
266+
succ.(DataFlow::ArrayCreationNode).getAnElement() = pred and
267+
not any(PromiseAllCreation call).getArrayNode() = succ
268+
}
269+
}
270+
263271
/**
264272
* A taint propagating data flow edge through object or array elements and
265273
* promises.
@@ -274,10 +282,6 @@ module TaintTracking {
274282
// spreading a tainted value into an array literal gives a tainted array
275283
succ.(DataFlow::ArrayCreationNode).getASpreadArgument() = pred
276284
or
277-
// arrays with tainted elements and objects with tainted property names are tainted
278-
succ.(DataFlow::ArrayCreationNode).getAnElement() = pred and
279-
not any(PromiseAllCreation call).getArrayNode() = succ
280-
or
281285
// reading from a tainted object yields a tainted result
282286
succ.(DataFlow::PropRead).getBase() = pred and
283287
not (

javascript/ql/lib/semmle/javascript/dataflow/internal/Contents.qll

+4-1
Original file line numberDiff line numberDiff line change
@@ -255,7 +255,10 @@ module Public {
255255
Content asSingleton() { this = MkSingletonContent(result) }
256256

257257
/** Gets the property name to be accessed. */
258-
PropertyName asPropertyName() { result = this.asSingleton().asPropertyName() }
258+
PropertyName asPropertyName() {
259+
// TODO: array indices should be mapped to a ContentSet that also reads from UnknownArrayElement
260+
result = this.asSingleton().asPropertyName()
261+
}
259262

260263
/** Gets the array index to be accessed. */
261264
int asArrayIndex() { result = this.asSingleton().asArrayIndex() }

javascript/ql/lib/semmle/javascript/dataflow/internal/DataFlowImplConsistency.qll

+12
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@ private module ConsistencyConfig implements InputSig<Location, JSDataFlow> {
2424
or
2525
n instanceof FlowSummaryIntermediateAwaitStoreNode
2626
or
27+
n instanceof FlowSummaryDynamicParameterArrayNode
28+
or
2729
n instanceof GenericSynthesizedNode
2830
or
2931
n = DataFlow::globalAccessPathRootPseudoNode()
@@ -37,6 +39,16 @@ private module ConsistencyConfig implements InputSig<Location, JSDataFlow> {
3739
isAmbientNode(call.asOrdinaryCall()) or
3840
isAmbientNode(call.asAccessorCall())
3941
}
42+
43+
predicate argHasPostUpdateExclude(ArgumentNode node) {
44+
// Side-effects directly on these can't propagate back to the caller, and for longer access paths it's too imprecise
45+
node instanceof TStaticArgumentArrayNode or
46+
node instanceof TDynamicArgumentArrayNode
47+
}
48+
49+
predicate reverseReadExclude(DataFlow::Node node) {
50+
node instanceof FlowSummaryDynamicParameterArrayNode
51+
}
4052
}
4153

4254
module Consistency = MakeConsistency<Location, JSDataFlow, JSTaintFlow, ConsistencyConfig>;

javascript/ql/lib/semmle/javascript/dataflow/internal/DataFlowNode.qll

+29-2
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,12 @@ private import semmle.javascript.dataflow.internal.VariableCapture as VariableCa
1515

1616
cached
1717
private module Cached {
18+
private Content dynamicArgumentsContent() {
19+
result.asArrayIndex() = [0 .. 10]
20+
or
21+
result.isUnknownArrayElement()
22+
}
23+
1824
/**
1925
* The raw data type underlying `DataFlow::Node`.
2026
*/
@@ -33,6 +39,25 @@ private module Cached {
3339
} or
3440
TThisNode(StmtContainer f) { f.(Function).getThisBinder() = f or f instanceof TopLevel } or
3541
TFunctionSelfReferenceNode(Function f) or
42+
TStaticArgumentArrayNode(InvokeExpr node) or
43+
TDynamicArgumentArrayNode(InvokeExpr node) { node.isSpreadArgument(_) } or
44+
TStaticParameterArrayNode(Function f) {
45+
f.getAParameter().isRestParameter() or f.usesArgumentsObject()
46+
} or
47+
TDynamicParameterArrayNode(Function f) or
48+
/** Data about to be stored in the rest parameter object. Needed for shifting array indices. */
49+
TRestParameterStoreNode(Function f, Content storeContent) {
50+
f.getRestParameter().getIndex() > 0 and
51+
storeContent = dynamicArgumentsContent()
52+
} or
53+
/** Data about to be stored in the dynamic argument array of an invocation. Needed for shifting array indices. */
54+
TDynamicArgumentStoreNode(InvokeExpr invoke, Content storeContent) {
55+
invoke.isSpreadArgument(_) and
56+
storeContent = dynamicArgumentsContent()
57+
} or
58+
TApplyCallTaintNode(MethodCallExpr node) {
59+
node.getMethodName() = "apply" and exists(node.getArgument(1))
60+
} or
3661
TDestructuredModuleImportNode(ImportDeclaration decl) {
3762
exists(decl.getASpecifier().getImportedName())
3863
} or
@@ -43,7 +68,7 @@ private module Cached {
4368
TExceptionalInvocationReturnNode(InvokeExpr e) or
4469
TGlobalAccessPathRoot() or
4570
TTemplatePlaceholderTag(Templating::TemplatePlaceholderTag tag) or
46-
TReflectiveParametersNode(Function f) or
71+
TReflectiveParametersNode(Function f) { f.usesArgumentsObject() } or
4772
TExprPostUpdateNode(AST::ValueNode e) {
4873
e = any(InvokeExpr invoke).getAnArgument() or
4974
e = any(PropAccess access).getBase() or
@@ -58,6 +83,7 @@ private module Cached {
5883
TConstructorThisArgumentNode(InvokeExpr e) { e instanceof NewExpr or e instanceof SuperCall } or
5984
TConstructorThisPostUpdate(Constructor ctor) or
6085
TFlowSummaryNode(FlowSummaryImpl::Private::SummaryNode sn) or
86+
TFlowSummaryDynamicParameterArrayNode(FlowSummaryImpl::Public::SummarizedCallable callable) or
6187
TFlowSummaryIntermediateAwaitStoreNode(FlowSummaryImpl::Private::SummaryNode sn) {
6288
// NOTE: This dependency goes through the 'Steps' module whose instantiation depends on the call graph,
6389
// but the specific predicate we're referering to does not use that information.
@@ -96,7 +122,8 @@ private class TEarlyStageNode =
96122
TFunctionSelfReferenceNode or TDestructuredModuleImportNode or THtmlAttributeNode or
97123
TFunctionReturnNode or TExceptionalFunctionReturnNode or TExceptionalInvocationReturnNode or
98124
TGlobalAccessPathRoot or TTemplatePlaceholderTag or TReflectiveParametersNode or
99-
TExprPostUpdateNode or TConstructorThisArgumentNode;
125+
TExprPostUpdateNode or TConstructorThisArgumentNode or TStaticArgumentArrayNode or
126+
TDynamicArgumentArrayNode or TStaticParameterArrayNode or TDynamicParameterArrayNode;
100127

101128
/**
102129
* A data-flow node that is not a flow summary node.

0 commit comments

Comments
 (0)