Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 64aa503

Browse files
committed
Python: Promote xml.etree modeling
1 parent 7f5f767 commit 64aa503

4 files changed

Lines changed: 119 additions & 118 deletions

File tree

python/ql/lib/semmle/python/frameworks/Stdlib.qll

Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3174,6 +3174,123 @@ private module StdlibPrivate {
31743174
}
31753175
}
31763176
}
3177+
3178+
// ---------------------------------------------------------------------------
3179+
// xml.etree
3180+
// ---------------------------------------------------------------------------
3181+
/**
3182+
* Provides models for `xml.etree` parsers
3183+
*
3184+
* See
3185+
* - https://docs.python.org/3.10/library/xml.etree.elementtree.html#xml.etree.ElementTree.XMLParser
3186+
* - https://docs.python.org/3.10/library/xml.etree.elementtree.html#xml.etree.ElementTree.XMLPullParser
3187+
*/
3188+
module XMLParser {
3189+
/**
3190+
* A source of instances of `xml.etree` parsers, extend this class to model new instances.
3191+
*
3192+
* This can include instantiations of the class, return values from function
3193+
* calls, or a special parameter that will be set when functions are called by an external
3194+
* library.
3195+
*
3196+
* Use the predicate `XMLParser::instance()` to get references to instances of `xml.etree` parsers.
3197+
*/
3198+
abstract class InstanceSource extends DataFlow::LocalSourceNode { }
3199+
3200+
/** A direct instantiation of `xml.etree` parsers. */
3201+
private class ClassInstantiation extends InstanceSource, DataFlow::CallCfgNode {
3202+
ClassInstantiation() {
3203+
this =
3204+
API::moduleImport("xml")
3205+
.getMember("etree")
3206+
.getMember("ElementTree")
3207+
.getMember("XMLParser")
3208+
.getACall()
3209+
or
3210+
this =
3211+
API::moduleImport("xml")
3212+
.getMember("etree")
3213+
.getMember("ElementTree")
3214+
.getMember("XMLPullParser")
3215+
.getACall()
3216+
}
3217+
}
3218+
3219+
/** Gets a reference to an `xml.etree` parser instance. */
3220+
private DataFlow::TypeTrackingNode instance(DataFlow::TypeTracker t) {
3221+
t.start() and
3222+
result instanceof InstanceSource
3223+
or
3224+
exists(DataFlow::TypeTracker t2 | result = instance(t2).track(t2, t))
3225+
}
3226+
3227+
/** Gets a reference to an `xml.etree` parser instance. */
3228+
DataFlow::Node instance() { instance(DataFlow::TypeTracker::end()).flowsTo(result) }
3229+
3230+
/**
3231+
* A call to the `feed` method of an `xml.etree` parser.
3232+
*/
3233+
private class XMLEtreeParserFeedCall extends DataFlow::MethodCallNode, XML::XMLParsing::Range {
3234+
XMLEtreeParserFeedCall() { this.calls(instance(), "feed") }
3235+
3236+
override DataFlow::Node getAnInput() { result in [this.getArg(0), this.getArgByName("data")] }
3237+
3238+
override predicate vulnerableTo(XML::XMLParsingVulnerabilityKind kind) {
3239+
kind.isBillionLaughs() or kind.isQuadraticBlowup()
3240+
}
3241+
3242+
override predicate mayExecuteInput() { none() }
3243+
3244+
override DataFlow::Node getOutput() {
3245+
exists(DataFlow::Node objRef |
3246+
DataFlow::localFlow(this.getObject(), objRef) and
3247+
result.(DataFlow::MethodCallNode).calls(objRef, "close")
3248+
)
3249+
}
3250+
}
3251+
}
3252+
3253+
/**
3254+
* A call to either of:
3255+
* - `xml.etree.ElementTree.fromstring`
3256+
* - `xml.etree.ElementTree.fromstringlist`
3257+
* - `xml.etree.ElementTree.XML`
3258+
* - `xml.etree.ElementTree.XMLID`
3259+
* - `xml.etree.ElementTree.parse`
3260+
* - `xml.etree.ElementTree.iterparse`
3261+
*/
3262+
private class XMLEtreeParsing extends DataFlow::CallCfgNode, XML::XMLParsing::Range {
3263+
XMLEtreeParsing() {
3264+
this =
3265+
API::moduleImport("xml")
3266+
.getMember("etree")
3267+
.getMember("ElementTree")
3268+
.getMember(["fromstring", "fromstringlist", "XML", "XMLID", "parse", "iterparse"])
3269+
.getACall()
3270+
}
3271+
3272+
override DataFlow::Node getAnInput() {
3273+
result in [
3274+
this.getArg(0),
3275+
// fromstring / XML / XMLID
3276+
this.getArgByName("text"),
3277+
// fromstringlist
3278+
this.getArgByName("sequence"),
3279+
// parse / iterparse
3280+
this.getArgByName("source"),
3281+
]
3282+
}
3283+
3284+
override predicate vulnerableTo(XML::XMLParsingVulnerabilityKind kind) {
3285+
// note: it does not matter what `xml.etree` parser you are using, you cannot
3286+
// change the security features anyway :|
3287+
kind.isBillionLaughs() or kind.isQuadraticBlowup()
3288+
}
3289+
3290+
override predicate mayExecuteInput() { none() }
3291+
3292+
override DataFlow::Node getOutput() { result = this }
3293+
}
31773294
}
31783295

31793296
// ---------------------------------------------------------------------------

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

Lines changed: 1 addition & 117 deletions
Original file line numberDiff line numberDiff line change
@@ -8,129 +8,13 @@ private import semmle.python.dataflow.new.DataFlow
88
private import semmle.python.Concepts
99
private import semmle.python.ApiGraphs
1010

11-
private module XmlEtree {
12-
/**
13-
* Provides models for `xml.etree` parsers
14-
*
15-
* See
16-
* - https://docs.python.org/3.10/library/xml.etree.elementtree.html#xml.etree.ElementTree.XMLParser
17-
* - https://docs.python.org/3.10/library/xml.etree.elementtree.html#xml.etree.ElementTree.XMLPullParser
18-
*/
19-
module XMLParser {
20-
/**
21-
* A source of instances of `xml.etree` parsers, extend this class to model new instances.
22-
*
23-
* This can include instantiations of the class, return values from function
24-
* calls, or a special parameter that will be set when functions are called by an external
25-
* library.
26-
*
27-
* Use the predicate `XMLParser::instance()` to get references to instances of `xml.etree` parsers.
28-
*/
29-
abstract class InstanceSource extends DataFlow::LocalSourceNode { }
30-
31-
/** A direct instantiation of `xml.etree` parsers. */
32-
private class ClassInstantiation extends InstanceSource, DataFlow::CallCfgNode {
33-
ClassInstantiation() {
34-
this =
35-
API::moduleImport("xml")
36-
.getMember("etree")
37-
.getMember("ElementTree")
38-
.getMember("XMLParser")
39-
.getACall()
40-
or
41-
this =
42-
API::moduleImport("xml")
43-
.getMember("etree")
44-
.getMember("ElementTree")
45-
.getMember("XMLPullParser")
46-
.getACall()
47-
}
48-
}
49-
50-
/** Gets a reference to an `xml.etree` parser instance. */
51-
private DataFlow::TypeTrackingNode instance(DataFlow::TypeTracker t) {
52-
t.start() and
53-
result instanceof InstanceSource
54-
or
55-
exists(DataFlow::TypeTracker t2 | result = instance(t2).track(t2, t))
56-
}
57-
58-
/** Gets a reference to an `xml.etree` parser instance. */
59-
DataFlow::Node instance() { instance(DataFlow::TypeTracker::end()).flowsTo(result) }
60-
61-
/**
62-
* A call to the `feed` method of an `xml.etree` parser.
63-
*/
64-
private class XMLEtreeParserFeedCall extends DataFlow::MethodCallNode, XML::XMLParsing::Range {
65-
XMLEtreeParserFeedCall() { this.calls(instance(), "feed") }
66-
67-
override DataFlow::Node getAnInput() { result in [this.getArg(0), this.getArgByName("data")] }
68-
69-
override predicate vulnerableTo(XML::XMLParsingVulnerabilityKind kind) {
70-
kind.isBillionLaughs() or kind.isQuadraticBlowup()
71-
}
72-
73-
override predicate mayExecuteInput() { none() }
74-
75-
override DataFlow::Node getOutput() {
76-
exists(DataFlow::Node objRef |
77-
DataFlow::localFlow(this.getObject(), objRef) and
78-
result.(DataFlow::MethodCallNode).calls(objRef, "close")
79-
)
80-
}
81-
}
82-
}
83-
84-
/**
85-
* A call to either of:
86-
* - `xml.etree.ElementTree.fromstring`
87-
* - `xml.etree.ElementTree.fromstringlist`
88-
* - `xml.etree.ElementTree.XML`
89-
* - `xml.etree.ElementTree.XMLID`
90-
* - `xml.etree.ElementTree.parse`
91-
* - `xml.etree.ElementTree.iterparse`
92-
*/
93-
private class XMLEtreeParsing extends DataFlow::CallCfgNode, XML::XMLParsing::Range {
94-
XMLEtreeParsing() {
95-
this =
96-
API::moduleImport("xml")
97-
.getMember("etree")
98-
.getMember("ElementTree")
99-
.getMember(["fromstring", "fromstringlist", "XML", "XMLID", "parse", "iterparse"])
100-
.getACall()
101-
}
102-
103-
override DataFlow::Node getAnInput() {
104-
result in [
105-
this.getArg(0),
106-
// fromstring / XML / XMLID
107-
this.getArgByName("text"),
108-
// fromstringlist
109-
this.getArgByName("sequence"),
110-
// parse / iterparse
111-
this.getArgByName("source"),
112-
]
113-
}
114-
115-
override predicate vulnerableTo(XML::XMLParsingVulnerabilityKind kind) {
116-
// note: it does not matter what `xml.etree` parser you are using, you cannot
117-
// change the security features anyway :|
118-
kind.isBillionLaughs() or kind.isQuadraticBlowup()
119-
}
120-
121-
override predicate mayExecuteInput() { none() }
122-
123-
override DataFlow::Node getOutput() { result = this }
124-
}
125-
}
126-
12711
private module SaxBasedParsing {
12812
/**
12913
* A call to the `setFeature` method on a XML sax parser.
13014
*
13115
* See https://docs.python.org/3.10/library/xml.sax.reader.html#xml.sax.xmlreader.XMLReader.setFeature
13216
*/
133-
class SaxParserSetFeatureCall extends DataFlow::MethodCallNode {
17+
private class SaxParserSetFeatureCall extends DataFlow::MethodCallNode {
13418
SaxParserSetFeatureCall() {
13519
this =
13620
API::moduleImport("xml")

python/ql/test/library-tests/frameworks/stdlib/XPathExecution.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
ns = {'dc': 'http://purl.org/dc/elements/1.1/'}
33

44
import xml.etree.ElementTree as ET
5-
tree = ET.parse('country_data.xml')
5+
tree = ET.parse('country_data.xml') # $ decodeFormat=XML decodeInput='country_data.xml' decodeOutput=ET.parse(..) xmlVuln='Billion Laughs' xmlVuln='Quadratic Blowup'
66
root = tree.getroot()
77

88
root.find(match, namespaces=ns) # $ getXPath=match

python/ql/test/experimental/library-tests/frameworks/XML/xml_etree.py renamed to python/ql/test/library-tests/frameworks/stdlib/xml_etree.py

File renamed without changes.

0 commit comments

Comments
 (0)