@@ -55,175 +55,59 @@ DataFlow::Node stringSink() {
5555/** Gets a node where regular expressions that flow to the node are used. */
5656DataFlow:: Node regSink ( ) { result = any ( RegexExecution exec ) .getRegex ( ) }
5757
58- private signature module TypeTrackInputSig {
59- DataFlow:: LocalSourceNode start ( TypeTracker t , DataFlow:: Node start ) ;
58+ private module RegexConfig implements DataFlow:: StateConfigSig {
59+ private newtype TFlowState =
60+ TStringState ( ) or
61+ TRegExpState ( )
6062
61- predicate end ( DataFlow :: Node n ) ;
63+ class FlowState = TFlowState ;
6264
63- predicate additionalStep ( DataFlow:: Node nodeFrom , DataFlow:: LocalSourceNode nodeTo ) ;
64- }
65-
66- /**
67- * Provides a version of type tracking where we first prune for reachable nodes,
68- * before doing the type tracking computation.
69- */
70- private module PrunedTypeTrack< TypeTrackInputSig Input> {
71- private predicate additionalStep (
72- DataFlow:: LocalSourceNode nodeFrom , DataFlow:: LocalSourceNode nodeTo
73- ) {
74- Input:: additionalStep ( nodeFrom .getALocalUse ( ) , nodeTo )
75- }
76-
77- /** Gets a node that is forwards reachable by type-tracking. */
78- pragma [ nomagic]
79- private DataFlow:: LocalSourceNode forward ( TypeTracker t ) {
80- result = Input:: start ( t , _)
65+ predicate isSource ( DataFlow:: Node source , FlowState state ) {
66+ state = TStringState ( ) and source = strStart ( )
8167 or
82- exists ( TypeTracker t2 | result = forward ( t2 ) .track ( t2 , t ) )
83- or
84- exists ( TypeTracker t2 | t2 = t .continue ( ) | additionalStep ( forward ( t2 ) , result ) )
68+ state = TRegExpState ( ) and source = regStart ( )
8569 }
8670
87- bindingset [ result , tbt]
88- pragma [ inline_late]
89- pragma [ noopt]
90- private DataFlow:: LocalSourceNode forwardLateInline ( TypeBackTracker tbt ) {
91- exists ( TypeTracker tt |
92- result = forward ( tt ) and
93- tt = tbt .getACompatibleTypeTracker ( )
94- )
71+ predicate isSink ( DataFlow:: Node sink , FlowState state ) {
72+ state = TStringState ( ) and sink = stringSink ( )
73+ or
74+ state = TRegExpState ( ) and sink = regSink ( )
9575 }
9676
97- /** Gets a node that is backwards reachable by type-tracking. */
98- pragma [ nomagic]
99- private DataFlow:: LocalSourceNode backwards ( TypeBackTracker t ) {
100- result = forwardLateInline ( t ) and
77+ predicate isAdditionalFlowStep (
78+ DataFlow:: Node node1 , FlowState state1 , DataFlow:: Node node2 , FlowState state2
79+ ) {
80+ regFromString ( node1 , node2 ) and state1 = TStringState ( ) and state2 = TRegExpState ( )
81+ or
82+ state1 = TStringState ( ) and
83+ state2 = TStringState ( ) and
10184 (
102- t . start ( ) and
103- Input :: end ( result . getALocalUse ( ) )
85+ // include taint flow through `String` summaries
86+ TaintTrackingPrivate :: summaryThroughStepTaint ( node1 , node2 , any ( String :: SummarizedCallable c ) )
10487 or
105- exists ( TypeBackTracker t2 | result = backwards ( t2 ) .backtrack ( t2 , t ) )
88+ // string concatenations, and
89+ exists ( CfgNodes:: ExprNodes:: OperationCfgNode op |
90+ op = node2 .asExpr ( ) and
91+ op .getAnOperand ( ) = node1 .asExpr ( ) and
92+ op .getExpr ( ) .( Ast:: BinaryOperation ) .getOperator ( ) = "+"
93+ )
10694 or
107- exists ( TypeBackTracker t2 | t2 = t .continue ( ) | additionalStep ( result , backwards ( t2 ) ) )
108- )
109- }
110-
111- bindingset [ result , tt]
112- pragma [ inline_late]
113- pragma [ noopt]
114- private DataFlow:: LocalSourceNode backwardsInlineLate ( TypeTracker tt ) {
115- exists ( TypeBackTracker tbt |
116- result = backwards ( tbt ) and
117- tt = tbt .getACompatibleTypeTracker ( )
118- )
119- }
120-
121- /** Holds if `n` is forwards and backwards reachable with type tracker `t`. */
122- pragma [ nomagic]
123- private predicate reached ( DataFlow:: LocalSourceNode n , TypeTracker t ) {
124- n = forward ( t ) and
125- n = backwardsInlineLate ( t )
126- }
127-
128- pragma [ nomagic]
129- private TypeTracker stepReached (
130- TypeTracker t , DataFlow:: LocalSourceNode nodeFrom , DataFlow:: LocalSourceNode nodeTo
131- ) {
132- exists ( StepSummary summary |
133- step ( nodeFrom , nodeTo , summary ) and
134- reached ( nodeFrom , t ) and
135- reached ( nodeTo , result ) and
136- result = append ( t , summary )
137- )
138- or
139- additionalStep ( nodeFrom , nodeTo ) and
140- reached ( nodeFrom , pragma [ only_bind_into ] ( t ) ) and
141- reached ( nodeTo , pragma [ only_bind_into ] ( t ) ) and
142- result = t .continue ( )
143- }
144-
145- /** Gets a node that has been tracked from the start node `start`. */
146- DataFlow:: LocalSourceNode track ( DataFlow:: Node start , TypeTracker t ) {
147- t .start ( ) and
148- result = Input:: start ( t , start ) and
149- reached ( result , t )
150- or
151- exists ( TypeTracker t2 | t = stepReached ( t2 , track ( start , t2 ) , result ) )
152- }
153- }
154-
155- /** Holds if `inputStr` is compiled to a regular expression that is returned at `call`. */
156- pragma [ nomagic]
157- private predicate regFromString ( DataFlow:: LocalSourceNode inputStr , DataFlow:: CallNode call ) {
158- exists ( DataFlow:: Node mid |
159- inputStr .flowsTo ( mid ) and
160- call = API:: getTopLevelMember ( "Regexp" ) .getAMethodCall ( [ "compile" , "new" ] ) and
161- mid = call .getArgument ( 0 )
162- )
163- }
164-
165- private module StringTypeTrackInput implements TypeTrackInputSig {
166- DataFlow:: LocalSourceNode start ( TypeTracker t , DataFlow:: Node start ) {
167- start = strStart ( ) and t .start ( ) and result = start
168- }
169-
170- predicate end ( DataFlow:: Node n ) {
171- n = stringSink ( ) or
172- regFromString ( n , _)
173- }
174-
175- predicate additionalStep ( DataFlow:: Node nodeFrom , DataFlow:: LocalSourceNode nodeTo ) {
176- // include taint flow through `String` summaries
177- TaintTrackingPrivate:: summaryThroughStepTaint ( nodeFrom , nodeTo ,
178- any ( String:: SummarizedCallable c ) )
179- or
180- // string concatenations, and
181- exists ( CfgNodes:: ExprNodes:: OperationCfgNode op |
182- op = nodeTo .asExpr ( ) and
183- op .getAnOperand ( ) = nodeFrom .asExpr ( ) and
184- op .getExpr ( ) .( Ast:: BinaryOperation ) .getOperator ( ) = "+"
95+ // string interpolations
96+ node1 .asExpr ( ) =
97+ node2 .asExpr ( ) .( CfgNodes:: ExprNodes:: StringlikeLiteralCfgNode ) .getAComponent ( )
18598 )
186- or
187- // string interpolations
188- nodeFrom .asExpr ( ) =
189- nodeTo .asExpr ( ) .( CfgNodes:: ExprNodes:: StringlikeLiteralCfgNode ) .getAComponent ( )
19099 }
191100}
192101
193- /**
194- * Gets a node that has been tracked from the string constant `start` to some node.
195- * This is used to figure out where `start` is evaluated as a regular expression against an input string,
196- * or where `start` is compiled into a regular expression.
197- */
198- private predicate trackStrings = PrunedTypeTrack< StringTypeTrackInput > :: track / 2 ;
102+ private module RegexTracking = DataFlow:: GlobalWithState< RegexConfig > ;
199103
200- /** Holds if `strConst` flows to a regex compilation (tracked by `t`), where the resulting regular expression is stored in `reg `. */
104+ /** Holds if `inputStr` is compiled to a regular expression that is returned at `call `. */
201105pragma [ nomagic]
202- private predicate regFromStringStart ( DataFlow:: Node strConst , TypeTracker t , DataFlow:: CallNode reg ) {
203- regFromString ( trackStrings ( strConst , t ) , reg ) and
204- exists ( t .continue ( ) )
205- }
206-
207- private module RegTypeTrackInput implements TypeTrackInputSig {
208- DataFlow:: LocalSourceNode start ( TypeTracker t , DataFlow:: Node start ) {
209- start = regStart ( ) and
210- t .start ( ) and
211- result = start
212- or
213- regFromStringStart ( start , t , result )
214- }
215-
216- predicate end ( DataFlow:: Node n ) { n = regSink ( ) }
217-
218- predicate additionalStep ( DataFlow:: Node nodeFrom , DataFlow:: LocalSourceNode nodeTo ) { none ( ) }
106+ private predicate regFromString ( DataFlow:: Node inputStr , DataFlow:: CallNode call ) {
107+ call = API:: getTopLevelMember ( "Regexp" ) .getAMethodCall ( [ "compile" , "new" ] ) and
108+ inputStr = call .getArgument ( 0 )
219109}
220110
221- /**
222- * Gets a node that has been tracked from the regular expression `start` to some node.
223- * This is used to figure out where `start` is executed against an input string.
224- */
225- private predicate trackRegs = PrunedTypeTrack< RegTypeTrackInput > :: track / 2 ;
226-
227111/** Gets a node that references a regular expression. */
228112private DataFlow:: LocalSourceNode trackRegexpType ( TypeTracker t ) {
229113 t .start ( ) and
@@ -240,12 +124,4 @@ DataFlow::Node trackRegexpType() { trackRegexpType(TypeTracker::end()).flowsTo(r
240124
241125/** Gets a node holding a value for the regular expression that is evaluated at `re`. */
242126cached
243- DataFlow:: Node regExpSource ( DataFlow:: Node re ) {
244- exists ( DataFlow:: LocalSourceNode end | end = trackStrings ( result , TypeTracker:: end ( ) ) |
245- end .getALocalUse ( ) = re and re = stringSink ( )
246- )
247- or
248- exists ( DataFlow:: LocalSourceNode end | end = trackRegs ( result , TypeTracker:: end ( ) ) |
249- end .getALocalUse ( ) = re and re = regSink ( )
250- )
251- }
127+ DataFlow:: Node regExpSource ( DataFlow:: Node re ) { RegexTracking:: flow ( result , re ) }
0 commit comments