Skip to content

Commit 12a6410

Browse files
authored
Merge pull request github#5478 from asgerf/js/shared-flow-step
Approved by erik-krogh
2 parents 02a5c08 + 98cee7d commit 12a6410

31 files changed

+626
-465
lines changed

javascript/ql/src/Security/CWE-327/BadRandomness.ql

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -87,11 +87,6 @@ private DataFlow::Node goodRandom(DataFlow::TypeTracker t, DataFlow::SourceNode
8787
or
8888
exists(DataFlow::TypeTracker t2 | t = t2.smallstep(goodRandom(t2, source), result))
8989
or
90-
// re-using the collection steps for `Set`.
91-
exists(DataFlow::TypeTracker t2 |
92-
result = CollectionsTypeTracking::collectionStep(goodRandom(t2, source), t, t2)
93-
)
94-
or
9590
InsecureRandomness::isAdditionalTaintStep(goodRandom(t.continue(), source), result) and
9691
// bit shifts and multiplication by powers of two are generally used for constructing larger numbers from smaller numbers.
9792
not exists(BinaryExpr binop | binop = result.asExpr() |

javascript/ql/src/meta/analysis-quality/TaintSteps.ql

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,17 +15,17 @@ predicate relevantStep(DataFlow::Node pred, DataFlow::Node succ) {
1515
(
1616
TaintTracking::sharedTaintStep(pred, succ)
1717
or
18-
any(DataFlow::AdditionalFlowStep cfg).step(pred, succ)
18+
DataFlow::SharedFlowStep::step(pred, succ)
1919
or
20-
any(DataFlow::AdditionalFlowStep cfg).step(pred, succ, _, _)
20+
DataFlow::SharedFlowStep::step(pred, succ, _, _)
2121
or
22-
any(DataFlow::AdditionalFlowStep cfg).loadStep(pred, succ, _)
22+
DataFlow::SharedFlowStep::loadStep(pred, succ, _)
2323
or
24-
any(DataFlow::AdditionalFlowStep cfg).storeStep(pred, succ, _)
24+
DataFlow::SharedFlowStep::storeStep(pred, succ, _)
2525
or
26-
any(DataFlow::AdditionalFlowStep cfg).loadStoreStep(pred, succ, _, _)
26+
DataFlow::SharedFlowStep::loadStoreStep(pred, succ, _, _)
2727
or
28-
any(DataFlow::AdditionalFlowStep cfg).loadStoreStep(pred, succ, _)
28+
DataFlow::SharedFlowStep::loadStoreStep(pred, succ, _)
2929
) and
3030
not pred.getFile() instanceof IgnoredFile and
3131
not succ.getFile() instanceof IgnoredFile

javascript/ql/src/semmle/javascript/Arrays.qll

Lines changed: 76 additions & 91 deletions
Original file line numberDiff line numberDiff line change
@@ -84,16 +84,17 @@ private module ArrayDataFlow {
8484
* A step modelling the creation of an Array using the `Array.from(x)` method.
8585
* The step copies the elements of the argument (set, array, or iterator elements) into the resulting array.
8686
*/
87-
private class ArrayFrom extends DataFlow::AdditionalFlowStep, DataFlow::CallNode {
88-
ArrayFrom() { this = DataFlow::globalVarRef("Array").getAMemberCall("from") }
89-
87+
private class ArrayFrom extends DataFlow::SharedFlowStep {
9088
override predicate loadStoreStep(
9189
DataFlow::Node pred, DataFlow::Node succ, string fromProp, string toProp
9290
) {
93-
pred = this.getArgument(0) and
94-
succ = this and
95-
fromProp = arrayLikeElement() and
96-
toProp = arrayElement()
91+
exists(DataFlow::CallNode call |
92+
call = DataFlow::globalVarRef("Array").getAMemberCall("from") and
93+
pred = call.getArgument(0) and
94+
succ = call and
95+
fromProp = arrayLikeElement() and
96+
toProp = arrayElement()
97+
)
9798
}
9899
}
99100

@@ -103,55 +104,45 @@ private module ArrayDataFlow {
103104
*
104105
* Such a step can occur both with the `push` and `unshift` methods, or when creating a new array.
105106
*/
106-
private class ArrayCopySpread extends DataFlow::AdditionalFlowStep {
107-
DataFlow::Node spreadArgument; // the spread argument containing the elements to be copied.
108-
DataFlow::Node base; // the object where the elements should be copied to.
109-
110-
ArrayCopySpread() {
111-
exists(DataFlow::MethodCallNode mcn | mcn = this |
112-
mcn.getMethodName() = ["push", "unshift"] and
113-
spreadArgument = mcn.getASpreadArgument() and
114-
base = mcn.getReceiver().getALocalSource()
115-
)
116-
or
117-
spreadArgument = this.(DataFlow::ArrayCreationNode).getASpreadArgument() and
118-
base = this
119-
}
120-
107+
private class ArrayCopySpread extends DataFlow::SharedFlowStep {
121108
override predicate loadStoreStep(
122109
DataFlow::Node pred, DataFlow::Node succ, string fromProp, string toProp
123110
) {
124-
pred = spreadArgument and
125-
succ = base and
126111
fromProp = arrayLikeElement() and
127-
toProp = arrayElement()
112+
toProp = arrayElement() and
113+
(
114+
exists(DataFlow::MethodCallNode mcn |
115+
mcn.getMethodName() = ["push", "unshift"] and
116+
pred = mcn.getASpreadArgument() and
117+
succ = mcn.getReceiver().getALocalSource()
118+
)
119+
or
120+
pred = succ.(DataFlow::ArrayCreationNode).getASpreadArgument()
121+
)
128122
}
129123
}
130124

131125
/**
132126
* A step for storing an element on an array using `arr.push(e)` or `arr.unshift(e)`.
133127
*/
134-
private class ArrayAppendStep extends DataFlow::AdditionalFlowStep, DataFlow::MethodCallNode {
135-
ArrayAppendStep() {
136-
this.getMethodName() = "push" or
137-
this.getMethodName() = "unshift"
138-
}
139-
128+
private class ArrayAppendStep extends DataFlow::SharedFlowStep {
140129
override predicate storeStep(DataFlow::Node element, DataFlow::SourceNode obj, string prop) {
141130
prop = arrayElement() and
142-
element = this.getAnArgument() and
143-
obj.getAMethodCall() = this
131+
exists(DataFlow::MethodCallNode call |
132+
call.getMethodName() = ["push", "unshift"] and
133+
element = call.getAnArgument() and
134+
obj.getAMethodCall() = call
135+
)
144136
}
145137
}
146138

147139
/**
148-
* A step for reading/writing an element from an array inside a for-loop.
149-
* E.g. a read from `foo[i]` to `bar` in `for(var i = 0; i < arr.length; i++) {bar = foo[i]}`.
140+
* A node that reads or writes an element from an array inside a for-loop.
150141
*/
151-
private class ArrayIndexingStep extends DataFlow::AdditionalFlowStep, DataFlow::Node {
142+
private class ArrayIndexingAccess extends DataFlow::Node {
152143
DataFlow::PropRef read;
153144

154-
ArrayIndexingStep() {
145+
ArrayIndexingAccess() {
155146
read = this and
156147
TTNumber() =
157148
unique(InferredType type | type = read.getPropertyNameExpr().flow().analyze().getAType()) and
@@ -162,34 +153,42 @@ private module ArrayDataFlow {
162153
i.getVariable().getADefinition().(VariableDeclarator).getDeclStmt() = init
163154
)
164155
}
156+
}
165157

158+
/**
159+
* A step for reading/writing an element from an array inside a for-loop.
160+
* E.g. a read from `foo[i]` to `bar` in `for(var i = 0; i < arr.length; i++) {bar = foo[i]}`.
161+
*/
162+
private class ArrayIndexingStep extends DataFlow::SharedFlowStep {
166163
override predicate loadStep(DataFlow::Node obj, DataFlow::Node element, string prop) {
167-
prop = arrayElement() and
168-
obj = this.(DataFlow::PropRead).getBase() and
169-
element = this
164+
exists(ArrayIndexingAccess access |
165+
prop = arrayElement() and
166+
obj = access.(DataFlow::PropRead).getBase() and
167+
element = access
168+
)
170169
}
171170

172171
override predicate storeStep(DataFlow::Node element, DataFlow::SourceNode obj, string prop) {
173-
prop = arrayElement() and
174-
element = this.(DataFlow::PropWrite).getRhs() and
175-
this = obj.getAPropertyWrite()
172+
exists(ArrayIndexingAccess access |
173+
prop = arrayElement() and
174+
element = access.(DataFlow::PropWrite).getRhs() and
175+
access = obj.getAPropertyWrite()
176+
)
176177
}
177178
}
178179

179180
/**
180181
* A step for retrieving an element from an array using `.pop()` or `.shift()`.
181182
* E.g. `array.pop()`.
182183
*/
183-
private class ArrayPopStep extends DataFlow::AdditionalFlowStep, DataFlow::MethodCallNode {
184-
ArrayPopStep() {
185-
getMethodName() = "pop" or
186-
getMethodName() = "shift"
187-
}
188-
184+
private class ArrayPopStep extends DataFlow::SharedFlowStep {
189185
override predicate loadStep(DataFlow::Node obj, DataFlow::Node element, string prop) {
190-
prop = arrayElement() and
191-
obj = this.getReceiver() and
192-
element = this
186+
exists(DataFlow::MethodCallNode call |
187+
call.getMethodName() = ["pop", "shift"] and
188+
prop = arrayElement() and
189+
obj = call.getReceiver() and
190+
element = call
191+
)
193192
}
194193
}
195194

@@ -235,12 +234,12 @@ private module ArrayDataFlow {
235234
/**
236235
* A step for creating an array and storing the elements in the array.
237236
*/
238-
private class ArrayCreationStep extends DataFlow::AdditionalFlowStep, DataFlow::ArrayCreationNode {
237+
private class ArrayCreationStep extends DataFlow::SharedFlowStep {
239238
override predicate storeStep(DataFlow::Node element, DataFlow::SourceNode obj, string prop) {
240-
exists(int i |
241-
element = this.getElement(i) and
242-
obj = this and
243-
if this = any(PromiseAllCreation c).getArrayNode()
239+
exists(DataFlow::ArrayCreationNode array, int i |
240+
element = array.getElement(i) and
241+
obj = array and
242+
if array = any(PromiseAllCreation c).getArrayNode()
244243
then prop = arrayElement(i)
245244
else prop = arrayElement()
246245
)
@@ -251,56 +250,42 @@ private module ArrayDataFlow {
251250
* A step modelling that `splice` can insert elements into an array.
252251
* For example in `array.splice(i, del, e)`: if `e` is tainted, then so is `array
253252
*/
254-
private class ArraySpliceStep extends DataFlow::AdditionalFlowStep, DataFlow::MethodCallNode {
255-
ArraySpliceStep() { this.getMethodName() = "splice" }
256-
253+
private class ArraySpliceStep extends DataFlow::SharedFlowStep {
257254
override predicate storeStep(DataFlow::Node element, DataFlow::SourceNode obj, string prop) {
258-
prop = arrayElement() and
259-
element = getArgument(2) and
260-
this = obj.getAMethodCall()
255+
exists(DataFlow::MethodCallNode call |
256+
call.getMethodName() = "splice" and
257+
prop = arrayElement() and
258+
element = call.getArgument(2) and
259+
call = obj.getAMethodCall()
260+
)
261261
}
262262
}
263263

264264
/**
265265
* A step for modelling `concat`.
266266
* For example in `e = arr1.concat(arr2, arr3)`: if any of the `arr` is tainted, then so is `e`.
267267
*/
268-
private class ArrayConcatStep extends DataFlow::AdditionalFlowStep, DataFlow::MethodCallNode {
269-
ArrayConcatStep() { this.getMethodName() = "concat" }
270-
268+
private class ArrayConcatStep extends DataFlow::SharedFlowStep {
271269
override predicate loadStoreStep(DataFlow::Node pred, DataFlow::Node succ, string prop) {
272-
prop = arrayElement() and
273-
(pred = this.getReceiver() or pred = this.getAnArgument()) and
274-
succ = this
270+
exists(DataFlow::MethodCallNode call |
271+
call.getMethodName() = "concat" and
272+
prop = arrayElement() and
273+
(pred = call.getReceiver() or pred = call.getAnArgument()) and
274+
succ = call
275+
)
275276
}
276277
}
277278

278279
/**
279280
* A step for modelling that elements from an array `arr` also appear in the result from calling `slice`/`splice`/`filter`.
280281
*/
281-
private class ArraySliceStep extends DataFlow::AdditionalFlowStep, DataFlow::MethodCallNode {
282-
ArraySliceStep() {
283-
this.getMethodName() = "slice" or
284-
this.getMethodName() = "splice" or
285-
this.getMethodName() = "filter"
286-
}
287-
282+
private class ArraySliceStep extends DataFlow::SharedFlowStep {
288283
override predicate loadStoreStep(DataFlow::Node pred, DataFlow::Node succ, string prop) {
289-
prop = arrayElement() and
290-
pred = this.getReceiver() and
291-
succ = this
292-
}
293-
}
294-
295-
/**
296-
* A step for modelling `for of` iteration on arrays.
297-
*/
298-
private class ForOfStep extends PreCallGraphStep {
299-
override predicate loadStep(DataFlow::Node obj, DataFlow::Node e, string prop) {
300-
exists(ForOfStmt forOf |
301-
obj = forOf.getIterationDomain().flow() and
302-
e = DataFlow::lvalueNode(forOf.getLValue()) and
303-
prop = arrayElement()
284+
exists(DataFlow::MethodCallNode call |
285+
call.getMethodName() = ["slice", "splice", "filter"] and
286+
prop = arrayElement() and
287+
pred = call.getReceiver() and
288+
succ = call
304289
)
305290
}
306291
}

0 commit comments

Comments
 (0)