python: add summaries for

copy, pop, get, getitem, setdefault

Also add read steps to taint tracking.

Reading from a tainted collection can be done in two situations:
1. There is an acces path
    In this case a read step (possibly from a flow summary)
    gives rise to a taint step.
2. There is no access path
    In this case an explicit taint step (possibly via a flow
    summary) should exist.
This commit is contained in:
Rasmus Lerchedahl Petersen
2023-05-23 14:22:52 +02:00
parent 144df9a39e
commit 9cb83fcdc9
36 changed files with 963 additions and 99 deletions

View File

@@ -123,23 +123,23 @@ def test_nested_list_display():
# 6.2.6. Set displays
def test_set_display():
x = {SOURCE}
SINK(x.pop()) #$ MISSING:flow="SOURCE, l:-1 -> x.pop()"
SINK(x.pop()) #$ flow="SOURCE, l:-1 -> x.pop()"
def test_set_comprehension():
x = {SOURCE for y in [NONSOURCE]}
SINK(x.pop()) #$ MISSING:flow="SOURCE, l:-1 -> x.pop()"
SINK(x.pop()) #$ flow="SOURCE, l:-1 -> x.pop()"
def test_set_comprehension_flow():
x = {y for y in [SOURCE]}
SINK(x.pop()) #$ MISSING:flow="SOURCE, l:-1 -> x.pop()"
SINK(x.pop()) #$ flow="SOURCE, l:-1 -> x.pop()"
def test_set_comprehension_inflow():
l = {SOURCE}
x = {y for y in l}
SINK(x.pop()) #$ MISSING:flow="SOURCE, l:-2 -> x.pop()"
SINK(x.pop()) #$ flow="SOURCE, l:-2 -> x.pop()"
def test_nested_set_display():
@@ -155,7 +155,7 @@ def test_dict_display():
def test_dict_display_pop():
x = {"s": SOURCE}
SINK(x.pop("s")) #$ MISSING:flow="SOURCE, l:-1 -> x.pop(..)"
SINK(x.pop("s")) #$ flow="SOURCE, l:-1 -> x.pop(..)"
def test_dict_comprehension():

View File

@@ -100,19 +100,19 @@ def test_set_from_list():
l = [SOURCE]
s = set(l)
v = s.pop()
SINK(v) #$ MISSING:flow="SOURCE, l:-3 -> v"
SINK(v) #$ flow="SOURCE, l:-3 -> v"
def test_set_from_tuple():
t = (SOURCE,)
s = set(t)
v = s.pop()
SINK(v) #$ MISSING:flow="SOURCE, l:-3 -> v"
SINK(v) #$ flow="SOURCE, l:-3 -> v"
def test_set_from_set():
s0 = {SOURCE}
s = set(s0)
v = s.pop()
SINK(v) #$ MISSING:flow="SOURCE, l:-3 -> v"
SINK(v) #$ flow="SOURCE, l:-3 -> v"
def test_set_from_dict():
d = {SOURCE: "val"}
@@ -149,24 +149,24 @@ def test_dict_from_dict():
def test_list_pop():
l = [SOURCE]
v = l.pop()
SINK(v) #$ MISSING:flow="SOURCE, l:-2 -> v"
SINK(v) #$ flow="SOURCE, l:-2 -> v"
def test_list_pop_index():
l = [SOURCE]
v = l.pop(0)
SINK(v) #$ MISSING: flow="SOURCE, l:-2 -> v"
SINK(v) #$ flow="SOURCE, l:-2 -> v"
def test_list_pop_index_imprecise():
l = [SOURCE, NONSOURCE]
v = l.pop(1)
SINK_F(v)
SINK_F(v) #$ SPURIOUS: flow="SOURCE, l:-2 -> v"
@expects(2)
def test_list_copy():
l0 = [SOURCE, NONSOURCE]
l = l0.copy()
SINK(l[0]) #$ MISSING: flow="SOURCE, l:-2 -> l[0]"
SINK_F(l[1])
SINK(l[0]) #$ flow="SOURCE, l:-2 -> l[0]"
SINK_F(l[1]) #$ SPURIOUS: flow="SOURCE, l:-3 -> l[1]"
def test_list_append():
l = [NONSOURCE]
@@ -178,12 +178,12 @@ def test_list_append():
def test_set_pop():
s = {SOURCE}
v = s.pop()
SINK(v) #$ MISSING:flow="SOURCE, l:-2 -> v"
SINK(v) #$ flow="SOURCE, l:-2 -> v"
def test_set_copy():
s0 = {SOURCE}
s = s0.copy()
SINK(s.pop()) #$ MISSING: flow="SOURCE, l:-2 -> s.pop()"
SINK(s.pop()) #$ flow="SOURCE, l:-2 -> s.pop()"
def test_set_add():
s = set([])
@@ -218,32 +218,32 @@ def test_dict_items():
def test_dict_pop():
d = {'k': SOURCE}
v = d.pop("k")
SINK(v) #$ MISSING:flow="SOURCE, l:-2 -> v"
SINK(v) #$ flow="SOURCE, l:-2 -> v"
v1 = d.pop("k", NONSOURCE)
SINK_F(v1)
SINK_F(v1) #$ SPURIOUS: flow="SOURCE, l:-4 -> v1"
v2 = d.pop("non-existing", SOURCE)
SINK(v2) #$ MISSING: flow="SOURCE, l:-1 -> v2"
SINK(v2) #$ flow="SOURCE, l:-1 -> v2"
@expects(2)
def test_dict_get():
d = {'k': SOURCE}
v = d.get("k")
SINK(v) #$ MISSING:flow="SOURCE, l:-2 -> v"
SINK(v) #$ flow="SOURCE, l:-2 -> v"
v1 = d.get("non-existing", SOURCE)
SINK(v1) #$ MISSING: flow="SOURCE, l:-1 -> v1"
SINK(v1) #$ flow="SOURCE, l:-1 -> v1"
@expects(2)
def test_dict_popitem():
d = {'k': SOURCE}
t = d.popitem() # could be any pair (before 3.7), but we only have one
SINK_F(t[0])
SINK(t[1]) #$ MISSING: flow="SOURCE, l:-3 -> t[1]"
SINK(t[1]) #$ flow="SOURCE, l:-3 -> t[1]"
@expects(2)
def test_dict_copy():
d = {'k': SOURCE, 'k1': NONSOURCE}
d1 = d.copy()
SINK(d1["k"]) #$ MISSING: flow="SOURCE, l:-2 -> d[k]"
SINK(d1["k"]) #$ flow="SOURCE, l:-2 -> d1['k']"
SINK_F(d1["k1"])

View File

@@ -35,7 +35,7 @@ def SINK_F(x):
def test_dict_literal():
d = {"key": SOURCE}
SINK(d["key"]) # $ flow="SOURCE, l:-1 -> d['key']"
SINK(d.get("key")) # $ MISSING:flow="SOURCE, l:-2 -> d.get(..)"
SINK(d.get("key")) # $ flow="SOURCE, l:-2 -> d.get(..)"
@expects(2) # $ unresolved_call=expects(..) unresolved_call=expects(..)(..)
@@ -43,7 +43,7 @@ def test_dict_update():
d = {}
d["key"] = SOURCE
SINK(d["key"]) # $ flow="SOURCE, l:-1 -> d['key']"
SINK(d.get("key")) # $ MISSING:flow="SOURCE, l:-2 -> d.get(..)"
SINK(d.get("key")) # $ flow="SOURCE, l:-2 -> d.get(..)"
@expects(3) # $ unresolved_call=expects(..) unresolved_call=expects(..)(..)
def test_dict_setdefault():
@@ -51,7 +51,7 @@ def test_dict_setdefault():
x = d.setdefault("key", SOURCE)
SINK(x) # $ flow="SOURCE, l:-1 -> x"
SINK(d["key"]) # $ flow="SOURCE, l:-2 -> d['key']"
SINK(d.setdefault("key", NONSOURCE)) # $ MISSING:flow="SOURCE, l:-3 -> d.setdefault(..)"
SINK(d.setdefault("key", NONSOURCE)) # $ flow="SOURCE, l:-3 -> d.setdefault(..)"
@expects(2) # $ unresolved_call=expects(..) unresolved_call=expects(..)(..)
def test_dict_override():

View File

@@ -13,7 +13,7 @@ def test_access():
tainted_list = TAINTED_LIST
ensure_tainted(
tainted_list.copy(), # $ MISSING: tainted
tainted_list.copy(), # $ tainted
)
for ((x, y, *z), a, b) in tainted_list:

View File

@@ -103,9 +103,9 @@ def test_dict_access(x):
ensure_tainted(
tainted_dict["name"], # $ tainted
tainted_dict.get("name"), # $ MISSING: tainted
tainted_dict.get("name"), # $ tainted
tainted_dict[x], # $ tainted
tainted_dict.copy(), # $ MISSING: tainted
tainted_dict.copy(), # $ tainted
)
for v in tainted_dict.values():