Files
codeql/cpp/ql/test/library-tests/dataflow/taint-tests/taint.cpp
2025-08-18 18:15:14 +02:00

845 lines
15 KiB
C++

int source();
void sink(...);
void arithAssignments(int source1, int clean1) {
sink(clean1); // clean
clean1 += source1;
clean1 += 1;
sink(clean1); // $ ast,ir
clean1 = source1 = 1;
sink(clean1); // clean
source1 = clean1 = source();
source1++;
++source1;
source1 += 1;
sink(source1); // $ ast,ir
sink(++source1); // $ ast,ir
}
// --- globals ---
int increment(int x) {return x + 1;}
int zero(int x) {return 0;}
int global1 = 0;
int global2 = source();
int global3 = global2 + 1;
int global4 = increment(source());
int global5 = zero(source());
int global6, global7, global8, global9, global10;
void do_source()
{
global6 = 0;
global7 = source();
global8 = global7 + 1;
global9 = increment(source());
global10 = zero(source());
sink(global6);
sink(global7); // $ ast,ir
sink(global8); // $ ast,ir
sink(global9); // $ ast,ir
sink(global10);
}
void do_sink()
{
sink(global1);
sink(global2); // $ ir MISSING: ast
sink(global3); // $ ir MISSING: ast
sink(global4); // $ ir MISSING: ast
sink(global5);
sink(global6);
sink(global7); // $ ir MISSING: ast
sink(global8); // $ ir MISSING: ast
sink(global9); // $ ir MISSING: ast
sink(global10);
}
void global_test()
{
do_source();
do_sink();
}
// --- class fields ---
class MyClass {
public:
MyClass() : a(0), b(source()) {
c = source();
d = 0;
}
void myMethod() {
d = source();
}
int a, b, c, d;
};
void class_field_test() {
MyClass mc1, mc2;
mc1.myMethod();
sink(mc1.a);
sink(mc1.b); // $ ast,ir
sink(mc1.c); // $ ast,ir
sink(mc1.d); // $ ast,ir
sink(mc2.a);
sink(mc2.b); // $ ast,ir
sink(mc2.c); // $ ast,ir
sink(mc2.d);
}
// --- arrays ---
void array_test(int i) {
int arr1[10] = {0};
int arr2[10] = {0};
int arr3[10] = {0};
arr1[5] = source();
arr2[i] = source();
arr3[5] = 0;
sink(arr1[5]); // $ ast,ir
sink(arr1[i]); // $ ast,ir
sink(arr2[5]); // $ ast,ir
sink(arr2[i]); // $ ast,ir
sink(arr3[5]);
sink(arr3[i]);
}
// --- pointers ---
void pointer_test() {
int t1 = source();
int t2 = 1;
int t3 = 1;
int *p1 = &t1;
int *p2 = &t2;
int *p3 = &t3;
*p2 = source();
sink(*p1); // $ ast,ir
sink(*p2); // $ ast,ir
sink(*p3);
p3 = &t1;
sink(*p3); // $ ast,ir
*p3 = 0;
sink(*p3); // $ SPURIOUS: ast
}
// --- return values ---
int select(int i, int a, int b) {
if (i == 1) {
return a;
} else {
return b;
}
}
void fn_test(int i) {
sink(select(i, 1, source())); // $ ast,ir
}
// --- strings ---
char *strcpy(char *destination, const char *source);
char *strcat(char *destination, const char *source);
namespace strings
{
char *source(); // char* source
void strings_test1() {
char *tainted = source();
char buffer[1024] = {0};
sink(source()); // $ ast,ir
sink(tainted); // $ ast,ir
strcpy(buffer, "Hello, ");
sink(buffer);
strcat(buffer, tainted);
sink(buffer); // $ ast,ir
}
}
// --- pass by reference ---
namespace refs {
void callee(int *p) {
sink(*p); // $ ast,ir
}
void caller() {
int x = source();
callee(&x);
}
}
void *memcpy(void *dest, void *src, int len);
void test_memcpy(int *source) {
int x;
memcpy(&x, source, sizeof(int));
sink(x); // $ ast=192:23 ir SPURIOUS: ast=193:6
}
// --- std::swap ---
#include "swap.h"
void test_swap() {
int x, y;
x = source();
y = 0;
sink(x); // $ ast,ir
sink(y); // clean
std::swap(x, y);
sink(x); // $ SPURIOUS: ast
sink(y); // $ ast,ir
}
// --- lambdas ---
void test_lambdas()
{
int t = source();
int u = 0;
int v = 0;
int w = 0;
auto a = [t, u]() -> int {
sink(t); // $ ast,ir
sink(u); // clean
return t;
};
sink(a()); // $ ast,ir
auto b = [&] {
sink(t); // $ ast,ir
sink(u); // clean
v = source(); // (v is reference captured)
};
b();
sink(v); // $ MISSING: ast,ir
auto c = [=] {
sink(t); // $ ast,ir
sink(u); // clean
};
c();
auto d = [](int a, int b) {
sink(a); // $ ast,ir
sink(b); // clean
};
d(t, u);
auto e = [](int &a, int &b, int &c) {
sink(a); // $ ast,ir
sink(b); // clean
c = source();
};
e(t, u, w);
sink(w); // $ ast,ir
}
// --- taint through return value ---
int id(int x)
{
return x;
}
void test_return()
{
int x, y, z, t;
t = source();
x = 0;
y = 0;
z = 0;
sink(t); // $ ast,ir
sink(x);
sink(y);
sink(z);
x = id(t);
y = id(id(t));
z = id(z);
sink(t); // $ ast,ir
sink(x); // $ ast,ir
sink(y); // $ ast,ir
sink(z);
}
// --- taint through parameters ---
void myAssign1(int &a, int &b)
{
a = b;
}
void myAssign2(int &a, int b)
{
a = b;
}
void myAssign3(int *a, int b)
{
*a = b;
}
void myAssign4(int *a, int b)
{
int c;
c = b + 1;
*a = c;
}
void myNotAssign(int &a, int &b)
{
a = a + 1;
b = b + 1;
}
void test_outparams()
{
int t, a, b, c, d, e;
t = source();
a = 0;
b = 0;
c = 0;
d = 0;
e = 0;
sink(t); // $ ast,ir
sink(a);
sink(b);
sink(c);
sink(d);
sink(e);
myAssign1(a, t);
myAssign2(b, t);
myAssign3(&c, t);
myAssign4(&d, t);
myNotAssign(e, t);
sink(t); // $ ast,ir
sink(a); // $ ast,ir
sink(b); // $ ast,ir
sink(c); // $ ast,ir
sink(d); // $ ast,ir
sink(e);
}
// --- strdup ---
typedef unsigned long size_t;
char *strdup(const char *s1);
char *strndup(const char *s1, size_t n);
wchar_t* wcsdup(const wchar_t* s1);
char *strdupa(const char *s1);
char *strndupa(const char *s1, size_t n);
void test_strdup(char *source)
{
char *a, *b, *c;
a = strdup(source);
b = strdup("hello, world");
c = strndup(source, 100);
sink(a); // $ ast,ir
sink(b);
sink(c); // $ ast,ir
}
void test_strndup(int source)
{
char *a;
a = strndup("hello, world", source);
sink(a); // $ ast,ir
}
void test_wcsdup(wchar_t *source)
{
wchar_t *a, *b;
a = wcsdup(source);
b = wcsdup(L"hello, world");
sink(a); // $ ast,ir
sink(b);
}
void test_strdupa(char *source)
{
char *a, *b, *c;
a = strdupa(source);
b = strdupa("hello, world");
c = strndupa(source, 100);
sink(a); // $ ast,ir
sink(b);
sink(c); // $ ast,ir
}
void test_strndupa(int source)
{
char *a;
a = strndupa("hello, world", source);
sink(a); // $ ast,ir
}
// --- qualifiers ---
class MyClass2 {
public:
MyClass2(int value);
void setMember(int value);
int getMember();
int member;
};
class MyClass3 {
public:
MyClass3(const char *string);
void setString(const char *string);
const char *getString();
const char *buffer;
};
void test_qualifiers()
{
MyClass2 a(0), b(0), *c;
MyClass3 d("");
sink(a);
sink(a.getMember());
a.setMember(source());
sink(a); // $ ast,ir
sink(a.getMember()); // $ ast,ir
sink(b);
sink(b.getMember());
b.member = source();
sink(b); // $ ir MISSING: ast
sink(b.member); // $ ast,ir
sink(b.getMember()); // $ MISSING: ir ast
c = new MyClass2(0);
sink(c);
sink(c->getMember());
c->setMember(source());
sink(c); // $ ast,ir
sink(c->getMember()); // $ ast,ir
delete c;
sink(d);
sink(d.getString());
d.setString(strings::source());
sink(d); // $ ast,ir
sink(d.getString()); // $ ast,ir
}
// --- non-standard swap ---
void swop(int &a, int &b)
{
int c = a;
a = b;
b = c;
}
void test_swop() {
int x, y;
x = source();
y = 0;
sink(x); // $ ast,ir
sink(y); // clean
swop(x, y);
sink(x); // $ SPURIOUS: ast,ir
sink(y); // $ ast,ir
}
// --- getdelim ---
struct FILE;
int getdelim(char ** lineptr, size_t * n, int delimiter, FILE *stream);
void test_getdelim(FILE* source1) {
char* line = nullptr;
size_t n;
getdelim(&line, &n, '\n', source1);
sink(line); // $ ir,ast
}
// --- strtok ---
char *strtok(char *str, const char *delim);
void test_strtok(char *source) {
const char* delim = ",.-;:_";
char* tokenized = strtok(source, delim);
sink(tokenized); // $ ast,ir
sink(delim);
}
// --- strset ---
char *_strset(char *str, int c);
void test_strset_1(char* ptr, char source) {
_strset(ptr, source);
sink(ptr); // $ SPURIOUS: ast,ir
sink(*ptr); // $ ast,ir
}
void test_strset_2(char* source) {
_strset(source, 0);
sink(source); // $ ast,ir
}
// --- mempcpy ---
void *mempcpy(void *dest, const void *src, size_t n);
void test_mempcpy(int *source) {
int x;
mempcpy(&x, source, sizeof(int));
sink(x); // $ ast=540:24 ir SPURIOUS: ast=541:6
}
// --- memccpy ---
void *memccpy(void *dest, const void *src, int c, size_t n);
void test_memccpy(int *source) {
int dest[16];
memccpy(dest, source, 42, sizeof(dest));
sink(dest); // $ ast=550:24 ir SPURIOUS: ast=551:6
}
// --- strcat and related functions ---
char* strcat (char*, const char*);
void test_strcat(char* dest1, char* dest2, char* clean, char* source) {
strcat(dest1, source);
sink(dest1); // $ ast,ir
strcat(dest2, clean);
sink(dest2);
}
typedef void* _locale_t;
unsigned char *_mbsncat_l(unsigned char *, const unsigned char *, int, _locale_t);
void test__mbsncat_l(unsigned char* dest1, unsigned const char* ptr, unsigned char* dest3,
_locale_t clean, _locale_t source, int n) {
unsigned char* dest2 = _mbsncat_l(dest1, ptr, n, source);
sink(dest1); // $ SPURIOUS: ast,ir
sink(*dest1); // $ ast,ir
sink(dest2); // $ SPURIOUS: ast,ir
sink(*dest2); // $ ast,ir
unsigned char* dest4 = _mbsncat_l(dest3, ptr, n, clean);
sink(dest3);
sink(*dest3);
sink(dest4);
sink(*dest4);
}
// --- strsep ---
char *strsep(char**, const char *);
void test_strsep(char *source) {
const char* delim = ",.-;:_";
char* tokenized;
while(tokenized = strsep(&source, delim)) {
sink(tokenized); // $ ast,ir
sink(*tokenized); // $ ast,ir
}
}
// --- _strinc and related functions ---
char* _strinc(const char*, _locale_t);
unsigned char* _mbsinc(const unsigned char*);
unsigned char *_strdec(const unsigned char*, const unsigned char*);
void test__strinc(char* source, char* clean, char* dest1, char* dest2, _locale_t locale) {
dest1 = _strinc(source, locale);
sink(dest1); // $ ast,ir
sink(*dest1); // $ ast,ir
dest2 = _strinc(clean, locale);
sink(dest2);
sink(*dest2);
}
void test__mbsinc(unsigned char* source_unsigned, char* source, unsigned char* dest_unsigned, char* dest) {
dest_unsigned = _mbsinc(source_unsigned);
sink(dest_unsigned); // $ ast,ir
sink(*dest_unsigned); // $ ast,ir
dest = (char*)_mbsinc((unsigned char*)source);
sink(dest); // $ ast,ir
sink(*dest); // $ ast,ir
}
void test__strdec(const unsigned char* source, unsigned char* clean, unsigned char* dest1, unsigned char* dest2, unsigned char* dest3) {
dest1 = _strdec(source + 12, source);
sink(dest1); // $ ast,ir
sink(*dest1); // $ ast,ir
// If `clean` does not precede `source` this technically breaks the precondition of _strdec.
// We would still like to have taint, though.
dest2 = _strdec(clean, source);
sink(dest2); // $ ast,ir
sink(*dest2); // $ ast,ir
// Also breaks the precondition on _strdec.
dest3 = _strdec(source, clean);
sink(dest3); // $ ast,ir
sink(*dest3); // $ ast,ir
}
// --- strnextc ---
unsigned int _strnextc(const char*);
void test__strnextc(const char* source) {
unsigned c = 0;
do {
c = _strnextc(source++);
sink(c); // $ ast,ir
} while(c != '\0');
c = _strnextc("");
sink(c);
}
// --- taint through const specified function ---
class C_no_const_member_function {
char* data_;
public:
char* data() { return data_; }
};
void test_no_const_member(char* source) {
C_no_const_member_function c;
memcpy(c.data(), source, 16);
sink(c.data()); // $ ast,ir
}
class C_const_member_function {
char* data_;
public:
char* data() const { return data_; }
};
void test_with_const_member(char* source) {
C_const_member_function c;
memcpy(c.data(), source, 16);
sink(c.data()); // $ ast,ir
}
void argument_source(void*);
struct two_members {
char *x, *y;
};
void test_argument_source_field_to_obj() {
two_members s;
argument_source(s.x);
sink(s); // $ SPURIOUS: ast,ir
sink(s.x); // $ ast,ir
sink(s.y); // clean
}
namespace strings {
void test_write_to_read_then_incr_then_deref() {
char* s = source();
char* p;
*p++ = *s;
sink(p); // $ ast ir
}
}
char * strncpy (char *, const char *, unsigned long);
void test_strncpy(char* d, char* s) {
argument_source(s);
strncpy(d, s, 16);
sink(d); // $ ast ir
}
char* indirect_source();
void test_strtok_indirect() {
char *source = indirect_source();
const char* delim = ",.-;:_";
char* tokenized = strtok(source, delim);
sink(*tokenized); // $ ir MISSING: ast
sink(*delim);
}
long int strtol(const char*, char**, int);
void test_strtol(char *source) {
char* endptr = nullptr;
long l = strtol(source, &endptr, 10);
sink(l); // $ ast,ir
sink(endptr); // $ ast,ir
sink(*endptr); // $ ast,ir
}
void *malloc(size_t);
void *realloc(void *, size_t);
void test_realloc() {
char *source = indirect_source();
char *dest = (char*)realloc(source, 16);
sink(dest); // $ ir MISSING: ast
}
void test_realloc_2_indirections(int **buffer) {
**buffer = source();
buffer = (int**)realloc(buffer, 16);
sink(**buffer); // $ ir MISSING: ast
}
void test_realloc_struct_field() {
struct A { int x; };
A* a = (A*)malloc(sizeof(A));
a->x = source();
A* a2 = (A*)realloc(a, sizeof(A));
sink(a2->x); // $ ir MISSING: ast
}
int sprintf(char *, const char *, ...);
void call_sprintf_twice(char* path, char* data) {
sprintf(path, "%s", "abc");
sprintf(path, "%s", data);
}
void test_call_sprintf() {
char path[10];
call_sprintf_twice(path, indirect_source());
sink(*path); // $ ast,ir
}
struct TaintInheritingContentObject {
int flowFromObject;
};
TaintInheritingContentObject source(bool);
void test_TaintInheritingContent() {
TaintInheritingContentObject obj = source(true);
sink(obj.flowFromObject); // $ ir MISSING: ast
}
FILE* fopen(const char*, const char*);
int fopen_s(FILE** pFile, const char *filename, const char *mode);
void fopen_test(char* source) {
FILE* f = fopen(source, "r");
sink(f); // $ ast,ir
FILE* f2;
fopen_s(&f2, source, "r");
sink(f2); // $ ast,ir
}
typedef wchar_t OLECHAR;
typedef OLECHAR* LPOLESTR;
typedef const LPOLESTR LPCOLESTR;
typedef OLECHAR* BSTR;
typedef const char* LPCSTR;
BSTR SysAllocString(const OLECHAR *);
BSTR SysAllocStringByteLen(LPCSTR, unsigned );
BSTR SysAllocStringLen(const OLECHAR *,unsigned);
void test_sysalloc() {
auto p1 = SysAllocString((LPOLESTR)indirect_source());
sink(*p1); // $ ir MISSING: ast
auto p2 = SysAllocStringByteLen(indirect_source(), 10);
sink(*p2); // $ ir MISSING: ast
auto p3 = SysAllocStringLen((LPOLESTR)indirect_source(), 10);
sink(*p3); // $ ir MISSING: ast
}
char* strchr(const char*, int);
void write_to_const_ptr_ptr(const char **p_out, const char **p_in) {
const char* q = *p_in;
*p_out = strchr(q, '/');
}
void take_const_ptr(const char *out, const char *in) {
// NOTE: We take the address of `out` in `take_const_ptr`'s stack space.
// Assigning to this pointer does not change `out` in
// `test_write_to_const_ptr_ptr`.
write_to_const_ptr_ptr(&out, &in);
}
void test_write_to_const_ptr_ptr() {
const char* in = indirect_source();
const char* out;
take_const_ptr(out, in);
sink(out); // $ SPURIOUS: ast
}
void indirect_sink(FILE *fp);
int fprintf(FILE *fp, const char *format, ...);
int f7(void)
{
FILE* fp = (FILE*)indirect_source();
fprintf(fp, "");
indirect_sink(fp); // $ ir MISSING: ast
return 0;
}