Skip to content

Commit e29aa29

Browse files
committed
JS: Use type-pruning to restrict callback flow
1 parent 97c4572 commit e29aa29

File tree

4 files changed

+44
-12
lines changed

4 files changed

+44
-12
lines changed

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

Lines changed: 43 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -297,16 +297,46 @@ DataFlowCallable nodeGetEnclosingCallable(Node node) {
297297
}
298298

299299
private newtype TDataFlowType =
300-
TTodoDataFlowType() or
301-
TTodoDataFlowType2() // Add a dummy value to prevent bad functionality-induced joins arising from a type of size 1.
300+
TFunctionType(Function f) or
301+
TAnyType()
302302

303303
class DataFlowType extends TDataFlowType {
304-
string toString() { result = "" }
304+
string toString() {
305+
this instanceof TFunctionType and
306+
result =
307+
"TFunctionType(" + this.asFunction().toString() + ") at line " +
308+
this.asFunction().getLocation().getStartLine()
309+
or
310+
this instanceof TAnyType and result = "TAnyType"
311+
}
312+
313+
Function asFunction() { this = TFunctionType(result) }
305314
}
306315

307-
predicate typeStrongerThan(DataFlowType t1, DataFlowType t2) { none() }
316+
/**
317+
* Holds if `t1` is strictly stronger than `t2`.
318+
*/
319+
predicate typeStrongerThan(DataFlowType t1, DataFlowType t2) {
320+
t1 instanceof TFunctionType and t2 = TAnyType()
321+
}
322+
323+
private DataFlowType getPreciseType(Node node) {
324+
exists(Function f |
325+
(node = TValueNode(f) or node = TFunctionSelfReferenceNode(f)) and
326+
result = TFunctionType(f)
327+
)
328+
or
329+
result = getPreciseType(node.getImmediatePredecessor())
330+
or
331+
result = getPreciseType(node.(PostUpdateNode).getPreUpdateNode())
332+
}
308333

309-
DataFlowType getNodeType(Node node) { result = TTodoDataFlowType() and exists(node) }
334+
DataFlowType getNodeType(Node node) {
335+
result = getPreciseType(node)
336+
or
337+
not exists(getPreciseType(node)) and
338+
result = TAnyType()
339+
}
310340

311341
predicate nodeIsHidden(Node node) {
312342
DataFlow::PathNode::shouldNodeBeHidden(node)
@@ -341,10 +371,16 @@ predicate neverSkipInPathGraph(Node node) {
341371
node.asExpr() instanceof VarRef
342372
}
343373

344-
string ppReprType(DataFlowType t) { none() }
374+
string ppReprType(DataFlowType t) { result = t.toString() }
345375

346376
pragma[inline]
347-
predicate compatibleTypes(DataFlowType t1, DataFlowType t2) { any() }
377+
predicate compatibleTypes(DataFlowType t1, DataFlowType t2) {
378+
t1 = t2
379+
or
380+
t1 instanceof TAnyType and exists(t2)
381+
or
382+
t2 instanceof TAnyType and exists(t1)
383+
}
348384

349385
predicate forceHighPrecision(Content c) { none() }
350386

javascript/ql/test/library-tests/TaintTracking/BasicTaintTracking.expected

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ legacyDataFlowDifference
55
| callbacks.js:37:17:37:24 | source() | callbacks.js:41:10:41:10 | x | only flow with NEW data flow library |
66
| callbacks.js:44:17:44:24 | source() | callbacks.js:37:37:37:37 | x | only flow with NEW data flow library |
77
| callbacks.js:44:17:44:24 | source() | callbacks.js:38:35:38:35 | x | only flow with NEW data flow library |
8-
| callbacks.js:73:17:73:24 | source() | callbacks.js:74:35:74:35 | x | only flow with NEW data flow library |
98
| capture-flow.js:89:13:89:20 | source() | capture-flow.js:89:6:89:21 | test3c(source()) | only flow with NEW data flow library |
109
| capture-flow.js:101:12:101:19 | source() | capture-flow.js:102:6:102:20 | test5("safe")() | only flow with OLD data flow library |
1110
| capture-flow.js:274:33:274:40 | source() | capture-flow.js:272:10:272:17 | this.foo | only flow with OLD data flow library |
@@ -94,7 +93,6 @@ flow
9493
| callbacks.js:51:18:51:25 | source() | callbacks.js:30:29:30:29 | y |
9594
| callbacks.js:53:23:53:30 | source() | callbacks.js:58:10:58:10 | x |
9695
| callbacks.js:73:17:73:24 | source() | callbacks.js:73:37:73:37 | x |
97-
| callbacks.js:73:17:73:24 | source() | callbacks.js:74:35:74:35 | x |
9896
| capture-flow.js:9:11:9:18 | source() | capture-flow.js:14:10:14:16 | outer() |
9997
| capture-flow.js:9:11:9:18 | source() | capture-flow.js:19:6:19:16 | outerMost() |
10098
| capture-flow.js:31:14:31:21 | source() | capture-flow.js:31:6:31:22 | confuse(source()) |

javascript/ql/test/library-tests/TaintTracking/DataFlowTracking.expected

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ legacyDataFlowDifference
77
| callbacks.js:37:17:37:24 | source() | callbacks.js:41:10:41:10 | x | only flow with NEW data flow library |
88
| callbacks.js:44:17:44:24 | source() | callbacks.js:37:37:37:37 | x | only flow with NEW data flow library |
99
| callbacks.js:44:17:44:24 | source() | callbacks.js:38:35:38:35 | x | only flow with NEW data flow library |
10-
| callbacks.js:73:17:73:24 | source() | callbacks.js:74:35:74:35 | x | only flow with NEW data flow library |
1110
| capture-flow.js:89:13:89:20 | source() | capture-flow.js:89:6:89:21 | test3c(source()) | only flow with NEW data flow library |
1211
| capture-flow.js:101:12:101:19 | source() | capture-flow.js:102:6:102:20 | test5("safe")() | only flow with OLD data flow library |
1312
| capture-flow.js:274:33:274:40 | source() | capture-flow.js:272:10:272:17 | this.foo | only flow with OLD data flow library |
@@ -69,7 +68,6 @@ flow
6968
| callbacks.js:51:18:51:25 | source() | callbacks.js:30:29:30:29 | y |
7069
| callbacks.js:53:23:53:30 | source() | callbacks.js:58:10:58:10 | x |
7170
| callbacks.js:73:17:73:24 | source() | callbacks.js:73:37:73:37 | x |
72-
| callbacks.js:73:17:73:24 | source() | callbacks.js:74:35:74:35 | x |
7371
| capture-flow.js:9:11:9:18 | source() | capture-flow.js:14:10:14:16 | outer() |
7472
| capture-flow.js:9:11:9:18 | source() | capture-flow.js:19:6:19:16 | outerMost() |
7573
| capture-flow.js:31:14:31:21 | source() | capture-flow.js:31:6:31:22 | confuse(source()) |

javascript/ql/test/library-tests/TaintTracking/callbacks.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,5 +71,5 @@ function forwardTaint4(x, cb) {
7171

7272
function test2() {
7373
forwardTaint4(source(), x => sink(x)); // NOT OK
74-
forwardTaint4("safe", x => sink(x)); // OK [INCONSISTENCY]
74+
forwardTaint4("safe", x => sink(x)); // OK
7575
}

0 commit comments

Comments
 (0)