|
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