Skip to content

Commit 22b9ab4

Browse files
authored
Merge pull request #13259 from alexrford/rb/actiondispatch-refactor
Ruby: Refactor and slightly expand `ActionDispatch` modelling
2 parents d9e3569 + 9ccfec0 commit 22b9ab4

File tree

8 files changed

+1183
-1145
lines changed

8 files changed

+1183
-1145
lines changed

ruby/ql/lib/codeql/ruby/frameworks/ActionController.qll

-143
Original file line numberDiff line numberDiff line change
@@ -204,149 +204,6 @@ private class ActionControllerParamsCall extends ParamsCallImpl {
204204
}
205205
}
206206

207-
/** Modeling for `ActionDispatch::Request`. */
208-
private module Request {
209-
/**
210-
* A call to `request` from within a controller. This is an instance of
211-
* `ActionDispatch::Request`.
212-
*/
213-
private class RequestNode extends DataFlow::CallNode {
214-
RequestNode() { this = actionControllerInstance().getAMethodCall("request") }
215-
}
216-
217-
/**
218-
* A method call on `request`.
219-
*/
220-
private class RequestMethodCall extends DataFlow::CallNode {
221-
RequestMethodCall() {
222-
any(RequestNode r).(DataFlow::LocalSourceNode).flowsTo(this.getReceiver())
223-
}
224-
}
225-
226-
abstract private class RequestInputAccess extends RequestMethodCall,
227-
Http::Server::RequestInputAccess::Range
228-
{
229-
override string getSourceType() { result = "ActionDispatch::Request#" + this.getMethodName() }
230-
}
231-
232-
/**
233-
* A method call on `request` which returns request parameters.
234-
*/
235-
private class ParametersCall extends RequestInputAccess {
236-
ParametersCall() {
237-
this.getMethodName() =
238-
[
239-
"parameters", "params", "GET", "POST", "query_parameters", "request_parameters",
240-
"filtered_parameters"
241-
]
242-
}
243-
244-
override Http::Server::RequestInputKind getKind() {
245-
result = Http::Server::parameterInputKind()
246-
}
247-
}
248-
249-
/** A method call on `request` which returns part or all of the request path. */
250-
private class PathCall extends RequestInputAccess {
251-
PathCall() {
252-
this.getMethodName() =
253-
["path", "filtered_path", "fullpath", "original_fullpath", "original_url", "url"]
254-
}
255-
256-
override Http::Server::RequestInputKind getKind() { result = Http::Server::urlInputKind() }
257-
}
258-
259-
/** A method call on `request` which returns a specific request header. */
260-
private class HeadersCall extends RequestInputAccess {
261-
HeadersCall() {
262-
this.getMethodName() =
263-
[
264-
"authorization", "script_name", "path_info", "user_agent", "referer", "referrer",
265-
"host_authority", "content_type", "host", "hostname", "accept_encoding",
266-
"accept_language", "if_none_match", "if_none_match_etags", "content_mime_type"
267-
]
268-
or
269-
// Request headers are prefixed with `HTTP_` to distinguish them from
270-
// "headers" supplied by Rack middleware.
271-
this.getMethodName() = ["get_header", "fetch_header"] and
272-
this.getArgument(0).getConstantValue().getString().regexpMatch("^HTTP_.+")
273-
}
274-
275-
override Http::Server::RequestInputKind getKind() { result = Http::Server::headerInputKind() }
276-
}
277-
278-
// TODO: each_header
279-
/**
280-
* A method call on `request` which returns part or all of the host.
281-
* This can be influenced by headers such as Host and X-Forwarded-Host.
282-
*/
283-
private class HostCall extends RequestInputAccess {
284-
HostCall() {
285-
this.getMethodName() =
286-
[
287-
"authority", "host", "host_authority", "host_with_port", "hostname", "forwarded_for",
288-
"forwarded_host", "port", "forwarded_port"
289-
]
290-
}
291-
292-
override Http::Server::RequestInputKind getKind() { result = Http::Server::headerInputKind() }
293-
}
294-
295-
/**
296-
* A method call on `request` which is influenced by one or more request
297-
* headers.
298-
*/
299-
private class HeaderTaintedCall extends RequestInputAccess {
300-
HeaderTaintedCall() {
301-
this.getMethodName() = ["media_type", "media_type_params", "content_charset", "base_url"]
302-
}
303-
304-
override Http::Server::RequestInputKind getKind() { result = Http::Server::headerInputKind() }
305-
}
306-
307-
/** A method call on `request` which returns the request body. */
308-
private class BodyCall extends RequestInputAccess {
309-
BodyCall() { this.getMethodName() = ["body", "raw_post", "body_stream"] }
310-
311-
override Http::Server::RequestInputKind getKind() { result = Http::Server::bodyInputKind() }
312-
}
313-
314-
private module Env {
315-
abstract private class Env extends DataFlow::LocalSourceNode { }
316-
317-
/**
318-
* A method call on `request` which returns the rack env.
319-
* This is a hash containing all the information about the request. Values
320-
* under keys starting with `HTTP_` are user-controlled.
321-
*/
322-
private class RequestEnvCall extends DataFlow::CallNode, Env {
323-
RequestEnvCall() { this.getMethodName() = ["env", "filtered_env"] }
324-
}
325-
326-
private import codeql.ruby.frameworks.Rack
327-
328-
private class RackEnv extends Env {
329-
RackEnv() { this = any(Rack::AppCandidate app).getEnv().getALocalUse() }
330-
}
331-
332-
/**
333-
* A read of a user-controlled parameter from the request env.
334-
*/
335-
private class EnvHttpAccess extends DataFlow::CallNode, Http::Server::RequestInputAccess::Range {
336-
EnvHttpAccess() {
337-
this = any(Env c).getAMethodCall("[]") and
338-
exists(string key | key = this.getArgument(0).getConstantValue().getString() |
339-
key.regexpMatch("^HTTP_.+") or key = "PATH_INFO"
340-
)
341-
}
342-
343-
override Http::Server::RequestInputKind getKind() { result = Http::Server::headerInputKind() }
344-
345-
override string getSourceType() { result = "ActionDispatch::Request#env[]" }
346-
}
347-
}
348-
}
349-
350207
/** A call to `render` from within a controller. */
351208
private class ActionControllerRenderCall extends RenderCallImpl {
352209
ActionControllerRenderCall() {

0 commit comments

Comments
 (0)