@@ -361,6 +361,67 @@ private module Django {
361
361
}
362
362
}
363
363
}
364
+
365
+ /**
366
+ * Provides models for the `django.core.files.uploadedfile.UploadedFile` class
367
+ *
368
+ * See https://docs.djangoproject.com/en/3.0/ref/files/uploads/#django.core.files.uploadedfile.UploadedFile.
369
+ */
370
+ module UploadedFile {
371
+ /** Gets a reference to the `django.core.files.uploadedfile.UploadedFile` class. */
372
+ private API:: Node classRef ( ) {
373
+ result =
374
+ API:: moduleImport ( "django" )
375
+ .getMember ( "core" )
376
+ .getMember ( "files" )
377
+ .getMember ( "uploadedfile" )
378
+ .getMember ( "UploadedFile" )
379
+ }
380
+
381
+ /**
382
+ * A source of instances of `django.core.files.uploadedfile.UploadedFile`, extend this class to model new instances.
383
+ *
384
+ * This can include instantiations of the class, return values from function
385
+ * calls, or a special parameter that will be set when functions are called by an external
386
+ * library.
387
+ *
388
+ * Use the predicate `UploadedFile::instance()` to get references to instances of `django.core.files.uploadedfile.UploadedFile`.
389
+ */
390
+ abstract class InstanceSource extends DataFlow:: LocalSourceNode { }
391
+
392
+ /** A direct instantiation of `django.core.files.uploadedfile.UploadedFile`. */
393
+ private class ClassInstantiation extends InstanceSource , DataFlow:: CallCfgNode {
394
+ override CallNode node ;
395
+
396
+ ClassInstantiation ( ) { this = classRef ( ) .getACall ( ) }
397
+ }
398
+
399
+ /** Gets a reference to an instance of `django.core.files.uploadedfile.UploadedFile`. */
400
+ private DataFlow:: TypeTrackingNode instance ( DataFlow:: TypeTracker t ) {
401
+ t .start ( ) and
402
+ result instanceof InstanceSource
403
+ or
404
+ exists ( DataFlow:: TypeTracker t2 | result = instance ( t2 ) .track ( t2 , t ) )
405
+ }
406
+
407
+ /** Gets a reference to an instance of `django.core.files.uploadedfile.UploadedFile`. */
408
+ DataFlow:: Node instance ( ) { instance ( DataFlow:: TypeTracker:: end ( ) ) .flowsTo ( result ) }
409
+
410
+ /**
411
+ * Taint propagation for `django.core.files.uploadedfile.UploadedFile`.
412
+ */
413
+ class UploadedFileAdditionalTaintStep extends TaintTracking:: AdditionalTaintStep {
414
+ override predicate step ( DataFlow:: Node nodeFrom , DataFlow:: Node nodeTo ) {
415
+ // Attributes
416
+ nodeFrom = instance ( ) and
417
+ nodeTo .( DataFlow:: AttrRead ) .getObject ( ) = nodeFrom and
418
+ nodeTo .( DataFlow:: AttrRead ) .getAttributeName ( ) in [
419
+ "content_type" , "content_type_extra" , "content_type_extra" , "charset" , "name" , "file"
420
+ ]
421
+ // TODO: Model `file` with shared-filelike such that `request.FILES["key"].file.read()` works
422
+ }
423
+ }
424
+ }
364
425
}
365
426
366
427
/**
@@ -2002,7 +2063,6 @@ private module PrivateDjango {
2002
2063
// HttpHeaders (case insensitive dict-like)
2003
2064
"headers" ,
2004
2065
// MultiValueDict[str, UploadedFile]
2005
- // TODO: Model UploadedFile
2006
2066
"FILES" ,
2007
2067
// django.urls.ResolverMatch
2008
2068
// TODO: Model ResolverMatch
@@ -2020,6 +2080,40 @@ private module PrivateDjango {
2020
2080
}
2021
2081
}
2022
2082
2083
+ /** An `UploadedFile` instance that originates from a django request. */
2084
+ class DjangoHttpRequestUploadedFileInstances extends Django:: UploadedFile:: InstanceSource {
2085
+ DjangoHttpRequestUploadedFileInstances ( ) {
2086
+ // TODO: this currently only works in local-scope, since writing type-trackers for
2087
+ // this is a little too much effort. Once API-graphs are available for more
2088
+ // things, we can rewrite this.
2089
+ //
2090
+ // TODO: This approach for identifying member-access is very adhoc, and we should
2091
+ // be able to do something more structured for providing modeling of the members
2092
+ // of a container-object.
2093
+ //
2094
+ // dicts
2095
+ exists ( DataFlow:: AttrRead files , DataFlow:: Node dict |
2096
+ files .accesses ( django:: http:: request:: HttpRequest:: instance ( ) , "FILES" ) and
2097
+ (
2098
+ dict = files
2099
+ or
2100
+ dict .( DataFlow:: MethodCallNode ) .calls ( files , "dict" )
2101
+ )
2102
+ |
2103
+ this .asCfgNode ( ) .( SubscriptNode ) .getObject ( ) = dict .asCfgNode ( )
2104
+ or
2105
+ this .( DataFlow:: MethodCallNode ) .calls ( dict , "get" )
2106
+ )
2107
+ or
2108
+ // getlist
2109
+ exists ( DataFlow:: AttrRead files , DataFlow:: MethodCallNode getlistCall |
2110
+ files .accesses ( django:: http:: request:: HttpRequest:: instance ( ) , "FILES" ) and
2111
+ getlistCall .calls ( files , "getlist" ) and
2112
+ this .asCfgNode ( ) .( SubscriptNode ) .getObject ( ) = getlistCall .asCfgNode ( )
2113
+ )
2114
+ }
2115
+ }
2116
+
2023
2117
// ---------------------------------------------------------------------------
2024
2118
// django.shortcuts.redirect
2025
2119
// ---------------------------------------------------------------------------
0 commit comments