Python: Add FileLikeObject modeling

Such that the result of `request.FILES["key"].file.read()` is tainted
This commit is contained in:
Rasmus Wriedt Larsen
2021-07-20 10:45:47 +02:00
parent 18c0d13efd
commit 7dc6518350
3 changed files with 73 additions and 5 deletions

View File

@@ -10,6 +10,7 @@ private import semmle.python.dataflow.new.TaintTracking
private import semmle.python.Concepts
private import semmle.python.ApiGraphs
private import semmle.python.frameworks.PEP249
private import semmle.python.frameworks.Stdlib
private import semmle.python.regex
private import semmle.python.frameworks.internal.PoorMansFunctionResolution
private import semmle.python.frameworks.internal.SelfRefMixin
@@ -418,9 +419,13 @@ private module Django {
nodeTo.(DataFlow::AttrRead).getAttributeName() in [
"content_type", "content_type_extra", "content_type_extra", "charset", "name", "file"
]
// TODO: Model `file` with shared-filelike such that `request.FILES["key"].file.read()` works
}
}
/** A file-like object instance that originates from a `UploadedFile`. */
class UploadedFileFileLikeInstances extends Stdlib::FileLikeObject::InstanceSource {
UploadedFileFileLikeInstances() { this.(DataFlow::AttrRead).accesses(instance(), "file") }
}
}
}

View File

@@ -12,7 +12,69 @@ private import semmle.python.ApiGraphs
private import semmle.python.frameworks.PEP249
/** Provides models for the Python standard library. */
private module Stdlib {
module Stdlib {
/**
* Provides models for file-like objects,
* mostly to define standard set of extra taint-steps.
*
* See
* - https://docs.python.org/3.9/glossary.html#term-file-like-object
* - https://docs.python.org/3.9/library/io.html#io.IOBase
*/
module FileLikeObject {
/**
* A source of a file-like object, extend this class to model new instances.
*
* This can include instantiations of the class, return values from function
* calls, or a special parameter that will be set when functions are called by an external
* library.
*
* Use the predicate `like::instance()` to get references to instances of `file.like`.
*/
abstract class InstanceSource extends DataFlow::LocalSourceNode { }
/** Gets a reference to a file-like object. */
private DataFlow::TypeTrackingNode instance(DataFlow::TypeTracker t) {
t.start() and
result instanceof InstanceSource
or
exists(DataFlow::TypeTracker t2 | result = instance(t2).track(t2, t))
}
/** Gets a reference to a file-like object. */
DataFlow::Node instance() { instance(DataFlow::TypeTracker::end()).flowsTo(result) }
/**
* Taint propagation for file-like objects.
*/
class FileLikeObjectAdditionalTaintStep extends TaintTracking::AdditionalTaintStep {
override predicate step(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) {
// result of method call is tainted
nodeFrom = instance() and
nodeTo.(DataFlow::MethodCallNode).calls(nodeFrom, ["read", "readline", "readlines"])
or
// taint-propagation back to instance from `foo.write(tainted_data)`
exists(DataFlow::AttrRead write, DataFlow::CallCfgNode call, DataFlow::Node instance_ |
instance_ = instance() and
write.accesses(instance_, "write")
|
nodeTo.(DataFlow::PostUpdateNode).getPreUpdateNode() = instance_ and
call.getFunction() = write and
nodeFrom = call.getArg(0)
)
}
}
}
}
/**
* Provides models for the Python standard library.
*
* This module is marked private as exposing it means committing to 1-year deprecation
* policy, and the code is not in a polished enough state that we want to do so -- at
* least not without having convincing use-cases for it :)
*/
private module StdlibPrivate {
// ---------------------------------------------------------------------------
// os
// ---------------------------------------------------------------------------
@@ -395,7 +457,8 @@ private module Stdlib {
* A call to the builtin `open` function.
* See https://docs.python.org/3/library/functions.html#open
*/
private class OpenCall extends FileSystemAccess::Range, DataFlow::CallCfgNode {
private class OpenCall extends FileSystemAccess::Range, Stdlib::FileLikeObject::InstanceSource,
DataFlow::CallCfgNode {
OpenCall() { this = getOpenFunctionRef().getACall() }
override DataFlow::Node getAPathArgument() {
@@ -1081,7 +1144,7 @@ private module Stdlib {
}
/** A call to the `open` method on a `pathlib.Path` instance. */
private class PathLibOpenCall extends PathlibFileAccess {
private class PathLibOpenCall extends PathlibFileAccess, Stdlib::FileLikeObject::InstanceSource {
PathLibOpenCall() { attrbuteName = "open" }
}