C++: Change the structure of the 'annotate_path_to_sink' tests to better test path-explanations.

This commit is contained in:
Mathias Vorreiter Pedersen
2021-11-03 20:22:15 +00:00
parent ab37ae6613
commit ae4b6c54bc
4 changed files with 72 additions and 58 deletions

View File

@@ -474,6 +474,24 @@ module TaintedWithPath {
}
}
/**
* INTERNAL: Do not use.
*/
module Private {
/** Gets a predecessor `PathNode` of `pathNode`, if any. */
PathNode getAPredecessor(PathNode pathNode) { edges(result, pathNode) }
/** Gets the element that `pathNode` wraps, if any. */
Element getElementFromPathNode(PathNode pathNode) {
exists(DataFlow::Node node | node = pathNode.(WrapPathNode).inner().getNode() |
result = node.asExpr() or
result = node.asParameter()
)
or
result = pathNode.(EndpointPathNode).inner()
}
}
private class WrapPathNode extends PathNode, TWrapPathNode {
DataFlow3::PathNode inner() { this = TWrapPathNode(result) }

View File

@@ -4,8 +4,8 @@ using SinkFunction = void (*)(int);
void notSink(int notSinkParam);
void callsSink(int sinkParam) {
sink(sinkParam); // $ ast,ir=31:28 ast,ir=32:31 ast,ir=34:22 MISSING: ast,ir=28
void callsSink(int sinkParam) { // $ ir-path=31:28 ir-path=32:31 ir-path=34:22
sink(sinkParam); // $ ir-sink=31:28 ir-sink=32:31 ir-sink=34:22 ast=31:28 ast=32:31 ast=34:22 MISSING: ast,ir=28
}
struct {
@@ -25,13 +25,13 @@ void assignGlobals() {
};
void testStruct() {
globalStruct.sinkPtr(atoi(getenv("TAINTED"))); // $ MISSING: ast,ir
globalStruct.sinkPtr(atoi(getenv("TAINTED"))); // $ ir MISSING: ast
globalStruct.notSinkPtr(atoi(getenv("TAINTED"))); // clean
globalUnion.sinkPtr(atoi(getenv("TAINTED"))); // $ ast,ir
globalUnion.notSinkPtr(atoi(getenv("TAINTED"))); // $ ast,ir
globalUnion.sinkPtr(atoi(getenv("TAINTED"))); // $ ast ir-path=31:28 ir-path=32:31 ir-path=34:22
globalUnion.notSinkPtr(atoi(getenv("TAINTED"))); // $ ast ir-path=31:28 ir-path=32:31 ir-path=34:22
globalSinkPtr(atoi(getenv("TAINTED"))); // $ ast,ir
globalSinkPtr(atoi(getenv("TAINTED"))); // $ ast ir-path=31:28 ir-path=32:31 ir-path=34:22
}
class B {
@@ -48,19 +48,19 @@ class D2 : public D1 {
class D3 : public D2 {
public:
void f(const char* p) override {
sink(p); // $ ast,ir=58:10 ast,ir=60:17 ast,ir=61:28 ast,ir=62:29 ast,ir=63:33 SPURIOUS: ast,ir=73:30
void f(const char* p) override { // $ ir-path=58:10 ir-path=60:17 ir-path=61:28 ir-path=62:29 ir-path=63:33 ir-path=73:30
sink(p); // $ ir-sink=58:10 ir-sink=60:17 ir-sink=61:28 ir-sink=62:29 ir-sink=63:33 ast=58:10 ast=60:17 ast=61:28 ast=62:29 ast=63:33 SPURIOUS: ast=73:30 ir-sink=73:30
}
};
void test_dynamic_cast() {
B* b = new D3();
b->f(getenv("VAR")); // $ ast,ir
b->f(getenv("VAR")); // $ ast ir-path=58:10 ir-path=60:17 ir-path=61:28 ir-path=62:29 ir-path=63:33 ir-path=73:30
((D2*)b)->f(getenv("VAR")); // $ ast,ir
static_cast<D2*>(b)->f(getenv("VAR")); // $ ast,ir
dynamic_cast<D2*>(b)->f(getenv("VAR")); // $ ast,ir
reinterpret_cast<D2*>(b)->f(getenv("VAR")); // $ ast,ir
((D2*)b)->f(getenv("VAR")); // $ ast ir-path=58:10 ir-path=60:17 ir-path=61:28 ir-path=62:29 ir-path=63:33 ir-path=73:30
static_cast<D2*>(b)->f(getenv("VAR")); // $ ast ir-path=58:10 ir-path=60:17 ir-path=61:28 ir-path=62:29 ir-path=63:33 ir-path=73:30
dynamic_cast<D2*>(b)->f(getenv("VAR")); // $ ast ir-path=58:10 ir-path=60:17 ir-path=61:28 ir-path=62:29 ir-path=63:33 ir-path=73:30
reinterpret_cast<D2*>(b)->f(getenv("VAR")); // $ ast ir-path=58:10 ir-path=60:17 ir-path=61:28 ir-path=62:29 ir-path=63:33 ir-path=73:30
B* b2 = new D2();
b2->f(getenv("VAR"));
@@ -70,5 +70,5 @@ void test_dynamic_cast() {
dynamic_cast<D2*>(b2)->f(getenv("VAR"));
reinterpret_cast<D2*>(b2)->f(getenv("VAR"));
dynamic_cast<D3*>(b2)->f(getenv("VAR")); // $ SPURIOUS: ast,ir
dynamic_cast<D3*>(b2)->f(getenv("VAR")); // $ SPURIOUS: ast ir-path=58:10 ir-path=60:17 ir-path=61:28 ir-path=62:29 ir-path=63:33 ir-path=73:30
}

View File

@@ -9,7 +9,7 @@ import semmle.code.cpp.ir.dataflow.DefaultTaintTracking as IRDefaultTaintTrackin
import IRDefaultTaintTracking::TaintedWithPath as TaintedWithPath
import TestUtilities.InlineExpectationsTest
predicate isSink(Element sink) {
predicate isSinkArgument(Element sink) {
exists(FunctionCall call |
call.getTarget().getName() = "sink" and
sink = call.getAnArgument()
@@ -19,31 +19,27 @@ predicate isSink(Element sink) {
predicate astTaint(Expr source, Element sink) { ASTTaintTracking::tainted(source, sink) }
class SourceConfiguration extends TaintedWithPath::TaintTrackingConfiguration {
override predicate isSink(Element e) { any() }
override predicate isSink(Element e) { isSinkArgument(e) }
}
predicate irTaint(Expr source, Element sink) {
TaintedWithPath::taintedWithPath(source, sink, _, _)
predicate irTaint(Element source, Element sink, string tag) {
exists(TaintedWithPath::PathNode sinkNode, TaintedWithPath::PathNode predNode |
TaintedWithPath::taintedWithPath(source, _, _, sinkNode) and
predNode = TaintedWithPath::Private::getAPredecessor*(sinkNode) and
sink = TaintedWithPath::Private::getElementFromPathNode(predNode) and
if sinkNode = predNode then tag = "ir-sink" else tag = "ir-path"
)
}
class IRDefaultTaintTrackingTest extends InlineExpectationsTest {
IRDefaultTaintTrackingTest() { this = "IRDefaultTaintTrackingTest" }
override string getARelevantTag() { result = "ir" }
override string getARelevantTag() { result = ["ir-path", "ir-sink"] }
override predicate hasActualResult(Location location, string element, string tag, string value) {
exists(Expr source, Element tainted, int n |
tag = "ir" and
irTaint(source, tainted) and
(
isSink(tainted)
or
exists(Element sink |
isSink(sink) and
irTaint(tainted, sink)
)
) and
n = strictcount(Expr otherSource | irTaint(otherSource, tainted)) and
exists(Element source, Element tainted, int n |
irTaint(source, tainted, tag) and
n = strictcount(Element otherSource | irTaint(otherSource, tainted, _)) and
(
n = 1 and value = ""
or
@@ -70,10 +66,10 @@ class ASTTaintTrackingTest extends InlineExpectationsTest {
tag = "ast" and
astTaint(source, tainted) and
(
isSink(tainted)
isSinkArgument(tainted)
or
exists(Element sink |
isSink(sink) and
isSinkArgument(sink) and
astTaint(tainted, sink)
)
) and

View File

@@ -13,8 +13,8 @@ struct S {
}
};
void calls_sink_with_argv(const char* a) {
sink(a); // $ ast,ir=96:26 ast,ir=98:18
void calls_sink_with_argv(const char* a) { // $ ir-path=96:26 ir-path=98:18
sink(a); // $ ast=96:26 ast=98:18 ir-sink=96:26 ir-sink=98:18
}
extern int i;
@@ -26,8 +26,8 @@ public:
class DerivedCallsSink : public BaseWithPureVirtual {
public:
void f(const char* p) override {
sink(p); // $ ir ast=108:10 SPURIOUS: ast=111:10
void f(const char* p) override { // $ ir-path
sink(p); // $ ir-sink ast=108:10 SPURIOUS: ast=111:10
}
};
@@ -38,8 +38,8 @@ public:
class DerivedCallsSinkDiamond1 : virtual public BaseWithPureVirtual {
public:
void f(const char* p) override {
sink(p); // $ ast,ir
void f(const char* p) override { // $ ir-path
sink(p); // $ ast ir-sink
}
};
@@ -49,7 +49,7 @@ public:
};
class DerivesMultiple : public DerivedCallsSinkDiamond1, public DerivedDoesNotCallSinkDiamond2 {
void f(const char* p) override {
void f(const char* p) override { // $ ir-path
DerivedCallsSinkDiamond1::f(p);
}
};
@@ -57,15 +57,15 @@ class DerivesMultiple : public DerivedCallsSinkDiamond1, public DerivedDoesNotCa
template<typename T>
class CRTP {
public:
void f(const char* p) {
void f(const char* p) { // $ ir-path
static_cast<T*>(this)->g(p);
}
};
class CRTPCallsSink : public CRTP<CRTPCallsSink> {
public:
void g(const char* p) {
sink(p); // $ ast,ir
void g(const char* p) { // $ ir-path
sink(p); // $ ast ir-sink
}
};
@@ -78,8 +78,8 @@ class Derived2 : public Derived1 {
class Derived3 : public Derived2 {
public:
void f(const char* p) override {
sink(p); // $ ast,ir=124:19 ast,ir=126:43 ast,ir=128:44
void f(const char* p) override { // $ ir-path=124:19 ir-path=126:43 ir-path=128:44
sink(p); // $ ir-sink=124:19 ir-sink=126:43 ir-sink=128:44 ast,ir=124:19 ast,ir=126:43 ast,ir=128:44
}
};
@@ -89,41 +89,41 @@ class CRTPDoesNotCallSink : public CRTP<CRTPDoesNotCallSink> {
};
int main(int argc, char *argv[]) {
sink(argv[0]); // $ ast,ir
sink(argv[0]); // $ ast ir-path ir-sink
sink(reinterpret_cast<int>(argv)); // $ ast,ir
sink(reinterpret_cast<int>(argv)); // $ ast ir-sink
calls_sink_with_argv(argv[1]); // $ ast,ir
calls_sink_with_argv(argv[1]); // $ ast ir-path=96:26 ir-path=98:18
char*** p = &argv; // $ ast,ir
char*** p = &argv; // $ ast ir-path=96:26 ir-path=98:18
sink(*p[0]); // $ ast,ir
sink(*p[0]); // $ ast ir-sink
calls_sink_with_argv(*p[i]); // $ MISSING: ast,ir
calls_sink_with_argv(*p[i]); // $ MISSING: ast,ir-path
sink(*(argv + 1)); // $ ast,ir
sink(*(argv + 1)); // $ ast ir-path ir-sink
BaseWithPureVirtual* b = new DerivedCallsSink;
b->f(argv[1]); // $ ast,ir
b->f(argv[1]); // $ ast ir-path
b = new DerivedDoesNotCallSink;
b->f(argv[0]); // $ SPURIOUS: ast
BaseWithPureVirtual* b2 = new DerivesMultiple;
b2->f(argv[i]); // $ ast,ir
b2->f(argv[i]); // $ ast ir-path
CRTP<CRTPDoesNotCallSink> crtp_not_call_sink;
crtp_not_call_sink.f(argv[0]); // clean
CRTP<CRTPCallsSink> crtp_calls_sink;
crtp_calls_sink.f(argv[0]); // $ ast,ir
crtp_calls_sink.f(argv[0]); // $ ast ir-path
Derived1* calls_sink = new Derived3;
calls_sink->f(argv[1]); // $ ast,ir
calls_sink->f(argv[1]); // $ ast ir-path=124:19 ir-path=126:43 ir-path=128:44
static_cast<Derived2*>(calls_sink)->f(argv[1]); // $ ast,ir
static_cast<Derived2*>(calls_sink)->f(argv[1]); // $ ast ir-path=124:19 ir-path=126:43 ir-path=128:44
dynamic_cast<Derived2*>(calls_sink)->f(argv[1]); // $ ast,ir
dynamic_cast<Derived2*>(calls_sink)->f(argv[1]); // $ ast ir-path=124:19 ir-path=126:43 ir-path=128:44
}