@@ -11,6 +11,7 @@ private import python
1111private import semmle.python.dataflow.new.DataFlow
1212private import semmle.python.dataflow.new.RemoteFlowSources
1313private import semmle.python.Concepts
14+ private import semmle.python.ApiGraphs
1415
1516/**
1617 * Provides classes modeling security-relevant aspects of the PyYAML package (obtained
@@ -20,78 +21,15 @@ private import semmle.python.Concepts
2021 * - https://pyyaml.org/wiki/PyYAMLDocumentation
2122 * - https://pyyaml.docsforge.com/master/documentation/
2223 */
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 { }
8725
8826/**
8927 * A call to any of the loading functions in `yaml` (`load`, `load_all`, `full_load`,
9028 * `full_load_all`, `unsafe_load`, `unsafe_load_all`, `safe_load`, `safe_load_all`)
9129 *
9230 * See https://pyyaml.org/wiki/PyYAMLDocumentation (you will have to scroll down).
9331 */
94- private class YamlLoadCall extends Decoding:: Range , DataFlow:: CfgNode {
32+ private class YamlLoadCall extends Decoding:: Range , DataFlow:: CallCfgNode {
9533 override CallNode node ;
9634 string func_name ;
9735
@@ -100,7 +38,7 @@ private class YamlLoadCall extends Decoding::Range, DataFlow::CfgNode {
10038 "load" , "load_all" , "full_load" , "full_load_all" , "unsafe_load" , "unsafe_load_all" ,
10139 "safe_load" , "safe_load_all"
10240 ] and
103- node . getFunction ( ) = Yaml :: yaml:: yaml_attr ( func_name ) .asCfgNode ( )
41+ this = API :: moduleImport ( " yaml" ) . getMember ( func_name ) .getACall ( )
10442 }
10543
10644 /**
@@ -117,13 +55,13 @@ private class YamlLoadCall extends Decoding::Range, DataFlow::CfgNode {
11755 // If the `Loader` is not set to either `SafeLoader` or `BaseLoader` or not set at all,
11856 // then the default loader will be used, which is not safe.
11957 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" ) ]
12159 |
122- loader_arg = Yaml :: yaml:: yaml_attr ( [ "SafeLoader" , "BaseLoader" ] )
60+ loader_arg = API :: moduleImport ( " yaml" ) . getMember ( [ "SafeLoader" , "BaseLoader" ] ) . getAUse ( )
12361 )
12462 }
12563
126- override DataFlow:: Node getAnInput ( ) { result . asCfgNode ( ) = node .getArg ( 0 ) }
64+ override DataFlow:: Node getAnInput ( ) { result = this .getArg ( 0 ) }
12765
12866 override DataFlow:: Node getOutput ( ) { result = this }
12967
0 commit comments