changes based on review feedback.

This commit is contained in:
Erik Krogh Kristensen
2019-12-17 17:29:49 +01:00
parent 0a8a2ecc61
commit 2e5b7273ab
2 changed files with 185 additions and 189 deletions

View File

@@ -73,7 +73,7 @@ module Electron {
/** /**
* A reference to the `webContents` property of a browser object. * A reference to the `webContents` property of a browser object.
*/ */
class WebContents extends DataFlow::SourceNode, EventEmitter::EventEmitterRange::NodeJSEventEmitter { class WebContents extends DataFlow::SourceNode, EventEmitter::NodeJSEventEmitter {
WebContents() { this.(DataFlow::PropRead).accesses(any(BrowserObject bo), "webContents") } WebContents() { this.(DataFlow::PropRead).accesses(any(BrowserObject bo), "webContents") }
} }
@@ -89,9 +89,9 @@ module Electron {
/** /**
* A model for the Main and Renderer process in an Electron app. * A model for the Main and Renderer process in an Electron app.
*/ */
abstract class Process extends EventEmitter::EventEmitterRange::Range { abstract class Process extends EventEmitter::Range {
/** /**
* Type tracking on a process. The type tracking tracks through chainable methods. * Gets a node that refers to a Process object.
*/ */
DataFlow::SourceNode ref() { result = EventEmitter::trackEventEmitter(this) } DataFlow::SourceNode ref() { result = EventEmitter::trackEventEmitter(this) }
} }
@@ -128,7 +128,7 @@ module Electron {
* Does mostly the same as an EventEmitter event handler, * Does mostly the same as an EventEmitter event handler,
* except that values can be returned through the `event.returnValue` property. * except that values can be returned through the `event.returnValue` property.
*/ */
class IPCSendRegistration extends EventEmitter::EventRegistration::Range, class IPCSendRegistration extends EventRegistration::Range,
DataFlow::MethodCallNode { DataFlow::MethodCallNode {
override Process emitter; override Process emitter;
@@ -138,17 +138,17 @@ module Electron {
result = this.getABoundCallbackParameter(1, 0).getAPropertyWrite("returnValue").getRhs() result = this.getABoundCallbackParameter(1, 0).getAPropertyWrite("returnValue").getRhs()
} }
override predicate canReturnTo(EventEmitter::EventDispatch dispatch) { override IPCDispatch getAReturnDispatch() {
dispatch.(IPCDispatch).getCalleeName() = "sendSync" result.getCalleeName() = "sendSync"
} }
} }
/** /**
* A dispatch of an IPC event. * A dispatch of an IPC event.
* An IPC event is sent from the Renderer to the Main process. * An IPC event is sent from the renderer to the main process.
* And a value can be returned through the `returnValue` property of the event (first parameter in the callback). * And a value can be returned through the `returnValue` property of the event (first parameter in the callback).
*/ */
class IPCDispatch extends EventEmitter::EventDispatch::Range, DataFlow::InvokeNode { class IPCDispatch extends EventDispatch::Range, DataFlow::InvokeNode {
override Process emitter; override Process emitter;
IPCDispatch() { IPCDispatch() {

View File

@@ -19,11 +19,21 @@ module EventEmitter {
result = "prependOnceListener" result = "prependOnceListener"
} }
/**
* Gets a node that refers to an EventEmitter object.
*/
DataFlow::SourceNode trackEventEmitter(EventEmitter::Range emitter) {
result = trackEventEmitter(DataFlow::TypeTracker::end(), emitter)
}
private DataFlow::SourceNode trackEventEmitter(DataFlow::TypeTracker t, EventEmitterRange::Range emitter) { private DataFlow::SourceNode trackEventEmitter(
DataFlow::TypeTracker t, EventEmitter::Range emitter
) {
t.start() and result = emitter t.start() and result = emitter
or or
exists(DataFlow::TypeTracker t2, DataFlow::SourceNode pred | pred = trackEventEmitter(t2, emitter) | exists(DataFlow::TypeTracker t2, DataFlow::SourceNode pred |
pred = trackEventEmitter(t2, emitter)
|
result = pred.track(t2, t) result = pred.track(t2, t)
or or
// invocation of a chainable method // invocation of a chainable method
@@ -37,30 +47,12 @@ module EventEmitter {
) )
} }
/**
* Type tracking of an EventEmitter. Types are tracked through the chainable methods in the NodeJS eventEmitter.
*/
DataFlow::SourceNode trackEventEmitter(EventEmitterRange::Range emitter) {
result = trackEventEmitter(DataFlow::TypeTracker::end(), emitter)
}
/**
* An EventEmitter instance that implements the NodeJS EventEmitter API.
* Extend EventEmitter::Range to mark something as being an EventEmitter.
*/
class EventEmitter extends DataFlow::Node {
EventEmitterRange::Range range;
EventEmitter() { this = range }
}
module EventEmitterRange {
/** /**
* An object that implements the EventEmitter API. * An object that implements the EventEmitter API.
* Extending this class does nothing, its mostly to indicate intent. * Extending this class does nothing, its mostly to indicate intent.
* The magic only happens when extending EventRegistration::Range and EventDispatch::Range. * The magic only happens when extending EventRegistration::Range and EventDispatch::Range.
*/ */
abstract class Range extends DataFlow::Node {} abstract class Range extends DataFlow::Node { }
/** /**
* An NodeJS EventEmitter instance. * An NodeJS EventEmitter instance.
@@ -68,6 +60,9 @@ module EventEmitter {
* (That is opposed to e.g. SocketIO, which implements the same interface, but where events cross object boundaries). * (That is opposed to e.g. SocketIO, which implements the same interface, but where events cross object boundaries).
*/ */
abstract class NodeJSEventEmitter extends Range { abstract class NodeJSEventEmitter extends Range {
/**
* Get a Node that refers to a NodeJS EventEmitter instance.
*/
DataFlow::SourceNode ref() { result = trackEventEmitter(this) } DataFlow::SourceNode ref() { result = trackEventEmitter(this) }
} }
@@ -81,12 +76,22 @@ module EventEmitter {
) )
} }
} }
} }
/** /**
* An EventEmitter instance that implements the NodeJS EventEmitter API.
* Extend EventEmitter::Range to mark something as being an EventEmitter.
*/
class EventEmitter extends DataFlow::Node {
EventEmitter::Range range;
EventEmitter() { this = range }
}
/**
* A registration of an event handler on an EventEmitter. * A registration of an event handler on an EventEmitter.
*/ */
class EventRegistration extends DataFlow::Node { class EventRegistration extends DataFlow::Node {
EventRegistration::Range range; EventRegistration::Range range;
EventRegistration() { this = range } EventRegistration() { this = range }
@@ -107,13 +112,13 @@ module EventEmitter {
DataFlow::Node getAReturnedValue() { result = range.getAReturnedValue() } DataFlow::Node getAReturnedValue() { result = range.getAReturnedValue() }
/** /**
* Holds if this event handler can return a value to the given `dispatch`. * Get a dispatch that this event handler can return a value to.
* The default implementation is that there exists no such dispatch. * The default implementation is that there exists no such dispatch.
*/ */
predicate canReturnTo(EventDispatch dispatch) { range.canReturnTo(dispatch) } EventDispatch getAReturnDispatch() { result = range.getAReturnDispatch() }
} }
module EventRegistration { module EventRegistration {
/** /**
* A registration of an event handler on an EventEmitter. * A registration of an event handler on an EventEmitter.
* The default implementation assumes that `this` is a DataFlow::InvokeNode where the * The default implementation assumes that `this` is a DataFlow::InvokeNode where the
@@ -121,13 +126,11 @@ module EventEmitter {
* argument is the event handler callback. * argument is the event handler callback.
*/ */
abstract class Range extends DataFlow::Node { abstract class Range extends DataFlow::Node {
EventEmitterRange::Range emitter; EventEmitter::Range emitter;
final EventEmitter getEmitter() { result = emitter } final EventEmitter getEmitter() { result = emitter }
string getChannel() { string getChannel() { this.(DataFlow::InvokeNode).getArgument(0).mayHaveStringValue(result) }
this.(DataFlow::InvokeNode).getArgument(0).mayHaveStringValue(result)
}
DataFlow::Node getReceivedItem(int i) { DataFlow::Node getReceivedItem(int i) {
result = this.(DataFlow::InvokeNode).getABoundCallbackParameter(1, i) result = this.(DataFlow::InvokeNode).getABoundCallbackParameter(1, i)
@@ -135,20 +138,20 @@ module EventEmitter {
DataFlow::Node getAReturnedValue() { none() } DataFlow::Node getAReturnedValue() { none() }
predicate canReturnTo(EventDispatch dispatch) { none() } EventDispatch::Range getAReturnDispatch() { none() }
} }
private class NodeJSEventRegistration extends Range, DataFlow::MethodCallNode { private class NodeJSEventRegistration extends Range, DataFlow::MethodCallNode {
override EventEmitterRange::NodeJSEventEmitter emitter; override EventEmitter::NodeJSEventEmitter emitter;
NodeJSEventRegistration() { this = emitter.ref().getAMethodCall(EventEmitter::on()) } NodeJSEventRegistration() { this = emitter.ref().getAMethodCall(EventEmitter::on()) }
} }
} }
/** /**
* A dispatch of an event on an EventEmitter. * A dispatch of an event on an EventEmitter.
*/ */
class EventDispatch extends DataFlow::Node { class EventDispatch extends DataFlow::Node {
EventDispatch::Range range; EventDispatch::Range range;
EventDispatch() { this = range } EventDispatch() { this = range }
@@ -168,9 +171,9 @@ module EventEmitter {
* Channels are by default ignored. * Channels are by default ignored.
*/ */
EventRegistration getAReceiver() { result = range.getAReceiver() } EventRegistration getAReceiver() { result = range.getAReceiver() }
} }
module EventDispatch { module EventDispatch {
/** /**
* A dispatch of an event on an EventEmitter. * A dispatch of an event on an EventEmitter.
* The default implementation assumes that the dispatch is a DataFlow::InvokeNode, * The default implementation assumes that the dispatch is a DataFlow::InvokeNode,
@@ -178,34 +181,28 @@ module EventEmitter {
* is the `i`th item sent to the event handler. * is the `i`th item sent to the event handler.
*/ */
abstract class Range extends DataFlow::Node { abstract class Range extends DataFlow::Node {
EventEmitterRange::Range emitter; EventEmitter::Range emitter;
final EventEmitter getEmitter() { result = emitter } final EventEmitter getEmitter() { result = emitter }
string getChannel() { string getChannel() { this.(DataFlow::InvokeNode).getArgument(0).mayHaveStringValue(result) }
this.(DataFlow::InvokeNode).getArgument(0).mayHaveStringValue(result)
}
DataFlow::Node getSentItem(int i) { DataFlow::Node getSentItem(int i) { result = this.(DataFlow::InvokeNode).getArgument(i + 1) }
result = this.(DataFlow::InvokeNode).getArgument(i + 1)
}
EventRegistration::Range getAReceiver() { EventRegistration::Range getAReceiver() { this.getEmitter() = result.getEmitter() }
this.getEmitter() = result.getEmitter()
}
} }
private class NodeJSEventDispatch extends Range, DataFlow::MethodCallNode { private class NodeJSEventDispatch extends Range, DataFlow::MethodCallNode {
override EventEmitterRange::NodeJSEventEmitter emitter; override EventEmitter::NodeJSEventEmitter emitter;
NodeJSEventDispatch() { this = emitter.ref().getAMethodCall("emit") } NodeJSEventDispatch() { this = emitter.ref().getAMethodCall("emit") }
} }
} }
/** /**
* A taint-step that models data-flow between event handlers and event dispatchers. * A taint-step that models data-flow between event handlers and event dispatchers.
*/ */
private class EventEmitterTaintStep extends DataFlow::AdditionalFlowStep { private class EventEmitterTaintStep extends DataFlow::AdditionalFlowStep {
EventRegistration reg; EventRegistration reg;
EventDispatch dispatch; EventDispatch dispatch;
@@ -221,9 +218,8 @@ module EventEmitter {
succ = reg.getReceivedItem(i) succ = reg.getReceivedItem(i)
) )
or or
reg.canReturnTo(dispatch) and dispatch = reg.getAReturnDispatch() and
pred = reg.getAReturnedValue() and pred = reg.getAReturnedValue() and
succ = dispatch succ = dispatch
} }
}
} }