diff --git a/ruby/ql/lib/codeql/ruby/frameworks/core/Kernel.qll b/ruby/ql/lib/codeql/ruby/frameworks/core/Kernel.qll index 2aa46ab550a..cc3ce9feb97 100644 --- a/ruby/ql/lib/codeql/ruby/frameworks/core/Kernel.qll +++ b/ruby/ql/lib/codeql/ruby/frameworks/core/Kernel.qll @@ -130,7 +130,6 @@ module Kernel { * `Kernel.spawn` takes the same argument forms as `Kernel.system`. * See `KernelSystemCall` for details. * Ruby documentation: https://docs.ruby-lang.org/en/3.0.0/Kernel.html#method-i-spawn - * Methods with the same effect exist in the `Process` and `PTY` classes, so they are also modeled here. * TODO: document and handle the env and option arguments. * ``` * spawn([env,] command... [,options]) -> pid @@ -140,8 +139,6 @@ module Kernel { KernelSpawnCall() { this.getMethodName() = "spawn" and this instanceof KernelMethodCall - or - this = DataFlow::getConstant(["Process", "PTY"]).getAMethodCall("spawn") } override DataFlow::Node getAnArgument() { result = super.getArgument(_) } diff --git a/ruby/ql/lib/codeql/ruby/frameworks/stdlib/Open3.qll b/ruby/ql/lib/codeql/ruby/frameworks/stdlib/Open3.qll index 5f349c451f3..f2eb16d2aa8 100644 --- a/ruby/ql/lib/codeql/ruby/frameworks/stdlib/Open3.qll +++ b/ruby/ql/lib/codeql/ruby/frameworks/stdlib/Open3.qll @@ -18,10 +18,8 @@ module Open3 { class Open3Call extends SystemCommandExecution::Range instanceof DataFlow::CallNode { Open3Call() { this = - API::getTopLevelMember(["Open3", "Open4"]) - .getAMethodCall([ - "popen3", "popen2", "popen2e", "capture3", "capture2", "capture2e", "popen4" - ]) + API::getTopLevelMember("Open3") + .getAMethodCall(["popen3", "popen2", "popen2e", "capture3", "capture2", "capture2e"]) } override DataFlow::Node getAnArgument() { result = super.getArgument(_) } @@ -33,6 +31,19 @@ module Open3 { } } + class Open4Call extends SystemCommandExecution::Range instanceof DataFlow::CallNode { + Open4Call() { + this = API::getTopLevelMember("Open4").getAMethodCall(["open4", "popen4", "spawn"]) + } + + override DataFlow::Node getAnArgument() { result = super.getArgument(_) } + + override predicate isShellInterpreted(DataFlow::Node arg) { + super.getNumberOfArguments() = 1 and + arg = this.getAnArgument() + } + } + /** * A pipeline of system commands constructed via one of the `Open3` methods. * These methods accept a variable argument list of commands. diff --git a/ruby/ql/test/library-tests/frameworks/stdlib/Open3.expected b/ruby/ql/test/library-tests/frameworks/stdlib/Open3.expected index a601d199ff6..48bc6fc27f6 100644 --- a/ruby/ql/test/library-tests/frameworks/stdlib/Open3.expected +++ b/ruby/ql/test/library-tests/frameworks/stdlib/Open3.expected @@ -11,3 +11,7 @@ open3PipelineCallExecutions | Open3.rb:9:1:9:40 | call to pipeline_w | | Open3.rb:10:1:10:44 | call to pipeline_start | | Open3.rb:11:1:11:38 | call to pipeline | +open4CallExecutions +| Open3.rb:13:1:13:24 | call to open4 | +| Open3.rb:14:1:14:25 | call to popen4 | +| Open3.rb:15:1:15:23 | call to spawn | diff --git a/ruby/ql/test/library-tests/frameworks/stdlib/Open3.ql b/ruby/ql/test/library-tests/frameworks/stdlib/Open3.ql index 8d98734832d..014573d7010 100644 --- a/ruby/ql/test/library-tests/frameworks/stdlib/Open3.ql +++ b/ruby/ql/test/library-tests/frameworks/stdlib/Open3.ql @@ -4,3 +4,5 @@ import codeql.ruby.DataFlow query predicate open3CallExecutions(Open3Call c) { any() } query predicate open3PipelineCallExecutions(Open3PipelineCall c) { any() } + +query predicate open4CallExecutions(Open4Call c) { any() } diff --git a/ruby/ql/test/library-tests/frameworks/stdlib/Open3.rb b/ruby/ql/test/library-tests/frameworks/stdlib/Open3.rb index b1a3d491be1..4a112335ffb 100644 --- a/ruby/ql/test/library-tests/frameworks/stdlib/Open3.rb +++ b/ruby/ql/test/library-tests/frameworks/stdlib/Open3.rb @@ -8,4 +8,8 @@ Open3.pipeline_rw("echo foo", "grep bar") Open3.pipeline_r("echo foo", "grep bar") Open3.pipeline_w("echo foo", "grep bar") Open3.pipeline_start("echo foo", "grep bar") -Open3.pipeline("echo foo", "grep bar") \ No newline at end of file +Open3.pipeline("echo foo", "grep bar") + +Open4::open4("echo foo") +Open4::popen4("echo foo") +Open4.spawn("echo bar")