Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit dcaf0f8

Browse files
authored
Merge pull request #978 from markshannon/python-turbogears
Python: Add support for turbogears; requests and responses.
2 parents 84c7f19 + a480da6 commit dcaf0f8

21 files changed

Lines changed: 273 additions & 5 deletions

File tree

change-notes/1.20/analysis-python.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,5 +38,7 @@ The API has been improved to declutter the global namespace and improve discover
3838
## Changes to QL libraries
3939

4040
* Added support for the `dill` pickle library.
41-
* Added support for the bottle web framework.
41+
* Added support for the `bottle` web framework.
42+
* Added support for the `turbogears` web framework.
43+
4244

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
Name, Category
2+
Bottle, Web framework
23
Django, Web application framework
34
Flask, Microframework
45
Pyramid, Web application framework
56
Tornado, Web application framework and asynchronous networking library
7+
Turbogears, Web framework
68
Twisted, Networking engine
79
WebOb, WSGI request library

python/ql/src/semmle/python/Function.qll

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,14 @@ class Function extends Function_, Scope, AstNode {
174174
Scope.super.contains(inner)
175175
}
176176

177+
/** Gets a control flow node for a return value of this function */
178+
ControlFlowNode getAReturnValueFlowNode() {
179+
exists(Return ret |
180+
ret.getScope() = this and
181+
ret.getValue() = result.getNode()
182+
)
183+
}
184+
177185
}
178186

179187
/** A def statement. Note that FunctionDef extends Assign as a function definition binds the newly created function */

python/ql/src/semmle/python/security/strings/Basic.qll

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,3 +115,14 @@ private predicate os_path_join(ControlFlowNode fromnode, CallNode tonode) {
115115
tonode = path_join.getACall() and tonode.getAnArg() = fromnode
116116
)
117117
}
118+
119+
/** A kind of "taint", representing a dictionary mapping str->"taint" */
120+
class StringDictKind extends DictKind {
121+
122+
StringDictKind() {
123+
this.getValue() instanceof StringKind
124+
}
125+
126+
}
127+
128+

python/ql/src/semmle/python/types/FunctionObject.qll

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -160,10 +160,7 @@ class PyFunctionObject extends FunctionObject {
160160

161161
/** Gets a control flow node corresponding to the value of a return statement */
162162
ControlFlowNode getAReturnedNode() {
163-
exists(Return ret |
164-
ret.getScope() = this.getFunction() and
165-
result.getNode() = ret.getValue()
166-
)
163+
result = this.getFunction().getAReturnValueFlowNode()
167164
}
168165

169166
override string descriptiveString() {

python/ql/src/semmle/python/web/HttpRequest.qll

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,4 @@ import semmle.python.web.tornado.Request
44
import semmle.python.web.pyramid.Request
55
import semmle.python.web.twisted.Request
66
import semmle.python.web.bottle.Request
7+
import semmle.python.web.turbogears.Request

python/ql/src/semmle/python/web/HttpResponse.qll

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,4 @@ import semmle.python.web.pyramid.Response
44
import semmle.python.web.tornado.Response
55
import semmle.python.web.twisted.Response
66
import semmle.python.web.bottle.Response
7+
import semmle.python.web.turbogears.Response
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
import python
2+
import semmle.python.security.strings.Untrusted
3+
4+
import TurboGears
5+
6+
private class ValidatedMethodParameter extends Parameter {
7+
8+
ValidatedMethodParameter() {
9+
exists(string name, TurboGearsControllerMethod method |
10+
method.getArgByName(name) = this and
11+
method.getValidationDict().getItem(_).(KeyValuePair).getKey().(StrConst).getText() = name
12+
)
13+
}
14+
15+
}
16+
17+
class UnvalidatedControllerMethodParameter extends TaintSource {
18+
19+
UnvalidatedControllerMethodParameter() {
20+
exists(Parameter p |
21+
any(TurboGearsControllerMethod m | not m.getName() = "onerror").getAnArg() = p and
22+
not p instanceof ValidatedMethodParameter and
23+
not p.isSelf() and
24+
p.(Name).getAFlowNode() = this
25+
)
26+
}
27+
28+
override predicate isSourceOf(TaintKind kind) {
29+
kind instanceof UntrustedStringKind
30+
}
31+
32+
}
33+
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
import python
2+
3+
import semmle.python.security.TaintTracking
4+
import semmle.python.security.strings.Basic
5+
6+
import TurboGears
7+
8+
9+
10+
class ControllerMethodReturnValue extends TaintSink {
11+
12+
ControllerMethodReturnValue() {
13+
exists(TurboGearsControllerMethod m |
14+
m.getAReturnValueFlowNode() = this and
15+
not m.isTemplated()
16+
)
17+
}
18+
19+
override predicate sinks(TaintKind kind) {
20+
kind instanceof StringKind
21+
}
22+
23+
}
24+
25+
class ControllerMethodTemplatedReturnValue extends TaintSink {
26+
27+
ControllerMethodTemplatedReturnValue() {
28+
exists(TurboGearsControllerMethod m |
29+
m.getAReturnValueFlowNode() = this and
30+
m.isTemplated()
31+
)
32+
}
33+
34+
override predicate sinks(TaintKind kind) {
35+
kind instanceof StringDictKind
36+
}
37+
38+
}
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
import python
2+
3+
import semmle.python.security.TaintTracking
4+
5+
private ClassObject theTurboGearsControllerClass() {
6+
result = ModuleObject::named("tg").getAttribute("TGController")
7+
}
8+
9+
10+
ClassObject aTurboGearsControllerClass() {
11+
result.getASuperType() = theTurboGearsControllerClass()
12+
}
13+
14+
15+
class TurboGearsControllerMethod extends Function {
16+
17+
ControlFlowNode decorator;
18+
19+
TurboGearsControllerMethod() {
20+
aTurboGearsControllerClass().getPyClass() = this.getScope() and
21+
decorator = this.getADecorator().getAFlowNode() and
22+
/* Is decorated with @expose() or @expose(path) */
23+
(
24+
decorator.(CallNode).getFunction().(NameNode).getId() = "expose"
25+
or
26+
decorator.refersTo(_, ModuleObject::named("tg").getAttribute("expose"), _)
27+
)
28+
}
29+
30+
private ControlFlowNode templateName() {
31+
result = decorator.(CallNode).getArg(0)
32+
}
33+
34+
predicate isTemplated() {
35+
exists(templateName())
36+
}
37+
38+
string getTemplateName() {
39+
exists(StringObject str |
40+
templateName().refersTo(str) and
41+
result = str.getText()
42+
)
43+
}
44+
45+
Dict getValidationDict() {
46+
exists(Call call, Object dict |
47+
call = this.getADecorator() and
48+
call.getFunc().(Name).getId() = "validate" and
49+
call.getArg(0).refersTo(dict) and
50+
result = dict.getOrigin()
51+
)
52+
}
53+
54+
}
55+

0 commit comments

Comments
 (0)