|
| 1 | +private import codeql_ruby.AST |
| 2 | +private import codeql_ruby.Concepts |
| 3 | +private import codeql_ruby.controlflow.CfgNodes |
| 4 | +private import codeql_ruby.DataFlow |
| 5 | +private import codeql_ruby.dataflow.RemoteFlowSources |
| 6 | +private import codeql_ruby.ast.internal.Module |
| 7 | + |
| 8 | +private class ActionControllerBaseAccess extends ConstantReadAccess { |
| 9 | + ActionControllerBaseAccess() { |
| 10 | + this.getName() = "Base" and |
| 11 | + this.getScopeExpr().(ConstantAccess).getName() = "ActionController" |
| 12 | + } |
| 13 | +} |
| 14 | + |
| 15 | +// ApplicationController extends ActionController::Base, but we |
| 16 | +// treat it separately in case the ApplicationController definition |
| 17 | +// is not in the database |
| 18 | +private class ApplicationControllerAccess extends ConstantReadAccess { |
| 19 | + ApplicationControllerAccess() { this.getName() = "ApplicationController" } |
| 20 | +} |
| 21 | + |
| 22 | +/** |
| 23 | + * A `ClassDeclaration` for a class that extends `ActionController::Base`. |
| 24 | + * For example, |
| 25 | + * |
| 26 | + * ```rb |
| 27 | + * class FooController < ActionController::Base |
| 28 | + * def delete_handler |
| 29 | + * uid = params[:id] |
| 30 | + * User.delete_all("id = ?", uid) |
| 31 | + * end |
| 32 | + * end |
| 33 | + * ``` |
| 34 | + */ |
| 35 | +class ActionControllerControllerClass extends ClassDeclaration { |
| 36 | + ActionControllerControllerClass() { |
| 37 | + // class FooController < ActionController::Base |
| 38 | + this.getSuperclassExpr() instanceof ActionControllerBaseAccess |
| 39 | + or |
| 40 | + // class FooController < ApplicationController |
| 41 | + this.getSuperclassExpr() instanceof ApplicationControllerAccess |
| 42 | + or |
| 43 | + // class BarController < FooController |
| 44 | + exists(ActionControllerControllerClass other | |
| 45 | + other.getModule() = resolveScopeExpr(this.getSuperclassExpr()) |
| 46 | + ) |
| 47 | + } |
| 48 | +} |
| 49 | + |
| 50 | +/** |
| 51 | + * A call to the `params` method within the context of an |
| 52 | + * `ActionControllerControllerClass`. For example, the `params` call in: |
| 53 | + * |
| 54 | + * ```rb |
| 55 | + * class FooController < ActionController::Base |
| 56 | + * def delete_handler |
| 57 | + * uid = params[:id] |
| 58 | + * User.delete_all("id = ?", uid) |
| 59 | + * end |
| 60 | + * end |
| 61 | + * ``` |
| 62 | + */ |
| 63 | +class ActionControllerParamsCall extends MethodCall { |
| 64 | + private ActionControllerControllerClass controllerClass; |
| 65 | + |
| 66 | + ActionControllerParamsCall() { |
| 67 | + this.getMethodName() = "params" and |
| 68 | + this.getReceiver() instanceof Self and |
| 69 | + this.getEnclosingModule() = controllerClass |
| 70 | + } |
| 71 | + |
| 72 | + ActionControllerControllerClass getControllerClass() { result = controllerClass } |
| 73 | +} |
| 74 | + |
| 75 | +/** |
| 76 | + * A `RemoteFlowSource::Range` to represent accessing the Action Controller |
| 77 | + * parameters available to a controller via the `params` method. |
| 78 | + */ |
| 79 | +class ActionControllerParamsSource extends RemoteFlowSource::Range { |
| 80 | + ActionControllerParamsCall call; |
| 81 | + |
| 82 | + ActionControllerParamsSource() { this.asExpr().getExpr() = call } |
| 83 | + |
| 84 | + // TODO: what to use here? |
| 85 | + override string getSourceType() { result = "ActionController::Metal#params" } |
| 86 | +} |
0 commit comments