Skip to content

Commit 78109db

Browse files
authored
Merge pull request #2181 from RasmusWL/python-modernise-pyramid-library
Python: modernise pyramid library
2 parents cb94e7d + 2874c54 commit 78109db

File tree

18 files changed

+125
-56
lines changed

18 files changed

+125
-56
lines changed

python/ql/src/semmle/python/Exprs.qll

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,11 @@ class Expr extends Expr_, AstNode {
126126
this.pointsTo(value, _)
127127
}
128128

129+
/** Gets a value that this expression might "point-to". */
130+
Value pointsTo() {
131+
this.pointsTo(result)
132+
}
133+
129134
}
130135

131136
/** An assignment expression, such as `x := y` */
Lines changed: 7 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,16 @@
1-
/** Provides class representing the `pyramid.redirect` function.
1+
/**
2+
* Provides class representing the `pyramid.redirect` function.
23
* This module is intended to be imported into a taint-tracking query
34
* to extend `TaintSink`.
45
*/
5-
import python
66

7+
import python
78
import semmle.python.security.TaintTracking
89
import semmle.python.security.strings.Basic
910
import semmle.python.web.Http
1011

11-
private ClassObject redirectClass() {
12-
exists(ModuleObject ex |
13-
ex.getName() = "pyramid.httpexceptions" |
12+
private ClassValue redirectClass() {
13+
exists(ModuleValue ex | ex.getName() = "pyramid.httpexceptions" |
1414
ex.attr("HTTPFound") = result
1515
or
1616
ex.attr("HTTPTemporaryRedirect") = result
@@ -21,19 +21,13 @@ private ClassObject redirectClass() {
2121
* Represents an argument to the `tornado.redirect` function.
2222
*/
2323
class PyramidRedirect extends HttpRedirectTaintSink {
24-
25-
override string toString() {
26-
result = "pyramid.redirect"
27-
}
24+
override string toString() { result = "pyramid.redirect" }
2825

2926
PyramidRedirect() {
30-
exists(CallNode call |
31-
call.getFunction().refersTo(redirectClass())
32-
|
27+
exists(CallNode call | call.getFunction().pointsTo(redirectClass()) |
3328
call.getArg(0) = this
3429
or
3530
call.getArgByName("location") = this
3631
)
3732
}
38-
3933
}
Lines changed: 4 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,39 +1,25 @@
11
import python
2-
32
import semmle.python.security.TaintTracking
43
import semmle.python.web.Http
54
private import semmle.python.web.webob.Request
65
private import semmle.python.web.pyramid.View
76

87
class PyramidRequest extends BaseWebobRequest {
8+
PyramidRequest() { this = "pyramid.request" }
99

10-
PyramidRequest() {
11-
this = "pyramid.request"
12-
}
13-
14-
override ClassValue getType() {
15-
result = Value::named("pyramid.request.Request")
16-
}
17-
10+
override ClassValue getType() { result = Value::named("pyramid.request.Request") }
1811
}
1912

2013
/** Source of pyramid request objects */
2114
class PyramidViewArgument extends TaintSource {
22-
2315
PyramidViewArgument() {
2416
exists(Function view_func |
2517
is_pyramid_view_function(view_func) and
2618
this.(ControlFlowNode).getNode() = view_func.getArg(0)
2719
)
2820
}
2921

30-
override predicate isSourceOf(TaintKind kind) {
31-
kind instanceof PyramidRequest
32-
}
33-
34-
override string toString() {
35-
result = "pyramid.view.argument"
36-
}
22+
override predicate isSourceOf(TaintKind kind) { kind instanceof PyramidRequest }
3723

24+
override string toString() { result = "pyramid.view.argument" }
3825
}
39-
Lines changed: 7 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,41 +1,32 @@
11
import python
2-
3-
42
import semmle.python.security.TaintTracking
53
import semmle.python.security.strings.Basic
64
import semmle.python.web.Http
7-
85
private import semmle.python.web.pyramid.View
96
private import semmle.python.web.Http
107

11-
/** A pyramid response, which is vulnerable to any sort of
12-
* http response malice. */
8+
/**
9+
* A pyramid response, which is vulnerable to any sort of
10+
* http response malice.
11+
*/
1312
class PyramidRoutedResponse extends HttpResponseTaintSink {
14-
1513
PyramidRoutedResponse() {
1614
exists(PyFunctionObject view |
1715
is_pyramid_view_function(view.getFunction()) and
1816
this = view.getAReturnedNode()
1917
)
2018
}
2119

22-
override predicate sinks(TaintKind kind) {
23-
kind instanceof StringKind
24-
}
25-
26-
override string toString() {
27-
result = "pyramid.routed.response"
28-
}
20+
override predicate sinks(TaintKind kind) { kind instanceof StringKind }
2921

22+
override string toString() { result = "pyramid.routed.response" }
3023
}
3124

32-
3325
class PyramidCookieSet extends CookieSet, CallNode {
34-
3526
PyramidCookieSet() {
3627
exists(ControlFlowNode f |
3728
f = this.getFunction().(AttrNode).getObject("set_cookie") and
38-
f.refersTo(_, ModuleObject::named("pyramid").attr("Response"), _)
29+
f.pointsTo().getClass() = Value::named("pyramid.response.Response")
3930
)
4031
}
4132

@@ -44,5 +35,4 @@ class PyramidCookieSet extends CookieSet, CallNode {
4435
override ControlFlowNode getKey() { result = this.getArg(0) }
4536

4637
override ControlFlowNode getValue() { result = this.getArg(1) }
47-
4838
}
Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,9 @@
11
import python
22

3-
ModuleObject thePyramidViewModule() {
4-
result.getName() = "pyramid.view"
5-
}
3+
ModuleValue thePyramidViewModule() { result.getName() = "pyramid.view" }
64

7-
Object thePyramidViewConfig() {
8-
result = thePyramidViewModule().attr("view_config")
9-
}
5+
Value thePyramidViewConfig() { result = thePyramidViewModule().attr("view_config") }
106

117
predicate is_pyramid_view_function(Function func) {
12-
func.getADecorator().refersTo(_, thePyramidViewConfig(), _)
8+
func.getADecorator().pointsTo().getClass() = thePyramidViewConfig()
139
}
14-
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
| test.py:7 | Function home |
2+
| test.py:15 | Function greet |
3+
| test.py:24 | Function stuff |
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import python
2+
3+
import semmle.python.web.pyramid.View
4+
5+
from Function func
6+
7+
where is_pyramid_view_function(func)
8+
9+
select func.getLocation().toString(), func.toString()
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
| test.py:8 | Response() | externally controlled string |
2+
| test.py:17 | Response() | externally controlled string |
3+
| test.py:25 | Dict | externally controlled string |
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
2+
import python
3+
4+
import semmle.python.web.HttpRequest
5+
import semmle.python.web.HttpResponse
6+
import semmle.python.security.strings.Untrusted
7+
8+
9+
from TaintSink sink, TaintKind kind
10+
where sink.sinks(kind) and sink.getLocation().getFile().getName().matches("%test.py")
11+
select sink.getLocation().toString(), sink.(ControlFlowNode).getNode().toString(), kind
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
| test.py:7 | request | pyramid.request |
2+
| test.py:15 | request | pyramid.request |
3+
| test.py:24 | request | pyramid.request |

0 commit comments

Comments
 (0)