Skip to content

Commit 88158e7

Browse files
committed
Python: Add basic model setup for aiohttp.web.Request
1 parent 2b992a6 commit 88158e7

File tree

2 files changed

+67
-2
lines changed

2 files changed

+67
-2
lines changed

python/ql/src/semmle/python/frameworks/Aiohttp.qll

Lines changed: 66 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55

66
private import python
77
private import semmle.python.dataflow.new.DataFlow
8+
private import semmle.python.dataflow.new.RemoteFlowSources
9+
private import semmle.python.dataflow.new.TaintTracking
810
private import semmle.python.Concepts
911
private import semmle.python.ApiGraphs
1012
private import semmle.python.frameworks.internal.PoorMansFunctionResolution
@@ -33,7 +35,6 @@ module AiohttpWebModel {
3335
}
3436

3537
// -- route modeling --
36-
3738
/** A route setup in `aiohttp.web` */
3839
abstract class AiohttpRouteSetup extends HTTP::Server::RouteSetup::Range {
3940
override Parameter getARoutedParameter() { none() }
@@ -138,4 +139,68 @@ module AiohttpWebModel {
138139

139140
override Function getARequestHandler() { result.getADecorator() = this.asExpr() }
140141
}
142+
143+
// ---------------------------------------------------------------------------
144+
// aiohttp.web.Request taint modeling
145+
// ---------------------------------------------------------------------------
146+
/**
147+
* Provides models for the `aiohttp.web.Request` class
148+
*
149+
* See https://docs.aiohttp.org/en/stable/web_reference.html#request-and-base-request
150+
*/
151+
module Request {
152+
/**
153+
* A source of instances of `aiohttp.web.Request`, extend this class to model new instances.
154+
*
155+
* This can include instantiations of the class, return values from function
156+
* calls, or a special parameter that will be set when functions are called by an external
157+
* library.
158+
*
159+
* Use `Request::instance()` predicate to get
160+
* references to instances of `aiohttp.web.Request`.
161+
*/
162+
abstract class InstanceSource extends DataFlow::Node { }
163+
164+
/** Gets a reference to an instance of `aiohttp.web.Request`. */
165+
private DataFlow::LocalSourceNode instance(DataFlow::TypeTracker t) {
166+
t.start() and
167+
result instanceof InstanceSource
168+
or
169+
exists(DataFlow::TypeTracker t2 | result = instance(t2).track(t2, t))
170+
}
171+
172+
/** Gets a reference to an instance of `aiohttp.web.Request`. */
173+
DataFlow::Node instance() { instance(DataFlow::TypeTracker::end()).flowsTo(result) }
174+
}
175+
176+
/**
177+
* A parameter that will receive a `aiohttp.web.Request` instance when a request
178+
* handler is invoked.
179+
*/
180+
class AiohttpRequestHandlerRequestParam extends Request::InstanceSource, RemoteFlowSource::Range,
181+
DataFlow::ParameterNode {
182+
AiohttpRequestHandlerRequestParam() {
183+
exists(Function requestHandler |
184+
requestHandler = any(AiohttpRouteSetup setup).getARequestHandler() and
185+
// We select the _last_ parameter for the request since that is what they do in
186+
// `aiohttp-jinja2`.
187+
// https://github.com/aio-libs/aiohttp-jinja2/blob/7fb4daf2c3003921d34031d38c2311ee0e02c18b/aiohttp_jinja2/__init__.py#L235
188+
//
189+
// I assume that is just to handle cases such as the one below
190+
// ```py
191+
// class MyCustomHandlerClass:
192+
// async def foo_handler(self, request):
193+
// ...
194+
//
195+
// my_custom_handler = MyCustomHandlerClass()
196+
// app.router.add_get("/MyCustomHandlerClass/foo", my_custom_handler.foo_handler)
197+
// ```
198+
this.getParameter() =
199+
max(Parameter param, int i | param = requestHandler.getArg(i) | param order by i)
200+
201+
)
202+
}
203+
204+
override string getSourceType() { result = "aiohttp.web.Request" }
205+
}
141206
}

python/ql/test/library-tests/frameworks/aiohttp/taint_test.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
async def test_taint(request: web.Request): # $ requestHandler
44

55
ensure_tainted(
6-
request, # $ MISSING: tainted
6+
request, # $ tainted
77

88
# yarl.URL instances
99
# https://yarl.readthedocs.io/en/stable/api.html#yarl.URL

0 commit comments

Comments
 (0)