Skip to content

Commit 7a76a51

Browse files
committed
Python: Add redirect modeling for Tornado
After making #4995, I realized how easy this would be :D Will need to do some manual merge-conflict handling, but it should be all good :)
1 parent 2f86937 commit 7a76a51

2 files changed

Lines changed: 39 additions & 1 deletion

File tree

  • python/ql
    • src/semmle/python/frameworks
    • test/experimental/library-tests/frameworks/tornado

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

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -216,6 +216,17 @@ private module Tornado {
216216
/** Gets a reference to one of the methods `get_arguments`, `get_body_arguments`, `get_query_arguments`. */
217217
DataFlow::Node argumentsMethod() { result = argumentsMethod(DataFlow::TypeTracker::end()) }
218218

219+
/** Gets a reference the `redirect` method. */
220+
private DataFlow::Node redirectMethod(DataFlow::TypeTracker t) {
221+
t.startInAttr("redirect") and
222+
result = instance()
223+
or
224+
exists(DataFlow::TypeTracker t2 | result = redirectMethod(t2).track(t2, t))
225+
}
226+
227+
/** Gets a reference the `redirect` method. */
228+
DataFlow::Node redirectMethod() { result = redirectMethod(DataFlow::TypeTracker::end()) }
229+
219230
private class AdditionalTaintStep extends TaintTracking::AdditionalTaintStep {
220231
override predicate step(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) {
221232
// Method access
@@ -540,4 +551,31 @@ private module Tornado {
540551
not result = this.getArg(0)
541552
}
542553
}
554+
555+
// ---------------------------------------------------------------------------
556+
// Response modeling
557+
// ---------------------------------------------------------------------------
558+
/**
559+
* A call to `tornado.web.RequestHandler.write` method.
560+
*
561+
* See https://www.tornadoweb.org/en/stable/web.html?highlight=write#tornado.web.RequestHandler.write
562+
*/
563+
private class TornadoRequestHandlerRedirectCall extends HTTP::Server::HttpRedirectResponse::Range,
564+
DataFlow::CfgNode {
565+
override CallNode node;
566+
567+
TornadoRequestHandlerRedirectCall() {
568+
node.getFunction() = tornado::web::RequestHandler::redirectMethod().asCfgNode()
569+
}
570+
571+
override DataFlow::Node getRedirectLocation() {
572+
result.asCfgNode() in [node.getArg(0), node.getArgByName("url")]
573+
}
574+
575+
override DataFlow::Node getBody() { none() }
576+
577+
override string getMimetypeDefault() { none() }
578+
579+
override DataFlow::Node getMimetypeOrContentTypeArg() { none() }
580+
}
543581
}

python/ql/test/experimental/library-tests/frameworks/tornado/basic.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ def get(self): # $ requestHandler
2525
req = self.request
2626
h = req.headers
2727
url = h["url"]
28-
self.redirect(url)
28+
self.redirect(url) # $ HttpRedirectResponse HttpResponse redirectLocation=url
2929

3030

3131
class BaseReverseInheritance(tornado.web.RequestHandler):

0 commit comments

Comments
 (0)