Skip to content

Commit a25933a

Browse files
authored
Merge pull request #5926 from RasmusWL/small-cleanups
Approved by tausbn
2 parents 3c8c2d1 + 81fab48 commit a25933a

File tree

3 files changed

+33
-32
lines changed

3 files changed

+33
-32
lines changed

python/ql/src/semmle/python/dataflow/new/internal/Attributes.qll

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,13 @@ abstract class AttrRef extends Node {
1717
*/
1818
abstract Node getObject();
1919

20+
/**
21+
* Holds if this data flow node accesses attribute named `attrName` on object `object`.
22+
*/
23+
predicate accesses(Node object, string attrName) {
24+
this.getObject() = object and this.getAttributeName() = attrName
25+
}
26+
2027
/**
2128
* Gets the expression node that defines the attribute being accessed, if any. This is
2229
* usually an identifier or literal.

python/ql/src/semmle/python/dataflow/new/internal/TaintTrackingPrivate.qll

Lines changed: 25 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
private import python
22
private import semmle.python.dataflow.new.DataFlow
3-
private import semmle.python.dataflow.new.internal.DataFlowPrivate
3+
private import semmle.python.dataflow.new.internal.DataFlowPrivate as DataFlowPrivate
44
private import semmle.python.dataflow.new.internal.TaintTrackingPublic
5+
private import semmle.python.ApiGraphs
56

67
/**
78
* Holds if `node` should be a sanitizer in all global taint flow configurations
@@ -82,13 +83,13 @@ predicate subscriptStep(DataFlow::CfgNode nodeFrom, DataFlow::CfgNode nodeTo) {
8283
*/
8384
predicate stringManipulation(DataFlow::CfgNode nodeFrom, DataFlow::CfgNode nodeTo) {
8485
// transforming something tainted into a string will make the string tainted
85-
exists(CallNode call | call = nodeTo.getNode() |
86-
call.getFunction().(NameNode).getId() in ["str", "bytes", "unicode"] and
86+
exists(DataFlow::CallCfgNode call | call = nodeTo |
8787
(
88-
nodeFrom.getNode() = call.getArg(0)
88+
call = API::builtin(["str", "bytes", "unicode"]).getACall()
8989
or
90-
nodeFrom.getNode() = call.getArgByName("object")
91-
)
90+
call.getFunction().asCfgNode().(NameNode).getId() in ["str", "bytes", "unicode"]
91+
) and
92+
nodeFrom in [call.getArg(0), call.getArgByName("object")]
9293
)
9394
or
9495
// String methods. Note that this doesn't recognize `meth = "foo".upper; meth()`
@@ -155,54 +156,47 @@ predicate stringManipulation(DataFlow::CfgNode nodeFrom, DataFlow::CfgNode nodeT
155156
predicate containerStep(DataFlow::CfgNode nodeFrom, DataFlow::Node nodeTo) {
156157
// construction by literal
157158
// TODO: Not limiting the content argument here feels like a BIG hack, but we currently get nothing for free :|
158-
storeStep(nodeFrom, _, nodeTo)
159+
DataFlowPrivate::storeStep(nodeFrom, _, nodeTo)
159160
or
160161
// constructor call
161-
exists(CallNode call | call = nodeTo.asCfgNode() |
162-
call.getFunction().(NameNode).getId() in [
163-
"list", "set", "frozenset", "dict", "defaultdict", "tuple"
164-
] and
165-
call.getArg(0) = nodeFrom.getNode()
162+
exists(DataFlow::CallCfgNode call | call = nodeTo |
163+
call = API::builtin(["list", "set", "frozenset", "dict", "tuple"]).getACall() and
164+
call.getArg(0) = nodeFrom
165+
// TODO: Properly handle defaultdict/namedtuple
166166
)
167167
or
168168
// functions operating on collections
169-
exists(CallNode call | call = nodeTo.asCfgNode() |
170-
call.getFunction().(NameNode).getId() in ["sorted", "reversed", "iter", "next"] and
171-
call.getArg(0) = nodeFrom.getNode()
169+
exists(DataFlow::CallCfgNode call | call = nodeTo |
170+
call = API::builtin(["sorted", "reversed", "iter", "next"]).getACall() and
171+
call.getArg(0) = nodeFrom
172172
)
173173
or
174174
// methods
175-
exists(CallNode call, string name | call = nodeTo.asCfgNode() |
176-
name in [
175+
exists(DataFlow::MethodCallNode call, string methodName | call = nodeTo |
176+
methodName in [
177177
// general
178178
"copy", "pop",
179179
// dict
180180
"values", "items", "get", "popitem"
181181
] and
182-
call.getFunction().(AttrNode).getObject(name) = nodeFrom.asCfgNode()
182+
call.calls(nodeFrom, methodName)
183183
)
184184
or
185185
// list.append, set.add
186-
exists(CallNode call, string name |
187-
name in ["append", "add"] and
188-
call.getFunction().(AttrNode).getObject(name) =
189-
nodeTo.(DataFlow::PostUpdateNode).getPreUpdateNode().asCfgNode() and
190-
call.getArg(0) = nodeFrom.getNode()
186+
exists(DataFlow::MethodCallNode call, DataFlow::Node obj |
187+
call.calls(obj, ["append", "add"]) and
188+
obj = nodeTo.(DataFlow::PostUpdateNode).getPreUpdateNode() and
189+
call.getArg(0) = nodeFrom
191190
)
192191
}
193192

194193
/**
195194
* Holds if taint can flow from `nodeFrom` to `nodeTo` with a step related to copying.
196195
*/
197196
predicate copyStep(DataFlow::CfgNode nodeFrom, DataFlow::CfgNode nodeTo) {
198-
exists(CallNode call | call = nodeTo.getNode() |
199-
// Fully qualified: copy.copy, copy.deepcopy
200-
(
201-
call.getFunction().(NameNode).getId() in ["copy", "deepcopy"]
202-
or
203-
call.getFunction().(AttrNode).getObject(["copy", "deepcopy"]).(NameNode).getId() = "copy"
204-
) and
205-
call.getArg(0) = nodeFrom.getNode()
197+
exists(DataFlow::CallCfgNode call | call = nodeTo |
198+
call = API::moduleImport("copy").getMember(["copy", "deepcopy"]).getACall() and
199+
call.getArg(0) = nodeFrom
206200
)
207201
}
208202

python/ql/test/experimental/dataflow/tainttracking/defaultAdditionalTaintStep/test_string.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ def non_syntactic():
104104
_str = str
105105
ensure_tainted(
106106
meth(), # $ MISSING: tainted
107-
_str(ts), # $ MISSING: tainted
107+
_str(ts), # $ tainted
108108
)
109109

110110

0 commit comments

Comments
 (0)