Skip to content

Commit 2e5b727

Browse files
committed
changes based on review feedback.
1 parent 0a8a2ec commit 2e5b727

File tree

2 files changed

+151
-155
lines changed

2 files changed

+151
-155
lines changed

javascript/ql/src/semmle/javascript/frameworks/Electron.qll

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ module Electron {
7373
/**
7474
* A reference to the `webContents` property of a browser object.
7575
*/
76-
class WebContents extends DataFlow::SourceNode, EventEmitter::EventEmitterRange::NodeJSEventEmitter {
76+
class WebContents extends DataFlow::SourceNode, EventEmitter::NodeJSEventEmitter {
7777
WebContents() { this.(DataFlow::PropRead).accesses(any(BrowserObject bo), "webContents") }
7878
}
7979

@@ -89,9 +89,9 @@ module Electron {
8989
/**
9090
* A model for the Main and Renderer process in an Electron app.
9191
*/
92-
abstract class Process extends EventEmitter::EventEmitterRange::Range {
92+
abstract class Process extends EventEmitter::Range {
9393
/**
94-
* Type tracking on a process. The type tracking tracks through chainable methods.
94+
* Gets a node that refers to a Process object.
9595
*/
9696
DataFlow::SourceNode ref() { result = EventEmitter::trackEventEmitter(this) }
9797
}
@@ -128,7 +128,7 @@ module Electron {
128128
* Does mostly the same as an EventEmitter event handler,
129129
* except that values can be returned through the `event.returnValue` property.
130130
*/
131-
class IPCSendRegistration extends EventEmitter::EventRegistration::Range,
131+
class IPCSendRegistration extends EventRegistration::Range,
132132
DataFlow::MethodCallNode {
133133
override Process emitter;
134134

@@ -138,17 +138,17 @@ module Electron {
138138
result = this.getABoundCallbackParameter(1, 0).getAPropertyWrite("returnValue").getRhs()
139139
}
140140

141-
override predicate canReturnTo(EventEmitter::EventDispatch dispatch) {
142-
dispatch.(IPCDispatch).getCalleeName() = "sendSync"
141+
override IPCDispatch getAReturnDispatch() {
142+
result.getCalleeName() = "sendSync"
143143
}
144144
}
145145

146146
/**
147147
* A dispatch of an IPC event.
148-
* An IPC event is sent from the Renderer to the Main process.
148+
* An IPC event is sent from the renderer to the main process.
149149
* And a value can be returned through the `returnValue` property of the event (first parameter in the callback).
150150
*/
151-
class IPCDispatch extends EventEmitter::EventDispatch::Range, DataFlow::InvokeNode {
151+
class IPCDispatch extends EventDispatch::Range, DataFlow::InvokeNode {
152152
override Process emitter;
153153

154154
IPCDispatch() {

javascript/ql/src/semmle/javascript/frameworks/EventEmitter.qll

Lines changed: 143 additions & 147 deletions
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,21 @@ module EventEmitter {
1919
result = "prependOnceListener"
2020
}
2121

22+
/**
23+
* Gets a node that refers to an EventEmitter object.
24+
*/
25+
DataFlow::SourceNode trackEventEmitter(EventEmitter::Range emitter) {
26+
result = trackEventEmitter(DataFlow::TypeTracker::end(), emitter)
27+
}
2228

23-
private DataFlow::SourceNode trackEventEmitter(DataFlow::TypeTracker t, EventEmitterRange::Range emitter) {
29+
private DataFlow::SourceNode trackEventEmitter(
30+
DataFlow::TypeTracker t, EventEmitter::Range emitter
31+
) {
2432
t.start() and result = emitter
2533
or
26-
exists(DataFlow::TypeTracker t2, DataFlow::SourceNode pred | pred = trackEventEmitter(t2, emitter) |
34+
exists(DataFlow::TypeTracker t2, DataFlow::SourceNode pred |
35+
pred = trackEventEmitter(t2, emitter)
36+
|
2737
result = pred.track(t2, t)
2838
or
2939
// invocation of a chainable method
@@ -38,192 +48,178 @@ module EventEmitter {
3848
}
3949

4050
/**
41-
* Type tracking of an EventEmitter. Types are tracked through the chainable methods in the NodeJS eventEmitter.
51+
* An object that implements the EventEmitter API.
52+
* Extending this class does nothing, its mostly to indicate intent.
53+
* The magic only happens when extending EventRegistration::Range and EventDispatch::Range.
4254
*/
43-
DataFlow::SourceNode trackEventEmitter(EventEmitterRange::Range emitter) {
44-
result = trackEventEmitter(DataFlow::TypeTracker::end(), emitter)
45-
}
55+
abstract class Range extends DataFlow::Node { }
4656

4757
/**
48-
* An EventEmitter instance that implements the NodeJS EventEmitter API.
49-
* Extend EventEmitter::Range to mark something as being an EventEmitter.
58+
* An NodeJS EventEmitter instance.
59+
* Events dispatched on this EventEmitter will be handled by event handlers registered on this EventEmitter.
60+
* (That is opposed to e.g. SocketIO, which implements the same interface, but where events cross object boundaries).
5061
*/
51-
class EventEmitter extends DataFlow::Node {
52-
EventEmitterRange::Range range;
53-
54-
EventEmitter() { this = range }
55-
}
56-
57-
module EventEmitterRange {
62+
abstract class NodeJSEventEmitter extends Range {
5863
/**
59-
* An object that implements the EventEmitter API.
60-
* Extending this class does nothing, its mostly to indicate intent.
61-
* The magic only happens when extending EventRegistration::Range and EventDispatch::Range.
64+
* Get a Node that refers to a NodeJS EventEmitter instance.
6265
*/
63-
abstract class Range extends DataFlow::Node {}
64-
65-
/**
66-
* An NodeJS EventEmitter instance.
67-
* Events dispatched on this EventEmitter will be handled by event handlers registered on this EventEmitter.
68-
* (That is opposed to e.g. SocketIO, which implements the same interface, but where events cross object boundaries).
69-
*/
70-
abstract class NodeJSEventEmitter extends Range {
71-
DataFlow::SourceNode ref() { result = trackEventEmitter(this) }
72-
}
66+
DataFlow::SourceNode ref() { result = trackEventEmitter(this) }
67+
}
7368

74-
private class ImportedNodeJSEventEmitter extends NodeJSEventEmitter {
75-
ImportedNodeJSEventEmitter() {
76-
exists(DataFlow::SourceNode clazz |
77-
clazz = DataFlow::moduleImport("events") or
78-
clazz = DataFlow::moduleMember("events", "EventEmitter")
79-
|
80-
this = clazz.getAnInstantiation()
81-
)
82-
}
69+
private class ImportedNodeJSEventEmitter extends NodeJSEventEmitter {
70+
ImportedNodeJSEventEmitter() {
71+
exists(DataFlow::SourceNode clazz |
72+
clazz = DataFlow::moduleImport("events") or
73+
clazz = DataFlow::moduleMember("events", "EventEmitter")
74+
|
75+
this = clazz.getAnInstantiation()
76+
)
8377
}
8478
}
79+
}
8580

86-
/**
87-
* A registration of an event handler on an EventEmitter.
88-
*/
89-
class EventRegistration extends DataFlow::Node {
90-
EventRegistration::Range range;
81+
/**
82+
* An EventEmitter instance that implements the NodeJS EventEmitter API.
83+
* Extend EventEmitter::Range to mark something as being an EventEmitter.
84+
*/
85+
class EventEmitter extends DataFlow::Node {
86+
EventEmitter::Range range;
9187

92-
EventRegistration() { this = range }
88+
EventEmitter() { this = range }
89+
}
9390

94-
/** Gets the EventEmitter that the event handler is registered on. */
95-
final EventEmitter getEmitter() { result = range.getEmitter() }
91+
/**
92+
* A registration of an event handler on an EventEmitter.
93+
*/
94+
class EventRegistration extends DataFlow::Node {
95+
EventRegistration::Range range;
9696

97-
/** Gets the name of the channel if possible. */
98-
string getChannel() { result = range.getChannel() }
97+
EventRegistration() { this = range }
9998

100-
/** Gets the `i`th parameter in the event handler. */
101-
DataFlow::Node getReceivedItem(int i) { result = range.getReceivedItem(i) }
99+
/** Gets the EventEmitter that the event handler is registered on. */
100+
final EventEmitter getEmitter() { result = range.getEmitter() }
102101

103-
/**
104-
* Gets a value that is returned by the event handler.
105-
* The default implementation is that no value can be returned.
106-
*/
107-
DataFlow::Node getAReturnedValue() { result = range.getAReturnedValue() }
102+
/** Gets the name of the channel if possible. */
103+
string getChannel() { result = range.getChannel() }
108104

109-
/**
110-
* Holds if this event handler can return a value to the given `dispatch`.
111-
* The default implementation is that there exists no such dispatch.
112-
*/
113-
predicate canReturnTo(EventDispatch dispatch) { range.canReturnTo(dispatch) }
114-
}
105+
/** Gets the `i`th parameter in the event handler. */
106+
DataFlow::Node getReceivedItem(int i) { result = range.getReceivedItem(i) }
115107

116-
module EventRegistration {
117-
/**
118-
* A registration of an event handler on an EventEmitter.
119-
* The default implementation assumes that `this` is a DataFlow::InvokeNode where the
120-
* first argument is a string describing which channel is registered, and the second
121-
* argument is the event handler callback.
122-
*/
123-
abstract class Range extends DataFlow::Node {
124-
EventEmitterRange::Range emitter;
108+
/**
109+
* Gets a value that is returned by the event handler.
110+
* The default implementation is that no value can be returned.
111+
*/
112+
DataFlow::Node getAReturnedValue() { result = range.getAReturnedValue() }
125113

126-
final EventEmitter getEmitter() { result = emitter }
114+
/**
115+
* Get a dispatch that this event handler can return a value to.
116+
* The default implementation is that there exists no such dispatch.
117+
*/
118+
EventDispatch getAReturnDispatch() { result = range.getAReturnDispatch() }
119+
}
127120

128-
string getChannel() {
129-
this.(DataFlow::InvokeNode).getArgument(0).mayHaveStringValue(result)
130-
}
121+
module EventRegistration {
122+
/**
123+
* A registration of an event handler on an EventEmitter.
124+
* The default implementation assumes that `this` is a DataFlow::InvokeNode where the
125+
* first argument is a string describing which channel is registered, and the second
126+
* argument is the event handler callback.
127+
*/
128+
abstract class Range extends DataFlow::Node {
129+
EventEmitter::Range emitter;
131130

132-
DataFlow::Node getReceivedItem(int i) {
133-
result = this.(DataFlow::InvokeNode).getABoundCallbackParameter(1, i)
134-
}
131+
final EventEmitter getEmitter() { result = emitter }
135132

136-
DataFlow::Node getAReturnedValue() { none() }
133+
string getChannel() { this.(DataFlow::InvokeNode).getArgument(0).mayHaveStringValue(result) }
137134

138-
predicate canReturnTo(EventDispatch dispatch) { none() }
135+
DataFlow::Node getReceivedItem(int i) {
136+
result = this.(DataFlow::InvokeNode).getABoundCallbackParameter(1, i)
139137
}
140138

141-
private class NodeJSEventRegistration extends Range, DataFlow::MethodCallNode {
142-
override EventEmitterRange::NodeJSEventEmitter emitter;
139+
DataFlow::Node getAReturnedValue() { none() }
143140

144-
NodeJSEventRegistration() { this = emitter.ref().getAMethodCall(EventEmitter::on()) }
145-
}
141+
EventDispatch::Range getAReturnDispatch() { none() }
146142
}
147143

148-
/**
149-
* A dispatch of an event on an EventEmitter.
150-
*/
151-
class EventDispatch extends DataFlow::Node {
152-
EventDispatch::Range range;
144+
private class NodeJSEventRegistration extends Range, DataFlow::MethodCallNode {
145+
override EventEmitter::NodeJSEventEmitter emitter;
153146

154-
EventDispatch() { this = range }
147+
NodeJSEventRegistration() { this = emitter.ref().getAMethodCall(EventEmitter::on()) }
148+
}
149+
}
155150

156-
/** Gets the emitter that the event dispatch happens on. */
157-
EventEmitter getEmitter() { result = range.getEmitter() }
151+
/**
152+
* A dispatch of an event on an EventEmitter.
153+
*/
154+
class EventDispatch extends DataFlow::Node {
155+
EventDispatch::Range range;
158156

159-
/** Gets the name of the channel if possible. */
160-
string getChannel() { result = range.getChannel() }
157+
EventDispatch() { this = range }
161158

162-
/** Gets the `i`th argument that is send to the event handler. */
163-
DataFlow::Node getSentItem(int i) { result = range.getSentItem(i) }
159+
/** Gets the emitter that the event dispatch happens on. */
160+
EventEmitter getEmitter() { result = range.getEmitter() }
164161

165-
/**
166-
* Get an EventRegistration that this event dispatch can send an event to.
167-
* The default implementation is that the emitters of the dispatch and registration have to be equal.
168-
* Channels are by default ignored.
169-
*/
170-
EventRegistration getAReceiver() { result = range.getAReceiver() }
171-
}
162+
/** Gets the name of the channel if possible. */
163+
string getChannel() { result = range.getChannel() }
172164

173-
module EventDispatch {
174-
/**
175-
* A dispatch of an event on an EventEmitter.
176-
* The default implementation assumes that the dispatch is a DataFlow::InvokeNode,
177-
* where the first argument is a string describing the channel, and the `i`+1 argument
178-
* is the `i`th item sent to the event handler.
179-
*/
180-
abstract class Range extends DataFlow::Node {
181-
EventEmitterRange::Range emitter;
165+
/** Gets the `i`th argument that is send to the event handler. */
166+
DataFlow::Node getSentItem(int i) { result = range.getSentItem(i) }
182167

183-
final EventEmitter getEmitter() { result = emitter }
168+
/**
169+
* Get an EventRegistration that this event dispatch can send an event to.
170+
* The default implementation is that the emitters of the dispatch and registration have to be equal.
171+
* Channels are by default ignored.
172+
*/
173+
EventRegistration getAReceiver() { result = range.getAReceiver() }
174+
}
184175

185-
string getChannel() {
186-
this.(DataFlow::InvokeNode).getArgument(0).mayHaveStringValue(result)
187-
}
176+
module EventDispatch {
177+
/**
178+
* A dispatch of an event on an EventEmitter.
179+
* The default implementation assumes that the dispatch is a DataFlow::InvokeNode,
180+
* where the first argument is a string describing the channel, and the `i`+1 argument
181+
* is the `i`th item sent to the event handler.
182+
*/
183+
abstract class Range extends DataFlow::Node {
184+
EventEmitter::Range emitter;
188185

189-
DataFlow::Node getSentItem(int i) {
190-
result = this.(DataFlow::InvokeNode).getArgument(i + 1)
191-
}
186+
final EventEmitter getEmitter() { result = emitter }
192187

193-
EventRegistration::Range getAReceiver() {
194-
this.getEmitter() = result.getEmitter()
195-
}
196-
}
188+
string getChannel() { this.(DataFlow::InvokeNode).getArgument(0).mayHaveStringValue(result) }
197189

198-
private class NodeJSEventDispatch extends Range, DataFlow::MethodCallNode {
199-
override EventEmitterRange::NodeJSEventEmitter emitter;
190+
DataFlow::Node getSentItem(int i) { result = this.(DataFlow::InvokeNode).getArgument(i + 1) }
200191

201-
NodeJSEventDispatch() { this = emitter.ref().getAMethodCall("emit") }
202-
}
192+
EventRegistration::Range getAReceiver() { this.getEmitter() = result.getEmitter() }
203193
}
204194

205-
/**
206-
* A taint-step that models data-flow between event handlers and event dispatchers.
207-
*/
208-
private class EventEmitterTaintStep extends DataFlow::AdditionalFlowStep {
209-
EventRegistration reg;
210-
EventDispatch dispatch;
211-
212-
EventEmitterTaintStep() {
213-
this = dispatch and
214-
reg = dispatch.getAReceiver() and
215-
not dispatch.getChannel() != reg.getChannel()
216-
}
195+
private class NodeJSEventDispatch extends Range, DataFlow::MethodCallNode {
196+
override EventEmitter::NodeJSEventEmitter emitter;
217197

218-
override predicate step(DataFlow::Node pred, DataFlow::Node succ) {
219-
exists(int i | i >= 0 |
220-
pred = dispatch.getSentItem(i) and
221-
succ = reg.getReceivedItem(i)
222-
)
223-
or
224-
reg.canReturnTo(dispatch) and
225-
pred = reg.getAReturnedValue() and
226-
succ = dispatch
227-
}
198+
NodeJSEventDispatch() { this = emitter.ref().getAMethodCall("emit") }
199+
}
200+
}
201+
202+
/**
203+
* A taint-step that models data-flow between event handlers and event dispatchers.
204+
*/
205+
private class EventEmitterTaintStep extends DataFlow::AdditionalFlowStep {
206+
EventRegistration reg;
207+
EventDispatch dispatch;
208+
209+
EventEmitterTaintStep() {
210+
this = dispatch and
211+
reg = dispatch.getAReceiver() and
212+
not dispatch.getChannel() != reg.getChannel()
213+
}
214+
215+
override predicate step(DataFlow::Node pred, DataFlow::Node succ) {
216+
exists(int i | i >= 0 |
217+
pred = dispatch.getSentItem(i) and
218+
succ = reg.getReceivedItem(i)
219+
)
220+
or
221+
dispatch = reg.getAReturnDispatch() and
222+
pred = reg.getAReturnedValue() and
223+
succ = dispatch
228224
}
229225
}

0 commit comments

Comments
 (0)