Skip to content

Commit 91cb2a3

Browse files
committed
Ruby: Model Process.exec
1 parent 179aaa1 commit 91cb2a3

File tree

5 files changed

+64
-0
lines changed

5 files changed

+64
-0
lines changed

ruby/ql/lib/codeql/ruby/frameworks/Stdlib.qll

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,4 @@
55
import stdlib.Open3
66
import stdlib.Logger
77
import stdlib.Pathname
8+
import stdlib.Process

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

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,4 +32,18 @@ module Process {
3232
super.getNumberOfArguments() = 1 and arg = this.getAnArgument()
3333
}
3434
}
35+
36+
/**
37+
* A system command executed via the `Process.exec` method.
38+
*/
39+
class ExecCall extends SystemCommandExecution::Range instanceof DataFlow::CallNode {
40+
ExecCall() { this = DataFlow::getConstant("Process").getAMethodCall("exec") }
41+
42+
override DataFlow::Node getAnArgument() { result = super.getArgument(_) }
43+
44+
override predicate isShellInterpreted(DataFlow::Node arg) {
45+
// Process.exec invokes a subshell if you provide a single string as argument
46+
super.getNumberOfArguments() = 1 and arg = this.getAnArgument()
47+
}
48+
}
3549
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
| Open3.rb:1:1:1:24 | call to popen3 | Open3.rb:1:14:1:23 | "echo foo" | true |
2+
| Open3.rb:2:1:2:24 | call to popen2 | Open3.rb:2:14:2:23 | "echo foo" | true |
3+
| Open3.rb:3:1:3:25 | call to popen2e | Open3.rb:3:15:3:24 | "echo foo" | true |
4+
| Open3.rb:4:1:4:26 | call to capture3 | Open3.rb:4:16:4:25 | "echo foo" | true |
5+
| Open3.rb:5:1:5:26 | call to capture2 | Open3.rb:5:16:5:25 | "echo foo" | true |
6+
| Open3.rb:6:1:6:27 | call to capture2e | Open3.rb:6:17:6:26 | "echo foo" | true |
7+
| Open3.rb:7:1:7:41 | call to pipeline_rw | Open3.rb:7:19:7:28 | "echo foo" | true |
8+
| Open3.rb:7:1:7:41 | call to pipeline_rw | Open3.rb:7:31:7:40 | "grep bar" | true |
9+
| Open3.rb:8:1:8:40 | call to pipeline_r | Open3.rb:8:18:8:27 | "echo foo" | true |
10+
| Open3.rb:8:1:8:40 | call to pipeline_r | Open3.rb:8:30:8:39 | "grep bar" | true |
11+
| Open3.rb:9:1:9:40 | call to pipeline_w | Open3.rb:9:18:9:27 | "echo foo" | true |
12+
| Open3.rb:9:1:9:40 | call to pipeline_w | Open3.rb:9:30:9:39 | "grep bar" | true |
13+
| Open3.rb:10:1:10:44 | call to pipeline_start | Open3.rb:10:22:10:31 | "echo foo" | true |
14+
| Open3.rb:10:1:10:44 | call to pipeline_start | Open3.rb:10:34:10:43 | "grep bar" | true |
15+
| Open3.rb:11:1:11:38 | call to pipeline | Open3.rb:11:16:11:25 | "echo foo" | true |
16+
| Open3.rb:11:1:11:38 | call to pipeline | Open3.rb:11:28:11:37 | "grep bar" | true |
17+
| Open3.rb:13:1:13:24 | call to open4 | Open3.rb:13:14:13:23 | "echo foo" | true |
18+
| Open3.rb:14:1:14:25 | call to popen4 | Open3.rb:14:15:14:24 | "echo foo" | true |
19+
| Open3.rb:15:1:15:23 | call to spawn | Open3.rb:15:13:15:22 | "echo bar" | true |
20+
| Open3.rb:16:1:16:27 | call to popen4ext | Open3.rb:16:17:16:26 | "echo foo" | true |
21+
| Open3.rb:17:1:17:30 | call to popen4ext | Open3.rb:17:17:17:22 | "echo" | false |
22+
| Open3.rb:17:1:17:30 | call to popen4ext | Open3.rb:17:25:17:29 | "foo" | false |
23+
| Open3.rb:18:1:18:33 | call to popen4ext | Open3.rb:18:17:18:20 | true | false |
24+
| Open3.rb:18:1:18:33 | call to popen4ext | Open3.rb:18:23:18:32 | "echo foo" | true |
25+
| Open3.rb:19:1:19:36 | call to popen4ext | Open3.rb:19:17:19:20 | true | false |
26+
| Open3.rb:19:1:19:36 | call to popen4ext | Open3.rb:19:23:19:28 | "echo" | false |
27+
| Open3.rb:19:1:19:36 | call to popen4ext | Open3.rb:19:31:19:35 | "foo" | false |
28+
| process.rb:1:1:1:25 | call to spawn | process.rb:1:15:1:24 | "echo foo" | true |
29+
| process.rb:2:1:2:30 | call to spawn | process.rb:2:15:2:29 | call to [] | true |
30+
| process.rb:3:1:3:24 | call to exec | process.rb:3:14:3:23 | "echo foo" | true |
31+
| process.rb:4:1:4:29 | call to exec | process.rb:4:14:4:28 | call to [] | true |
32+
| process.rb:5:1:5:21 | call to spawn | process.rb:5:11:5:20 | "echo foo" | true |
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import codeql.ruby.Frameworks
2+
import codeql.ruby.Concepts
3+
import codeql.ruby.DataFlow
4+
5+
query predicate commandExecutions(
6+
SystemCommandExecution execution, DataFlow::Node arg, boolean isShellInterpreted
7+
) {
8+
arg = execution.getAnArgument() and
9+
if execution.isShellInterpreted(arg)
10+
then isShellInterpreted = true
11+
else isShellInterpreted = false
12+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
Process.spawn("echo foo")
2+
Process.spawn(["echo", "foo"])
3+
Process.exec("echo foo")
4+
Process.exec(["echo", "foo"])
5+
PTY.spawn("echo foo")

0 commit comments

Comments
 (0)