Skip to content

Commit 3d4f64f

Browse files
authored
Merge pull request #11397 from erik-krogh/call-instanceof
Rb: use `instanceof` instead of `extends` on `DataFlow::CallNode` in some case
2 parents efdfc36 + 33216f3 commit 3d4f64f

File tree

5 files changed

+22
-33
lines changed

5 files changed

+22
-33
lines changed

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -168,7 +168,7 @@ module ActiveStorage {
168168
* A call on an ActiveStorage object that results in an image transformation.
169169
* Arguments to these calls may be executed as system commands.
170170
*/
171-
private class ImageProcessingCall extends DataFlow::CallNode, SystemCommandExecution::Range {
171+
private class ImageProcessingCall extends SystemCommandExecution::Range instanceof DataFlow::CallNode {
172172
ImageProcessingCall() {
173173
this.getReceiver() instanceof BlobInstance and
174174
this.getMethodName() = ["variant", "preview", "representation"]
@@ -209,7 +209,7 @@ module ActiveStorage {
209209
this = API::getTopLevelMember("ActiveStorage").getAMethodCall("video_preview_arguments=")
210210
}
211211

212-
override DataFlow::Node getAnArgument() { result = this.getArgument(0) }
212+
override DataFlow::Node getAnArgument() { result = super.getArgument(0) }
213213
}
214214

215215
/**

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

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ module PosixSpawn {
2020
/**
2121
* A call to `POSIX::Spawn::Child.new` or `POSIX::Spawn::Child.build`.
2222
*/
23-
class ChildCall extends SystemCommandExecution::Range, DataFlow::CallNode {
23+
class ChildCall extends SystemCommandExecution::Range instanceof DataFlow::CallNode {
2424
ChildCall() {
2525
this =
2626
[
@@ -30,7 +30,7 @@ module PosixSpawn {
3030
}
3131

3232
override DataFlow::Node getAnArgument() {
33-
result = this.getArgument(_) and not result.asExpr() instanceof ExprNodes::PairCfgNode
33+
result = super.getArgument(_) and not result.asExpr() instanceof ExprNodes::PairCfgNode
3434
}
3535

3636
override predicate isShellInterpreted(DataFlow::Node arg) { none() }
@@ -39,7 +39,7 @@ module PosixSpawn {
3939
/**
4040
* A call to `POSIX::Spawn.spawn` or a related method.
4141
*/
42-
class SystemCall extends SystemCommandExecution::Range, DataFlow::CallNode {
42+
class SystemCall extends SystemCommandExecution::Range instanceof DataFlow::CallNode {
4343
SystemCall() {
4444
this =
4545
posixSpawnModule()
@@ -71,7 +71,7 @@ module PosixSpawn {
7171
}
7272

7373
private predicate argument(DataFlow::Node arg) {
74-
arg = this.getArgument(_) and
74+
arg = super.getArgument(_) and
7575
not arg.asExpr() instanceof ExprNodes::HashLiteralCfgNode and
7676
not arg.asExpr() instanceof ExprNodes::ArrayLiteralCfgNode and
7777
not arg.asExpr() instanceof ExprNodes::PairCfgNode

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

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,28 +27,28 @@ module Railties {
2727
* A call to `Rails::Generators::Actions#execute_command`.
2828
* This method concatenates its first and second arguments and executes the result as a shell command.
2929
*/
30-
private class ExecuteCommandCall extends SystemCommandExecution::Range, DataFlow::CallNode {
30+
private class ExecuteCommandCall extends SystemCommandExecution::Range instanceof DataFlow::CallNode {
3131
ExecuteCommandCall() {
3232
this = generatorsActionsClass().getAnInstanceSelf().getAMethodCall("execute_command")
3333
}
3434

35-
override DataFlow::Node getAnArgument() { result = this.getArgument([0, 1]) }
35+
override DataFlow::Node getAnArgument() { result = super.getArgument([0, 1]) }
3636

3737
override predicate isShellInterpreted(DataFlow::Node arg) { arg = this.getAnArgument() }
3838
}
3939

4040
/**
4141
* A call to a method in `Rails::Generators::Actions` which delegates to `execute_command`.
4242
*/
43-
private class ExecuteCommandWrapperCall extends SystemCommandExecution::Range, DataFlow::CallNode {
43+
private class ExecuteCommandWrapperCall extends SystemCommandExecution::Range instanceof DataFlow::CallNode {
4444
ExecuteCommandWrapperCall() {
4545
this =
4646
generatorsActionsClass()
4747
.getAnInstanceSelf()
4848
.getAMethodCall(["rake", "rails_command", "git"])
4949
}
5050

51-
override DataFlow::Node getAnArgument() { result = this.getArgument(0) }
51+
override DataFlow::Node getAnArgument() { result = super.getArgument(0) }
5252

5353
override predicate isShellInterpreted(DataFlow::Node arg) { arg = this.getAnArgument() }
5454
}

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,7 @@ module IO {
114114
* ```
115115
* Ruby documentation: https://docs.ruby-lang.org/en/3.1/IO.html#method-c-popen
116116
*/
117-
class POpenCall extends SystemCommandExecution::Range, DataFlow::CallNode {
117+
class POpenCall extends SystemCommandExecution::Range instanceof DataFlow::CallNode {
118118
POpenCall() { this = API::getTopLevelMember("IO").getAMethodCall("popen") }
119119

120120
override DataFlow::Node getAnArgument() { this.argument(result, _) }
@@ -131,15 +131,15 @@ module IO {
131131
not n instanceof ExprNodes::ArrayLiteralCfgNode and
132132
(
133133
// IO.popen({var: "a"}, "cmd", {some: :opt})
134-
arg = this.getArgument([0, 1]) and
134+
arg = super.getArgument([0, 1]) and
135135
// We over-approximate by assuming a subshell if the argument isn't an array or "-".
136136
// This increases the sensitivity of the CommandInjection query at the risk of some FPs.
137137
if n.getConstantValue().getString() = "-" then shell = false else shell = true
138138
or
139139
// IO.popen([{var: "b"}, "cmd", "arg1", "arg2", {some: :opt}])
140140
// IO.popen({var: "a"}, ["cmd", "arg1", "arg2", {some: :opt}])
141141
shell = false and
142-
exists(ExprNodes::ArrayLiteralCfgNode arr | this.getArgument([0, 1]).asExpr() = arr |
142+
exists(ExprNodes::ArrayLiteralCfgNode arr | super.getArgument([0, 1]).asExpr() = arr |
143143
n = arr.getAnArgument()
144144
or
145145
// IO.popen([{var: "b"}, ["cmd", "argv0"], "arg1", "arg2", {some: :opt}])

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

Lines changed: 9 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,8 @@
22
* Provides modeling for the `Open3` library.
33
*/
44

5-
private import codeql.ruby.AST
6-
private import codeql.ruby.DataFlow
5+
private import ruby
76
private import codeql.ruby.ApiGraphs
8-
private import codeql.ruby.frameworks.Stdlib
97
private import codeql.ruby.Concepts
108

119
/**
@@ -17,23 +15,19 @@ module Open3 {
1715
* These methods take the same argument forms as `Kernel.system`.
1816
* See `KernelSystemCall` for details.
1917
*/
20-
class Open3Call extends SystemCommandExecution::Range {
21-
MethodCall methodCall;
22-
18+
class Open3Call extends SystemCommandExecution::Range instanceof DataFlow::CallNode {
2319
Open3Call() {
24-
this.asExpr().getExpr() = methodCall and
2520
this =
2621
API::getTopLevelMember("Open3")
2722
.getAMethodCall(["popen3", "popen2", "popen2e", "capture3", "capture2", "capture2e"])
2823
}
2924

30-
override DataFlow::Node getAnArgument() {
31-
result.asExpr().getExpr() = methodCall.getAnArgument()
32-
}
25+
override DataFlow::Node getAnArgument() { result = super.getArgument(_) }
3326

3427
override predicate isShellInterpreted(DataFlow::Node arg) {
3528
// These Open3 methods invoke a subshell if you provide a single string as argument
36-
methodCall.getNumberOfArguments() = 1 and arg.asExpr().getExpr() = methodCall.getAnArgument()
29+
super.getNumberOfArguments() = 1 and
30+
arg = this.getAnArgument()
3731
}
3832
}
3933

@@ -47,26 +41,21 @@ module Open3 {
4741
* Open3.pipeline([{}, "cat", "foo.txt"], "tail")
4842
* Open3.pipeline([["cat", "cat"], "foo.txt"], "tail")
4943
*/
50-
class Open3PipelineCall extends SystemCommandExecution::Range {
51-
MethodCall methodCall;
52-
44+
class Open3PipelineCall extends SystemCommandExecution::Range instanceof DataFlow::CallNode {
5345
Open3PipelineCall() {
54-
this.asExpr().getExpr() = methodCall and
5546
this =
5647
API::getTopLevelMember("Open3")
5748
.getAMethodCall([
5849
"pipeline_rw", "pipeline_r", "pipeline_w", "pipeline_start", "pipeline"
5950
])
6051
}
6152

62-
override DataFlow::Node getAnArgument() {
63-
result.asExpr().getExpr() = methodCall.getAnArgument()
64-
}
53+
override DataFlow::Node getAnArgument() { result = super.getArgument(_) }
6554

6655
override predicate isShellInterpreted(DataFlow::Node arg) {
6756
// A command in the pipeline is executed in a subshell if it is given as a single string argument.
68-
arg.asExpr().getExpr() instanceof StringlikeLiteral and
69-
arg.asExpr().getExpr() = methodCall.getAnArgument()
57+
arg.asExpr().getExpr() instanceof Ast::StringlikeLiteral and
58+
arg = this.getAnArgument()
7059
}
7160
}
7261
}

0 commit comments

Comments
 (0)