Ruby: add ActionCable channel RPC params as remote-flow sources

This commit is contained in:
Nick Rolfe
2022-11-03 15:51:19 +00:00
parent 07f50e275d
commit db20e7d143
4 changed files with 47 additions and 0 deletions

View File

@@ -6,6 +6,8 @@
private import codeql.ruby.AST
private import codeql.ruby.Concepts
private import codeql.ruby.ApiGraphs
private import codeql.ruby.DataFlow
private import codeql.ruby.dataflow.RemoteFlowSources
private import codeql.ruby.frameworks.stdlib.Logger::Logger as StdlibLogger
/**
@@ -26,4 +28,33 @@ module ActionCable {
}
}
}
/**
* The data argument in an RPC endpoint method on a subclass of
* `ActionCable::Channel::Base`, considered as a remote flow source.
*/
class ActionCableChannelRpcParam extends RemoteFlowSource::Range {
ActionCableChannelRpcParam() {
exists(DataFlow::MethodNode m |
// Any method on a subclass of `ActionCable::Channel::Base`
// automatically becomes an RPC endpoint
m =
DataFlow::getConstant("ActionCable")
.getConstant("Channel")
.getConstant("Base")
.getADescendentModule()
.getAnOwnInstanceMethod() and
// as long as it's public
m.asCallableAstNode().isPublic() and
// and is not called `subscribed` or `unsubscribed`.
not m.getMethodName() = ["subscribed", "unsubscribed"]
|
// If the method takes a parameter, it contains data from the remote
// request.
this = m.getParameter(0)
)
}
override string getSourceType() { result = "ActionCable channel RPC data" }
}
}

View File

@@ -1 +1,4 @@
loggerInstantiations
| action_cable.rb:1:1:1:54 | call to new |
remoteFlowSources
| action_cable.rb:9:10:9:13 | data |

View File

@@ -1,4 +1,7 @@
import codeql.ruby.frameworks.ActionCable
import codeql.ruby.frameworks.stdlib.Logger
import codeql.ruby.dataflow.RemoteFlowSources
query predicate loggerInstantiations(Logger::LoggerInstantiation l) { any() }
query predicate remoteFlowSources(RemoteFlowSource s) { any() }

View File

@@ -1 +1,11 @@
ActionCable::Connection::TaggedLoggerProxy.new(logger)
class MyChannel < ActionCable::Channel::Base
# An RPC endpoint without the optional data parm, so no remote flow source.
def foo
end
# An RPC endpoint including the optional data parm, which is a remote flow source.
def bar(data)
end
end