mirror of
https://github.com/github/codeql.git
synced 2025-12-24 04:36:35 +01:00
use instanceof instead of extends on DataFlow::CallNode in some case
This commit is contained in:
@@ -168,7 +168,7 @@ module ActiveStorage {
|
||||
* A call on an ActiveStorage object that results in an image transformation.
|
||||
* Arguments to these calls may be executed as system commands.
|
||||
*/
|
||||
private class ImageProcessingCall extends DataFlow::CallNode, SystemCommandExecution::Range {
|
||||
private class ImageProcessingCall extends SystemCommandExecution::Range instanceof DataFlow::CallNode {
|
||||
ImageProcessingCall() {
|
||||
this.getReceiver() instanceof BlobInstance and
|
||||
this.getMethodName() = ["variant", "preview", "representation"]
|
||||
@@ -209,7 +209,7 @@ module ActiveStorage {
|
||||
this = API::getTopLevelMember("ActiveStorage").getAMethodCall("video_preview_arguments=")
|
||||
}
|
||||
|
||||
override DataFlow::Node getAnArgument() { result = this.getArgument(0) }
|
||||
override DataFlow::Node getAnArgument() { result = super.getArgument(0) }
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -20,7 +20,7 @@ module PosixSpawn {
|
||||
/**
|
||||
* A call to `POSIX::Spawn::Child.new` or `POSIX::Spawn::Child.build`.
|
||||
*/
|
||||
class ChildCall extends SystemCommandExecution::Range, DataFlow::CallNode {
|
||||
class ChildCall extends SystemCommandExecution::Range instanceof DataFlow::CallNode {
|
||||
ChildCall() {
|
||||
this =
|
||||
[
|
||||
@@ -30,7 +30,7 @@ module PosixSpawn {
|
||||
}
|
||||
|
||||
override DataFlow::Node getAnArgument() {
|
||||
result = this.getArgument(_) and not result.asExpr() instanceof ExprNodes::PairCfgNode
|
||||
result = super.getArgument(_) and not result.asExpr() instanceof ExprNodes::PairCfgNode
|
||||
}
|
||||
|
||||
override predicate isShellInterpreted(DataFlow::Node arg) { none() }
|
||||
@@ -39,7 +39,7 @@ module PosixSpawn {
|
||||
/**
|
||||
* A call to `POSIX::Spawn.spawn` or a related method.
|
||||
*/
|
||||
class SystemCall extends SystemCommandExecution::Range, DataFlow::CallNode {
|
||||
class SystemCall extends SystemCommandExecution::Range instanceof DataFlow::CallNode {
|
||||
SystemCall() {
|
||||
this =
|
||||
posixSpawnModule()
|
||||
@@ -71,7 +71,7 @@ module PosixSpawn {
|
||||
}
|
||||
|
||||
private predicate argument(DataFlow::Node arg) {
|
||||
arg = this.getArgument(_) and
|
||||
arg = super.getArgument(_) and
|
||||
not arg.asExpr() instanceof ExprNodes::HashLiteralCfgNode and
|
||||
not arg.asExpr() instanceof ExprNodes::ArrayLiteralCfgNode and
|
||||
not arg.asExpr() instanceof ExprNodes::PairCfgNode
|
||||
|
||||
@@ -27,12 +27,12 @@ module Railties {
|
||||
* A call to `Rails::Generators::Actions#execute_command`.
|
||||
* This method concatenates its first and second arguments and executes the result as a shell command.
|
||||
*/
|
||||
private class ExecuteCommandCall extends SystemCommandExecution::Range, DataFlow::CallNode {
|
||||
private class ExecuteCommandCall extends SystemCommandExecution::Range instanceof DataFlow::CallNode {
|
||||
ExecuteCommandCall() {
|
||||
this = generatorsActionsClass().getAnInstanceSelf().getAMethodCall("execute_command")
|
||||
}
|
||||
|
||||
override DataFlow::Node getAnArgument() { result = this.getArgument([0, 1]) }
|
||||
override DataFlow::Node getAnArgument() { result = super.getArgument([0, 1]) }
|
||||
|
||||
override predicate isShellInterpreted(DataFlow::Node arg) { arg = this.getAnArgument() }
|
||||
}
|
||||
@@ -40,7 +40,7 @@ module Railties {
|
||||
/**
|
||||
* A call to a method in `Rails::Generators::Actions` which delegates to `execute_command`.
|
||||
*/
|
||||
private class ExecuteCommandWrapperCall extends SystemCommandExecution::Range, DataFlow::CallNode {
|
||||
private class ExecuteCommandWrapperCall extends SystemCommandExecution::Range instanceof DataFlow::CallNode {
|
||||
ExecuteCommandWrapperCall() {
|
||||
this =
|
||||
generatorsActionsClass()
|
||||
@@ -48,7 +48,7 @@ module Railties {
|
||||
.getAMethodCall(["rake", "rails_command", "git"])
|
||||
}
|
||||
|
||||
override DataFlow::Node getAnArgument() { result = this.getArgument(0) }
|
||||
override DataFlow::Node getAnArgument() { result = super.getArgument(0) }
|
||||
|
||||
override predicate isShellInterpreted(DataFlow::Node arg) { arg = this.getAnArgument() }
|
||||
}
|
||||
|
||||
@@ -114,7 +114,7 @@ module IO {
|
||||
* ```
|
||||
* Ruby documentation: https://docs.ruby-lang.org/en/3.1/IO.html#method-c-popen
|
||||
*/
|
||||
class POpenCall extends SystemCommandExecution::Range, DataFlow::CallNode {
|
||||
class POpenCall extends SystemCommandExecution::Range instanceof DataFlow::CallNode {
|
||||
POpenCall() { this = API::getTopLevelMember("IO").getAMethodCall("popen") }
|
||||
|
||||
override DataFlow::Node getAnArgument() { this.argument(result, _) }
|
||||
@@ -131,7 +131,7 @@ module IO {
|
||||
not n instanceof ExprNodes::ArrayLiteralCfgNode and
|
||||
(
|
||||
// IO.popen({var: "a"}, "cmd", {some: :opt})
|
||||
arg = this.getArgument([0, 1]) and
|
||||
arg = super.getArgument([0, 1]) and
|
||||
// We over-approximate by assuming a subshell if the argument isn't an array or "-".
|
||||
// This increases the sensitivity of the CommandInjection query at the risk of some FPs.
|
||||
if n.getConstantValue().getString() = "-" then shell = false else shell = true
|
||||
@@ -139,7 +139,7 @@ module IO {
|
||||
// IO.popen([{var: "b"}, "cmd", "arg1", "arg2", {some: :opt}])
|
||||
// IO.popen({var: "a"}, ["cmd", "arg1", "arg2", {some: :opt}])
|
||||
shell = false and
|
||||
exists(ExprNodes::ArrayLiteralCfgNode arr | this.getArgument([0, 1]).asExpr() = arr |
|
||||
exists(ExprNodes::ArrayLiteralCfgNode arr | super.getArgument([0, 1]).asExpr() = arr |
|
||||
n = arr.getAnArgument()
|
||||
or
|
||||
// IO.popen([{var: "b"}, ["cmd", "argv0"], "arg1", "arg2", {some: :opt}])
|
||||
|
||||
@@ -2,11 +2,13 @@
|
||||
* Provides modeling for the `Open3` library.
|
||||
*/
|
||||
|
||||
private import ruby
|
||||
private import codeql.ruby.AST
|
||||
private import codeql.ruby.DataFlow
|
||||
private import codeql.ruby.ApiGraphs
|
||||
private import codeql.ruby.frameworks.Stdlib
|
||||
private import codeql.ruby.Concepts
|
||||
private import codeql.ruby.frameworks.core.Kernel
|
||||
|
||||
/**
|
||||
* Provides modeling for the `Open3` library.
|
||||
@@ -17,23 +19,19 @@ module Open3 {
|
||||
* These methods take the same argument forms as `Kernel.system`.
|
||||
* See `KernelSystemCall` for details.
|
||||
*/
|
||||
class Open3Call extends SystemCommandExecution::Range {
|
||||
MethodCall methodCall;
|
||||
|
||||
class Open3Call extends SystemCommandExecution::Range instanceof DataFlow::CallNode {
|
||||
Open3Call() {
|
||||
this.asExpr().getExpr() = methodCall and
|
||||
this =
|
||||
API::getTopLevelMember("Open3")
|
||||
.getAMethodCall(["popen3", "popen2", "popen2e", "capture3", "capture2", "capture2e"])
|
||||
}
|
||||
|
||||
override DataFlow::Node getAnArgument() {
|
||||
result.asExpr().getExpr() = methodCall.getAnArgument()
|
||||
}
|
||||
override DataFlow::Node getAnArgument() { result = super.getArgument(_) }
|
||||
|
||||
override predicate isShellInterpreted(DataFlow::Node arg) {
|
||||
// These Open3 methods invoke a subshell if you provide a single string as argument
|
||||
methodCall.getNumberOfArguments() = 1 and arg.asExpr().getExpr() = methodCall.getAnArgument()
|
||||
super.getNumberOfArguments() = 1 and
|
||||
arg = this.getAnArgument()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -47,11 +45,8 @@ module Open3 {
|
||||
* Open3.pipeline([{}, "cat", "foo.txt"], "tail")
|
||||
* Open3.pipeline([["cat", "cat"], "foo.txt"], "tail")
|
||||
*/
|
||||
class Open3PipelineCall extends SystemCommandExecution::Range {
|
||||
MethodCall methodCall;
|
||||
|
||||
class Open3PipelineCall extends SystemCommandExecution::Range instanceof DataFlow::CallNode {
|
||||
Open3PipelineCall() {
|
||||
this.asExpr().getExpr() = methodCall and
|
||||
this =
|
||||
API::getTopLevelMember("Open3")
|
||||
.getAMethodCall([
|
||||
@@ -59,14 +54,12 @@ module Open3 {
|
||||
])
|
||||
}
|
||||
|
||||
override DataFlow::Node getAnArgument() {
|
||||
result.asExpr().getExpr() = methodCall.getAnArgument()
|
||||
}
|
||||
override DataFlow::Node getAnArgument() { result = super.getArgument(_) }
|
||||
|
||||
override predicate isShellInterpreted(DataFlow::Node arg) {
|
||||
// A command in the pipeline is executed in a subshell if it is given as a single string argument.
|
||||
arg.asExpr().getExpr() instanceof StringlikeLiteral and
|
||||
arg.asExpr().getExpr() = methodCall.getAnArgument()
|
||||
arg = this.getAnArgument()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user