C++: Add tests with higher level of indirection.

This commit is contained in:
Mathias Vorreiter Pedersen
2024-02-02 12:04:06 +00:00
parent 0729c602c5
commit 439d3d2438
4 changed files with 138 additions and 0 deletions

View File

@@ -49,6 +49,53 @@ module IRTest {
import semmle.code.cpp.ir.dataflow.DataFlow
private import semmle.code.cpp.ir.IR
private import semmle.code.cpp.controlflow.IRGuards
private import semmle.code.cpp.models.interfaces.DataFlow
boolean isOne(string s) {
s = "1" and result = true
or
s = "0" and result = false
}
/**
* A model of a test function called `strdup_ptr_xyz` where `x, y, z in {0, 1}`.
* `x` is 1 if there's flow from the argument to the function return,
* `y` is 1 if there's flow from the first indirection of the argument to
* the first indirection of the function return, and
* `z` is 1 if there's flow from the second indirection of the argument to
* the second indirection of the function return.
*/
class StrDupPtr extends DataFlowFunction {
boolean argToReturnFlow;
boolean argIndToReturnInd;
boolean argIndInToReturnIndInd;
StrDupPtr() {
exists(string r |
r = "strdup_ptr_([01])([01])([01])" and
argToReturnFlow = isOne(this.getName().regexpCapture(r, 1)) and
argIndToReturnInd = isOne(this.getName().regexpCapture(r, 2)) and
argIndInToReturnIndInd = isOne(this.getName().regexpCapture(r, 3))
)
}
/**
* Flow from `**ptr` to `**return`
*/
override predicate hasDataFlow(FunctionInput input, FunctionOutput output) {
argToReturnFlow = true and
input.isParameter(0) and
output.isReturnValue()
or
argIndToReturnInd = true and
input.isParameterDeref(0, 1) and
output.isReturnValueDeref(1)
or
argIndInToReturnIndInd = true and
input.isParameterDeref(0, 2) and
output.isReturnValueDeref(2)
}
}
/**
* A `BarrierGuard` that stops flow to all occurrences of `x` within statement

View File

@@ -24,6 +24,7 @@ postIsInSameCallable
reverseRead
argHasPostUpdate
| flowOut.cpp:55:14:55:16 | * ... | ArgumentNode is missing PostUpdateNode. |
| flowOut.cpp:185:8:185:9 | * ... | ArgumentNode is missing PostUpdateNode. |
| lambdas.cpp:18:7:18:7 | a | ArgumentNode is missing PostUpdateNode. |
| lambdas.cpp:25:2:25:2 | b | ArgumentNode is missing PostUpdateNode. |
| lambdas.cpp:32:2:32:2 | c | ArgumentNode is missing PostUpdateNode. |
@@ -64,6 +65,8 @@ postWithInFlow
| flowOut.cpp:90:3:90:4 | * ... [post update] | PostUpdateNode should not be the target of local flow. |
| flowOut.cpp:90:4:90:4 | q [inner post update] | PostUpdateNode should not be the target of local flow. |
| flowOut.cpp:101:14:101:14 | p [inner post update] | PostUpdateNode should not be the target of local flow. |
| flowOut.cpp:168:3:168:10 | * ... [post update] | PostUpdateNode should not be the target of local flow. |
| flowOut.cpp:168:4:168:10 | toTaint [inner post update] | PostUpdateNode should not be the target of local flow. |
| globals.cpp:13:5:13:19 | flowTestGlobal1 [post update] | PostUpdateNode should not be the target of local flow. |
| globals.cpp:23:5:23:19 | flowTestGlobal2 [post update] | PostUpdateNode should not be the target of local flow. |
| lambdas.cpp:23:3:23:14 | v [post update] | PostUpdateNode should not be the target of local flow. |

View File

@@ -115,4 +115,89 @@ void modify_copy_via_memcpy(char* p) { // $ ast-def=p
void test_modify_copy_via_memcpy(char* p) { // $ ast-def=p
modify_copy_via_memcpy(p);
sink(*p); // clean
}
// These functions from any real database. We add a dataflow model of
// them as part of dataflow library testing.
// `r = strdup_ptr_001`(p) has flow from **p to **r
// `r = strdup_ptr_011`(p) has flow from *p to *r, and **p to **r
// `r = strdup_ptr_111`(p) has flow from p to r, *p to *r, **p to **r
char** strdup_ptr_001(const char** p);
char** strdup_ptr_011(const char** p);
char** strdup_ptr_111(const char** p);
void source_ref_ref(char** toTaint) { // $ ast-def=toTaint ir-def=*toTaint ir-def=**toTaint
// source -> **toTaint
**toTaint = source(true);
}
// This function copies the value of **p into a new location **p2 and then
// taints **p. Thus, **p does not contain tainted data after returning from
// this function.
void modify_copy_via_strdup_ptr_001(char** p) { // $ ast-def=p
// **p -> **p2
char** p2 = strdup_ptr_001(p);
// source -> **p2
source_ref_ref(p2);
}
void test_modify_copy_via_strdup_001(char** p) { // $ ast-def=p
modify_copy_via_strdup_ptr_001(p);
sink(**p); // clean
}
// This function copies the value of *p into a new location *p2 and then
// taints **p2. Thus, **p contains tainted data after returning from this
// function.
void modify_copy_via_strdup_ptr_011(char** p) { // $ ast-def=p
// **p -> **p2 and *p -> *p2
char** p2 = strdup_ptr_011(p);
// source -> **p2
source_ref_ref(p2);
}
void test_modify_copy_via_strdup_011(char** p) { // $ ast-def=p
modify_copy_via_strdup_ptr_011(p);
sink(**p); // $ ir MISSING: ast
}
char* source(int);
void source_ref_2(char** toTaint) { // $ ast-def=toTaint ir-def=*toTaint ir-def=**toTaint
// source -> *toTaint
*toTaint = source(42);
}
// This function copies the value of p into a new location p2 and then
// taints *p2. Thus, *p contains tainted data after returning from this
// function.
void modify_copy_via_strdup_ptr_111_taint_ind(char** p) { // $ ast-def=p
// **p -> **p2, *p -> *p2, and p -> p2
char** p2 = strdup_ptr_111(p);
// source -> *p2
source_ref_2(p2);
}
void sink(char*);
void test_modify_copy_via_strdup_111_taint_ind(char** p) { // $ ast-def=p
modify_copy_via_strdup_ptr_111_taint_ind(p);
sink(*p); // $ ir MISSING: ast
}
// This function copies the value of p into a new location p2 and then
// taints **p2. Thus, **p contains tainted data after returning from this
// function.
void modify_copy_via_strdup_ptr_111_taint_ind_ind(char** p) { // $ ast-def=p
// **p -> **p2, *p -> *p2, and p -> p2
char** p2 = strdup_ptr_111(p);
// source -> **p2
source_ref_ref(p2);
}
void sink(char*);
void test_modify_copy_via_strdup_111_taint_ind_ind(char** p) { // $ ast-def=p
modify_copy_via_strdup_ptr_111_taint_ind_ind(p);
sink(**p); // $ ir MISSING: ast
}

View File

@@ -176,6 +176,9 @@ irFlow
| flowOut.cpp:5:16:5:21 | call to source | flowOut.cpp:61:8:61:11 | access to array |
| flowOut.cpp:84:18:84:23 | call to source | flowOut.cpp:85:8:85:9 | * ... |
| flowOut.cpp:90:8:90:13 | call to source | flowOut.cpp:102:8:102:9 | * ... |
| flowOut.cpp:131:15:131:20 | call to source | flowOut.cpp:161:8:161:10 | * ... |
| flowOut.cpp:131:15:131:20 | call to source | flowOut.cpp:202:8:202:10 | * ... |
| flowOut.cpp:168:14:168:19 | call to source | flowOut.cpp:185:8:185:9 | * ... |
| globals.cpp:5:17:5:22 | call to source | globals.cpp:6:10:6:14 | local |
| globals.cpp:13:23:13:28 | call to source | globals.cpp:12:10:12:24 | flowTestGlobal1 |
| globals.cpp:23:23:23:28 | call to source | globals.cpp:19:10:19:24 | flowTestGlobal2 |