Skip to content

Commit 441fc1b

Browse files
committed
Python: type trackers to API graph
base on new subscript in the API graph There are a few more uses of type tracking through `SubscriptNode`s, but these start from an instance given by a data flow node.
1 parent 9b1ec03 commit 441fc1b

File tree

3 files changed

+32
-62
lines changed

3 files changed

+32
-62
lines changed

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

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -408,21 +408,21 @@ module Flask {
408408
}
409409
}
410410

411+
private API::Node requestFileStorage() {
412+
// TODO: This approach for identifying member-access is very adhoc, and we should
413+
// be able to do something more structured for providing modeling of the members
414+
// of a container-object.
415+
result = request().getMember("files").getASubscript()
416+
or
417+
result = request().getMember("files").getMember("get").getReturn()
418+
or
419+
result = request().getMember("files").getMember("getlist").getReturn().getASubscript()
420+
}
421+
411422
/** An `FileStorage` instance that originates from a flask request. */
412423
private class FlaskRequestFileStorageInstances extends Werkzeug::FileStorage::InstanceSource {
413424
FlaskRequestFileStorageInstances() {
414-
// TODO: This approach for identifying member-access is very adhoc, and we should
415-
// be able to do something more structured for providing modeling of the members
416-
// of a container-object.
417-
exists(API::Node files | files = request().getMember("files") |
418-
this.asCfgNode().(SubscriptNode).getObject() =
419-
files.getAValueReachableFromSource().asCfgNode()
420-
or
421-
this = files.getMember("get").getACall()
422-
or
423-
this.asCfgNode().(SubscriptNode).getObject() =
424-
files.getMember("getlist").getReturn().getAValueReachableFromSource().asCfgNode()
425-
)
425+
this = requestFileStorage().getAValueReachableFromSource()
426426
}
427427
}
428428

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

Lines changed: 12 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1725,39 +1725,21 @@ private module StdlibPrivate {
17251725
API::Node getlistResult() { result = getlistRef().getReturn() }
17261726

17271727
/** Gets a reference to a list of fields. */
1728-
private DataFlow::TypeTrackingNode fieldList(DataFlow::TypeTracker t) {
1729-
t.start() and
1730-
// TODO: Should have better handling of subscripting
1731-
result.asCfgNode().(SubscriptNode).getObject() =
1732-
instance().getAValueReachableFromSource().asCfgNode()
1728+
API::Node fieldList() {
1729+
result = getlistResult()
17331730
or
1734-
exists(DataFlow::TypeTracker t2 | result = fieldList(t2).track(t2, t))
1735-
}
1736-
1737-
/** Gets a reference to a list of fields. */
1738-
DataFlow::Node fieldList() {
1739-
result = getlistResult().getAValueReachableFromSource() or
1740-
result = getvalueResult().getAValueReachableFromSource() or
1741-
fieldList(DataFlow::TypeTracker::end()).flowsTo(result)
1742-
}
1743-
1744-
/** Gets a reference to a field. */
1745-
private DataFlow::TypeTrackingNode field(DataFlow::TypeTracker t) {
1746-
t.start() and
1747-
// TODO: Should have better handling of subscripting
1748-
result.asCfgNode().(SubscriptNode).getObject() =
1749-
[instance().getAValueReachableFromSource(), fieldList()].asCfgNode()
1731+
result = getvalueResult()
17501732
or
1751-
exists(DataFlow::TypeTracker t2 | result = field(t2).track(t2, t))
1733+
result = instance().getASubscript()
17521734
}
17531735

17541736
/** Gets a reference to a field. */
1755-
DataFlow::Node field() {
1756-
result = getfirstResult().getAValueReachableFromSource()
1737+
API::Node field() {
1738+
result = getfirstResult()
17571739
or
1758-
result = getvalueResult().getAValueReachableFromSource()
1740+
result = getvalueResult()
17591741
or
1760-
field(DataFlow::TypeTracker::end()).flowsTo(result)
1742+
result = [instance(), fieldList()].getASubscript()
17611743
}
17621744

17631745
private class AdditionalTaintStep extends TaintTracking::AdditionalTaintStep {
@@ -1780,11 +1762,13 @@ private module StdlibPrivate {
17801762
)
17811763
or
17821764
// Indexing
1783-
nodeFrom in [instance().getAValueReachableFromSource(), fieldList()] and
1765+
nodeFrom in [
1766+
instance().getAValueReachableFromSource(), fieldList().getAValueReachableFromSource()
1767+
] and
17841768
nodeTo.asCfgNode().(SubscriptNode).getObject() = nodeFrom.asCfgNode()
17851769
or
17861770
// Attributes on Field
1787-
nodeFrom = field() and
1771+
nodeFrom = field().getAValueReachableFromSource() and
17881772
exists(DataFlow::AttrRead read | nodeTo = read and read.getObject() = nodeFrom |
17891773
read.getAttributeName() in ["value", "file", "filename"]
17901774
)

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

Lines changed: 8 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -85,35 +85,20 @@ private module ExperimentalPrivateDjango {
8585
DataFlow::Node instance() { instance(DataFlow::TypeTracker::end()).flowsTo(result) }
8686

8787
/** Gets a reference to a header instance. */
88-
private DataFlow::LocalSourceNode headerInstance(DataFlow::TypeTracker t) {
89-
t.start() and
90-
(
91-
exists(SubscriptNode subscript |
92-
subscript.getObject() =
93-
baseClassRef().getReturn().getAValueReachableFromSource().asCfgNode() and
94-
result.asCfgNode() = subscript
95-
)
96-
or
97-
result.(DataFlow::AttrRead).getObject() =
98-
baseClassRef().getReturn().getAValueReachableFromSource()
99-
)
88+
API::Node headerInstance() {
89+
result = baseClassRef().getReturn().getASubscript()
10090
or
101-
exists(DataFlow::TypeTracker t2 | result = headerInstance(t2).track(t2, t))
102-
}
103-
104-
/** Gets a reference to a header instance use. */
105-
private DataFlow::Node headerInstance() {
106-
headerInstance(DataFlow::TypeTracker::end()).flowsTo(result)
91+
result = baseClassRef().getReturn().getAMember()
10792
}
10893

10994
/** Gets a reference to a header instance call with `__setitem__`. */
110-
private DataFlow::Node headerSetItemCall() {
95+
API::Node headerSetItem() {
11196
result = headerInstance() and
112-
result.(DataFlow::AttrRead).getAttributeName() = "__setitem__"
97+
result.asSource().(DataFlow::AttrRead).getAttributeName() = "__setitem__"
11398
}
11499

115100
class DjangoResponseSetItemCall extends DataFlow::CallCfgNode, HeaderDeclaration::Range {
116-
DjangoResponseSetItemCall() { this.getFunction() = headerSetItemCall() }
101+
DjangoResponseSetItemCall() { this = headerSetItem().getACall() }
117102

118103
override DataFlow::Node getNameArg() { result = this.getArg(0) }
119104

@@ -124,7 +109,8 @@ private module ExperimentalPrivateDjango {
124109
DataFlow::Node headerInput;
125110

126111
DjangoResponseDefinition() {
127-
this.asCfgNode().(DefinitionNode) = headerInstance().asCfgNode() and
112+
this.asCfgNode().(DefinitionNode) =
113+
headerInstance().getAValueReachableFromSource().asCfgNode() and
128114
headerInput.asCfgNode() = this.asCfgNode().(DefinitionNode).getValue()
129115
}
130116

0 commit comments

Comments
 (0)