Merge pull request #11337 from hmac/actionmailbox

Ruby: Model ActionMailbox
This commit is contained in:
Harry Maclean
2022-12-12 10:29:23 +13:00
committed by GitHub
6 changed files with 102 additions and 0 deletions

View File

@@ -0,0 +1,4 @@
---
category: minorAnalysis
---
* Calls to `mail` and `inbound_mail` in `ActionMailbox` controllers are now considered sources of remote input.

View File

@@ -7,6 +7,7 @@ private import codeql.ruby.frameworks.ActionCable
private import codeql.ruby.frameworks.ActionController
private import codeql.ruby.frameworks.ActiveJob
private import codeql.ruby.frameworks.ActionMailer
private import codeql.ruby.frameworks.ActionMailbox
private import codeql.ruby.frameworks.ActiveRecord
private import codeql.ruby.frameworks.ActiveResource
private import codeql.ruby.frameworks.ActiveStorage

View File

@@ -0,0 +1,54 @@
/**
* Models the `ActionMailbox` library, which is part of Rails.
* Version: 7.0.4.
*/
private import codeql.ruby.AST
private import codeql.ruby.Concepts
private import codeql.ruby.DataFlow
private import codeql.ruby.dataflow.RemoteFlowSources
/**
* Models the `ActionMailbox` library, which is part of Rails.
* Version: 7.0.4.
*/
module ActionMailbox {
private DataFlow::ClassNode controller() {
result = DataFlow::getConstant("ActionMailbox").getConstant("Base").getADescendentModule()
}
/**
* A call to `mail` on the return value of
* `ActionMailbox::Base#inbound_email`, or a direct call to
* `ActionMailbox::Base#mail`, which is equivalent. The returned object
* contains data from the incoming email.
*/
class Mail extends DataFlow::CallNode {
Mail() {
this =
[
controller().getAnInstanceSelf().getAMethodCall("inbound_email").getAMethodCall("mail"),
controller().getAnInstanceSelf().getAMethodCall("mail")
]
}
}
/**
* A method call on a `Mail::Message` object which may return data from a remote source.
*/
private class RemoteContent extends DataFlow::CallNode, RemoteFlowSource::Range {
RemoteContent() {
this =
any(Mail m)
.(DataFlow::LocalSourceNode)
.getAMethodCall([
"body", "to", "from", "raw_source", "subject", "from_address",
"recipients_addresses", "cc_addresses", "bcc_addresses", "in_reply_to",
"references", "reply_to", "raw_envelope", "to_s", "encoded", "header", "bcc", "cc",
"text_part", "html_part"
])
}
override string getSourceType() { result = "ActionMailbox" }
}
}

View File

@@ -0,0 +1,12 @@
messageInstances
| action_mailbox.rb:3:5:3:8 | call to mail |
| action_mailbox.rb:4:5:4:8 | call to mail |
| action_mailbox.rb:6:5:6:10 | call to mail |
| action_mailbox.rb:10:5:10:8 | call to mail |
| action_mailbox.rb:16:9:16:12 | call to mail |
remoteFlowSources
| action_mailbox.rb:3:5:3:13 | call to body |
| action_mailbox.rb:4:5:4:11 | call to to |
| action_mailbox.rb:6:5:6:13 | call to to |
| action_mailbox.rb:10:5:10:18 | call to text_part |
| action_mailbox.rb:16:9:16:23 | call to raw_source |

View File

@@ -0,0 +1,7 @@
private import codeql.ruby.frameworks.ActionMailbox
private import codeql.ruby.DataFlow
private import codeql.ruby.dataflow.RemoteFlowSources
query predicate messageInstances(ActionMailbox::Mail c) { any() }
query predicate remoteFlowSources(RemoteFlowSource r) { any() }

View File

@@ -0,0 +1,24 @@
class A < ActionMailbox::Base
def process
mail.body
mail.to
m = inbound_email
m.mail.to
end
def other_method
mail.text_part
end
end
class B < A
def process
mail.raw_source
end
end
class C # not a mailbox class
def process
mail.subject
end
end