@@ -12,7 +12,69 @@ private import semmle.python.ApiGraphs
12
12
private import semmle.python.frameworks.PEP249
13
13
14
14
/** Provides models for the Python standard library. */
15
- private module Stdlib {
15
+ module Stdlib {
16
+ /**
17
+ * Provides models for file-like objects,
18
+ * mostly to define standard set of extra taint-steps.
19
+ *
20
+ * See
21
+ * - https://docs.python.org/3.9/glossary.html#term-file-like-object
22
+ * - https://docs.python.org/3.9/library/io.html#io.IOBase
23
+ */
24
+ module FileLikeObject {
25
+ /**
26
+ * A source of a file-like object, extend this class to model new instances.
27
+ *
28
+ * This can include instantiations of the class, return values from function
29
+ * calls, or a special parameter that will be set when functions are called by an external
30
+ * library.
31
+ *
32
+ * Use the predicate `like::instance()` to get references to instances of `file.like`.
33
+ */
34
+ abstract class InstanceSource extends DataFlow:: LocalSourceNode { }
35
+
36
+ /** Gets a reference to a file-like object. */
37
+ private DataFlow:: TypeTrackingNode instance ( DataFlow:: TypeTracker t ) {
38
+ t .start ( ) and
39
+ result instanceof InstanceSource
40
+ or
41
+ exists ( DataFlow:: TypeTracker t2 | result = instance ( t2 ) .track ( t2 , t ) )
42
+ }
43
+
44
+ /** Gets a reference to a file-like object. */
45
+ DataFlow:: Node instance ( ) { instance ( DataFlow:: TypeTracker:: end ( ) ) .flowsTo ( result ) }
46
+
47
+ /**
48
+ * Taint propagation for file-like objects.
49
+ */
50
+ class FileLikeObjectAdditionalTaintStep extends TaintTracking:: AdditionalTaintStep {
51
+ override predicate step ( DataFlow:: Node nodeFrom , DataFlow:: Node nodeTo ) {
52
+ // result of method call is tainted
53
+ nodeFrom = instance ( ) and
54
+ nodeTo .( DataFlow:: MethodCallNode ) .calls ( nodeFrom , [ "read" , "readline" , "readlines" ] )
55
+ or
56
+ // taint-propagation back to instance from `foo.write(tainted_data)`
57
+ exists ( DataFlow:: AttrRead write , DataFlow:: CallCfgNode call , DataFlow:: Node instance_ |
58
+ instance_ = instance ( ) and
59
+ write .accesses ( instance_ , "write" )
60
+ |
61
+ nodeTo .( DataFlow:: PostUpdateNode ) .getPreUpdateNode ( ) = instance_ and
62
+ call .getFunction ( ) = write and
63
+ nodeFrom = call .getArg ( 0 )
64
+ )
65
+ }
66
+ }
67
+ }
68
+ }
69
+
70
+ /**
71
+ * Provides models for the Python standard library.
72
+ *
73
+ * This module is marked private as exposing it means committing to 1-year deprecation
74
+ * policy, and the code is not in a polished enough state that we want to do so -- at
75
+ * least not without having convincing use-cases for it :)
76
+ */
77
+ private module StdlibPrivate {
16
78
// ---------------------------------------------------------------------------
17
79
// os
18
80
// ---------------------------------------------------------------------------
@@ -395,7 +457,8 @@ private module Stdlib {
395
457
* A call to the builtin `open` function.
396
458
* See https://docs.python.org/3/library/functions.html#open
397
459
*/
398
- private class OpenCall extends FileSystemAccess:: Range , DataFlow:: CallCfgNode {
460
+ private class OpenCall extends FileSystemAccess:: Range , Stdlib:: FileLikeObject:: InstanceSource ,
461
+ DataFlow:: CallCfgNode {
399
462
OpenCall ( ) { this = getOpenFunctionRef ( ) .getACall ( ) }
400
463
401
464
override DataFlow:: Node getAPathArgument ( ) {
@@ -1081,7 +1144,7 @@ private module Stdlib {
1081
1144
}
1082
1145
1083
1146
/** A call to the `open` method on a `pathlib.Path` instance. */
1084
- private class PathLibOpenCall extends PathlibFileAccess {
1147
+ private class PathLibOpenCall extends PathlibFileAccess , Stdlib :: FileLikeObject :: InstanceSource {
1085
1148
PathLibOpenCall ( ) { attrbuteName = "open" }
1086
1149
}
1087
1150
0 commit comments