-
Notifications
You must be signed in to change notification settings - Fork 2k
Expand file tree
/
Copy pathTwirp.qll
More file actions
149 lines (130 loc) · 4.88 KB
/
Twirp.qll
File metadata and controls
149 lines (130 loc) · 4.88 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
141
142
143
144
145
146
147
148
149
/** Provides models of commonly used functions and types in the twirp packages. */
import go
private import semmle.go.security.RequestForgeryCustomizations
/** Provides models of commonly used functions and types in the twirp packages. */
module Twirp {
/**
* A *.pb.go file generated by Twirp.
*
* This file contains all the types representing protobuf messages and should have a companion *.twirp.go file.
*/
class ProtobufGeneratedFile extends File {
ProtobufGeneratedFile() {
exists(string prefix, File f |
prefix = this.getBaseName().regexpCapture("^(.*)\\.pb\\.go$", 1) and
this.getParentContainer() = f.getParentContainer() and
f.getBaseName() = prefix + ".twirp.go"
)
}
}
/**
* A *.twirp.go file generated by Twirp.
*
* This file contains all the types representing protobuf services and should have a companion *.pb.go file.
*/
class ServicesGeneratedFile extends File {
ServicesGeneratedFile() {
exists(string prefix, File f |
prefix = this.getBaseName().regexpCapture("^(.*)\\.twirp\\.go$", 1) and
this.getParentContainer() = f.getParentContainer() and
f.getBaseName() = prefix + ".pb.go"
)
}
}
/** A type representing a protobuf message. */
class ProtobufMessageType extends Type {
ProtobufMessageType() { this.getLocation().getFile() instanceof ProtobufGeneratedFile }
}
/** An interface type representing a Twirp service. */
class ServiceInterfaceType extends InterfaceType {
DefinedType definedType;
ServiceInterfaceType() {
definedType.getUnderlyingType() = this and
definedType.getLocation().getFile() instanceof ServicesGeneratedFile
}
/** Gets the name of the interface. */
override string getName() { result = definedType.getName() }
/** DEPRECATED: Use `getDefinedType` instead. */
deprecated DefinedType getNamedType() { result = this.getDefinedType() }
/** Gets the defined type on top of this interface type. */
DefinedType getDefinedType() { result = definedType }
}
/** A Twirp client. */
class ServiceClientType extends DefinedType {
ServiceClientType() {
exists(ServiceInterfaceType i, PointerType p |
p.implements(i) and
this = p.getBaseType() and
this.getName().regexpMatch("(?i)" + i.getName() + "(protobuf|json)client") and
this.getLocation().getFile() instanceof ServicesGeneratedFile
)
}
}
/** A Twirp server. */
class ServiceServerType extends DefinedType {
ServiceServerType() {
exists(ServiceInterfaceType i |
this.implements(i) and
this.getName().regexpMatch("(?i)" + i.getName() + "server") and
this.getLocation().getFile() instanceof ServicesGeneratedFile
)
}
}
/** A Twirp function to construct a Client. */
class ClientConstructor extends Function {
ClientConstructor() {
this.getName().regexpMatch("(?i)new" + any(ServiceClientType c).getName()) and
this.getParameterType(0) instanceof StringType and
this.getParameterType(1).getName() = "HTTPClient" and
this.getLocation().getFile() instanceof ServicesGeneratedFile
}
}
/**
* A Twirp function to construct a Server.
*
* Its first argument should be an implementation of the service interface.
*/
class ServerConstructor extends Function {
ServerConstructor() {
this.getName().regexpMatch("(?i)new" + any(ServiceServerType c).getName()) and
this.getParameterType(0) = any(ServiceInterfaceType i).getDefinedType() and
this.getLocation().getFile() instanceof ServicesGeneratedFile
}
}
/** An SSRF sink for the Client constructor. */
class ClientRequestUrlAsSink extends RequestForgery::Sink {
ClientRequestUrlAsSink() {
exists(DataFlow::CallNode call |
call.getArgument(0) = this and
call.getTarget() instanceof ClientConstructor
)
}
override DataFlow::Node getARequest() { result = this }
override string getKind() { result = "URL" }
}
bindingset[m]
pragma[inline_late]
private predicate implementsServiceType(Method m) {
m.implements(any(ServiceInterfaceType i).getDefinedType().getMethod(_))
}
/** A service handler. */
class ServiceHandler extends Method {
ServiceHandler() {
exists(DataFlow::CallNode call |
call.getTarget() instanceof ServerConstructor and
this = call.getArgument(0).getType().getMethod(_) and
implementsServiceType(this)
)
}
}
/** A request coming to the service handler. */
class Request extends RemoteFlowSource::Range instanceof DataFlow::ParameterNode {
Request() {
exists(ServiceHandler handler |
this.asParameter().isParameterOf(handler.getFuncDecl(), 1) and
handler.getParameterType(0).hasQualifiedName("context", "Context") and
this.getType().(PointerType).getBaseType() instanceof ProtobufMessageType
)
}
}
}