Python: Require MISSING: flow annotations for normal data-flow tests

I had to rewrite the SINK1-SINK7 definitions, since this new requirement
complained that we had to add this `MISSING: flow` annotation :D

Doing this implementation also revealed that there was a bug, since I
did not compare files when checking for these `MISSING:` annotations. So
fixed that up in the implementation for inline taint tests as well.

(extra whitespace in argumentPassing.py to avoid changing line numbers
for other tests)
This commit is contained in:
Rasmus Wriedt Larsen
2022-02-01 16:46:37 +01:00
parent 2bc4a60496
commit 5ee755db09
8 changed files with 50 additions and 23 deletions

View File

@@ -16,3 +16,22 @@ class DataFlowTest extends FlowTest {
super.hasActualResult(location, element, tag, value)
}
}
query predicate missingAnnotationOnSINK(Location location, string error, string element) {
error = "ERROR, you should add `# $ MISSING: flow` annotation" and
exists(DataFlow::Node sink |
exists(DataFlow::CallCfgNode call |
// note: we only care about `SINK` and not `SINK_F`, so we have to reconstruct manually.
call.getFunction().asCfgNode().(NameNode).getId() = "SINK" and
(sink = call.getArg(_) or sink = call.getArgByName(_))
) and
location = sink.getLocation() and
element = prettyExpr(sink.asExpr()) and
not any(TestConfiguration config).hasFlow(_, sink) and
not exists(FalseNegativeExpectation missingResult |
missingResult.getTag() = "flow" and
missingResult.getLocation().getFile() = location.getFile() and
missingResult.getLocation().getStartLine() = location.getStartLine()
)
)
}

View File

@@ -0,0 +1,2 @@
missingAnnotationOnSINK
failures

View File

@@ -1,5 +1,6 @@
import sys
import os
import functools
sys.path.append(os.path.dirname(os.path.dirname((__file__))))
from testlib import *
@@ -29,36 +30,35 @@ def SINK_F(x, unexpected=arg):
SINK_TEST(x, test=lambda x: x != unexpected)
def SINK1(x):
SINK(x, expected=arg1)
SINK1 = functools.partial(SINK, expected=arg1)
SINK2 = functools.partial(SINK, expected=arg2)
SINK3 = functools.partial(SINK, expected=arg3)
SINK4 = functools.partial(SINK, expected=arg4)
SINK5 = functools.partial(SINK, expected=arg5)
SINK6 = functools.partial(SINK, expected=arg6)
SINK7 = functools.partial(SINK, expected=arg7)
def SINK2(x):
SINK(x, expected=arg2)
def SINK2_F(x):
SINK_F(x, unexpected=arg2)
def SINK3(x):
SINK(x, expected=arg3)
def SINK4(x):
SINK(x, expected=arg4)
def SINK5(x):
SINK(x, expected=arg5)
def SINK6(x):
SINK(x, expected=arg6)
def SINK7(x):
SINK(x, expected=arg7)
def argument_passing(

View File

@@ -90,11 +90,11 @@ def gen(x, count):
n -= 1
iter = gen(SOURCE, 1)
SINK(iter.__next__())
SINK(iter.__next__()) # $ MISSING: flow
# SINK_F(iter.__next__()) # throws StopIteration, FP
oiter = c.gen(SOURCE, 1)
SINK(oiter.__next__())
SINK(oiter.__next__()) # $ MISSING: flow
# SINK_F(oiter.__next__()) # throws StopIteration, FP
# Coroutine functions
@@ -103,8 +103,8 @@ async def coro(x):
return x
import asyncio
SINK(asyncio.run(coro(SOURCE)))
SINK(asyncio.run(c.coro(SOURCE)))
SINK(asyncio.run(coro(SOURCE))) # $ MISSING: flow
SINK(asyncio.run(c.coro(SOURCE))) # $ MISSING: flow
class A:
@@ -116,7 +116,7 @@ async def agen(x):
a = A()
return await a
SINK(asyncio.run(agen(SOURCE)))
SINK(asyncio.run(agen(SOURCE))) # $ MISSING: flow
# Asynchronous generator functions
# A function or method which is defined using async def and which uses the yield statement is called a asynchronous generator function. Such a function, when called, returns an asynchronous iterator object which can be used in an async for statement to execute the body of the function.

View File

@@ -0,0 +1,2 @@
missingAnnotationOnSINK
failures

View File

@@ -61,7 +61,7 @@ def test_example1_method():
myobj = MyObj("OK")
myobj.setFoo(SOURCE)
SINK(myobj.foo)
SINK(myobj.foo) # $ MISSING: flow
def test_example2():
@@ -81,7 +81,7 @@ def test_example2_method():
a.getObj().foo = x
SINK(a.obj.foo)
SINK(a.obj.foo) # $ MISSING: flow
def test_example3():

View File

@@ -0,0 +1,2 @@
missingAnnotationOnSINK
failures

View File

@@ -100,6 +100,8 @@ query predicate untaintedArgumentToEnsureTaintedNotMarkedAsMissing(
not any(TestTaintTrackingConfiguration config).hasFlow(_, sink) and
location = sink.getLocation() and
not exists(FalseNegativeExpectation missingResult |
missingResult.getTag() = "tainted" and
missingResult.getLocation().getFile() = location.getFile() and
missingResult.getLocation().getStartLine() = location.getStartLine()
)
)