22 * Provides modeling for the Rack library.
33 */
44
5+ private import codeql.ruby.Concepts
56private import codeql.ruby.controlflow.CfgNodes:: ExprNodes
67private import codeql.ruby.DataFlow
78private import codeql.ruby.typetracking.TypeTracker
@@ -17,48 +18,63 @@ module Rack {
1718 */
1819 class AppCandidate extends DataFlow:: ClassNode {
1920 private DataFlow:: MethodNode call ;
21+ private PotentialResponseNode resp ;
2022
2123 AppCandidate ( ) {
2224 call = this .getInstanceMethod ( "call" ) and
2325 call .getNumberOfParameters ( ) = 1 and
24- call .getReturn ( ) = trackRackResponse ( )
26+ call .getReturn ( ) = trackRackResponse ( resp )
2527 }
2628
2729 /**
2830 * Gets the environment of the request, which is the lone parameter to the `call` method.
2931 */
3032 DataFlow:: ParameterNode getEnv ( ) { result = call .getParameter ( 0 ) }
33+
34+ /** Gets the response returned from the request. */
35+ PotentialResponseNode getResponse ( ) { result = resp }
3136 }
3237
33- private DataFlow:: LocalSourceNode trackStatusCode ( TypeTracker t , int i ) {
38+ private DataFlow:: LocalSourceNode trackInt ( TypeTracker t , int i ) {
3439 t .start ( ) and
3540 result .getConstantValue ( ) .isInt ( i )
3641 or
37- exists ( TypeTracker t2 | result = trackStatusCode ( t2 , i ) .track ( t2 , t ) )
42+ exists ( TypeTracker t2 | result = trackInt ( t2 , i ) .track ( t2 , t ) )
3843 }
3944
40- private DataFlow:: Node trackStatusCode ( int i ) {
41- trackStatusCode ( TypeTracker:: end ( ) , i ) .flowsTo ( result )
42- }
45+ private DataFlow:: Node trackInt ( int i ) { trackInt ( TypeTracker:: end ( ) , i ) .flowsTo ( result ) }
4346
44- class ResponseNode extends DataFlow:: ArrayLiteralNode {
47+ private class PotentialResponseNode extends DataFlow:: ArrayLiteralNode {
4548 // [status, headers, body]
46- ResponseNode ( ) { this .getNumberOfArguments ( ) = 3 }
49+ PotentialResponseNode ( ) { this .getNumberOfArguments ( ) = 3 }
4750
4851 /**
4952 * Gets an HTTP status code that may be returned in this response.
5053 */
51- int getAStatusCode ( ) { this .getElement ( 0 ) = trackStatusCode ( result ) }
54+ int getAStatusCode ( ) { this .getElement ( 0 ) = trackInt ( result ) }
5255 }
5356
54- private DataFlow:: LocalSourceNode trackRackResponse ( TypeTracker t ) {
57+ private DataFlow:: LocalSourceNode trackRackResponse ( TypeTracker t , PotentialResponseNode n ) {
5558 t .start ( ) and
56- result instanceof ResponseNode
59+ result = n
5760 or
58- exists ( TypeTracker t2 | result = trackRackResponse ( t2 ) .track ( t2 , t ) )
61+ exists ( TypeTracker t2 | result = trackRackResponse ( t2 , n ) .track ( t2 , t ) )
62+ }
63+
64+ private DataFlow:: Node trackRackResponse ( PotentialResponseNode n ) {
65+ trackRackResponse ( TypeTracker:: end ( ) , n ) .flowsTo ( result )
5966 }
6067
61- private DataFlow:: Node trackRackResponse ( ) {
62- trackRackResponse ( TypeTracker:: end ( ) ) .flowsTo ( result )
68+ /** A `DataFlow::Node` returned from a rack request. */
69+ class ResponseNode extends PotentialResponseNode , Http:: Server:: HttpResponse:: Range {
70+ ResponseNode ( ) { this = any ( AppCandidate app ) .getResponse ( ) }
71+
72+ override DataFlow:: Node getBody ( ) { result = this .getElement ( 2 ) }
73+
74+ // TODO
75+ override DataFlow:: Node getMimetypeOrContentTypeArg ( ) { none ( ) }
76+
77+ // TODO
78+ override string getMimetypeDefault ( ) { none ( ) }
6379 }
6480}
0 commit comments