Skip to content

Commit 5a2dfd4

Browse files
authored
Merge pull request #2639 from RasmusWL/python-improve-dict-taint
Python: Improve tests for tainted collections
2 parents 98d527c + 5778764 commit 5a2dfd4

File tree

10 files changed

+309
-113
lines changed

10 files changed

+309
-113
lines changed
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
import python
2+
import semmle.python.security.TaintTracking
3+
import semmle.python.security.strings.Untrusted
4+
5+
6+
class SimpleSource extends TaintSource {
7+
8+
SimpleSource() { this.(NameNode).getId() = "TAINTED_STRING" }
9+
10+
override predicate isSourceOf(TaintKind kind) {
11+
kind instanceof ExternalStringKind
12+
}
13+
14+
override string toString() {
15+
result = "taint source"
16+
}
17+
18+
}
19+
20+
class ListSource extends TaintSource {
21+
22+
ListSource() { this.(NameNode).getId() = "TAINTED_LIST" }
23+
24+
override predicate isSourceOf(TaintKind kind) {
25+
kind instanceof ExternalStringSequenceKind
26+
}
27+
28+
override string toString() {
29+
result = "list taint source"
30+
}
31+
32+
}
33+
34+
class DictSource extends TaintSource {
35+
36+
DictSource() { this.(NameNode).getId() = "TAINTED_DICT" }
37+
38+
override predicate isSourceOf(TaintKind kind) {
39+
kind instanceof ExternalStringDictKind
40+
}
41+
42+
override string toString() {
43+
result = "dict taint source"
44+
}
45+
46+
}
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
| Taint [externally controlled string] | test.py:9 | test.py:9:20:9:35 | List | | --> | Taint [externally controlled string] | test.py:14 | test.py:14:14:14:25 | tainted_list | |
2+
| Taint [externally controlled string] | test.py:9 | test.py:9:20:9:35 | List | | --> | Taint [externally controlled string] | test.py:20 | test.py:20:15:20:26 | tainted_list | |
3+
| Taint [externally controlled string] | test.py:9 | test.py:9:20:9:35 | List | | --> | Taint [externally controlled string] | test.py:21 | test.py:21:13:21:24 | tainted_list | |
4+
| Taint [externally controlled string] | test.py:9 | test.py:9:20:9:35 | List | | --> | Taint [externally controlled string] | test.py:22 | test.py:22:19:22:30 | tainted_list | |
5+
| Taint [externally controlled string] | test.py:10 | test.py:10:22:10:36 | Tuple | | --> | Taint [externally controlled string] | test.py:15 | test.py:15:14:15:26 | tainted_tuple | |
6+
| Taint [externally controlled string] | test.py:14 | test.py:14:9:14:26 | list() | | --> | Taint [externally controlled string] | test.py:23 | test.py:23:10:23:10 | a | |
7+
| Taint [externally controlled string] | test.py:14 | test.py:14:14:14:25 | tainted_list | | --> | Taint [externally controlled string] | test.py:14 | test.py:14:9:14:26 | list() | |
8+
| Taint [externally controlled string] | test.py:15 | test.py:15:9:15:27 | list() | | --> | Taint [externally controlled string] | test.py:23 | test.py:23:13:23:13 | b | |
9+
| Taint [externally controlled string] | test.py:15 | test.py:15:14:15:26 | tainted_tuple | | --> | Taint [externally controlled string] | test.py:15 | test.py:15:9:15:27 | list() | |
10+
| Taint [externally controlled string] | test.py:17 | test.py:17:9:17:35 | list() | | --> | Taint [externally controlled string] | test.py:23 | test.py:23:19:23:19 | d | |
11+
| Taint [externally controlled string] | test.py:17 | test.py:17:14:17:34 | Attribute() | | --> | Taint [externally controlled string] | test.py:17 | test.py:17:9:17:35 | list() | |
12+
| Taint [externally controlled string] | test.py:20 | test.py:20:9:20:27 | tuple() | | --> | Taint [externally controlled string] | test.py:23 | test.py:23:25:23:25 | f | |
13+
| Taint [externally controlled string] | test.py:20 | test.py:20:15:20:26 | tainted_list | | --> | Taint [externally controlled string] | test.py:20 | test.py:20:9:20:27 | tuple() | |
14+
| Taint [externally controlled string] | test.py:21 | test.py:21:9:21:25 | set() | | --> | Taint [externally controlled string] | test.py:23 | test.py:23:28:23:28 | g | |
15+
| Taint [externally controlled string] | test.py:21 | test.py:21:13:21:24 | tainted_list | | --> | Taint [externally controlled string] | test.py:21 | test.py:21:9:21:25 | set() | |
16+
| Taint [externally controlled string] | test.py:26 | test.py:26:20:26:31 | TAINTED_LIST | | --> | Taint [externally controlled string] | test.py:27 | test.py:27:9:27:20 | tainted_list | |
17+
| Taint [externally controlled string] | test.py:26 | test.py:26:20:26:31 | TAINTED_LIST | | --> | Taint [externally controlled string] | test.py:28 | test.py:28:9:28:20 | tainted_list | |
18+
| Taint [externally controlled string] | test.py:26 | test.py:26:20:26:31 | TAINTED_LIST | | --> | Taint [externally controlled string] | test.py:29 | test.py:29:9:29:20 | tainted_list | |
19+
| Taint [externally controlled string] | test.py:26 | test.py:26:20:26:31 | TAINTED_LIST | | --> | Taint [externally controlled string] | test.py:30 | test.py:30:9:30:20 | tainted_list | |
20+
| Taint [externally controlled string] | test.py:26 | test.py:26:20:26:31 | TAINTED_LIST | | --> | Taint [externally controlled string] | test.py:31 | test.py:31:15:31:26 | tainted_list | |
21+
| Taint [externally controlled string] | test.py:26 | test.py:26:20:26:31 | TAINTED_LIST | | --> | Taint [externally controlled string] | test.py:33 | test.py:33:14:33:25 | tainted_list | |
22+
| Taint [externally controlled string] | test.py:26 | test.py:26:20:26:31 | TAINTED_LIST | | --> | Taint [externally controlled string] | test.py:35 | test.py:35:23:35:34 | tainted_list | |
23+
| Taint [externally controlled string] | test.py:27 | test.py:27:9:27:20 | tainted_list | | --> | Taint externally controlled string | test.py:27 | test.py:27:9:27:23 | Subscript | |
24+
| Taint [externally controlled string] | test.py:28 | test.py:28:9:28:20 | tainted_list | | --> | Taint externally controlled string | test.py:28 | test.py:28:9:28:23 | Subscript | |
25+
| Taint [externally controlled string] | test.py:29 | test.py:29:9:29:20 | tainted_list | | --> | Taint [externally controlled string] | test.py:29 | test.py:29:9:29:25 | Subscript | |
26+
| Taint [externally controlled string] | test.py:29 | test.py:29:9:29:25 | Subscript | | --> | Taint [externally controlled string] | test.py:32 | test.py:32:16:32:16 | c | |
27+
| Taint [externally controlled string] | test.py:30 | test.py:30:9:30:20 | tainted_list | | --> | Taint [externally controlled string] | test.py:30 | test.py:30:9:30:27 | Attribute() | |
28+
| Taint [externally controlled string] | test.py:30 | test.py:30:9:30:27 | Attribute() | | --> | Taint [externally controlled string] | test.py:32 | test.py:32:19:32:19 | d | |
29+
| Taint [externally controlled string] | test.py:33 | test.py:33:14:33:25 | tainted_list | | --> | Taint externally controlled string | test.py:33 | test.py:33:5:33:26 | For | |
30+
| Taint [externally controlled string] | test.py:35 | test.py:35:14:35:35 | reversed() | | --> | Taint externally controlled string | test.py:35 | test.py:35:5:35:36 | For | |
31+
| Taint [externally controlled string] | test.py:35 | test.py:35:23:35:34 | tainted_list | | --> | Taint [externally controlled string] | test.py:35 | test.py:35:14:35:35 | reversed() | |
32+
| Taint [externally controlled string] | test.py:44 | test.py:44:14:44:34 | Attribute() | | --> | Taint externally controlled string | test.py:44 | test.py:44:5:44:35 | For | |
33+
| Taint externally controlled string | test.py:8 | test.py:8:22:8:35 | TAINTED_STRING | | --> | Taint externally controlled string | test.py:9 | test.py:9:21:9:34 | tainted_string | |
34+
| Taint externally controlled string | test.py:8 | test.py:8:22:8:35 | TAINTED_STRING | | --> | Taint externally controlled string | test.py:10 | test.py:10:22:10:35 | tainted_string | |
35+
| Taint externally controlled string | test.py:8 | test.py:8:22:8:35 | TAINTED_STRING | | --> | Taint externally controlled string | test.py:11 | test.py:11:20:11:33 | tainted_string | |
36+
| Taint externally controlled string | test.py:8 | test.py:8:22:8:35 | TAINTED_STRING | | --> | Taint externally controlled string | test.py:12 | test.py:12:28:12:41 | tainted_string | |
37+
| Taint externally controlled string | test.py:9 | test.py:9:21:9:34 | tainted_string | | --> | Taint [externally controlled string] | test.py:9 | test.py:9:20:9:35 | List | |
38+
| Taint externally controlled string | test.py:10 | test.py:10:22:10:35 | tainted_string | | --> | Taint [externally controlled string] | test.py:10 | test.py:10:22:10:36 | Tuple | |
39+
| Taint externally controlled string | test.py:12 | test.py:12:28:12:41 | tainted_string | | --> | Taint {externally controlled string} | test.py:12 | test.py:12:20:12:42 | Dict | |
40+
| Taint externally controlled string | test.py:27 | test.py:27:9:27:23 | Subscript | | --> | Taint externally controlled string | test.py:32 | test.py:32:10:32:10 | a | |
41+
| Taint externally controlled string | test.py:28 | test.py:28:9:28:23 | Subscript | | --> | Taint externally controlled string | test.py:32 | test.py:32:13:32:13 | b | |
42+
| Taint externally controlled string | test.py:33 | test.py:33:5:33:26 | For | | --> | Taint externally controlled string | test.py:34 | test.py:34:14:34:14 | h | |
43+
| Taint externally controlled string | test.py:35 | test.py:35:5:35:36 | For | | --> | Taint externally controlled string | test.py:36 | test.py:36:14:36:14 | i | |
44+
| Taint externally controlled string | test.py:40 | test.py:40:9:40:28 | Subscript | | --> | Taint externally controlled string | test.py:43 | test.py:43:10:43:10 | a | |
45+
| Taint externally controlled string | test.py:41 | test.py:41:9:41:23 | Subscript | | --> | Taint externally controlled string | test.py:43 | test.py:43:13:43:13 | b | |
46+
| Taint externally controlled string | test.py:44 | test.py:44:5:44:35 | For | | --> | Taint externally controlled string | test.py:45 | test.py:45:14:45:14 | d | |
47+
| Taint externally controlled string | test.py:62 | test.py:62:34:62:47 | TAINTED_STRING | | --> | Taint externally controlled string | test.py:62 | test.py:62:5:62:47 | BinaryExpr | |
48+
| Taint {externally controlled string} | test.py:12 | test.py:12:20:12:42 | Dict | | --> | Taint {externally controlled string} | test.py:17 | test.py:17:14:17:25 | tainted_dict | |
49+
| Taint {externally controlled string} | test.py:12 | test.py:12:20:12:42 | Dict | | --> | Taint {externally controlled string} | test.py:18 | test.py:18:14:18:25 | tainted_dict | |
50+
| Taint {externally controlled string} | test.py:17 | test.py:17:14:17:25 | tainted_dict | | --> | Taint [externally controlled string] | test.py:17 | test.py:17:14:17:34 | Attribute() | |
51+
| Taint {externally controlled string} | test.py:39 | test.py:39:20:39:31 | TAINTED_DICT | | --> | Taint {externally controlled string} | test.py:40 | test.py:40:9:40:20 | tainted_dict | |
52+
| Taint {externally controlled string} | test.py:39 | test.py:39:20:39:31 | TAINTED_DICT | | --> | Taint {externally controlled string} | test.py:41 | test.py:41:9:41:20 | tainted_dict | |
53+
| Taint {externally controlled string} | test.py:39 | test.py:39:20:39:31 | TAINTED_DICT | | --> | Taint {externally controlled string} | test.py:42 | test.py:42:9:42:20 | tainted_dict | |
54+
| Taint {externally controlled string} | test.py:39 | test.py:39:20:39:31 | TAINTED_DICT | | --> | Taint {externally controlled string} | test.py:44 | test.py:44:14:44:25 | tainted_dict | |
55+
| Taint {externally controlled string} | test.py:39 | test.py:39:20:39:31 | TAINTED_DICT | | --> | Taint {externally controlled string} | test.py:46 | test.py:46:17:46:28 | tainted_dict | |
56+
| Taint {externally controlled string} | test.py:40 | test.py:40:9:40:20 | tainted_dict | | --> | Taint externally controlled string | test.py:40 | test.py:40:9:40:28 | Subscript | |
57+
| Taint {externally controlled string} | test.py:41 | test.py:41:9:41:20 | tainted_dict | | --> | Taint externally controlled string | test.py:41 | test.py:41:9:41:23 | Subscript | |
58+
| Taint {externally controlled string} | test.py:42 | test.py:42:9:42:20 | tainted_dict | | --> | Taint {externally controlled string} | test.py:42 | test.py:42:9:42:27 | Attribute() | |
59+
| Taint {externally controlled string} | test.py:42 | test.py:42:9:42:27 | Attribute() | | --> | Taint {externally controlled string} | test.py:43 | test.py:43:16:43:16 | c | |
60+
| Taint {externally controlled string} | test.py:44 | test.py:44:14:44:25 | tainted_dict | | --> | Taint [externally controlled string] | test.py:44 | test.py:44:14:44:34 | Attribute() | |
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import python
2+
import semmle.python.security.TaintTracking
3+
import Taint
4+
5+
from TaintedNode n, TaintedNode s
6+
where
7+
n.getLocation().getFile().getShortName() = "test.py" and
8+
s.getLocation().getFile().getShortName() = "test.py" and
9+
s = n.getASuccessor()
10+
select "Taint " + n.getTaintKind(), n.getLocation().toString(), n.getAstNode(), n.getContext(),
11+
" --> ", "Taint " + s.getTaintKind(), s.getLocation().toString(), s.getAstNode(), s.getContext()
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
| test.py:23 | test_construction | a | [externally controlled string] |
2+
| test.py:23 | test_construction | b | [externally controlled string] |
3+
| test.py:23 | test_construction | c | NO TAINT |
4+
| test.py:23 | test_construction | d | [externally controlled string] |
5+
| test.py:23 | test_construction | e | NO TAINT |
6+
| test.py:23 | test_construction | f | [externally controlled string] |
7+
| test.py:23 | test_construction | g | [externally controlled string] |
8+
| test.py:23 | test_construction | h | NO TAINT |
9+
| test.py:32 | test_access | a | externally controlled string |
10+
| test.py:32 | test_access | b | externally controlled string |
11+
| test.py:32 | test_access | c | [externally controlled string] |
12+
| test.py:32 | test_access | d | [externally controlled string] |
13+
| test.py:32 | test_access | e | NO TAINT |
14+
| test.py:32 | test_access | f | NO TAINT |
15+
| test.py:32 | test_access | g | NO TAINT |
16+
| test.py:34 | test_access | h | externally controlled string |
17+
| test.py:36 | test_access | i | externally controlled string |
18+
| test.py:43 | test_dict_access | a | externally controlled string |
19+
| test.py:43 | test_dict_access | b | externally controlled string |
20+
| test.py:43 | test_dict_access | c | {externally controlled string} |
21+
| test.py:45 | test_dict_access | d | externally controlled string |
22+
| test.py:47 | test_dict_access | e | NO TAINT |
23+
| test.py:58 | test_named_tuple | a | NO TAINT |
24+
| test.py:58 | test_named_tuple | b | NO TAINT |
25+
| test.py:58 | test_named_tuple | c | NO TAINT |
26+
| test.py:58 | test_named_tuple | d | NO TAINT |
27+
| test.py:58 | test_named_tuple | e | NO TAINT |
28+
| test.py:58 | test_named_tuple | f | NO TAINT |
29+
| test.py:67 | test_defaultdict | a | NO TAINT |
30+
| test.py:67 | test_defaultdict | b | NO TAINT |
31+
| test.py:67 | test_defaultdict | c | NO TAINT |
32+
| test.py:69 | test_defaultdict | d | NO TAINT |
33+
| test.py:71 | test_defaultdict | e | NO TAINT |
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import python
2+
import semmle.python.security.TaintTracking
3+
import Taint
4+
5+
from Call call, Expr arg, string taint_string
6+
where
7+
call.getLocation().getFile().getShortName() = "test.py" and
8+
call.getFunc().(Name).getId() = "test" and
9+
arg = call.getAnArg() and
10+
(
11+
not exists(TaintedNode tainted | tainted.getAstNode() = arg) and
12+
taint_string = "NO TAINT"
13+
or
14+
exists(TaintedNode tainted | tainted.getAstNode() = arg |
15+
taint_string = tainted.getTaintKind().toString()
16+
)
17+
)
18+
select arg.getLocation().toString(), call.getScope().(Function).getName(), arg.toString(), taint_string
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
from collections import defaultdict, namedtuple
2+
3+
# Use to show only interesting results in qltest output
4+
def test(*args):
5+
pass
6+
7+
def test_construction():
8+
tainted_string = TAINTED_STRING
9+
tainted_list = [tainted_string]
10+
tainted_tuple = (tainted_string,)
11+
tainted_set = {tainted_string} # TODO: set currently not handled
12+
tainted_dict = {'key': tainted_string}
13+
14+
a = list(tainted_list)
15+
b = list(tainted_tuple)
16+
c = list(tainted_set) # TODO: set currently not handled
17+
d = list(tainted_dict.values())
18+
e = list(tainted_dict.items()) # TODO: dict.items() currently not handled
19+
20+
f = tuple(tainted_list)
21+
g = set(tainted_list)
22+
h = frozenset(tainted_list) # TODO: frozenset constructor currently not handled
23+
test(a, b, c, d, e, f, g, h)
24+
25+
def test_access():
26+
tainted_list = TAINTED_LIST
27+
a = tainted_list[0]
28+
b = tainted_list[x]
29+
c = tainted_list[y:z]
30+
d = tainted_list.copy()
31+
e, f, g = tainted_list # TODO: currently not handled
32+
test(a, b, c, d, e, f, g)
33+
for h in tainted_list:
34+
test(h)
35+
for i in reversed(tainted_list):
36+
test(i)
37+
38+
def test_dict_access(x):
39+
tainted_dict = TAINTED_DICT
40+
a = tainted_dict["name"]
41+
b = tainted_dict[x]
42+
c = tainted_dict.copy()
43+
test(a, b, c)
44+
for d in tainted_dict.values():
45+
test(d)
46+
for _, e in tainted_dict.items(): # TODO: dict.items() currently not handled
47+
test(e)
48+
49+
def test_named_tuple(): # TODO: namedtuple currently not handled
50+
Point = namedtuple('Point', ['x', 'y'])
51+
point = Point(TAINTED_STRING, 'const')
52+
53+
a = point[0]
54+
b = point.x
55+
c = point[1]
56+
d = point.y
57+
e, f = point
58+
test(a, b, c, d, e, f)
59+
60+
def test_defaultdict(key, x): # TODO: defaultdict currently not handled
61+
tainted_default_dict = defaultdict(str)
62+
tainted_default_dict[key] += TAINTED_STRING
63+
64+
a = tainted_dict["name"]
65+
b = tainted_dict[x]
66+
c = tainted_dict.copy()
67+
test(a, b, c)
68+
for d in tainted_dict.values():
69+
test(d)
70+
for _, e in tainted_dict.items():
71+
test(e)

0 commit comments

Comments
 (0)