Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit e8e6491

Browse files
committed
JS: Also propagate out of returns
1 parent 8c36b99 commit e8e6491

5 files changed

Lines changed: 72 additions & 5 deletions

File tree

javascript/ql/src/semmle/javascript/dataflow/Configuration.qll

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -751,7 +751,7 @@ private predicate flowThroughCall(
751751
) {
752752
exists(Function f, DataFlow::ValueNode ret |
753753
ret.asExpr() = f.getAReturnedExpr() and
754-
calls(output, f) and // Do not consider partial calls
754+
(calls(output, f) or callsBound(output, f, _)) and // Do not consider partial calls
755755
reachableFromInput(f, output, input, ret, cfg, summary) and
756756
not isBarrierEdge(cfg, ret, output) and
757757
not isLabeledBarrierEdge(cfg, ret, output, summary.getEndLabel()) and
@@ -761,7 +761,7 @@ private predicate flowThroughCall(
761761
exists(Function f, DataFlow::Node invk, DataFlow::Node ret |
762762
DataFlow::exceptionalFunctionReturnNode(ret, f) and
763763
DataFlow::exceptionalInvocationReturnNode(output, invk.asExpr()) and
764-
calls(invk, f) and
764+
(calls(invk, f) or callsBound(invk, f, _)) and
765765
reachableFromInput(f, invk, input, ret, cfg, summary) and
766766
not isBarrierEdge(cfg, ret, output) and
767767
not isLabeledBarrierEdge(cfg, ret, output, summary.getEndLabel()) and

javascript/ql/src/semmle/javascript/dataflow/internal/FlowSteps.qll

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -179,7 +179,7 @@ private module CachedSteps {
179179
*/
180180
cached
181181
predicate returnStep(DataFlow::Node pred, DataFlow::Node succ) {
182-
exists(Function f | calls(succ, f) |
182+
exists(Function f | calls(succ, f) or callsBound(succ, f, _) |
183183
returnExpr(f, pred, _)
184184
or
185185
succ instanceof DataFlow::NewNode and
@@ -188,8 +188,11 @@ private module CachedSteps {
188188
or
189189
exists(InvokeExpr invoke, Function fun |
190190
DataFlow::exceptionalFunctionReturnNode(pred, fun) and
191-
DataFlow::exceptionalInvocationReturnNode(succ, invoke) and
191+
DataFlow::exceptionalInvocationReturnNode(succ, invoke)
192+
|
192193
calls(invoke.flow(), fun)
194+
or
195+
callsBound(invoke.flow(), fun, _)
193196
)
194197
}
195198

@@ -485,4 +488,3 @@ module PathSummary {
485488
*/
486489
PathSummary return() { exists(FlowLabel lbl | result = MkPathSummary(true, false, lbl, lbl)) }
487490
}
488-

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,11 @@ typeInferenceMismatch
1515
| booleanOps.js:2:11:2:18 | source() | booleanOps.js:13:10:13:10 | x |
1616
| booleanOps.js:2:11:2:18 | source() | booleanOps.js:19:10:19:10 | x |
1717
| booleanOps.js:2:11:2:18 | source() | booleanOps.js:22:10:22:10 | x |
18+
| bound-function.js:12:12:12:19 | source() | bound-function.js:4:10:4:10 | y |
19+
| bound-function.js:14:6:14:13 | source() | bound-function.js:4:10:4:10 | y |
20+
| bound-function.js:45:10:45:17 | source() | bound-function.js:45:6:45:18 | id3(source()) |
21+
| bound-function.js:49:12:49:19 | source() | bound-function.js:54:6:54:14 | source0() |
22+
| bound-function.js:49:12:49:19 | source() | bound-function.js:55:6:55:14 | source1() |
1823
| callbacks.js:4:6:4:13 | source() | callbacks.js:34:27:34:27 | x |
1924
| callbacks.js:4:6:4:13 | source() | callbacks.js:35:27:35:27 | x |
2025
| callbacks.js:5:6:5:13 | source() | callbacks.js:34:27:34:27 | x |

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,11 @@
66
| booleanOps.js:2:11:2:18 | source() | booleanOps.js:13:10:13:10 | x |
77
| booleanOps.js:2:11:2:18 | source() | booleanOps.js:19:10:19:10 | x |
88
| booleanOps.js:2:11:2:18 | source() | booleanOps.js:22:10:22:10 | x |
9+
| bound-function.js:12:12:12:19 | source() | bound-function.js:4:10:4:10 | y |
10+
| bound-function.js:14:6:14:13 | source() | bound-function.js:4:10:4:10 | y |
11+
| bound-function.js:45:10:45:17 | source() | bound-function.js:45:6:45:18 | id3(source()) |
12+
| bound-function.js:49:12:49:19 | source() | bound-function.js:54:6:54:14 | source0() |
13+
| bound-function.js:49:12:49:19 | source() | bound-function.js:55:6:55:14 | source1() |
914
| callbacks.js:4:6:4:13 | source() | callbacks.js:34:27:34:27 | x |
1015
| callbacks.js:4:6:4:13 | source() | callbacks.js:35:27:35:27 | x |
1116
| callbacks.js:5:6:5:13 | source() | callbacks.js:34:27:34:27 | x |
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
import * as dummy from 'dummy';
2+
3+
function foo(x, y) {
4+
sink(y);
5+
}
6+
7+
let foo0 = foo.bind(null);
8+
let foo1 = foo.bind(null, null);
9+
let foo2 = foo.bind(null, null, null);
10+
11+
foo0(source(), null); // OK
12+
foo0(null, source()); // NOT OK
13+
14+
foo1(source()); // NOT OK
15+
foo1(null, source()); // OK
16+
17+
foo2(source()); // OK
18+
foo2(null, source()); // OK
19+
20+
21+
function takesCallback(cb) {
22+
cb(source()); // NOT OK - but not found
23+
}
24+
function callback(x, y) {
25+
sink(y);
26+
}
27+
takesCallback(callback.bind(null, null));
28+
29+
function id(x) {
30+
return x;
31+
}
32+
33+
let sourceGetter = id.bind(null, source());
34+
let constGetter = id.bind(null, 'safe');
35+
36+
sink(sourceGetter()); // NOT OK - but not flagged
37+
sink(constGetter()); // OK
38+
39+
function id2(x, y) {
40+
return y;
41+
}
42+
43+
let id3 = id2.bind(null, null);
44+
45+
sink(id3(source())); // NOT OK
46+
sink(id3('safe')); // OK
47+
48+
function getSource() {
49+
return source();
50+
}
51+
let source0 = getSource.bind(null);
52+
let source1 = getSource.bind(null, null);
53+
54+
sink(source0()); // NOT OK
55+
sink(source1()); // NOT OK

0 commit comments

Comments
 (0)