mirror of
https://github.com/github/codeql.git
synced 2026-01-17 16:34:49 +01:00
301 lines
12 KiB
Plaintext
301 lines
12 KiB
Plaintext
/**
|
|
* Provides classes modeling security-relevant aspects of the `fabric` PyPI package, for
|
|
* both version 1.x and 2.x.
|
|
*
|
|
* See
|
|
* - http://docs.fabfile.org/en/1.14/tutorial.html and
|
|
* - http://docs.fabfile.org/en/2.5/getting-started.html
|
|
*/
|
|
|
|
private import python
|
|
private import semmle.python.dataflow.new.DataFlow
|
|
private import semmle.python.dataflow.new.RemoteFlowSources
|
|
private import semmle.python.Concepts
|
|
private import semmle.python.ApiGraphs
|
|
private import semmle.python.frameworks.data.ModelsAsData
|
|
|
|
/**
|
|
* Provides classes modeling security-relevant aspects of the `fabric` PyPI package, for
|
|
* version 1.x.
|
|
*
|
|
* See http://docs.fabfile.org/en/1.14/tutorial.html.
|
|
*/
|
|
private module FabricV1 {
|
|
/** Gets a reference to the `fabric` module. */
|
|
API::Node fabric() { result = API::moduleImport("fabric") }
|
|
|
|
/** Provides models for the `fabric` module. */
|
|
module Fabric {
|
|
// -------------------------------------------------------------------------
|
|
// fabric.api
|
|
// -------------------------------------------------------------------------
|
|
/** Gets a reference to the `fabric.api` module. */
|
|
API::Node api() { result = fabric().getMember("api") }
|
|
|
|
/** Provides models for the `fabric.api` module */
|
|
module Api {
|
|
/**
|
|
* A call to either
|
|
* - `fabric.api.local`
|
|
* - `fabric.api.run`
|
|
* - `fabric.api.sudo`
|
|
* See
|
|
* - https://docs.fabfile.org/en/1.14/api/core/operations.html#fabric.operations.local
|
|
* - https://docs.fabfile.org/en/1.14/api/core/operations.html#fabric.operations.run
|
|
* - https://docs.fabfile.org/en/1.14/api/core/operations.html#fabric.operations.sudo
|
|
*/
|
|
private class FabricApiLocalRunSudoCall extends SystemCommandExecution::Range, API::CallNode {
|
|
FabricApiLocalRunSudoCall() { this = api().getMember(["local", "run", "sudo"]).getACall() }
|
|
|
|
override DataFlow::Node getCommand() {
|
|
result = [this.getArg(0), this.getArgByName("command")]
|
|
}
|
|
|
|
override predicate isShellInterpreted(DataFlow::Node arg) {
|
|
arg = this.getCommand() and
|
|
// defaults to running in a shell
|
|
not this.getParameter(1, "shell")
|
|
.getAValueReachingSink()
|
|
.asExpr()
|
|
.(ImmutableLiteral)
|
|
.booleanValue() = false
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* INTERNAL: Do not use.
|
|
*
|
|
* Provides classes modeling security-relevant aspects of the `fabric` PyPI package, for
|
|
* version 2.x.
|
|
*
|
|
* See http://docs.fabfile.org/en/2.5/getting-st arted.html.
|
|
*/
|
|
module FabricV2 {
|
|
/** Gets a reference to the `fabric` module. */
|
|
API::Node fabric() { result = API::moduleImport("fabric") }
|
|
|
|
/** Provides models for the `fabric` module. */
|
|
module Fabric {
|
|
// -------------------------------------------------------------------------
|
|
// fabric.connection
|
|
// -------------------------------------------------------------------------
|
|
/** Gets a reference to the `fabric.connection` module. */
|
|
API::Node connection() { result = fabric().getMember("connection") }
|
|
|
|
/** Provides models for the `fabric.connection` module */
|
|
module Connection {
|
|
/**
|
|
* Provides models for the `fabric.connection.Connection` class
|
|
*
|
|
* See https://docs.fabfile.org/en/2.5/api/connection.html#fabric.connection.Connection.
|
|
*/
|
|
module ConnectionClass {
|
|
/** Gets a reference to the `fabric.connection.Connection` class. */
|
|
API::Node classRef() {
|
|
result = fabric().getMember("Connection")
|
|
or
|
|
result = connection().getMember("Connection")
|
|
or
|
|
result =
|
|
ModelOutput::getATypeNode("fabric.connection.Connection~Subclass").getASubclass*()
|
|
}
|
|
|
|
/**
|
|
* A source of instances of `fabric.connection.Connection`, extend this class to model new instances.
|
|
*
|
|
* This can include instantiations of the class, return values from function
|
|
* calls, or a special parameter that will be set when functions are called by an external
|
|
* library.
|
|
*
|
|
* Use the predicate `Connection::instance()` to get references to instances of `fabric.connection.Connection`.
|
|
*/
|
|
abstract class InstanceSource extends DataFlow::LocalSourceNode { }
|
|
|
|
private class ClassInstantiation extends InstanceSource, DataFlow::CallCfgNode {
|
|
ClassInstantiation() { this = classRef().getACall() }
|
|
}
|
|
|
|
/** Gets a reference to an instance of `fabric.connection.Connection`. */
|
|
private DataFlow::TypeTrackingNode instance(DataFlow::TypeTracker t) {
|
|
t.start() and
|
|
result instanceof InstanceSource
|
|
or
|
|
exists(DataFlow::TypeTracker t2 | result = instance(t2).track(t2, t))
|
|
}
|
|
|
|
/** Gets a reference to an instance of `fabric.connection.Connection`. */
|
|
DataFlow::Node instance() { instance(DataFlow::TypeTracker::end()).flowsTo(result) }
|
|
|
|
/**
|
|
* Gets a reference to either `run`, `sudo`, or `local` method on a
|
|
* `fabric.connection.Connection` instance.
|
|
*
|
|
* See
|
|
* - https://docs.fabfile.org/en/2.5/api/connection.html#fabric.connection.Connection.run
|
|
* - https://docs.fabfile.org/en/2.5/api/connection.html#fabric.connection.Connection.sudo
|
|
* - https://docs.fabfile.org/en/2.5/api/connection.html#fabric.connection.Connection.local
|
|
*/
|
|
private DataFlow::TypeTrackingNode instanceRunMethods(DataFlow::TypeTracker t) {
|
|
t.startInAttr(["run", "sudo", "local"]) and
|
|
result = instance()
|
|
or
|
|
exists(DataFlow::TypeTracker t2 | result = instanceRunMethods(t2).track(t2, t))
|
|
}
|
|
|
|
/**
|
|
* Gets a reference to either `run`, `sudo`, or `local` method on a
|
|
* `fabric.connection.Connection` instance.
|
|
*
|
|
* See
|
|
* - https://docs.fabfile.org/en/2.5/api/connection.html#fabric.connection.Connection.run
|
|
* - https://docs.fabfile.org/en/2.5/api/connection.html#fabric.connection.Connection.sudo
|
|
* - https://docs.fabfile.org/en/2.5/api/connection.html#fabric.connection.Connection.local
|
|
*/
|
|
DataFlow::Node instanceRunMethods() {
|
|
instanceRunMethods(DataFlow::TypeTracker::end()).flowsTo(result)
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* A call to either `run`, `sudo`, or `local` on a `fabric.connection.Connection` instance.
|
|
* See
|
|
* - https://docs.fabfile.org/en/2.5/api/connection.html#fabric.connection.Connection.run
|
|
* - https://docs.fabfile.org/en/2.5/api/connection.html#fabric.connection.Connection.sudo
|
|
* - https://docs.fabfile.org/en/2.5/api/connection.html#fabric.connection.Connection.local
|
|
*/
|
|
private class FabricConnectionRunSudoLocalCall extends SystemCommandExecution::Range,
|
|
DataFlow::CallCfgNode
|
|
{
|
|
FabricConnectionRunSudoLocalCall() {
|
|
this.getFunction() = Fabric::Connection::ConnectionClass::instanceRunMethods()
|
|
}
|
|
|
|
override DataFlow::Node getCommand() {
|
|
result = [this.getArg(0), this.getArgByName("command")]
|
|
}
|
|
|
|
override predicate isShellInterpreted(DataFlow::Node arg) { arg = this.getCommand() }
|
|
}
|
|
|
|
// -------------------------------------------------------------------------
|
|
// fabric.tasks
|
|
// -------------------------------------------------------------------------
|
|
/** Gets a reference to the `fabric.tasks` module. */
|
|
API::Node tasks() { result = fabric().getMember("tasks") }
|
|
|
|
/** Provides models for the `fabric.tasks` module */
|
|
module Tasks {
|
|
/** Gets a reference to the `fabric.tasks.task` decorator. */
|
|
API::Node task() { result in [tasks().getMember("task"), fabric().getMember("task")] }
|
|
}
|
|
|
|
class FabricTaskFirstParamConnectionInstance extends Fabric::Connection::ConnectionClass::InstanceSource,
|
|
DataFlow::ParameterNode
|
|
{
|
|
FabricTaskFirstParamConnectionInstance() {
|
|
exists(Function func |
|
|
func.getADecorator() = Fabric::Tasks::task().getAValueReachableFromSource().asExpr() and
|
|
this.getParameter() = func.getArg(0)
|
|
)
|
|
}
|
|
}
|
|
|
|
// -------------------------------------------------------------------------
|
|
// fabric.group
|
|
// -------------------------------------------------------------------------
|
|
/** Gets a reference to the `fabric.group` module. */
|
|
API::Node group() { result = fabric().getMember("group") }
|
|
|
|
/** Provides models for the `fabric.group` module */
|
|
module Group {
|
|
/**
|
|
* Provides models for the `fabric.group.Group` class and its subclasses.
|
|
*
|
|
* `fabric.group.Group` is an abstract class, that has concrete implementations
|
|
* `SerialGroup` and `ThreadingGroup`.
|
|
*
|
|
* See
|
|
* - https://docs.fabfile.org/en/2.5/api/group.html#fabric.group.Group
|
|
* - https://docs.fabfile.org/en/2.5/api/group.html#fabric.group.SerialGroup
|
|
* - https://docs.fabfile.org/en/2.5/api/group.html#fabric.group.ThreadingGroup
|
|
*/
|
|
module GroupClass {
|
|
/**
|
|
* A source of instances of a subclass of `fabric.group, extend this class to model new instances.Group`
|
|
*
|
|
* This can include instantiation of a class, return value from function
|
|
* calls, or a special parameter that will be set when functions are called by an external
|
|
* library.
|
|
*
|
|
* Use `Group::subclassInstance()` predicate to get references to an instance of a subclass of `fabric.group.Group`.
|
|
*/
|
|
abstract class ModeledSubclass extends API::Node {
|
|
/** Gets a string representation of this element. */
|
|
override string toString() { result = this.(API::Node).toString() }
|
|
}
|
|
|
|
/** Gets a reference to an instance of a subclass of `fabric.group.Group`. */
|
|
API::Node subclassInstance() { result = any(ModeledSubclass m).getASubclass*().getReturn() }
|
|
|
|
/**
|
|
* Gets a reference to the `run` method on an instance of a subclass of `fabric.group.Group`.
|
|
*
|
|
* See https://docs.fabfile.org/en/2.5/api/group.html#fabric.group.Group.run
|
|
*/
|
|
API::Node subclassInstanceRunMethod() { result = subclassInstance().getMember("run") }
|
|
}
|
|
|
|
/**
|
|
* A call to `run` on an instance of a subclass of `fabric.group.Group`.
|
|
*
|
|
* See https://docs.fabfile.org/en/2.5/api/group.html#fabric.group.Group.run
|
|
*/
|
|
private class FabricGroupRunCall extends SystemCommandExecution::Range, DataFlow::CallCfgNode {
|
|
FabricGroupRunCall() {
|
|
this = Fabric::Group::GroupClass::subclassInstanceRunMethod().getACall()
|
|
}
|
|
|
|
override DataFlow::Node getCommand() {
|
|
result = [this.getArg(0), this.getArgByName("command")]
|
|
}
|
|
|
|
override predicate isShellInterpreted(DataFlow::Node arg) { arg = this.getCommand() }
|
|
}
|
|
|
|
/**
|
|
* Provides models for the `fabric.group.SerialGroup` class
|
|
*
|
|
* See https://docs.fabfile.org/en/2.5/api/group.html#fabric.group.SerialGroup.
|
|
*/
|
|
module SerialGroup {
|
|
private class ClassInstantiation extends GroupClass::ModeledSubclass {
|
|
ClassInstantiation() {
|
|
this = group().getMember("SerialGroup")
|
|
or
|
|
this = fabric().getMember("SerialGroup")
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Provides models for the `fabric.group.ThreadingGroup` class
|
|
*
|
|
* See https://docs.fabfile.org/en/2.5/api/group.html#fabric.group.ThreadingGroup.
|
|
*/
|
|
module ThreadingGroup {
|
|
private class ClassInstantiation extends GroupClass::ModeledSubclass {
|
|
ClassInstantiation() {
|
|
this = group().getMember("ThreadingGroup")
|
|
or
|
|
this = fabric().getMember("ThreadingGroup")
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|