-
Notifications
You must be signed in to change notification settings - Fork 2k
Expand file tree
/
Copy pathInvoke.qll
More file actions
92 lines (82 loc) · 3.59 KB
/
Invoke.qll
File metadata and controls
92 lines (82 loc) · 3.59 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
/**
* Provides classes modeling security-relevant aspects of the `invoke` PyPI package.
* See https://www.pyinvoke.org/.
*/
private import python
private import semmle.python.dataflow.new.DataFlow
private import semmle.python.Concepts
private import semmle.python.ApiGraphs
private import semmle.python.frameworks.data.ModelsAsData
/**
* INTERNAL: Do not use.
*
* Provides models for the `invoke` PyPI package.
* See https://www.pyinvoke.org/.
*/
module Invoke {
// ---------------------------------------------------------------------------
// invoke
// ---------------------------------------------------------------------------
/** Gets a reference to the `invoke` module. */
API::Node invoke() { result = API::moduleImport("invoke") }
/** Provides models for the `invoke` module. */
module InvokeModule {
/** Provides models for the `invoke.context` module */
module Context {
/** Provides models for the `invoke.context.Context` class */
module ContextClass {
/** Gets a reference to the `invoke.context.Context` class. */
API::Node classRef() {
result = API::moduleImport("invoke").getMember("context").getMember("Context")
or
result = API::moduleImport("invoke").getMember("Context")
or
result = ModelOutput::getATypeNode("invoke.context.Context~Subclass").getASubclass*()
}
/** Gets a reference to an instance of `invoke.context.Context`. */
private DataFlow::TypeTrackingNode instance(DataFlow::TypeTracker t) {
t.start() and
(
result = InvokeModule::Context::ContextClass::classRef().getACall()
or
exists(Function func |
func.getADecorator() =
invoke().getMember("task").getAValueReachableFromSource().asExpr() and
result.(DataFlow::ParameterNode).getParameter() = func.getArg(0)
)
)
or
exists(DataFlow::TypeTracker t2 | result = instance(t2).track(t2, t))
}
/** Gets a reference to an instance of `invoke.context.Context`. */
DataFlow::Node instance() { instance(DataFlow::TypeTracker::end()).flowsTo(result) }
/** Gets a reference to the `run` or `sudo` methods on a `invoke.context.Context` instance. */
private DataFlow::TypeTrackingNode instanceRunMethods(DataFlow::TypeTracker t) {
t.startInAttr(["run", "sudo"]) and
result = InvokeModule::Context::ContextClass::instance()
or
exists(DataFlow::TypeTracker t2 | result = instanceRunMethods(t2).track(t2, t))
}
/** Gets a reference to the `run` or `sudo` methods on a `invoke.context.Context` instance. */
DataFlow::Node instanceRunMethods() {
instanceRunMethods(DataFlow::TypeTracker::end()).flowsTo(result)
}
}
}
}
/**
* A call to either
* - `invoke.run` or `invoke.sudo` functions (http://docs.pyinvoke.org/en/stable/api/__init__.html)
* - `run` or `sudo` methods on a `invoke.context.Context` instance (http://docs.pyinvoke.org/en/stable/api/context.html#invoke.context.Context.run)
*/
private class InvokeRunCommandCall extends SystemCommandExecution::Range, DataFlow::CallCfgNode {
InvokeRunCommandCall() {
this = invoke().getMember(["run", "sudo"]).getACall() or
this.getFunction() = InvokeModule::Context::ContextClass::instanceRunMethods()
}
override DataFlow::Node getCommand() {
result in [this.getArg(0), this.getArgByName("command")]
}
override predicate isShellInterpreted(DataFlow::Node arg) { arg = this.getCommand() }
}
}