@@ -8,221 +8,49 @@ private import semmle.python.dataflow.new.DataFlow
88private import semmle.python.dataflow.new.TaintTracking
99private import semmle.python.dataflow.new.RemoteFlowSources
1010private import experimental.semmle.python.Concepts
11+ private import semmle.python.ApiGraphs
1112
1213/** Provides models for the Python standard library. */
13- private module Stdlib {
14- // ---------------------------------------------------------------------------
15- // re
16- // ---------------------------------------------------------------------------
17- private module Re {
18- /** Gets a reference to the `re` module. */
19- private DataFlow:: Node re ( DataFlow:: TypeTracker t ) {
20- t .start ( ) and
21- result = DataFlow:: importNode ( "re" )
22- or
23- exists ( DataFlow:: TypeTracker t2 | result = re ( t2 ) .track ( t2 , t ) )
14+ private module Re {
15+ /** List of re methods. */
16+ private class ReMethods extends string {
17+ ReMethods ( ) {
18+ this in [ "match" , "fullmatch" , "search" , "split" , "findall" , "finditer" , "sub" , "subn" ]
2419 }
20+ }
2521
26- /** Gets a reference to the `re` module. */
27- DataFlow:: Node re ( ) { result = re ( DataFlow:: TypeTracker:: end ( ) ) }
22+ private class DirectRegex extends DataFlow:: CallCfgNode , RegexExecution:: Range {
23+ DataFlow:: Node regexNode ;
24+ Attribute regexMethod ;
2825
29- /**
30- * Gets a reference to the attribute `attr_name` of the `re` module.
31- * WARNING: Only holds for a few predefined attributes.
32- */
33- private DataFlow:: Node re_attr ( DataFlow:: TypeTracker t , string attr_name ) {
34- attr_name in [
35- "match" , "fullmatch" , "search" , "split" , "findall" , "finditer" , "sub" , "subn" , "compile" ,
36- "escape"
37- ] and
38- (
39- t .start ( ) and
40- result = DataFlow:: importNode ( "re" + "." + attr_name )
41- or
42- t .startInAttr ( attr_name ) and
43- result = re ( )
44- )
45- or
46- // Due to bad performance when using normal setup with `re_attr(t2, attr_name).track(t2, t)`
47- // we have inlined that code and forced a join
48- exists ( DataFlow:: TypeTracker t2 |
49- exists ( DataFlow:: StepSummary summary |
50- re_attr_first_join ( t2 , attr_name , result , summary ) and
51- t = t2 .append ( summary )
52- )
53- )
26+ DirectRegex ( ) {
27+ this = API:: moduleImport ( "re" ) .getMember ( any ( ReMethods m ) ) .getACall ( ) and
28+ regexNode = this .getArg ( 0 ) and
29+ regexMethod = this .asExpr ( ) .( Attribute )
5430 }
5531
56- pragma [ nomagic]
57- private predicate re_attr_first_join (
58- DataFlow:: TypeTracker t2 , string attr_name , DataFlow:: Node res , DataFlow:: StepSummary summary
59- ) {
60- DataFlow:: StepSummary:: step ( re_attr ( t2 , attr_name ) , res , summary )
61- }
32+ override DataFlow:: Node getRegexNode ( ) { result = regexNode }
6233
63- /**
64- * Gets a reference to the attribute `attr_name` of the `re` module.
65- * WARNING: Only holds for a few predefined attributes.
66- */
67- private DataFlow:: Node re_attr ( string attr_name ) {
68- result = re_attr ( DataFlow:: TypeTracker:: end ( ) , attr_name )
69- }
34+ override Attribute getRegexMethod ( ) { result = regexMethod }
35+ }
7036
71- /**
72- * Gets a reference to any `attr_name` of the `re` module that immediately executes an expression.
73- * WARNING: Only holds for a few predefined attributes.
74- */
75- private DataFlow:: Node re_exec_attr ( ) {
76- exists ( string attr_name |
77- attr_name in [ "match" , "fullmatch" , "search" , "split" , "findall" , "finditer" , "sub" , "subn" ] and
78- result = re_attr ( DataFlow:: TypeTracker:: end ( ) , attr_name )
37+ private class CompiledRegex extends DataFlow:: CallCfgNode , RegexExecution:: Range {
38+ DataFlow:: Node regexNode ;
39+ Attribute regexMethod ;
40+
41+ CompiledRegex ( ) {
42+ exists ( DataFlow:: CallCfgNode patternCall , DirectRegex reMethod |
43+ this = reMethod and
44+ patternCall = API:: moduleImport ( "re" ) .getMember ( "compile" ) .getACall ( ) and
45+ patternCall = reMethod .( DataFlow:: AttrRead ) .getObject ( ) .getALocalSource ( ) and
46+ regexNode = patternCall .getArg ( 0 ) and
47+ // regexMethod is *not* worked out outside class instanciation because `CompiledRegex` focuses on re.compile(pattern).ReMethod
48+ regexMethod = reMethod .getRegexMethod ( )
7949 )
8050 }
8151
82- /**
83- * A call to `re.match`
84- * See https://docs.python.org/3/library/re.html#re.match
85- */
86- private class ReMatchCall extends RegexExecution:: Range , DataFlow:: CfgNode {
87- override CallNode node ;
88-
89- ReMatchCall ( ) { node .getFunction ( ) = re_attr ( "match" ) .asCfgNode ( ) }
90-
91- override DataFlow:: Node getRegexNode ( ) { result .asCfgNode ( ) = node .getArg ( 0 ) }
92-
93- override Attribute getRegexMethod ( ) { result = node .getNode ( ) .getFunc ( ) .( Attribute ) }
94- }
95-
96- /**
97- * A call to `re.fullmatch`
98- * See https://docs.python.org/3/library/re.html#re.fullmatch
99- */
100- private class ReFullMatchCall extends RegexExecution:: Range , DataFlow:: CfgNode {
101- override CallNode node ;
102-
103- ReFullMatchCall ( ) { node .getFunction ( ) = re_attr ( "fullmatch" ) .asCfgNode ( ) }
104-
105- override DataFlow:: Node getRegexNode ( ) { result .asCfgNode ( ) = node .getArg ( 0 ) }
106-
107- override Attribute getRegexMethod ( ) { result = node .getNode ( ) .getFunc ( ) .( Attribute ) }
108- }
109-
110- /**
111- * A call to `re.search`
112- * See https://docs.python.org/3/library/re.html#re.search
113- */
114- private class ReSearchCall extends RegexExecution:: Range , DataFlow:: CfgNode {
115- override CallNode node ;
116-
117- ReSearchCall ( ) { node .getFunction ( ) = re_attr ( "search" ) .asCfgNode ( ) }
118-
119- override DataFlow:: Node getRegexNode ( ) { result .asCfgNode ( ) = node .getArg ( 0 ) }
120-
121- override Attribute getRegexMethod ( ) { result = node .getNode ( ) .getFunc ( ) .( Attribute ) }
122- }
123-
124- /**
125- * A call to `re.split`
126- * See https://docs.python.org/3/library/re.html#re.split
127- */
128- private class ReSplitCall extends RegexExecution:: Range , DataFlow:: CfgNode {
129- override CallNode node ;
130-
131- ReSplitCall ( ) { node .getFunction ( ) = re_attr ( "split" ) .asCfgNode ( ) }
132-
133- override DataFlow:: Node getRegexNode ( ) { result .asCfgNode ( ) = node .getArg ( 0 ) }
134-
135- override Attribute getRegexMethod ( ) { result = node .getNode ( ) .getFunc ( ) .( Attribute ) }
136- }
137-
138- /**
139- * A call to `re.findall`
140- * See https://docs.python.org/3/library/re.html#re.findall
141- */
142- private class ReFindAllCall extends RegexExecution:: Range , DataFlow:: CfgNode {
143- override CallNode node ;
144-
145- ReFindAllCall ( ) { node .getFunction ( ) = re_attr ( "findall" ) .asCfgNode ( ) }
146-
147- override DataFlow:: Node getRegexNode ( ) { result .asCfgNode ( ) = node .getArg ( 0 ) }
148-
149- override Attribute getRegexMethod ( ) { result = node .getNode ( ) .getFunc ( ) .( Attribute ) }
150- }
151-
152- /**
153- * A call to `re.finditer`
154- * See https://docs.python.org/3/library/re.html#re.finditer
155- */
156- private class ReFindIterCall extends RegexExecution:: Range , DataFlow:: CfgNode {
157- override CallNode node ;
158-
159- ReFindIterCall ( ) { node .getFunction ( ) = re_attr ( "finditer" ) .asCfgNode ( ) }
160-
161- override DataFlow:: Node getRegexNode ( ) { result .asCfgNode ( ) = node .getArg ( 0 ) }
162-
163- override Attribute getRegexMethod ( ) { result = node .getNode ( ) .getFunc ( ) .( Attribute ) }
164- }
165-
166- /**
167- * A call to `re.sub`
168- * See https://docs.python.org/3/library/re.html#re.sub
169- */
170- private class ReSubCall extends RegexExecution:: Range , DataFlow:: CfgNode {
171- override CallNode node ;
172-
173- ReSubCall ( ) { node .getFunction ( ) = re_attr ( "sub" ) .asCfgNode ( ) }
174-
175- override DataFlow:: Node getRegexNode ( ) { result .asCfgNode ( ) = node .getArg ( 0 ) }
176-
177- override Attribute getRegexMethod ( ) { result = node .getNode ( ) .getFunc ( ) .( Attribute ) }
178- }
179-
180- /**
181- * A call to `re.subn`
182- * See https://docs.python.org/3/library/re.html#re.subn
183- */
184- private class ReSubNCall extends RegexExecution:: Range , DataFlow:: CfgNode {
185- override CallNode node ;
52+ override DataFlow:: Node getRegexNode ( ) { result = regexNode }
18653
187- ReSubNCall ( ) { node .getFunction ( ) = re_attr ( "subn" ) .asCfgNode ( ) }
188-
189- override DataFlow:: Node getRegexNode ( ) { result .asCfgNode ( ) = node .getArg ( 0 ) }
190-
191- override Attribute getRegexMethod ( ) { result = node .getNode ( ) .getFunc ( ) .( Attribute ) }
192- }
193-
194- /**
195- * A call to `re.escape`
196- * See https://docs.python.org/3/library/re.html#re.escape
197- */
198- private class ReEscapeCall extends RegexExecution:: Range , DataFlow:: CfgNode {
199- override CallNode node ;
200-
201- ReEscapeCall ( ) { node .getFunction ( ) = re_attr ( "escape" ) .asCfgNode ( ) }
202-
203- override DataFlow:: Node getRegexNode ( ) { result .asCfgNode ( ) = node .getArg ( 0 ) }
204-
205- override Attribute getRegexMethod ( ) { result = node .getNode ( ) .getFunc ( ) .( Attribute ) }
206- }
207-
208- /**
209- * A call to `re.compile`
210- * See https://docs.python.org/3/library/re.html#re.match
211- */
212- private class ReCompileCall extends RegexExecution:: Range , DataFlow:: CfgNode {
213- override CallNode node ;
214-
215- ReCompileCall ( ) { node .getFunction ( ) = re_attr ( "compile" ) .asCfgNode ( ) }
216-
217- override DataFlow:: Node getRegexNode ( ) { result .asCfgNode ( ) = node .getArg ( 0 ) }
218-
219- override Attribute getRegexMethod ( ) {
220- exists ( DataFlow:: AttrRead reMethod |
221- reMethod = re_exec_attr ( ) and
222- node .getFunction ( ) = reMethod .getObject ( ) .getALocalSource ( ) .asCfgNode ( ) and
223- result = reMethod .asExpr ( ) .( Attribute )
224- )
225- }
226- }
54+ override Attribute getRegexMethod ( ) { result = regexMethod }
22755 }
22856}
0 commit comments