mirror of
https://github.com/github/codeql.git
synced 2025-12-19 02:13:17 +01:00
This is the quick-and-dirty solution, as discussed. An even quicker-and-dirtier solution would have used `ModuleValue::attr` and take the `getOrigin` of that as the source of the jump step. However, this turns out to be a bad choice, since `attr` might fail to have a value for the given attribute (for a variety of reasons). Thus, we instead appeal to a helper predicate that keeps track of which names are defined by which right-hand-sides in a given module. (Observe that type tracking works correctly for `x` in `mymodule.py`, even though `x` is never assigned a value in the eyes of the Value API.) This means that points-to is only used to actually figure out if the object we're looking an attribute up on is a module or not. This is the next thing to replace in order to eliminate the dependence on points-to, but this will require some care to ensure that all module lookups are handled correctly. Only two test files needed to be changed for the tests to pass. The first was the fixed false negative in the type tracker, and the other was a bunch of missing flow in the regression test. I have manually removed the `# Flow not found` annotations to make them consistent with the output. Pay particular attention to the annotation on line 117 -- I believe it was misplaced and should have been on line 106 instead (where, indeed, we now have flow where none appeared before).
215 lines
3.2 KiB
Python
215 lines
3.2 KiB
Python
|
|
def test1():
|
|
SINK(SOURCE)
|
|
|
|
def test2():
|
|
s = SOURCE
|
|
SINK(s)
|
|
|
|
def source():
|
|
return SOURCE
|
|
|
|
def sink(arg):
|
|
SINK(arg)
|
|
|
|
def test3():
|
|
t = source()
|
|
SINK(t)
|
|
|
|
def test4():
|
|
t = SOURCE
|
|
sink(t)
|
|
|
|
def test5():
|
|
t = source()
|
|
sink(t)
|
|
|
|
def test6(cond):
|
|
if cond:
|
|
t = "Safe"
|
|
else:
|
|
t = SOURCE
|
|
if cond:
|
|
SINK_F(t)
|
|
|
|
def test7(cond):
|
|
if cond:
|
|
t = SOURCE
|
|
else:
|
|
t = "Safe"
|
|
if cond:
|
|
SINK(t)
|
|
|
|
def source2():
|
|
return source()
|
|
|
|
def sink2(arg):
|
|
sink(arg)
|
|
|
|
def sink3(cond, arg):
|
|
if cond:
|
|
sink(arg)
|
|
|
|
def test8(cond): # This test currently adds nothing, as we only track SOURCE -> SINK, and previous tests already add flow from line 10 to line 13
|
|
t = source2()
|
|
sink2(t)
|
|
|
|
#False positive
|
|
def test9(cond):
|
|
if cond:
|
|
t = "Safe"
|
|
else:
|
|
t = SOURCE
|
|
sink3(cond, t)
|
|
|
|
def test10(cond):
|
|
if cond:
|
|
t = SOURCE
|
|
else:
|
|
t = "Safe"
|
|
sink3(cond, t)
|
|
|
|
def hub(arg):
|
|
return arg
|
|
|
|
def test11():
|
|
t = SOURCE
|
|
t = hub(t)
|
|
SINK(t)
|
|
|
|
def test12():
|
|
t = "safe"
|
|
t = hub(t)
|
|
SINK_F(t)
|
|
|
|
import module
|
|
|
|
def test13():
|
|
t = module.dangerous
|
|
SINK(t)
|
|
|
|
def test14():
|
|
t = module.safe
|
|
SINK_F(t)
|
|
|
|
def test15():
|
|
t = module.safe2
|
|
SINK_F(t)
|
|
|
|
def test16():
|
|
t = module.dangerous_func()
|
|
SINK(t)
|
|
|
|
class C(object): pass
|
|
|
|
def x_sink(arg):
|
|
SINK(arg.x)
|
|
|
|
def test17():
|
|
t = C()
|
|
t.x = module.dangerous
|
|
SINK(t.x)
|
|
|
|
def test18():
|
|
t = C()
|
|
t.x = module.dangerous
|
|
t = hub(t)
|
|
x_sink(t)
|
|
|
|
def test19():
|
|
t = CUSTOM_SOURCE
|
|
t = hub(TAINT_FROM_ARG(t))
|
|
CUSTOM_SINK(t)
|
|
|
|
def test20(cond):
|
|
if cond:
|
|
t = CUSTOM_SOURCE
|
|
else:
|
|
t = SOURCE
|
|
if cond:
|
|
CUSTOM_SINK(t)
|
|
else:
|
|
SINK(t)
|
|
|
|
def test21(cond):
|
|
if cond:
|
|
t = CUSTOM_SOURCE
|
|
else:
|
|
t = SOURCE
|
|
if not cond:
|
|
CUSTOM_SINK_F(t)
|
|
else:
|
|
SINK_F(t)
|
|
|
|
def test22(cond):
|
|
if cond:
|
|
t = CUSTOM_SOURCE
|
|
else:
|
|
t = SOURCE
|
|
t = TAINT_FROM_ARG(t) # Blocks data flow
|
|
if cond:
|
|
CUSTOM_SINK(t)
|
|
else:
|
|
SINK(t)
|
|
|
|
from module import dangerous as unsafe
|
|
SINK(unsafe)
|
|
|
|
def test23():
|
|
with SOURCE as t:
|
|
SINK(t)
|
|
|
|
def test24():
|
|
s = SOURCE
|
|
SANITIZE(s) # Does not block data flow
|
|
SINK_F(s)
|
|
|
|
def test_update_extend(x, y):
|
|
l = [SOURCE]
|
|
d = {"key" : SOURCE}
|
|
x.extend(l)
|
|
y.update(d)
|
|
SINK(x[0]) # Flow not found
|
|
SINK(y["key"]) # Flow not found
|
|
l2 = list(l)
|
|
d2 = dict(d)
|
|
|
|
def test_truth():
|
|
t = SOURCE
|
|
if t:
|
|
SINK(t)
|
|
else:
|
|
SINK_F(t) # False positive
|
|
if not t:
|
|
SINK_F(t) # False positive
|
|
else:
|
|
SINK(t)
|
|
|
|
def test_early_exit():
|
|
t = FALSEY
|
|
if not t:
|
|
return
|
|
t
|
|
|
|
def flow_through_type_test_if_no_class():
|
|
t = SOURCE
|
|
if isinstance(t, str):
|
|
SINK(t) # Flows's both here..
|
|
else:
|
|
SINK(t) # ..and here
|
|
|
|
def flow_in_iteration():
|
|
t = [SOURCE]
|
|
for i in t:
|
|
SINK(i) # Flow not found
|
|
SINK(i) # Flow not found
|
|
|
|
def flow_in_generator():
|
|
seq = [SOURCE]
|
|
for i in seq:
|
|
yield i
|
|
|
|
def flow_from_generator():
|
|
for x in flow_in_generator():
|
|
SINK(x) # Flow not found
|