Skip to content

Commit d3099ff

Browse files
committed
fix tests, move from SharedXss::Sink to Http::* classes
1 parent ffe2e39 commit d3099ff

File tree

2 files changed

+111
-54
lines changed

2 files changed

+111
-54
lines changed

go/ql/lib/semmle/go/frameworks/Fasthttp.qll

Lines changed: 104 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,109 @@ module Fasthttp {
1616
/** Gets the path for the root package of fasthttp. */
1717
string packagePath() { result = package(v1modulePath(), "") }
1818

19+
private class HeaderWrite extends Http::HeaderWrite::Range, DataFlow::MethodCallNode {
20+
string methodName;
21+
22+
HeaderWrite() {
23+
this.getTarget().hasQualifiedName(packagePath(), "ResponseHeader", methodName) and
24+
methodName in [
25+
"Add", "AddBytesK", "AddBytesKV", "AddBytesV", "Set", "SetBytesK", "SetBytesKV",
26+
"SetCanonical", "SetContentType", "SetContentTypeBytes"
27+
]
28+
or
29+
this.getTarget().hasQualifiedName(packagePath(), "RequestCtx", methodName) and
30+
methodName in ["SetContentType", "SetContentTypeBytes", "Success", "SuccessString"]
31+
}
32+
33+
override DataFlow::Node getName() {
34+
methodName =
35+
[
36+
"Add", "AddBytesK", "AddBytesKV", "AddBytesV", "Set", "SetBytesK", "SetBytesKV",
37+
"SetCanonical"
38+
] and
39+
result = this.getArgument(0)
40+
}
41+
42+
override string getHeaderName() {
43+
result = Http::HeaderWrite::Range.super.getHeaderName()
44+
or
45+
methodName = ["SetContentType", "SetContentTypeBytes", "Success", "SuccessString"] and
46+
result = "content-type"
47+
}
48+
49+
override DataFlow::Node getValue() {
50+
if methodName = ["SetContentType", "SetContentTypeBytes", "Success", "SuccessString"]
51+
then result = this.getArgument(0)
52+
else result = this.getArgument(1)
53+
}
54+
55+
override Http::ResponseWriter getResponseWriter() {
56+
result.(ResponseWriter).getAHeaderObject() = this
57+
}
58+
}
59+
60+
private class ResponseWriter extends Http::ResponseWriter::Range {
61+
SsaWithFields v;
62+
63+
ResponseWriter() {
64+
this = v.getBaseVariable().getSourceVariable() and
65+
(
66+
v.getType().hasQualifiedName(packagePath(), ["Response", "ResponseHeader"]) or
67+
v.getType().(PointerType).getBaseType().hasQualifiedName(packagePath(), "RequestCtx")
68+
)
69+
}
70+
71+
override DataFlow::Node getANode() { result = v.similar().getAUse().getASuccessor*() }
72+
73+
/** Gets a header object that corresponds to this HTTP response. */
74+
DataFlow::MethodCallNode getAHeaderObject() {
75+
result.getTarget().getName() =
76+
[
77+
"Add", "AddBytesK", "AddBytesKV", "AddBytesV", "Set", "SetBytesK", "SetBytesKV",
78+
"SetCanonical", "SetContentType", "SetContentTypeBytes", "Success", "SuccessString"
79+
] and
80+
this.getANode() = result.getReceiver()
81+
}
82+
}
83+
84+
/**
85+
* The methods that can write to HTTP Response Body.
86+
* These methods can be dangerous if they are user controllable.
87+
*/
88+
class HttpResponseBodySink extends SharedXss::Sink {
89+
HttpResponseBodySink() {
90+
exists(Method m |
91+
m.hasQualifiedName(packagePath(), "RequestCtx", ["Success", "SuccessString"]) and
92+
this = m.getACall().getArgument(1)
93+
)
94+
}
95+
}
96+
97+
private class ResponseBody extends Http::ResponseBody::Range {
98+
DataFlow::MethodCallNode call;
99+
string methodName;
100+
101+
ResponseBody() {
102+
exists(Method m |
103+
m.hasQualifiedName(packagePath(), "Response", methodName) and
104+
call = m.getACall() and
105+
this = call.getArgument(0)
106+
or
107+
m.hasQualifiedName(packagePath(), "RequestCtx", ["Success", "SuccessString"]) and
108+
this = m.getACall().getArgument(1)
109+
) and
110+
methodName =
111+
[
112+
"AppendBody", "AppendBodyString", "SetBody", "SetBodyRaw", "SetBodyStream",
113+
"SetBodyString", "Success", "SuccessString"
114+
]
115+
}
116+
117+
override Http::ResponseWriter getResponseWriter() { result.getANode() = call.getReceiver() }
118+
119+
override string getAContentType() { result = super.getAContentType() }
120+
}
121+
19122
/**
20123
* Provide models for sanitizer/Dangerous Functions of fasthttp.
21124
*/
@@ -208,7 +311,7 @@ module Fasthttp {
208311
*/
209312
module Response {
210313
/**
211-
* A Method That send files from its input.
314+
* A Method that sends files from its input.
212315
* It does not check the input path against path traversal attacks, So it is a dangerous method.
213316
*/
214317
class FileSystemAccess extends FileSystemAccess::Range, DataFlow::CallNode {
@@ -221,39 +324,6 @@ module Fasthttp {
221324

222325
override DataFlow::Node getAPathArgument() { result = this.getArgument(0) }
223326
}
224-
225-
/**
226-
* The methods that can write to HTTP Response Body.
227-
* These methods can be dangerous if they are user controllable.
228-
*/
229-
class HttpResponseBodySink extends SharedXss::Sink {
230-
HttpResponseBodySink() {
231-
exists(Method m |
232-
m.hasQualifiedName(packagePath(), "Response",
233-
[
234-
"AppendBody", "AppendBodyString", "SetBody", "SetBodyRaw", "SetBodyStream",
235-
"SetBodyString"
236-
]) and
237-
this = m.getACall().getArgument(0)
238-
)
239-
or
240-
exists(Method write, DataFlow::CallNode writeCall |
241-
write.hasQualifiedName("io", "Writer", "Write") and
242-
writeCall = write.getACall() and
243-
ResponseBodyWriterFlow::flowsTo(writeCall.getReceiver()) and
244-
this = writeCall.getArgument(0)
245-
)
246-
}
247-
}
248-
249-
private predicate responseBodyWriterResult(DataFlow::Node src) {
250-
exists(Method responseBodyWriter |
251-
responseBodyWriter.hasQualifiedName(packagePath(), "Response", "BodyWriter") and
252-
src = responseBodyWriter.getACall().getResult(0)
253-
)
254-
}
255-
256-
private module ResponseBodyWriterFlow = DataFlow::SimpleGlobal<responseBodyWriterResult/1>;
257327
}
258328

259329
/**
@@ -348,19 +418,6 @@ module Fasthttp {
348418
)
349419
}
350420
}
351-
352-
/**
353-
* The methods that can write to HTTP Response Body.
354-
* These methods can be dangerous if they are user controllable.
355-
*/
356-
class HttpResponseBodySink extends SharedXss::Sink {
357-
HttpResponseBodySink() {
358-
exists(Method m |
359-
m.hasQualifiedName(packagePath(), "RequestCtx", ["Success", "SuccessString"]) and
360-
this = m.getACall().getArgument(1)
361-
)
362-
}
363-
}
364421
}
365422

366423
/**

go/ql/test/library-tests/semmle/go/frameworks/Fasthttp/fasthttp.go

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -160,10 +160,10 @@ func fasthttpServer() {
160160
requestCtx.Request.Host() // $ UntrustedFlowSource="call to Host"
161161
requestCtx.Request.Body() // $ UntrustedFlowSource="call to Body"
162162
requestCtx.Request.RequestURI() // $ UntrustedFlowSource="call to RequestURI"
163-
body1, _ := requestCtx.Request.BodyGunzip() //$ UntrustedFlowSource="... := ...[0]"
164-
body2, _ := requestCtx.Request.BodyInflate() //$ UntrustedFlowSource="... := ...[0]"
165-
body3, _ := requestCtx.Request.BodyUnbrotli() //$ UntrustedFlowSource="... := ...[0]"
166-
body4, _ := requestCtx.Request.BodyUncompressed() //$ UntrustedFlowSource="... := ...[0]"
163+
body1, _ := requestCtx.Request.BodyGunzip() // $ UntrustedFlowSource="... := ...[0]"
164+
body2, _ := requestCtx.Request.BodyInflate() // $ UntrustedFlowSource="... := ...[0]"
165+
body3, _ := requestCtx.Request.BodyUnbrotli() // $ UntrustedFlowSource="... := ...[0]"
166+
body4, _ := requestCtx.Request.BodyUncompressed() // $ UntrustedFlowSource="... := ...[0]"
167167
requestCtx.Request.BodyStream() // $ UntrustedFlowSource="call to BodyStream"
168168
requestCtx.Request.ReadBody(dstReader, 100, 1000)
169169
requestCtx.Request.ReadLimitBody(dstReader, 100)
@@ -175,9 +175,9 @@ func fasthttpServer() {
175175
// Xss Sinks Related method
176176
userInput := "user Controlled input"
177177
userInputByte := []byte("user Controlled input")
178-
requestCtx.Response.AppendBody(userInputByte) // $ XssSink=userInputByte
179-
requestCtx.Response.AppendBodyString(userInput) // $ XssSink=userInput
180-
rspWriter := requestCtx.Response.BodyWriter() // IDK how to handle this that returns a `io.Writer`
178+
requestCtx.Response.AppendBody(userInputByte) // $ XssSink=userInputByte
179+
requestCtx.Response.AppendBodyString(userInput) // $ XssSink=userInput
180+
rspWriter := requestCtx.Response.BodyWriter()
181181
rspWriter.Write(userInputByte) // $ XssSink=userInputByte
182182
requestCtx.Response.SetBody(userInputByte) // $ XssSink=userInputByte
183183
requestCtx.Response.SetBodyString(userInput) // $ XssSink=userInput

0 commit comments

Comments
 (0)