Skip to content

Commit de0e67f

Browse files
committed
Python: Restructure overall XML modeling
1 parent 46238d5 commit de0e67f

File tree

1 file changed

+44
-38
lines changed
  • python/ql/src/experimental/semmle/python/frameworks

1 file changed

+44
-38
lines changed

python/ql/src/experimental/semmle/python/frameworks/Xml.qll

Lines changed: 44 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ private import semmle.python.dataflow.new.DataFlow
88
private import experimental.semmle.python.Concepts
99
private import semmle.python.ApiGraphs
1010

11-
private module Xml {
11+
private module XmlEtree {
1212
/**
1313
* Gets a call to `xml.etree.ElementTree.XMLParser`.
1414
*/
@@ -100,7 +100,9 @@ private module Xml {
100100
kind.isBillionLaughs() or kind.isQuadraticBlowup()
101101
}
102102
}
103+
}
103104

105+
private module SaxBasedParsing {
104106
/**
105107
* A call to the `setFeature` method on a XML sax parser.
106108
*
@@ -251,6 +253,45 @@ private module Xml {
251253
}
252254
}
253255

256+
/**
257+
* A call to the `parse` or `parseString` methods from `xml.dom.minidom` or `xml.dom.pulldom`.
258+
*
259+
* Both of these modules are based on SAX parsers.
260+
*/
261+
private class XMLDomParsing extends DataFlow::CallCfgNode, XML::XMLParsing::Range {
262+
XMLDomParsing() {
263+
this =
264+
API::moduleImport("xml")
265+
.getMember("dom")
266+
.getMember(["minidom", "pulldom"])
267+
.getMember(["parse", "parseString"])
268+
.getACall()
269+
}
270+
271+
override DataFlow::Node getAnInput() {
272+
result in [
273+
this.getArg(0),
274+
// parseString
275+
this.getArgByName("string"),
276+
// minidom.parse
277+
this.getArgByName("file"),
278+
// pulldom.parse
279+
this.getArgByName("stream_or_string"),
280+
]
281+
}
282+
283+
DataFlow::Node getParserArg() { result in [this.getArg(1), this.getArgByName("parser")] }
284+
285+
override predicate vulnerable(XML::XMLVulnerabilityKind kind) {
286+
this.getParserArg() = saxParserWithFeatureExternalGesTurnedOn() and
287+
(kind.isXxe() or kind.isDtdRetrieval())
288+
or
289+
(kind.isBillionLaughs() or kind.isQuadraticBlowup())
290+
}
291+
}
292+
}
293+
294+
private module Lxml {
254295
/**
255296
* A call to `lxml.etree.get_default_parser`.
256297
*
@@ -379,7 +420,9 @@ private module Xml {
379420
)
380421
}
381422
}
423+
}
382424

425+
private module Xmltodict {
383426
/**
384427
* Gets a call to `xmltodict.parse`.
385428
*
@@ -405,41 +448,4 @@ private module Xml {
405448
this.getArgByName("disable_entities").getALocalSource().asExpr() = any(False f)
406449
}
407450
}
408-
409-
/**
410-
* A call to the `parse` or `parseString` methods from `xml.dom.minidom` or `xml.dom.pulldom`.
411-
*
412-
* Both of these modules are based on SAX parsers.
413-
*/
414-
private class XMLDomParsing extends DataFlow::CallCfgNode, XML::XMLParsing::Range {
415-
XMLDomParsing() {
416-
this =
417-
API::moduleImport("xml")
418-
.getMember("dom")
419-
.getMember(["minidom", "pulldom"])
420-
.getMember(["parse", "parseString"])
421-
.getACall()
422-
}
423-
424-
override DataFlow::Node getAnInput() {
425-
result in [
426-
this.getArg(0),
427-
// parseString
428-
this.getArgByName("string"),
429-
// minidom.parse
430-
this.getArgByName("file"),
431-
// pulldom.parse
432-
this.getArgByName("stream_or_string"),
433-
]
434-
}
435-
436-
DataFlow::Node getParserArg() { result in [this.getArg(1), this.getArgByName("parser")] }
437-
438-
override predicate vulnerable(XML::XMLVulnerabilityKind kind) {
439-
this.getParserArg() = saxParserWithFeatureExternalGesTurnedOn() and
440-
(kind.isXxe() or kind.isDtdRetrieval())
441-
or
442-
(kind.isBillionLaughs() or kind.isQuadraticBlowup())
443-
}
444-
}
445451
}

0 commit comments

Comments
 (0)