@@ -50,7 +50,7 @@ module Electron {
5050 */
5151 private class BrowserObjectByType extends BrowserObject {
5252 BrowserObjectByType ( ) {
53- exists ( string tp | tp = "BrowserWindow" or tp = "BrowserView" |
53+ exists ( string tp | tp = "BrowserWindow" or tp = "BrowserView" |
5454 asExpr ( ) .getType ( ) .hasUnderlyingType ( "electron" , tp )
5555 )
5656 }
@@ -60,17 +60,202 @@ module Electron {
6060 * A data flow node whose value may originate from a browser object instantiation.
6161 */
6262 private class BrowserObjectByFlow extends BrowserObject {
63- BrowserObjectByFlow ( ) {
64- any ( NewBrowserObject nbo ) .flowsTo ( this )
65- }
63+ BrowserObjectByFlow ( ) { any ( NewBrowserObject nbo ) .flowsTo ( this ) }
6664 }
6765
6866 /**
6967 * A reference to the `webContents` property of a browser object.
7068 */
7169 class WebContents extends DataFlow:: SourceNode {
72- WebContents ( ) {
73- this .( DataFlow:: PropRead ) .accesses ( any ( BrowserObject bo ) , "webContents" )
70+ WebContents ( ) { this .( DataFlow:: PropRead ) .accesses ( any ( BrowserObject bo ) , "webContents" ) }
71+ }
72+
73+ /**
74+ * Provides classes and predicates for modelling Electron IPC.
75+ */
76+ private module IPC {
77+ class Process extends string {
78+ Process ( ) { this = "main" or this = "renderer" }
79+
80+ DataFlow:: SourceNode getAnImport ( ) {
81+ this = Process:: main ( ) and result = DataFlow:: moduleMember ( "electron" , "ipcMain" )
82+ or
83+ this = Process:: renderer ( ) and result = DataFlow:: moduleMember ( "electron" , "ipcRenderer" )
84+ }
85+ }
86+
87+ module Process {
88+ Process main ( ) { result = "main" }
89+
90+ Process renderer ( ) { result = "renderer" }
91+ }
92+
93+ /**
94+ * An IPC callback.
95+ */
96+ class Callback extends DataFlow:: FunctionNode {
97+ DataFlow:: Node channel ;
98+
99+ Process process ;
100+
101+ Callback ( ) {
102+ exists ( DataFlow:: MethodCallNode mc |
103+ mc = process .getAnImport ( ) .getAMemberCall ( "on" ) and
104+ this = mc .getCallback ( 1 ) and
105+ channel = mc .getArgument ( 0 )
106+ )
107+ }
108+
109+ /** Gets the process on which this callback is executed. */
110+ Process getProcess ( ) { result = process }
111+
112+ /** Gets the name of the channel the callback is listening on. */
113+ string getChannelName ( ) { result = channel .asExpr ( ) .getStringValue ( ) }
114+
115+ /** Gets the data flow node containing the message received by the callback. */
116+ DataFlow:: Node getMessage ( ) {
117+ result = getParameter ( 1 )
118+ }
119+ }
120+
121+ /**
122+ * An IPC message.
123+ */
124+ abstract class Message extends DataFlow:: Node {
125+ /** Gets the process that sends this message. */
126+ abstract Process getProcess ( ) ;
127+
128+ /** Gets the name of the channel this message is sent on. */
129+ abstract string getChannelName ( ) ;
130+ }
131+
132+ /**
133+ * An IPC message sent directly from a process.
134+ */
135+ class DirectMessage extends Message {
136+ DataFlow:: MethodCallNode mc ;
137+
138+ Process process ;
139+
140+ DataFlow:: Node channel ;
141+
142+ boolean isSync ;
143+
144+ DirectMessage ( ) {
145+ exists ( string send |
146+ send = "send" and isSync = false
147+ or
148+ send = "sendSync" and isSync = true
149+ |
150+ mc = process .getAnImport ( ) .getAMemberCall ( send ) and
151+ this = mc .getArgument ( 1 ) and
152+ channel = mc .getArgument ( 0 )
153+ )
154+ }
155+
156+ override Process getProcess ( ) { result = process }
157+
158+ override string getChannelName ( ) { result = channel .asExpr ( ) .getStringValue ( ) }
159+ }
160+
161+ /**
162+ * A synchronous IPC message sent directly from a process.
163+ */
164+ class SyncDirectMessage extends DirectMessage {
165+ SyncDirectMessage ( ) { isSync = true }
166+
167+ /** Gets the data flow node holding the reply to the message. */
168+ DataFlow:: Node getReply ( ) {
169+ result = mc
170+ }
171+ }
172+
173+ /**
174+ * An asynchronous IPC reply sent from within an IPC callback.
175+ */
176+ class AsyncReplyMessage extends Message {
177+ Callback callback ;
178+
179+ DataFlow:: Node channel ;
180+
181+ AsyncReplyMessage ( ) {
182+ exists ( DataFlow:: MethodCallNode mc |
183+ mc = callback .getParameter ( 0 ) .getAPropertyRead ( "sender" ) .getAMemberCall ( "send" ) and
184+ this = mc .getArgument ( 1 ) and
185+ channel = mc .getArgument ( 0 )
186+ )
187+ }
188+
189+ override Process getProcess ( ) { result = callback .getProcess ( ) }
190+
191+ override string getChannelName ( ) { result = channel .asExpr ( ) .getStringValue ( ) }
192+ }
193+
194+ /**
195+ * A synchronous IPC reply sent from within an IPC callback.
196+ */
197+ class SyncReplyMessage extends Message {
198+ Callback callback ;
199+
200+ SyncReplyMessage ( ) {
201+ this = callback .getParameter ( 0 ) .getAPropertyWrite ( "returnValue" ) .getRhs ( )
202+ }
203+
204+ override Process getProcess ( ) { result = callback .getProcess ( ) }
205+
206+ override string getChannelName ( ) { result = callback .getChannelName ( ) }
207+ }
208+
209+ /**
210+ * An asynchronous Electron IPC message sent from the main process via a `webContents` object.
211+ */
212+ class WebContentsMessage extends Message {
213+ DataFlow:: Node channel ;
214+
215+ WebContentsMessage ( ) {
216+ exists ( WebContents wc , DataFlow:: MethodCallNode mc |
217+ wc .flowsTo ( mc .getReceiver ( ) ) and
218+ this = mc .getArgument ( 1 ) and
219+ channel = mc .getArgument ( 0 ) and
220+ mc .getCalleeName ( ) = "send"
221+ )
222+ }
223+
224+ override Process getProcess ( ) { result = Process:: main ( ) }
225+
226+ override string getChannelName ( ) { result = channel .asExpr ( ) .getStringValue ( ) }
227+ }
228+
229+ /**
230+ * Holds if `pred` flows to `succ` via Electron IPC.
231+ */
232+ private predicate ipcFlowStep ( DataFlow:: Node pred , DataFlow:: Node succ ) {
233+ // match a message sent from one process with a callback parameter in the other process
234+ exists ( Callback callback , Message msg |
235+ callback .getChannelName ( ) = msg .getChannelName ( ) and
236+ callback .getProcess ( ) != msg .getProcess ( ) and
237+ pred = msg and
238+ succ = callback .getMessage ( )
239+ )
240+ or
241+ // match a synchronous reply sent from one process with a `sendSync` call in the other process
242+ exists ( SyncDirectMessage sendSync , SyncReplyMessage msg |
243+ sendSync .getChannelName ( ) = msg .getChannelName ( ) and
244+ sendSync .getProcess ( ) != msg .getProcess ( ) and
245+ pred = msg and
246+ succ = sendSync .getReply ( )
247+ )
248+ }
249+
250+ /**
251+ * An additional flow step via an Electron IPC message.
252+ */
253+ private class IPCAdditionalFlowStep extends DataFlow:: Configuration {
254+ IPCAdditionalFlowStep ( ) { this instanceof DataFlow:: Configuration }
255+
256+ override predicate isAdditionalFlowStep ( DataFlow:: Node pred , DataFlow:: Node succ ) {
257+ ipcFlowStep ( pred , succ )
258+ }
74259 }
75260 }
76261
0 commit comments