Skip to content

Commit d046fb0

Browse files
committed
Separate open3 pipeline methods
These have a slightly different structure than the other open3 methods.
1 parent 174ba25 commit d046fb0

File tree

4 files changed

+48
-14
lines changed

4 files changed

+48
-14
lines changed

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

Lines changed: 35 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -165,17 +165,19 @@ class KernelSpawnCall extends SystemCommandExecution::Range {
165165
}
166166
}
167167

168+
/**
169+
* A system command executed via one of the `Open3` methods.
170+
* These methods take the same argument forms as `Kernel.system`.
171+
* See `KernelSystemCall` for details.
172+
*/
168173
class Open3Call extends SystemCommandExecution::Range {
169174
MethodCall methodCall;
170175

171176
Open3Call() {
172177
this.asExpr().getExpr() = methodCall and
173178
this =
174179
API::getTopLevelMember("Open3")
175-
.getAMethodCall([
176-
"popen3", "popen2", "popen2e", "capture3", "capture2", "capture2e", "pipeline_rw",
177-
"pipeline_r", "pipeline_w", "pipeline_start", "pipeline"
178-
])
180+
.getAMethodCall(["popen3", "popen2", "popen2e", "capture3", "capture2", "capture2e"])
179181
}
180182

181183
override DataFlow::Node getAnArgument() { result.asExpr().getExpr() = methodCall.getAnArgument() }
@@ -185,3 +187,32 @@ class Open3Call extends SystemCommandExecution::Range {
185187
methodCall.getNumberOfArguments() = 1 and arg.asExpr().getExpr() = methodCall.getAnArgument()
186188
}
187189
}
190+
191+
/**
192+
* A pipeline of system commands constructed via one of the `Open3` methods.
193+
* These methods accept a variable argument list of commands.
194+
* Commands can be in any form supported by `Kernel.system`. See `KernelSystemCall` for details.
195+
* ```ruby
196+
* Open3.pipeline("cat foo.txt", "tail")
197+
* Open3.pipeline(["cat", "foo.txt"], "tail")
198+
* Open3.pipeline([{}, "cat", "foo.txt"], "tail")
199+
* Open3.pipeline([["cat", "cat"], "foo.txt"], "tail")
200+
*/
201+
class Open3PipelineCall extends SystemCommandExecution::Range {
202+
MethodCall methodCall;
203+
204+
Open3PipelineCall() {
205+
this.asExpr().getExpr() = methodCall and
206+
this =
207+
API::getTopLevelMember("Open3")
208+
.getAMethodCall(["pipeline_rw", "pipeline_r", "pipeline_w", "pipeline_start", "pipeline"])
209+
}
210+
211+
override DataFlow::Node getAnArgument() { result.asExpr().getExpr() = methodCall.getAnArgument() }
212+
213+
override predicate isShellInterpreted(DataFlow::Node arg) {
214+
// A command in the pipeline is executed in a subshell if it is given as a single string argument.
215+
arg.asExpr().getExpr() instanceof StringlikeLiteral and
216+
arg.asExpr().getExpr() = methodCall.getAnArgument()
217+
}
218+
}

ql/test/library-tests/frameworks/CommandExecution.rb

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -58,11 +58,11 @@
5858
Open3.capture3("echo foo")
5959
Open3.capture2("echo foo")
6060
Open3.capture2e("echo foo")
61-
Open3.pipeline_rw("echo foo")
62-
Open3.pipeline_r("echo foo")
63-
Open3.pipeline_w("echo foo")
64-
Open3.pipeline_start("echo foo")
65-
Open3.pipeline("echo foo")
61+
Open3.pipeline_rw("echo foo", "grep bar")
62+
Open3.pipeline_r("echo foo", "grep bar")
63+
Open3.pipeline_w("echo foo", "grep bar")
64+
Open3.pipeline_start("echo foo", "grep bar")
65+
Open3.pipeline("echo foo", "grep bar")
6666

6767
<<`EOF`
6868
echo foo

ql/test/library-tests/frameworks/StandardLibrary.expected

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -52,8 +52,9 @@ open3CallExecutions
5252
| CommandExecution.rb:58:1:58:26 | call to capture3 |
5353
| CommandExecution.rb:59:1:59:26 | call to capture2 |
5454
| CommandExecution.rb:60:1:60:27 | call to capture2e |
55-
| CommandExecution.rb:61:1:61:29 | call to pipeline_rw |
56-
| CommandExecution.rb:62:1:62:28 | call to pipeline_r |
57-
| CommandExecution.rb:63:1:63:28 | call to pipeline_w |
58-
| CommandExecution.rb:64:1:64:32 | call to pipeline_start |
59-
| CommandExecution.rb:65:1:65:26 | call to pipeline |
55+
open3PipelineCallExecutions
56+
| CommandExecution.rb:61:1:61:41 | call to pipeline_rw |
57+
| CommandExecution.rb:62:1:62:40 | call to pipeline_r |
58+
| CommandExecution.rb:63:1:63:40 | call to pipeline_w |
59+
| CommandExecution.rb:64:1:64:44 | call to pipeline_start |
60+
| CommandExecution.rb:65:1:65:38 | call to pipeline |

ql/test/library-tests/frameworks/StandardLibrary.ql

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,3 +11,5 @@ query predicate kernelExecCallExecutions(KernelExecCall c) { any() }
1111
query predicate kernelSpawnCallExecutions(KernelSpawnCall c) { any() }
1212

1313
query predicate open3CallExecutions(Open3Call c) { any() }
14+
15+
query predicate open3PipelineCallExecutions(Open3PipelineCall c) { any() }

0 commit comments

Comments
 (0)