Skip to content

Commit 23d2f11

Browse files
committed
JS: Handle inheritance
1 parent 3d94ccf commit 23d2f11

File tree

4 files changed

+58
-2
lines changed

4 files changed

+58
-2
lines changed

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

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -163,16 +163,36 @@ module CallGraph {
163163
)
164164
}
165165

166+
/** Holds if a property setter named `name` exists in a class. */
167+
private predicate isSetterName(string name) {
168+
exists(any(DataFlow::ClassNode cls).getInstanceMember(name, DataFlow::MemberKind::setter()))
169+
}
170+
171+
/**
172+
* Gets a property write that assigns to the property `name` on an instance of this class,
173+
* and `name` is the name of a property setter.
174+
*/
175+
private DataFlow::PropWrite getAnInstanceMemberAssignment(DataFlow::ClassNode cls, string name) {
176+
isSetterName(name) and // restrict size of predicate
177+
result = cls.getAnInstanceReference().getAPropertyWrite(name)
178+
or
179+
exists(DataFlow::ClassNode subclass |
180+
result = getAnInstanceMemberAssignment(subclass, name) and
181+
not exists(subclass.getInstanceMember(name, DataFlow::MemberKind::setter())) and
182+
cls = subclass.getADirectSuperClass()
183+
)
184+
}
185+
166186
/**
167187
* Gets a getter or setter invoked as a result of the given property access.
168188
*/
169189
cached
170190
DataFlow::FunctionNode getAnAccessorCallee(DataFlow::PropRef ref) {
171191
exists(DataFlow::ClassNode cls, string name |
172-
ref = cls.getAnInstanceReference().getAPropertyRead(name) and
192+
ref = cls.getAnInstanceMemberAccess(name) and
173193
result = cls.getInstanceMember(name, DataFlow::MemberKind::getter())
174194
or
175-
ref = cls.getAnInstanceReference().getAPropertyWrite(name) and
195+
ref = getAnInstanceMemberAssignment(cls, name) and
176196
result = cls.getInstanceMember(name, DataFlow::MemberKind::setter())
177197
)
178198
or

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,10 @@ typeInferenceMismatch
7272
| getters-and-setters.js:47:23:47:30 | source() | getters-and-setters.js:45:14:45:16 | c.x |
7373
| getters-and-setters.js:60:20:60:27 | source() | getters-and-setters.js:66:10:66:14 | obj.x |
7474
| getters-and-setters.js:67:13:67:20 | source() | getters-and-setters.js:63:18:63:22 | value |
75+
| getters-and-setters.js:79:20:79:27 | source() | getters-and-setters.js:88:10:88:18 | new C().x |
76+
| getters-and-setters.js:79:20:79:27 | source() | getters-and-setters.js:92:14:92:16 | c.x |
77+
| getters-and-setters.js:79:20:79:27 | source() | getters-and-setters.js:100:10:100:22 | getX(new C()) |
78+
| getters-and-setters.js:89:17:89:24 | source() | getters-and-setters.js:82:18:82:22 | value |
7579
| importedReactComponent.jsx:4:40:4:47 | source() | exportedReactComponent.jsx:2:10:2:19 | props.text |
7680
| indexOf.js:4:11:4:18 | source() | indexOf.js:9:10:9:10 | x |
7781
| json-stringify.js:2:16:2:23 | source() | json-stringify.js:5:8:5:29 | JSON.st ... source) |

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,10 @@
4747
| getters-and-setters.js:47:23:47:30 | source() | getters-and-setters.js:45:14:45:16 | c.x |
4848
| getters-and-setters.js:60:20:60:27 | source() | getters-and-setters.js:66:10:66:14 | obj.x |
4949
| getters-and-setters.js:67:13:67:20 | source() | getters-and-setters.js:63:18:63:22 | value |
50+
| getters-and-setters.js:79:20:79:27 | source() | getters-and-setters.js:88:10:88:18 | new C().x |
51+
| getters-and-setters.js:79:20:79:27 | source() | getters-and-setters.js:92:14:92:16 | c.x |
52+
| getters-and-setters.js:79:20:79:27 | source() | getters-and-setters.js:100:10:100:22 | getX(new C()) |
53+
| getters-and-setters.js:89:17:89:24 | source() | getters-and-setters.js:82:18:82:22 | value |
5054
| indexOf.js:4:11:4:18 | source() | indexOf.js:9:10:9:10 | x |
5155
| indexOf.js:4:11:4:18 | source() | indexOf.js:13:10:13:10 | x |
5256
| nested-props.js:4:13:4:20 | source() | nested-props.js:5:10:5:14 | obj.x |

javascript/ql/test/library-tests/TaintTracking/getters-and-setters.js

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,3 +72,31 @@ function testFlowThroughObjectLiteralAccessors() {
7272
indirection(obj);
7373
indirection(null);
7474
}
75+
76+
function testFlowThroughSubclass() {
77+
class Base {
78+
get x() {
79+
return source();
80+
}
81+
set y(value) {
82+
sink(value); // NOT OK
83+
}
84+
};
85+
class C extends Base {
86+
}
87+
88+
sink(new C().x); // NOT OK
89+
new C().y = source();
90+
91+
function indirection(c) {
92+
sink(c.x); // NOT OK
93+
}
94+
indirection(new C());
95+
indirection(null);
96+
97+
function getX(c) {
98+
return c.x;
99+
}
100+
sink(getX(new C())); // NOT OK - but not flagged
101+
getX(null);
102+
}

0 commit comments

Comments
 (0)