|
1 | 1 | private import python
|
2 | 2 | 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 |
4 | 4 | private import semmle.python.dataflow.new.internal.TaintTrackingPublic
|
| 5 | +private import semmle.python.ApiGraphs |
5 | 6 |
|
6 | 7 | /**
|
7 | 8 | * 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) {
|
82 | 83 | */
|
83 | 84 | predicate stringManipulation(DataFlow::CfgNode nodeFrom, DataFlow::CfgNode nodeTo) {
|
84 | 85 | // 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 | |
87 | 87 | (
|
88 |
| - nodeFrom.getNode() = call.getArg(0) |
| 88 | + call = API::builtin(["str", "bytes", "unicode"]).getACall() |
89 | 89 | 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")] |
92 | 93 | )
|
93 | 94 | or
|
94 | 95 | // String methods. Note that this doesn't recognize `meth = "foo".upper; meth()`
|
@@ -155,54 +156,47 @@ predicate stringManipulation(DataFlow::CfgNode nodeFrom, DataFlow::CfgNode nodeT
|
155 | 156 | predicate containerStep(DataFlow::CfgNode nodeFrom, DataFlow::Node nodeTo) {
|
156 | 157 | // construction by literal
|
157 | 158 | // 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) |
159 | 160 | or
|
160 | 161 | // 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 |
166 | 166 | )
|
167 | 167 | or
|
168 | 168 | // 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 |
172 | 172 | )
|
173 | 173 | or
|
174 | 174 | // 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 [ |
177 | 177 | // general
|
178 | 178 | "copy", "pop",
|
179 | 179 | // dict
|
180 | 180 | "values", "items", "get", "popitem"
|
181 | 181 | ] and
|
182 |
| - call.getFunction().(AttrNode).getObject(name) = nodeFrom.asCfgNode() |
| 182 | + call.calls(nodeFrom, methodName) |
183 | 183 | )
|
184 | 184 | or
|
185 | 185 | // 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 |
191 | 190 | )
|
192 | 191 | }
|
193 | 192 |
|
194 | 193 | /**
|
195 | 194 | * Holds if taint can flow from `nodeFrom` to `nodeTo` with a step related to copying.
|
196 | 195 | */
|
197 | 196 | 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 |
206 | 200 | )
|
207 | 201 | }
|
208 | 202 |
|
|
0 commit comments