22 * Provides modeling for Rack applications.
33 */
44
5+ private import codeql.ruby.AST
56private import codeql.ruby.ApiGraphs
67private import codeql.ruby.DataFlow
78private import codeql.ruby.typetracking.TypeTracker
@@ -15,8 +16,18 @@ private class PotentialCallNode extends DataFlow::CallableNode {
1516 PotentialCallNode ( ) {
1617 this .getNumberOfParameters ( ) = 1 and
1718 (
18- this .( DataFlow:: MethodNode ) .getMethodName ( ) = "call" or
19- not this instanceof DataFlow:: MethodNode
19+ this .( DataFlow:: MethodNode ) .getMethodName ( ) = "call"
20+ or
21+ not this instanceof DataFlow:: MethodNode and
22+ exists ( DataFlow:: CallNode cn | cn .getMethodName ( ) = "run" |
23+ this .( DataFlow:: LocalSourceNode ) .flowsTo ( cn .getArgument ( 0 ) )
24+ or
25+ // TODO: `Proc.new` should automatically propagate flow from its block argument
26+ any ( DataFlow:: CallNode proc |
27+ proc = API:: getTopLevelMember ( "Proc" ) .getAnInstantiation ( ) and
28+ proc .getBlock ( ) = this
29+ ) .( DataFlow:: LocalSourceNode ) .flowsTo ( cn .getArgument ( 0 ) )
30+ )
2031 )
2132 }
2233}
@@ -33,14 +44,14 @@ private class CallNode extends PotentialCallNode {
3344 RP:: PotentialResponseNode getResponse ( ) { result = resp }
3445}
3546
36- private DataFlow:: LocalSourceNode trackRackResponse ( TypeBackTracker t , DataFlow :: CallableNode call ) {
47+ private DataFlow:: LocalSourceNode trackRackResponse ( TypeBackTracker t , PotentialCallNode call ) {
3748 t .start ( ) and
3849 result = call .getAReturnNode ( ) .getALocalSource ( )
3950 or
4051 exists ( TypeBackTracker t2 | result = trackRackResponse ( t2 , call ) .backtrack ( t2 , t ) )
4152}
4253
43- private RP:: PotentialResponseNode trackRackResponse ( DataFlow :: CallableNode call ) {
54+ private RP:: PotentialResponseNode trackRackResponse ( PotentialCallNode call ) {
4455 result = trackRackResponse ( TypeBackTracker:: end ( ) , call )
4556}
4657
0 commit comments