Skip to content

Commit 98cee5c

Browse files
authored
Merge pull request github#2967 from asger-semmle/js/flow-through-prop
Approved by esbena
2 parents 85ee5fc + a204209 commit 98cee5c

File tree

4 files changed

+100
-2
lines changed

4 files changed

+100
-2
lines changed

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

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -901,8 +901,14 @@ private predicate reachableFromStoreBase(
901901
string prop, DataFlow::Node rhs, DataFlow::Node nd, DataFlow::Configuration cfg,
902902
PathSummary summary
903903
) {
904-
isRelevant(rhs, cfg) and
905-
storeStep(rhs, nd, prop, cfg, summary)
904+
exists(PathSummary s1, PathSummary s2 |
905+
reachableFromSource(rhs, cfg, s1)
906+
or
907+
reachableFromStoreBase(_, _, rhs, cfg, s1)
908+
|
909+
storeStep(rhs, nd, prop, cfg, s2) and
910+
summary = MkPathSummary(false, s1.hasCall().booleanOr(s2.hasCall()), s2.getStartLabel(), s2.getEndLabel())
911+
)
906912
or
907913
exists(DataFlow::Node mid, PathSummary oldSummary, PathSummary newSummary |
908914
reachableFromStoreBase(prop, rhs, mid, cfg, oldSummary) and

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

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,12 @@ typeInferenceMismatch
6767
| exceptions.js:158:13:158:20 | source() | exceptions.js:161:10:161:10 | e |
6868
| importedReactComponent.jsx:4:40:4:47 | source() | exportedReactComponent.jsx:2:10:2:19 | props.text |
6969
| indexOf.js:4:11:4:18 | source() | indexOf.js:9:10:9:10 | x |
70+
| nested-props.js:4:13:4:20 | source() | nested-props.js:5:10:5:14 | obj.x |
71+
| nested-props.js:9:18:9:25 | source() | nested-props.js:10:10:10:16 | obj.x.y |
72+
| nested-props.js:35:13:35:20 | source() | nested-props.js:36:10:36:20 | doLoad(obj) |
73+
| nested-props.js:43:13:43:20 | source() | nested-props.js:44:10:44:18 | id(obj).x |
74+
| nested-props.js:67:31:67:38 | source() | nested-props.js:68:10:68:10 | x |
75+
| nested-props.js:77:36:77:43 | source() | nested-props.js:78:10:78:10 | x |
7076
| partialCalls.js:4:17:4:24 | source() | partialCalls.js:17:14:17:14 | x |
7177
| partialCalls.js:4:17:4:24 | source() | partialCalls.js:20:14:20:14 | y |
7278
| partialCalls.js:4:17:4:24 | source() | partialCalls.js:30:14:30:20 | x.value |

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,11 @@
4242
| exceptions.js:158:13:158:20 | source() | exceptions.js:161:10:161:10 | e |
4343
| indexOf.js:4:11:4:18 | source() | indexOf.js:9:10:9:10 | x |
4444
| indexOf.js:4:11:4:18 | source() | indexOf.js:13:10:13:10 | x |
45+
| nested-props.js:4:13:4:20 | source() | nested-props.js:5:10:5:14 | obj.x |
46+
| nested-props.js:9:18:9:25 | source() | nested-props.js:10:10:10:16 | obj.x.y |
47+
| nested-props.js:35:13:35:20 | source() | nested-props.js:36:10:36:20 | doLoad(obj) |
48+
| nested-props.js:43:13:43:20 | source() | nested-props.js:44:10:44:18 | id(obj).x |
49+
| nested-props.js:67:31:67:38 | source() | nested-props.js:68:10:68:10 | x |
4550
| partialCalls.js:4:17:4:24 | source() | partialCalls.js:17:14:17:14 | x |
4651
| partialCalls.js:4:17:4:24 | source() | partialCalls.js:20:14:20:14 | y |
4752
| partialCalls.js:4:17:4:24 | source() | partialCalls.js:30:14:30:20 | x.value |
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
import * as dummy from 'dummy';
2+
3+
function storeLoadFlow(obj) {
4+
obj.x = source();
5+
sink(obj.x); // NOT OK
6+
}
7+
8+
function storeStoreLoadLoadFlow(obj) {
9+
obj.x = { y: source() };
10+
sink(obj.x.y); // NOT OK
11+
}
12+
13+
function loadStoreFlow(obj) {
14+
obj.x.y = source();
15+
sink(obj.x.y); // NOT OK - but not found
16+
}
17+
18+
function loadLoadStoreFlow(obj) {
19+
obj.x.y.z = source();
20+
sink(obj.x.y.z); // NOT OK - but not found
21+
}
22+
23+
function doStore(obj, x) {
24+
obj.x = x;
25+
}
26+
function callStoreBackcallFlow(obj) {
27+
doStore(obj, source());
28+
sink(obj.x); // NOT OK - but not found
29+
}
30+
31+
function doLoad(obj) {
32+
return obj.x
33+
}
34+
function storeCallLoadReturnFlow(obj) {
35+
obj.x = source();
36+
sink(doLoad(obj)); // NOT OK
37+
}
38+
39+
function id(obj) {
40+
return obj
41+
}
42+
function storeCallReturnLoadFlow(obj) {
43+
obj.x = source();
44+
sink(id(obj).x); // NOT OK
45+
}
46+
47+
function doLoadStore(obj, val) {
48+
obj.x.y = val;
49+
}
50+
function callStoreBackloadBackcallLoadLoad(obj) {
51+
doLoadStore(obj, source());
52+
sink(obj.x.y); // NOT OK - but not found
53+
}
54+
55+
function doLoadLoad(obj) {
56+
return obj.x.y
57+
}
58+
function storeBackloadCallLoadLoadReturn(obj) {
59+
obj.x.y = source();
60+
sink(doLoadStore(obj)); // NOT OK - but not found
61+
}
62+
63+
function doStoreReturn(val) {
64+
return { x: val }
65+
}
66+
function callStoreReturnLoad() {
67+
let { x } = doStoreReturn(source());
68+
sink(x); // NOT OK
69+
70+
doStoreReturn(null); // ensure multiple call sites exist
71+
}
72+
73+
function doTaintStoreReturn(val) {
74+
return { x: val + "!!" }
75+
}
76+
function callTaintStoreReturnLoadFlow() {
77+
let { x } = doTaintStoreReturn(source());
78+
sink(x); // NOT OK
79+
80+
doTaintStoreReturn(null); // ensure multiple call sites exist
81+
}

0 commit comments

Comments
 (0)