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