Skip to content

Commit d61f055

Browse files
committed
Ruby: add ActionMailer#params as a RemoteFlowSource
1 parent 4b1f6f0 commit d61f055

File tree

6 files changed

+83
-0
lines changed

6 files changed

+83
-0
lines changed

ruby/ql/lib/codeql/ruby/Frameworks.qll

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
private import codeql.ruby.frameworks.Core
66
private import codeql.ruby.frameworks.ActionCable
77
private import codeql.ruby.frameworks.ActionController
8+
private import codeql.ruby.frameworks.ActionMailer
89
private import codeql.ruby.frameworks.ActiveRecord
910
private import codeql.ruby.frameworks.ActiveResource
1011
private import codeql.ruby.frameworks.ActiveStorage
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
/**
2+
* Provides modeling for the `ActionMailer` library.
3+
*/
4+
5+
private import codeql.ruby.AST
6+
private import codeql.ruby.ApiGraphs
7+
private import codeql.ruby.frameworks.internal.Rails
8+
9+
/**
10+
* A `ClassDeclaration` for a class that extends `ActionMailer::Base`.
11+
* For example,
12+
*
13+
* ```rb
14+
* class FooMailer < ActionMailer::Base
15+
* ...
16+
* end
17+
* ```
18+
*/
19+
class ActionMailerMailerClass extends ClassDeclaration {
20+
ActionMailerMailerClass() {
21+
this.getSuperclassExpr() =
22+
[
23+
API::getTopLevelMember("ActionMailer").getMember("Base"),
24+
// In Rails applications `ApplicationMailer` typically extends
25+
// `ActionMailer::Base`, but we treat it separately in case the
26+
// `ApplicationMailer` definition is not in the database.
27+
API::getTopLevelMember("ApplicationMailer")
28+
].getASubclass().getAValueReachableFromSource().asExpr().getExpr()
29+
}
30+
}
31+
32+
/** A method call with a `self` receiver from within a mailer class */
33+
private class ActionMailerContextCall extends MethodCall {
34+
private ActionMailerMailerClass mailerClass;
35+
36+
ActionMailerContextCall() {
37+
this.getReceiver() instanceof SelfVariableAccess and
38+
this.getEnclosingModule() = mailerClass
39+
}
40+
41+
/** Gets the mailer class containing this method. */
42+
ActionMailerMailerClass getMailerClass() { result = mailerClass }
43+
}
44+
45+
/** A call to `params` from within a mailer. */
46+
class ActionMailerParamsCall extends ActionMailerContextCall, ParamsCallImpl {
47+
ActionMailerParamsCall() { this.getMethodName() = "params" }
48+
}

ruby/ql/test/library-tests/frameworks/ActionController.expected

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,7 @@ paramsCalls
115115
| action_controller/params_flow.rb:144:10:144:15 | call to params |
116116
| action_controller/params_flow.rb:145:32:145:37 | call to params |
117117
| action_controller/params_flow.rb:148:22:148:27 | call to params |
118+
| action_mailer/mailer.rb:3:10:3:15 | call to params |
118119
| active_record/ActiveRecord.rb:28:30:28:35 | call to params |
119120
| active_record/ActiveRecord.rb:29:29:29:34 | call to params |
120121
| active_record/ActiveRecord.rb:30:31:30:36 | call to params |
@@ -189,6 +190,7 @@ paramsSources
189190
| action_controller/params_flow.rb:144:10:144:15 | call to params |
190191
| action_controller/params_flow.rb:145:32:145:37 | call to params |
191192
| action_controller/params_flow.rb:148:22:148:27 | call to params |
193+
| action_mailer/mailer.rb:3:10:3:15 | call to params |
192194
| active_record/ActiveRecord.rb:28:30:28:35 | call to params |
193195
| active_record/ActiveRecord.rb:29:29:29:34 | call to params |
194196
| active_record/ActiveRecord.rb:30:31:30:36 | call to params |
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
class MyMailer < ActionMailer::Base
2+
def foo
3+
sink params[:foo] # $hasTaintFlow
4+
end
5+
end
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
failures
2+
edges
3+
| mailer.rb:3:10:3:15 | call to params : | mailer.rb:3:10:3:21 | ...[...] |
4+
nodes
5+
| mailer.rb:3:10:3:15 | call to params : | semmle.label | call to params : |
6+
| mailer.rb:3:10:3:21 | ...[...] | semmle.label | ...[...] |
7+
subpaths
8+
#select
9+
| mailer.rb:3:10:3:21 | ...[...] | mailer.rb:3:10:3:15 | call to params : | mailer.rb:3:10:3:21 | ...[...] | $@ | mailer.rb:3:10:3:15 | call to params : | call to params : |
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
/**
2+
* @kind path-problem
3+
*/
4+
5+
import ruby
6+
import TestUtilities.InlineFlowTest
7+
import PathGraph
8+
import codeql.ruby.frameworks.Rails
9+
10+
class ParamsTaintFlowConf extends DefaultTaintFlowConf {
11+
override predicate isSource(DataFlow::Node n) {
12+
n.asExpr().getExpr() instanceof Rails::ParamsCall
13+
}
14+
}
15+
16+
from DataFlow::PathNode source, DataFlow::PathNode sink, ParamsTaintFlowConf conf
17+
where conf.hasFlowPath(source, sink)
18+
select sink, source, sink, "$@", source, source.toString()

0 commit comments

Comments
 (0)