@@ -11,6 +11,7 @@ private import python
11
11
private import semmle.python.dataflow.new.DataFlow
12
12
private import semmle.python.dataflow.new.RemoteFlowSources
13
13
private import semmle.python.Concepts
14
+ private import semmle.python.ApiGraphs
14
15
15
16
/**
16
17
* Provides classes modeling security-relevant aspects of the PyYAML package (obtained
@@ -20,78 +21,15 @@ private import semmle.python.Concepts
20
21
* - https://pyyaml.org/wiki/PyYAMLDocumentation
21
22
* - https://pyyaml.docsforge.com/master/documentation/
22
23
*/
23
- private module Yaml {
24
- /** Gets a reference to the `yaml` module. */
25
- private DataFlow:: Node yaml ( DataFlow:: TypeTracker t ) {
26
- t .start ( ) and
27
- result = DataFlow:: importNode ( "yaml" )
28
- or
29
- exists ( DataFlow:: TypeTracker t2 | result = yaml ( t2 ) .track ( t2 , t ) )
30
- }
31
-
32
- /** Gets a reference to the `yaml` module. */
33
- DataFlow:: Node yaml ( ) { result = yaml ( DataFlow:: TypeTracker:: end ( ) ) }
34
-
35
- /** Provides models for the `yaml` module. */
36
- module yaml {
37
- /**
38
- * Gets a reference to the attribute `attr_name` of the `yaml` module.
39
- * WARNING: Only holds for a few predefined attributes.
40
- *
41
- * For example, using `attr_name = "load"` will get all uses of `yaml.load`.
42
- */
43
- private DataFlow:: Node yaml_attr ( DataFlow:: TypeTracker t , string attr_name ) {
44
- attr_name in [
45
- // functions
46
- "load" , "load_all" , "full_load" , "full_load_all" , "unsafe_load" , "unsafe_load_all" ,
47
- "safe_load" , "safe_load_all" ,
48
- // Classes
49
- "SafeLoader" , "BaseLoader"
50
- ] and
51
- (
52
- t .start ( ) and
53
- result = DataFlow:: importNode ( "yaml." + attr_name )
54
- or
55
- t .startInAttr ( attr_name ) and
56
- result = yaml ( )
57
- )
58
- or
59
- // Due to bad performance when using normal setup with `yaml_attr(t2, attr_name).track(t2, t)`
60
- // we have inlined that code and forced a join
61
- exists ( DataFlow:: TypeTracker t2 |
62
- exists ( DataFlow:: StepSummary summary |
63
- yaml_attr_first_join ( t2 , attr_name , result , summary ) and
64
- t = t2 .append ( summary )
65
- )
66
- )
67
- }
68
-
69
- pragma [ nomagic]
70
- private predicate yaml_attr_first_join (
71
- DataFlow:: TypeTracker t2 , string attr_name , DataFlow:: Node res , DataFlow:: StepSummary summary
72
- ) {
73
- DataFlow:: StepSummary:: step ( yaml_attr ( t2 , attr_name ) , res , summary )
74
- }
75
-
76
- /**
77
- * Gets a reference to the attribute `attr_name` of the `yaml` module.
78
- * WARNING: Only holds for a few predefined attributes.
79
- *
80
- * For example, using `attr_name = "load"` will get all uses of `yaml.load`.
81
- */
82
- DataFlow:: Node yaml_attr ( string attr_name ) {
83
- result = yaml_attr ( DataFlow:: TypeTracker:: end ( ) , attr_name )
84
- }
85
- }
86
- }
24
+ private module Yaml { }
87
25
88
26
/**
89
27
* A call to any of the loading functions in `yaml` (`load`, `load_all`, `full_load`,
90
28
* `full_load_all`, `unsafe_load`, `unsafe_load_all`, `safe_load`, `safe_load_all`)
91
29
*
92
30
* See https://pyyaml.org/wiki/PyYAMLDocumentation (you will have to scroll down).
93
31
*/
94
- private class YamlLoadCall extends Decoding:: Range , DataFlow:: CfgNode {
32
+ private class YamlLoadCall extends Decoding:: Range , DataFlow:: CallCfgNode {
95
33
override CallNode node ;
96
34
string func_name ;
97
35
@@ -100,7 +38,7 @@ private class YamlLoadCall extends Decoding::Range, DataFlow::CfgNode {
100
38
"load" , "load_all" , "full_load" , "full_load_all" , "unsafe_load" , "unsafe_load_all" ,
101
39
"safe_load" , "safe_load_all"
102
40
] and
103
- node . getFunction ( ) = Yaml :: yaml:: yaml_attr ( func_name ) .asCfgNode ( )
41
+ this = API :: moduleImport ( " yaml" ) . getMember ( func_name ) .getACall ( )
104
42
}
105
43
106
44
/**
@@ -117,13 +55,13 @@ private class YamlLoadCall extends Decoding::Range, DataFlow::CfgNode {
117
55
// If the `Loader` is not set to either `SafeLoader` or `BaseLoader` or not set at all,
118
56
// then the default loader will be used, which is not safe.
119
57
not exists ( DataFlow:: Node loader_arg |
120
- loader_arg . asCfgNode ( ) in [ node .getArg ( 1 ) , node .getArgByName ( "Loader" ) ]
58
+ loader_arg in [ this .getArg ( 1 ) , this .getArgByName ( "Loader" ) ]
121
59
|
122
- loader_arg = Yaml :: yaml:: yaml_attr ( [ "SafeLoader" , "BaseLoader" ] )
60
+ loader_arg = API :: moduleImport ( " yaml" ) . getMember ( [ "SafeLoader" , "BaseLoader" ] ) . getAUse ( )
123
61
)
124
62
}
125
63
126
- override DataFlow:: Node getAnInput ( ) { result . asCfgNode ( ) = node .getArg ( 0 ) }
64
+ override DataFlow:: Node getAnInput ( ) { result = this .getArg ( 0 ) }
127
65
128
66
override DataFlow:: Node getOutput ( ) { result = this }
129
67
0 commit comments