Skip to content

Commit beef996

Browse files
committed
Ruby: Model Open4 library
Also remove duplicate modeling of Process.spawn.
1 parent a03c068 commit beef996

File tree

5 files changed

+26
-8
lines changed

5 files changed

+26
-8
lines changed

ruby/ql/lib/codeql/ruby/frameworks/core/Kernel.qll

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,6 @@ module Kernel {
130130
* `Kernel.spawn` takes the same argument forms as `Kernel.system`.
131131
* See `KernelSystemCall` for details.
132132
* Ruby documentation: https://docs.ruby-lang.org/en/3.0.0/Kernel.html#method-i-spawn
133-
* Methods with the same effect exist in the `Process` and `PTY` classes, so they are also modeled here.
134133
* TODO: document and handle the env and option arguments.
135134
* ```
136135
* spawn([env,] command... [,options]) -> pid
@@ -140,8 +139,6 @@ module Kernel {
140139
KernelSpawnCall() {
141140
this.getMethodName() = "spawn" and
142141
this instanceof KernelMethodCall
143-
or
144-
this = DataFlow::getConstant(["Process", "PTY"]).getAMethodCall("spawn")
145142
}
146143

147144
override DataFlow::Node getAnArgument() { result = super.getArgument(_) }

ruby/ql/lib/codeql/ruby/frameworks/stdlib/Open3.qll

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,8 @@ module Open3 {
1818
class Open3Call extends SystemCommandExecution::Range instanceof DataFlow::CallNode {
1919
Open3Call() {
2020
this =
21-
API::getTopLevelMember(["Open3", "Open4"])
22-
.getAMethodCall([
23-
"popen3", "popen2", "popen2e", "capture3", "capture2", "capture2e", "popen4"
24-
])
21+
API::getTopLevelMember("Open3")
22+
.getAMethodCall(["popen3", "popen2", "popen2e", "capture3", "capture2", "capture2e"])
2523
}
2624

2725
override DataFlow::Node getAnArgument() { result = super.getArgument(_) }
@@ -33,6 +31,19 @@ module Open3 {
3331
}
3432
}
3533

34+
class Open4Call extends SystemCommandExecution::Range instanceof DataFlow::CallNode {
35+
Open4Call() {
36+
this = API::getTopLevelMember("Open4").getAMethodCall(["open4", "popen4", "spawn"])
37+
}
38+
39+
override DataFlow::Node getAnArgument() { result = super.getArgument(_) }
40+
41+
override predicate isShellInterpreted(DataFlow::Node arg) {
42+
super.getNumberOfArguments() = 1 and
43+
arg = this.getAnArgument()
44+
}
45+
}
46+
3647
/**
3748
* A pipeline of system commands constructed via one of the `Open3` methods.
3849
* These methods accept a variable argument list of commands.

ruby/ql/test/library-tests/frameworks/stdlib/Open3.expected

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,3 +11,7 @@ open3PipelineCallExecutions
1111
| Open3.rb:9:1:9:40 | call to pipeline_w |
1212
| Open3.rb:10:1:10:44 | call to pipeline_start |
1313
| Open3.rb:11:1:11:38 | call to pipeline |
14+
open4CallExecutions
15+
| Open3.rb:13:1:13:24 | call to open4 |
16+
| Open3.rb:14:1:14:25 | call to popen4 |
17+
| Open3.rb:15:1:15:23 | call to spawn |

ruby/ql/test/library-tests/frameworks/stdlib/Open3.ql

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,5 @@ import codeql.ruby.DataFlow
44
query predicate open3CallExecutions(Open3Call c) { any() }
55

66
query predicate open3PipelineCallExecutions(Open3PipelineCall c) { any() }
7+
8+
query predicate open4CallExecutions(Open4Call c) { any() }

ruby/ql/test/library-tests/frameworks/stdlib/Open3.rb

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,8 @@
88
Open3.pipeline_r("echo foo", "grep bar")
99
Open3.pipeline_w("echo foo", "grep bar")
1010
Open3.pipeline_start("echo foo", "grep bar")
11-
Open3.pipeline("echo foo", "grep bar")
11+
Open3.pipeline("echo foo", "grep bar")
12+
13+
Open4::open4("echo foo")
14+
Open4::popen4("echo foo")
15+
Open4.spawn("echo bar")

0 commit comments

Comments
 (0)