forked from github/codeql
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathYarl.qll
More file actions
140 lines (125 loc) · 5.07 KB
/
Copy pathYarl.qll
File metadata and controls
140 lines (125 loc) · 5.07 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
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
/**
* Provides classes modeling security-relevant aspects of the `yarl` PyPI package.
* See https://yarl.readthedocs.io/en/stable/.
*/
private import python
private import semmle.python.dataflow.new.DataFlow
private import semmle.python.dataflow.new.TaintTracking
private import semmle.python.Concepts
private import semmle.python.ApiGraphs
private import semmle.python.frameworks.Multidict
private import semmle.python.frameworks.internal.InstanceTaintStepsHelper
private import semmle.python.security.dataflow.UrlRedirectCustomizations
/**
* INTERNAL: Do not use.
*
* Provides models for the `yarl` PyPI package.
* See https://multidict.readthedocs.io/en/stable/.
*/
module Yarl {
/**
* Provides models for a the `yarl.URL` class:
*
* See https://yarl.readthedocs.io/en/stable/api.html#yarl.URL
*/
module Url {
/**
* A source of instances of `yarl.URL`, 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 `Url::instance()` predicate to get references to instances of `yarl.URL`.
*/
abstract class InstanceSource extends DataFlow::LocalSourceNode { }
/** A direct instantiation of `yarl.URL`. */
private class ClassInstantiation extends InstanceSource, DataFlow::CallCfgNode {
ClassInstantiation() { this = API::moduleImport("yarl").getMember("URL").getACall() }
}
/** Gets a reference to an instance of `yarl.URL`. */
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 `yarl.URL`. */
DataFlow::Node instance() { instance(DataFlow::TypeTracker::end()).flowsTo(result) }
/**
* Taint propagation for `yarl.URL`.
*/
private class InstanceTaintSteps extends InstanceTaintStepsHelper {
InstanceTaintSteps() { this = "yarl.URL" }
override DataFlow::Node getInstance() { result = instance() }
override string getAttributeName() {
result in [
"user", "raw_user", "password", "raw_password", "host", "raw_host", "port",
"explicit_port", "authority", "raw_authority", "path", "raw_path", "path_qs",
"raw_path_qs", "query_string", "raw_query_string", "fragment", "raw_fragment", "parts",
"raw_parts", "name", "raw_name", "query"
]
}
override string getMethodName() { result = "human_repr" }
override string getAsyncMethodName() { none() }
}
/**
* Extra taint propagation for `yarl.URL`, not covered by `InstanceTaintSteps`.
*/
private class AdditionalTaintStep extends TaintTracking::AdditionalTaintStep {
override predicate step(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) {
// class instantiation
exists(ClassInstantiation call |
nodeFrom in [call.getArg(0), call.getArgByName("val")] and
nodeTo = call
)
or
// methods that give an altered URL. taint both from object, and form argument
// (to result of call)
exists(DataFlow::MethodCallNode call |
call.calls(instance(),
[
"with_scheme", "with_user", "with_password", "with_host", "with_port", "with_path",
"with_query", "with_query", "update_query", "update_query", "with_fragment",
"with_name",
// join is a bit different, but is still correct to add here :+1:
"join"
]) and
nodeTo = call and
nodeFrom in [call.getObject(), call.getArg(_), call.getArgByName(_)]
)
}
}
/** An attribute read on a `yarl.URL` that is a `MultiDictProxy` instance. */
class YarlUrlMultiDictProxyInstance extends Multidict::MultiDictProxy::InstanceSource {
YarlUrlMultiDictProxyInstance() {
this.(DataFlow::AttrRead).getObject() = Yarl::Url::instance() and
this.(DataFlow::AttrRead).getAttributeName() = "query"
}
}
private predicate yarlUrlIsAbsoluteCall(
DataFlow::GuardNode g, ControlFlowNode node, boolean branch
) {
exists(ClassInstantiation instance, DataFlow::MethodCallNode call |
call.calls(instance, "is_absolute") and
g = call.asCfgNode() and
node = instance.getArg(0).asCfgNode() and
branch = false
)
}
/**
* A call to `yarl.URL.is_absolute`, considered as a sanitizer-guard for URL redirection.
*
* See https://yarl.aio-libs.org/en/latest/api/#absolute-and-relative-urls.
*/
private class YarlIsAbsoluteUrl extends UrlRedirect::Sanitizer {
YarlIsAbsoluteUrl() {
this = DataFlow::BarrierGuard<yarlUrlIsAbsoluteCall/3>::getABarrierNode()
}
override predicate sanitizes(UrlRedirect::FlowState state) {
// `is_absolute` does not handle backslashes
state instanceof UrlRedirect::NoBackslashes
}
}
}
}