@@ -22,28 +22,59 @@ private module Yaml {
2222
2323 /** Provides models for the `yaml` module. */
2424 module yaml {
25- /** Gets a reference to the `yaml.load` function. */
26- private DataFlow:: Node load ( DataFlow:: TypeTracker t ) {
27- t .start ( ) and
28- result = DataFlow:: importNode ( "yaml.load" )
25+ /**
26+ * Gets a reference to the attribute `attr_name` of the `yaml` module.
27+ * WARNING: Only holds for a few predefined attributes.
28+ *
29+ * For example, using `attr_name = "load"` will get all uses of `yaml.load`.
30+ */
31+ private DataFlow:: Node yaml_attr ( DataFlow:: TypeTracker t , string attr_name ) {
32+ attr_name in [ "load" , "SafeLoader" , "BaseLoader" ] and
33+ (
34+ t .start ( ) and
35+ result = DataFlow:: importNode ( "yaml." + attr_name )
36+ or
37+ t .startInAttr ( attr_name ) and
38+ result = yaml ( )
39+ )
2940 or
30- t .startInAttr ( "load" ) and
31- result = yaml ( )
32- or
33- exists ( DataFlow:: TypeTracker t2 | result = load ( t2 ) .track ( t2 , t ) )
41+ // Due to bad performance when using normal setup with `yaml_attr(t2, attr_name).track(t2, t)`
42+ // we have inlined that code and forced a join
43+ exists ( DataFlow:: TypeTracker t2 |
44+ exists ( DataFlow:: StepSummary summary |
45+ yaml_attr_first_join ( t2 , attr_name , result , summary ) and
46+ t = t2 .append ( summary )
47+ )
48+ )
49+ }
50+
51+ pragma [ nomagic]
52+ private predicate yaml_attr_first_join (
53+ DataFlow:: TypeTracker t2 , string attr_name , DataFlow:: Node res , DataFlow:: StepSummary summary
54+ ) {
55+ DataFlow:: StepSummary:: step ( yaml_attr ( t2 , attr_name ) , res , summary )
3456 }
3557
36- /** Gets a reference to the `yaml.load` function. */
37- DataFlow:: Node load ( ) { result = load ( DataFlow:: TypeTracker:: end ( ) ) }
58+ /**
59+ * Gets a reference to the attribute `attr_name` of the `yaml` module.
60+ * WARNING: Only holds for a few predefined attributes.
61+ *
62+ * For example, using `attr_name = "load"` will get all uses of `yaml.load`.
63+ */
64+ DataFlow:: Node yaml_attr ( string attr_name ) {
65+ result = yaml_attr ( DataFlow:: TypeTracker:: end ( ) , attr_name )
66+ }
3867 }
3968}
4069
4170/**
4271 * A call to `yaml.load`
4372 * See https://pyyaml.org/wiki/PyYAMLDocumentation (you will have to scroll down).
4473 */
45- private class YamlLoadCall extends Decoding:: Range {
46- YamlLoadCall ( ) { this .asCfgNode ( ) .( CallNode ) .getFunction ( ) = Yaml:: yaml:: load ( ) .asCfgNode ( ) }
74+ private class YamlLoadCall extends Decoding:: Range , DataFlow:: CfgNode {
75+ override CallNode node ;
76+
77+ YamlLoadCall ( ) { node .getFunction ( ) = Yaml:: yaml:: yaml_attr ( "load" ) .asCfgNode ( ) }
4778
4879 /**
4980 * This function was thought safe from the 5.1 release in 2017, when the default loader was changed to `FullLoader`.
@@ -55,13 +86,11 @@ private class YamlLoadCall extends Decoding::Range {
5586 override predicate unsafe ( ) {
5687 // If the `Loader` is not set to either `SafeLoader` or `BaseLoader` or not set at all,
5788 // then the default loader will be used, which is not safe.
58- not this . asCfgNode ( ) . ( CallNode ) . getArgByName ( "Loader" ) . ( NameNode ) . getId ( ) in [ "SafeLoader" ,
59- "BaseLoader" ]
89+ not node . getArgByName ( "Loader" ) =
90+ Yaml :: yaml :: yaml_attr ( [ "SafeLoader" , "BaseLoader" ] ) . asCfgNode ( )
6091 }
6192
62- override DataFlow:: Node getAnInput ( ) {
63- result .asCfgNode ( ) = this .asCfgNode ( ) .( CallNode ) .getArg ( 0 )
64- }
93+ override DataFlow:: Node getAnInput ( ) { result .asCfgNode ( ) = node .getArg ( 0 ) }
6594
6695 override DataFlow:: Node getOutput ( ) { result = this }
6796
0 commit comments