2
2
* Provides classes for working with XML parser APIs.
3
3
*/
4
4
5
- import javascript as js
5
+ private import javascript as js
6
+ private import js:: DataFlow as DataFlow
7
+ private import js:: API as API
6
8
7
9
module XML {
8
10
/**
@@ -12,9 +14,9 @@ module XML {
12
14
/** Internal general entity. */
13
15
InternalEntity ( ) or
14
16
/** External general entity, either parsed or unparsed. */
15
- ExternalEntity ( boolean parsed ) { parsed = true or parsed = false } or
17
+ ExternalEntity ( boolean parsed ) { parsed = [ true , false ] } or
16
18
/** Parameter entity, either internal or external. */
17
- ParameterEntity ( boolean external ) { external = true or external = false }
19
+ ParameterEntity ( boolean external ) { external = [ true , false ] }
18
20
19
21
/**
20
22
* A call to an XML parsing function.
@@ -27,16 +29,19 @@ module XML {
27
29
abstract predicate resolvesEntities ( EntityKind kind ) ;
28
30
29
31
/** Gets a reference to a value resulting from parsing the XML. */
30
- js :: DataFlow:: Node getAResult ( ) { none ( ) }
32
+ DataFlow:: Node getAResult ( ) { none ( ) }
31
33
}
32
34
33
35
/**
34
36
* An invocation of `libxmljs.parseXml` or `libxmljs.parseXmlString`.
35
37
*/
36
38
class LibXmlJsParserInvocation extends ParserInvocation {
39
+ API:: CallNode call ;
40
+
37
41
LibXmlJsParserInvocation ( ) {
38
42
exists ( string m |
39
- this = js:: DataFlow:: moduleMember ( "libxmljs" , m ) .getACall ( ) .asExpr ( ) and
43
+ call = API:: moduleImport ( "libxmljs" ) .getMember ( m ) .getACall ( ) and
44
+ this = call .asExpr ( ) and
40
45
m .matches ( "parseXml%" )
41
46
)
42
47
}
@@ -53,24 +58,67 @@ module XML {
53
58
noent .mayHaveBooleanValue ( true )
54
59
)
55
60
}
56
- }
57
61
58
- /**
59
- * Gets a call to method `methodName` on an instance of class `className` from module `modName`.
60
- */
61
- private js:: MethodCallExpr moduleMethodCall ( string modName , string className , string methodName ) {
62
- exists ( js:: DataFlow:: ModuleImportNode mod |
63
- mod .getPath ( ) = modName and
64
- result = mod .getAConstructorInvocation ( className ) .getAMethodCall ( methodName ) .asExpr ( )
65
- )
62
+ /**
63
+ * A document from the `libxmljs` library.
64
+ * The API is based on https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/libxmljs/index.d.ts
65
+ */
66
+ private API:: Node doc ( ) {
67
+ result = call .getReturn ( )
68
+ or
69
+ result = doc ( ) .getMember ( "encoding" ) .getReturn ( )
70
+ or
71
+ result = element ( ) .getMember ( "doc" ) .getReturn ( )
72
+ or
73
+ result = element ( ) .getMember ( "parent" ) .getReturn ( )
74
+ }
75
+
76
+ /**
77
+ * An `Element` from the `libxmljs` library.
78
+ */
79
+ private API:: Node element ( ) {
80
+ result = doc ( ) .getMember ( [ "child" , "get" , "node" , "root" ] ) .getReturn ( )
81
+ or
82
+ result = [ doc ( ) , element ( ) ] .getMember ( [ "childNodes" , "find" ] ) .getReturn ( ) .getAMember ( )
83
+ or
84
+ result =
85
+ element ( )
86
+ .getMember ( [
87
+ "parent" , "prevSibling" , "nextSibling" , "remove" , "clone" , "node" , "child" ,
88
+ "prevElement" , "nextElement"
89
+ ] )
90
+ .getReturn ( )
91
+ }
92
+
93
+ /**
94
+ * An `Attr` from the `libxmljs` library.
95
+ */
96
+ private API:: Node attr ( ) {
97
+ result = element ( ) .getMember ( "attr" ) .getReturn ( )
98
+ or
99
+ result = element ( ) .getMember ( "attrs" ) .getReturn ( ) .getAMember ( )
100
+ }
101
+
102
+ override DataFlow:: Node getAResult ( ) {
103
+ result = [ doc ( ) , element ( ) , attr ( ) ] .getAnImmediateUse ( )
104
+ or
105
+ result = element ( ) .getMember ( [ "name" , "text" ] ) .getACall ( )
106
+ or
107
+ result = attr ( ) .getMember ( [ "name" , "value" ] ) .getACall ( )
108
+ or
109
+ result = element ( ) .getMember ( "namespace" ) .getReturn ( ) .getMember ( [ "href" , "prefix" ] ) .getACall ( )
110
+ }
66
111
}
67
112
68
113
/**
69
114
* An invocation of `libxmljs.SaxParser.parseString`.
70
115
*/
71
116
class LibXmlJsSaxParserInvocation extends ParserInvocation {
117
+ API:: Node parser ;
118
+
72
119
LibXmlJsSaxParserInvocation ( ) {
73
- this = moduleMethodCall ( "libxmljs" , "SaxParser" , "parseString" )
120
+ parser = API:: moduleImport ( "libxmljs" ) .getMember ( "SaxParser" ) .getInstance ( ) and
121
+ this = parser .getMember ( "parseString" ) .getACall ( ) .asExpr ( )
74
122
}
75
123
76
124
override js:: Expr getSourceArgument ( ) { result = getArgument ( 0 ) }
@@ -79,14 +127,21 @@ module XML {
79
127
// entities are resolved by default
80
128
any ( )
81
129
}
130
+
131
+ override DataFlow:: Node getAResult ( ) {
132
+ result = parser .getMember ( "on" ) .getACall ( ) .getABoundCallbackParameter ( 1 , _)
133
+ }
82
134
}
83
135
84
136
/**
85
137
* An invocation of `libxmljs.SaxPushParser.push`.
86
138
*/
87
139
class LibXmlJsSaxPushParserInvocation extends ParserInvocation {
140
+ API:: Node parser ;
141
+
88
142
LibXmlJsSaxPushParserInvocation ( ) {
89
- this = moduleMethodCall ( "libxmljs" , "SaxPushParser" , "push" )
143
+ parser = API:: moduleImport ( "libxmljs" ) .getMember ( "SaxPushParser" ) .getInstance ( ) and
144
+ this = parser .getMember ( "push" ) .getACall ( ) .asExpr ( )
90
145
}
91
146
92
147
override js:: Expr getSourceArgument ( ) { result = getArgument ( 0 ) }
@@ -95,17 +150,21 @@ module XML {
95
150
// entities are resolved by default
96
151
any ( )
97
152
}
153
+
154
+ override DataFlow:: Node getAResult ( ) {
155
+ result = parser .getMember ( "on" ) .getACall ( ) .getABoundCallbackParameter ( 1 , _)
156
+ }
98
157
}
99
158
100
159
/**
101
160
* An invocation of `expat.Parser.parse` or `expat.Parser.write`.
102
161
*/
103
162
class ExpatParserInvocation extends ParserInvocation {
104
- js :: DataFlow :: NewNode parser ;
163
+ API :: Node parser ;
105
164
106
165
ExpatParserInvocation ( ) {
107
- parser = js :: DataFlow :: moduleMember ( "node-expat" , "Parser" ) .getAnInstantiation ( ) and
108
- this = parser .getAMemberCall ( [ "parse" , "write" ] ) .asExpr ( )
166
+ parser = API :: moduleImport ( "node-expat" ) . getMember ( "Parser" ) .getInstance ( ) and
167
+ this = parser .getMember ( [ "parse" , "write" ] ) . getACall ( ) .asExpr ( )
109
168
}
110
169
111
170
override js:: Expr getSourceArgument ( ) { result = getArgument ( 0 ) }
@@ -115,8 +174,8 @@ module XML {
115
174
kind = InternalEntity ( )
116
175
}
117
176
118
- override js :: DataFlow:: Node getAResult ( ) {
119
- result = parser .getAMemberCall ( "on" ) .getABoundCallbackParameter ( 1 , _)
177
+ override DataFlow:: Node getAResult ( ) {
178
+ result = parser .getMember ( "on" ) . getACall ( ) .getABoundCallbackParameter ( 1 , _)
120
179
}
121
180
}
122
181
@@ -125,26 +184,31 @@ module XML {
125
184
*/
126
185
private class DOMParserXmlParserInvocation extends XML:: ParserInvocation {
127
186
DOMParserXmlParserInvocation ( ) {
128
- exists ( js:: DataFlow:: GlobalVarRefNode domparser |
129
- domparser .getName ( ) = "DOMParser" and
130
- this = domparser .getAnInstantiation ( ) .getAMethodCall ( "parseFromString" ) .asExpr ( ) and
131
- // type contains the string `xml`, that is, it's not `text/html`
132
- getArgument ( 1 ) .mayHaveStringValue ( any ( string tp | tp .matches ( "%xml%" ) ) )
133
- )
187
+ this =
188
+ DataFlow:: globalVarRef ( "DOMParser" )
189
+ .getAnInstantiation ( )
190
+ .getAMethodCall ( "parseFromString" )
191
+ .asExpr ( ) and
192
+ // type contains the string `xml`, that is, it's not `text/html`
193
+ getArgument ( 1 ) .mayHaveStringValue ( any ( string tp | tp .matches ( "%xml%" ) ) )
134
194
}
135
195
136
196
override js:: Expr getSourceArgument ( ) { result = getArgument ( 0 ) }
137
197
138
198
override predicate resolvesEntities ( XML:: EntityKind kind ) { kind = InternalEntity ( ) }
199
+
200
+ // The result is an XMLDocument (https://developer.mozilla.org/en-US/docs/Web/API/XMLDocument).
201
+ // The API of the XMLDocument is not modelled.
202
+ override DataFlow:: Node getAResult ( ) { result .asExpr ( ) = this }
139
203
}
140
204
141
205
/**
142
206
* An invocation of `loadXML` on an IE legacy XML DOM or MSXML object.
143
207
*/
144
208
private class IELegacyXmlParserInvocation extends XML:: ParserInvocation {
145
209
IELegacyXmlParserInvocation ( ) {
146
- exists ( js :: DataFlow:: NewNode activeXObject , string activeXType |
147
- activeXObject = js :: DataFlow:: globalVarRef ( "ActiveXObject" ) .getAnInstantiation ( ) and
210
+ exists ( DataFlow:: NewNode activeXObject , string activeXType |
211
+ activeXObject = DataFlow:: globalVarRef ( "ActiveXObject" ) .getAnInstantiation ( ) and
148
212
activeXObject .getArgument ( 0 ) .asExpr ( ) .mayHaveStringValue ( activeXType ) and
149
213
activeXType .regexpMatch ( "Microsoft\\.XMLDOM|Msxml.*\\.DOMDocument.*" ) and
150
214
this = activeXObject .getAMethodCall ( "loadXML" ) .asExpr ( )
@@ -173,10 +237,10 @@ module XML {
173
237
* An invocation of `xml2js`.
174
238
*/
175
239
private class Xml2JSInvocation extends XML:: ParserInvocation {
176
- js :: DataFlow :: CallNode call ;
240
+ API :: CallNode call ;
177
241
178
242
Xml2JSInvocation ( ) {
179
- exists ( js :: API:: Node imp | imp = js :: API:: moduleImport ( "xml2js" ) |
243
+ exists ( API:: Node imp | imp = API:: moduleImport ( "xml2js" ) |
180
244
call = [ imp , imp .getMember ( "Parser" ) .getInstance ( ) ] .getMember ( "parseString" ) .getACall ( ) and
181
245
this = call .asExpr ( )
182
246
)
@@ -189,7 +253,7 @@ module XML {
189
253
none ( )
190
254
}
191
255
192
- override js :: DataFlow:: Node getAResult ( ) {
256
+ override DataFlow:: Node getAResult ( ) {
193
257
result = call .getABoundCallbackParameter ( call .getNumArgument ( ) - 1 , 1 )
194
258
}
195
259
}
@@ -198,10 +262,10 @@ module XML {
198
262
* An invocation of `sax`.
199
263
*/
200
264
private class SaxInvocation extends XML:: ParserInvocation {
201
- js :: DataFlow :: InvokeNode parser ;
265
+ API :: InvokeNode parser ;
202
266
203
267
SaxInvocation ( ) {
204
- exists ( js :: API:: Node imp | imp = js :: API:: moduleImport ( "sax" ) |
268
+ exists ( API:: Node imp | imp = API:: moduleImport ( "sax" ) |
205
269
parser = imp .getMember ( "parser" ) .getACall ( )
206
270
or
207
271
parser = imp .getMember ( "SAXParser" ) .getAnInstantiation ( )
@@ -216,13 +280,13 @@ module XML {
216
280
none ( )
217
281
}
218
282
219
- override js :: DataFlow:: Node getAResult ( ) {
283
+ override DataFlow:: Node getAResult ( ) {
220
284
result =
221
285
parser
222
- .getAPropertyWrite ( any ( string s | s .matches ( "on%" ) ) )
223
- .getRhs ( )
224
- .getAFunctionValue ( )
286
+ .getReturn ( )
287
+ .getMember ( any ( string s | s .matches ( "on%" ) ) )
225
288
.getAParameter ( )
289
+ .getAnImmediateUse ( )
226
290
}
227
291
}
228
292
@@ -232,7 +296,8 @@ module XML {
232
296
private class XmlJSInvocation extends XML:: ParserInvocation {
233
297
XmlJSInvocation ( ) {
234
298
this =
235
- js:: DataFlow:: moduleMember ( "xml-js" , [ "xml2json" , "xml2js" , "json2xml" , "js2xml" ] )
299
+ API:: moduleImport ( "xml-js" )
300
+ .getMember ( [ "xml2json" , "xml2js" , "json2xml" , "js2xml" ] )
236
301
.getACall ( )
237
302
.asExpr ( )
238
303
}
@@ -244,18 +309,18 @@ module XML {
244
309
none ( )
245
310
}
246
311
247
- override js :: DataFlow:: Node getAResult ( ) { result .asExpr ( ) = this }
312
+ override DataFlow:: Node getAResult ( ) { result .asExpr ( ) = this }
248
313
}
249
314
250
315
/**
251
316
* An invocation of `htmlparser2`.
252
317
*/
253
318
private class HtmlParser2Invocation extends XML:: ParserInvocation {
254
- js :: DataFlow :: NewNode parser ;
319
+ API :: NewNode parser ;
255
320
256
321
HtmlParser2Invocation ( ) {
257
- parser = js :: DataFlow :: moduleMember ( "htmlparser2" , "Parser" ) .getAnInstantiation ( ) and
258
- this = parser .getAMemberCall ( "write" ) .asExpr ( )
322
+ parser = API :: moduleImport ( "htmlparser2" ) . getMember ( "Parser" ) .getAnInstantiation ( ) and
323
+ this = parser .getReturn ( ) . getMember ( "write" ) . getACall ( ) .asExpr ( )
259
324
}
260
325
261
326
override js:: Expr getSourceArgument ( ) { result = getArgument ( 0 ) }
@@ -265,7 +330,7 @@ module XML {
265
330
none ( )
266
331
}
267
332
268
- override js :: DataFlow:: Node getAResult ( ) {
333
+ override DataFlow:: Node getAResult ( ) {
269
334
result =
270
335
parser
271
336
.getArgument ( 0 )
@@ -277,7 +342,7 @@ module XML {
277
342
}
278
343
279
344
private class XMLParserTaintStep extends js:: TaintTracking:: SharedTaintStep {
280
- override predicate deserializeStep ( js :: DataFlow:: Node pred , js :: DataFlow:: Node succ ) {
345
+ override predicate deserializeStep ( DataFlow:: Node pred , DataFlow:: Node succ ) {
281
346
exists ( XML:: ParserInvocation parser |
282
347
pred .asExpr ( ) = parser .getSourceArgument ( ) and
283
348
succ = parser .getAResult ( )
0 commit comments