Skip to content

Commit d96ef73

Browse files
committed
Python: Handle taint for f-strings
Which we seem to not handle in the current taint tracking :O f-strings needs to be Python 3 only, so enabled that test setup. I really liked the idea for having the version specific tests right next to the normal tests, so you don't have to look in test/experimental/3/dataflow/i/will/forget/to/look/here.
1 parent cb4b4e9 commit d96ef73

File tree

7 files changed

+64
-0
lines changed

7 files changed

+64
-0
lines changed

python/ql/src/experimental/dataflow/internal/TaintTrackingPrivate.qll

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,9 @@ predicate stringMethods(DataFlow::CfgNode nodeFrom, DataFlow::CfgNode nodeTo) {
125125
mult.getOp() instanceof Mult and
126126
mult.getLeft() = nodeFrom.getNode()
127127
)
128+
or
129+
// f-strings
130+
nodeTo.getNode().getNode().(Fstring).getAValue() = nodeFrom.getNode().getNode()
128131
// TODO: Handle encode/decode from base64/quopri
129132
// TODO: Handle os.path.join
130133
// TODO: Handle functions in https://docs.python.org/3/library/binascii.html

python/ql/test/experimental/dataflow/tainttracking/string/TestTaint.ql renamed to python/ql/test/experimental/dataflow/tainttracking/TestTaint.ql

File renamed without changes.
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
| test.py:28 | fail | binary_decode_encode | base64.a85encode(..) |
2+
| test.py:29 | fail | binary_decode_encode | base64.a85decode(..) |
3+
| test.py:32 | fail | binary_decode_encode | base64.b85encode(..) |
4+
| test.py:33 | fail | binary_decode_encode | base64.b85decode(..) |
5+
| test.py:36 | fail | binary_decode_encode | base64.encodebytes(..) |
6+
| test.py:37 | fail | binary_decode_encode | base64.decodebytes(..) |
7+
| test.py:45 | ok | f_strings | Fstring |
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
../TestTaint.ql
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
semmle-extractor-options: --max-import-depth=1 --lang=3
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
# Python 3 specific taint tracking for string
2+
3+
TAINTED_STRING = "TAINTED_STRING"
4+
TAINTED_BYTES = b"TAINTED_BYTES"
5+
6+
7+
def ensure_tainted(*args):
8+
print("- ensure_tainted")
9+
for i, arg in enumerate(args):
10+
print("arg {}: {!r}".format(i, arg))
11+
12+
13+
def ensure_not_tainted(*args):
14+
print("- ensure_not_tainted")
15+
for i, arg in enumerate(args):
16+
print("arg {}: {!r}".format(i, arg))
17+
18+
19+
# Actual tests
20+
21+
def binary_decode_encode():
22+
print("\n#percent_fmt")
23+
tb = TAINTED_BYTES
24+
import base64
25+
26+
ensure_tainted(
27+
# New in Python 3.4
28+
base64.a85encode(tb),
29+
base64.a85decode(base64.a85encode(tb)),
30+
31+
# New in Python 3.4
32+
base64.b85encode(tb),
33+
base64.b85decode(base64.b85encode(tb)),
34+
35+
# New in Python 3.1
36+
base64.encodebytes(tb),
37+
base64.decodebytes(base64.encodebytes(tb)),
38+
)
39+
40+
41+
def f_strings():
42+
print("\n#f_strings")
43+
ts = TAINTED_STRING
44+
45+
ensure_tainted(f"foo {ts} bar")
46+
47+
48+
# Make tests runable
49+
50+
binary_decode_encode()
51+
f_strings()
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
../TestTaint.ql

0 commit comments

Comments
 (0)