1399 lines · c
1// RUN: rm -rf %t && mkdir %t2// RUN: sed -e "s|DIR|%/S/Inputs|g" %S/Inputs/taint-generic-config-vfs.json > %t/taint-generic-config-vfs.json3 4// RUN: %clang_analyze_cc1 -Wno-format-security -Wno-pointer-to-int-cast \5// RUN: -Wno-incompatible-library-redeclaration -verify %s \6// RUN: -analyzer-checker=optin.taint.GenericTaint \7// RUN: -analyzer-checker=optin.taint.TaintedDiv \8// RUN: -analyzer-checker=core \9// RUN: -analyzer-checker=security.ArrayBound \10// RUN: -analyzer-checker=debug.ExprInspection \11// RUN: -analyzer-config \12// RUN: optin.taint.TaintPropagation:Config=%S/Inputs/taint-generic-config-virtual.yaml \13// RUN: -ivfsoverlay %t/taint-generic-config-vfs.json14 15// RUN: %clang_analyze_cc1 -Wno-format-security -Wno-pointer-to-int-cast \16// RUN: -Wno-incompatible-library-redeclaration -verify %s \17// RUN: -DFILE_IS_STRUCT \18// RUN: -analyzer-checker=optin.taint.GenericTaint \19// RUN: -analyzer-checker=optin.taint.TaintedDiv \20// RUN: -analyzer-checker=core \21// RUN: -analyzer-checker=security.ArrayBound \22// RUN: -analyzer-checker=debug.ExprInspection \23// RUN: -analyzer-config \24// RUN: optin.taint.TaintPropagation:Config=%S/Inputs/taint-generic-config.yaml25 26// RUN: not %clang_analyze_cc1 -verify %s \27// RUN: -analyzer-checker=optin.taint.GenericTaint \28// RUN: -analyzer-config \29// RUN: optin.taint.TaintPropagation:Config=justguessit \30// RUN: 2>&1 | FileCheck %s -check-prefix=CHECK-INVALID-FILE31 32// CHECK-INVALID-FILE: (frontend): invalid input for checker option33// CHECK-INVALID-FILE-SAME: 'optin.taint.TaintPropagation:Config',34// CHECK-INVALID-FILE-SAME: that expects a valid filename instead of35// CHECK-INVALID-FILE-SAME: 'justguessit'36 37// RUN: not %clang_analyze_cc1 -verify %s \38// RUN: -analyzer-checker=optin.taint.GenericTaint \39// RUN: -analyzer-config \40// RUN: optin.taint.TaintPropagation:Config=%S/Inputs/taint-generic-config-ill-formed.yaml \41// RUN: 2>&1 | FileCheck -DMSG=%errc_EINVAL %s -check-prefix=CHECK-ILL-FORMED42 43// CHECK-ILL-FORMED: (frontend): invalid input for checker option44// CHECK-ILL-FORMED-SAME: 'optin.taint.TaintPropagation:Config',45// CHECK-ILL-FORMED-SAME: that expects a valid yaml file: [[MSG]]46 47// RUN: not %clang_analyze_cc1 -verify %s \48// RUN: -analyzer-checker=optin.taint.GenericTaint \49// RUN: -analyzer-config \50// RUN: optin.taint.TaintPropagation:Config=%S/Inputs/taint-generic-config-invalid-arg.yaml \51// RUN: 2>&1 | FileCheck %s -check-prefix=CHECK-INVALID-ARG52 53// CHECK-INVALID-ARG: (frontend): invalid input for checker option54// CHECK-INVALID-ARG-SAME: 'optin.taint.TaintPropagation:Config',55// CHECK-INVALID-ARG-SAME: that expects an argument number for propagation56// CHECK-INVALID-ARG-SAME: rules greater or equal to -157 58typedef long long rsize_t;59typedef __typeof(sizeof(int)) size_t;60typedef signed long long ssize_t;61typedef __WCHAR_TYPE__ wchar_t;62void clang_analyzer_isTainted_char(char);63void clang_analyzer_isTainted_wchar(wchar_t);64void clang_analyzer_isTainted_charp(char*);65void clang_analyzer_isTainted_int(int);66void clang_analyzer_dump_int(int);67 68int coin();69 70int scanf(const char *restrict format, ...);71char *gets(char *str);72char *gets_s(char *str, rsize_t n);73int getchar(void);74 75typedef struct _FILE FILE;76#ifdef FILE_IS_STRUCT77extern struct _FILE *stdin;78#else79extern FILE *stdin;80#endif81 82#define bool _Bool83#define NULL (void*)084 85wchar_t *fgetws(wchar_t *ws, int n, FILE *stream);86wchar_t *wmemset(wchar_t *wcs, wchar_t wc, unsigned long n);87wchar_t *wmemcpy(wchar_t *dest, const wchar_t *src, size_t n);88wchar_t *wmemmove(wchar_t *dest, const wchar_t *src, size_t n);89size_t wcslen(const wchar_t *s);90wchar_t *wcscpy(wchar_t * dest, const wchar_t * src);91wchar_t *wcsncpy(wchar_t *dest, const wchar_t *src, size_t n);92wchar_t *wcscat(wchar_t *dest, const wchar_t *src);93wchar_t *wcsncat(wchar_t *dest,const wchar_t *src, size_t n);94int swprintf(wchar_t *wcs, size_t maxlen, const wchar_t *format, ...);95 96char *getenv(const char *name);97 98FILE *fopen(const char *name, const char *mode);99 100int fscanf(FILE *restrict stream, const char *restrict format, ...);101int sprintf(char *str, const char *format, ...);102void setproctitle(const char *fmt, ...);103void setproctitle_init(int argc, char *argv[], char *envp[]);104 105// Define string functions. Use builtin for some of them. They all default to106// the processing in the taint checker.107#define strcpy(dest, src) \108 ((__builtin_object_size(dest, 0) != -1ULL) \109 ? __builtin___strcpy_chk (dest, src, __builtin_object_size(dest, 1)) \110 : __inline_strcpy_chk(dest, src))111 112static char *__inline_strcpy_chk (char *dest, const char *src) {113 return __builtin___strcpy_chk(dest, src, __builtin_object_size(dest, 1));114}115char *stpcpy(char *restrict s1, const char *restrict s2);116char *strncpy( char * destination, const char * source, size_t num );117char *strndup(const char *s, size_t n);118char *strncat(char *restrict s1, const char *restrict s2, size_t n);119 120void *malloc(size_t);121void *calloc(size_t nmemb, size_t size);122void bcopy(void *s1, void *s2, size_t n);123 124 125// function | pathname | filename | fd | arglist | argv[] | envp[]126// ===============================================================127// 1 execl | X | | | X | |128// 2 execle | X | | | X | | X129// 3 execlp | | X | | X | |130// 4 execv | X | | | | X |131// 5 execve | X | | | | X | X132// 6 execvp | | X | | | X |133// 7 execvpe | | X | | | X | X134// 8 fexecve | | | X | | X | X135// ===============================================================136// letter | | p | f | l | v | e137//138// legend:139// - pathname: rel/abs path to the binary140// - filename: file name searched in PATH to execute the binary141// - fd: accepts a file descriptor142// - arglist: accepts variadic arguments143// - argv: accepts a pointer to array, denoting the new argv144// - envp: accepts a pointer to array, denoting the new envp145 146int execl(const char *path, const char *arg, ...);147int execle(const char *path, const char *arg, ...);148int execlp(const char *file, const char *arg, ...);149int execv(const char *path, char *const argv[]);150int execve(const char *path, char *const argv[], char *const envp[]);151int execvp(const char *file, char *const argv[]);152int execvpe(const char *file, char *const argv[], char *const envp[]);153int fexecve(int fd, char *const argv[], char *const envp[]);154FILE *popen(const char *command, const char *type);155int pclose(FILE *stream);156int system(const char *command);157 158 159typedef size_t socklen_t;160 161struct sockaddr {162 unsigned short sa_family;163 char sa_data[14];164};165 166#define BUFSIZE 10167 168int Buffer[BUFSIZE];169void bufferScanfDirect(void)170{171 int n;172 scanf("%d", &n);173 Buffer[n] = 1; // expected-warning {{Potential out of bound access }}174}175 176void bufferScanfArithmetic1(int x) {177 int n;178 scanf("%d", &n);179 int m = (n - 3);180 Buffer[m] = 1; // expected-warning {{Potential out of bound access }}181}182 183void bufferScanfArithmetic2(int x) {184 int n;185 scanf("%d", &n);186 int m = 100 - (n + 3) * x;187 Buffer[m] = 1; // expected-warning {{Potential out of bound access }}188}189 190void bufferScanfAssignment(int x) {191 int n;192 scanf("%d", &n);193 int m;194 if (x > 0) {195 m = n;196 Buffer[m] = 1; // expected-warning {{Potential out of bound access }}197 }198}199 200void scanfArg(void) {201 int t = 0;202 scanf("%d", t); // expected-warning {{format specifies type 'int *' but the argument has type 'int'}}203}204 205void bufferGetchar(int x) {206 int m = getchar();207 Buffer[m] = 1; //expected-warning {{Potential out of bound access}}208}209 210extern const unsigned short int **__ctype_b_loc (void);211enum { _ISdigit = 2048 };212# define isdigit(c) ((*__ctype_b_loc ())[(int) (c)] & (unsigned short int) _ISdigit)213 214int isdigitImplFalsePositive(void) {215 // If this code no longer produces a bug report, then consider removing the216 // special case that disables buffer overflow reports coming from the isXXXXX217 // macros in ctypes.h.218 int c = getchar();219 return ((*__ctype_b_loc ())[(int) (c)] & (unsigned short int) _ISdigit);220 //expected-warning@-1 {{Potential out of bound access}}221}222 223int isdigitSuppressed(void) {224 // Same code as above, but reports are suppressed based on macro name:225 int c = getchar();226 return isdigit(c); //no-warning227}228 229// Some later tests use isdigit as a function, so we need to undef it:230#undef isdigit231 232void testUncontrolledFormatString(char **p) {233 char s[80];234 fscanf(stdin, "%s", s);235 char buf[128];236 sprintf(buf,s); // expected-warning {{Uncontrolled Format String}}237 setproctitle(s, 3); // expected-warning {{Uncontrolled Format String}}238 239 // Test taint propagation through strcpy and family.240 char scpy[80];241 strcpy(scpy, s);242 sprintf(buf,scpy); // expected-warning {{Uncontrolled Format String}}243 244 stpcpy(*(++p), s); // this generates __inline.245 setproctitle(*(p), 3); // expected-warning {{Uncontrolled Format String}}246 247 char spcpy[80];248 stpcpy(spcpy, s);249 setproctitle(spcpy, 3); // expected-warning {{Uncontrolled Format String}}250 251 char *spcpyret;252 spcpyret = stpcpy(spcpy, s);253 setproctitle(spcpyret, 3); // expected-warning {{Uncontrolled Format String}}254 255 char sncpy[80];256 strncpy(sncpy, s, 20);257 setproctitle(sncpy, 3); // expected-warning {{Uncontrolled Format String}}258 259 char *dup;260 dup = strndup(s, 20);261 setproctitle(dup, 3); // expected-warning {{Uncontrolled Format String}}262 263}264 265void testTaintSystemCall(void) {266 char buffer[156];267 char addr[128];268 scanf("%s", addr);269 system(addr); // expected-warning {{Untrusted data is passed to a system call}}270 271 // Test that spintf transfers taint.272 sprintf(buffer, "/bin/mail %s < /tmp/email", addr);273 system(buffer); // expected-warning {{Untrusted data is passed to a system call}}274}275 276void testTaintSystemCall2(void) {277 // Test that snpintf transfers taint.278 char buffern[156];279 char addr[128];280 scanf("%s", addr);281 __builtin_snprintf(buffern, 10, "/bin/mail %s < /tmp/email", addr);282 // expected-warning@-1 {{'snprintf' will always be truncated; specified size is 10, but format string expands to at least 24}}283 system(buffern); // expected-warning {{Untrusted data is passed to a system call}}284}285 286void testTaintSystemCall3(void) {287 char buffern2[156];288 int numt;289 char addr[128];290 scanf("%s %d", addr, &numt);291 __builtin_snprintf(buffern2, numt, "/bin/mail %s < /tmp/email", "abcd");292 system(buffern2); // expected-warning {{Untrusted data is passed to a system call}}293}294 295void testGets(void) {296 char str[50];297 gets(str);298 system(str); // expected-warning {{Untrusted data is passed to a system call}}299}300 301void testGets_s(void) {302 char str[50];303 gets_s(str, 49);304 system(str); // expected-warning {{Untrusted data is passed to a system call}}305}306 307void testTaintedBufferSize(void) {308 size_t ts;309 // The functions malloc, calloc, bcopy and memcpy are not taint sinks in the310 // default config of GenericTaintChecker (because that would cause too many311 // false positives).312 // FIXME: We should generate warnings when a value passed to these functions313 // is tainted and _can be very large_ (because that's exploitable). This314 // functionality probably belongs to the checkers that do more detailed315 // modeling of these functions (MallocChecker and CStringChecker).316 scanf("%zd", &ts);317 int *buf1 = (int*)malloc(ts*sizeof(int)); // warn here, ts is unbounded and tainted318 char *dst = (char*)calloc(ts, sizeof(char)); // warn here, ts is unbounded tainted319 bcopy(buf1, dst, ts); // no warning here, since the size of buf1, dst equals ts. Cannot overflow.320 __builtin_memcpy(dst, buf1, (ts + 4)*sizeof(char)); // warn here, dst overflows (whatever the value of ts)321 322 // If both buffers are trusted, do not issue a warning.323 char *dst2 = (char*)malloc(ts*sizeof(char)); // warn here, ts in unbounded324 strncat(dst2, dst, ts); // no-warning325}326 327#define AF_UNIX 1 /* local to host (pipes) */328#define AF_INET 2 /* internetwork: UDP, TCP, etc. */329#define AF_LOCAL AF_UNIX /* backward compatibility */330#define SOCK_STREAM 1331int socket(int, int, int);332size_t read(int, void *, size_t);333 334void testSocket(void) {335 int sock;336 char buffer[100];337 338 sock = socket(AF_INET, SOCK_STREAM, 0);339 read(sock, buffer, 100);340 execl(buffer, "filename", 0); // expected-warning {{Untrusted data is passed to a system call}}341 342 sock = socket(AF_LOCAL, SOCK_STREAM, 0);343 read(sock, buffer, 100);344 execl(buffer, "filename", 0); // no-warning345 346 sock = socket(AF_INET, SOCK_STREAM, 0);347 // References to both buffer and &buffer as an argument should taint the argument348 read(sock, &buffer, 100);349 execl(buffer, "filename", 0); // expected-warning {{Untrusted data is passed to a system call}}350}351 352void testStruct(void) {353 struct {354 char buf[16];355 int length;356 } tainted;357 358 char buffer[16];359 int sock;360 361 sock = socket(AF_INET, SOCK_STREAM, 0);362 read(sock, &tainted, sizeof(tainted));363 clang_analyzer_isTainted_int(tainted.length); // expected-warning {{YES }}364}365 366void testStructArray(void) {367 struct {368 int length;369 } tainted[4];370 371 char dstbuf[16], srcbuf[16];372 int sock;373 374 sock = socket(AF_INET, SOCK_STREAM, 0);375 __builtin_memset(srcbuf, 0, sizeof(srcbuf));376 377 read(sock, &tainted[0], sizeof(tainted));378 clang_analyzer_isTainted_int(tainted[0].length); // expected-warning {{YES}}379 380 __builtin_memset(&tainted, 0, sizeof(tainted));381 read(sock, &tainted, sizeof(tainted));382 clang_analyzer_isTainted_int(tainted[0].length); // expected-warning {{YES}}383 384 __builtin_memset(&tainted, 0, sizeof(tainted));385 // If we taint element 1, we should not raise an alert on taint for element 0 or element 2386 read(sock, &tainted[1], sizeof(tainted));387 clang_analyzer_isTainted_int(tainted[0].length); // expected-warning {{NO}}388 clang_analyzer_isTainted_int(tainted[2].length); // expected-warning {{NO}}389}390 391void testUnion(void) {392 union {393 int x;394 char y[4];395 } tainted;396 397 char buffer[4];398 399 int sock = socket(AF_INET, SOCK_STREAM, 0);400 read(sock, &tainted.y, sizeof(tainted.y));401 // FIXME: overlapping regions aren't detected by isTainted yet402 __builtin_memcpy(buffer, tainted.y, tainted.x);403}404 405int testDivByZero(void) {406 int x;407 scanf("%d", &x);408 return 5/x; // expected-warning {{Division by a tainted value, possibly zero}}409}410 411int testTaintedDivFP(void) {412 int x;413 scanf("%d", &x);414 if (!x)415 return 0;416 return 5/x; // x cannot be 0, so no tainted warning either417}418 419void clang_analyzer_warnIfReached();420 421int testTaintDivZeroNonfatal() {422 int x;423 scanf("%d", &x);424 int y = 5/x; // expected-warning {{Division by a tainted value, possibly zero}}425 if (x == 0)426 clang_analyzer_warnIfReached();427 else428 clang_analyzer_warnIfReached(); // expected-warning {{REACHABLE}}429 return y;430}431 432// Zero-sized VLAs.433void testTaintedVLASize(void) {434 int x;435 scanf("%d", &x);436 int vla[x]; // expected-warning{{Declared variable-length array (VLA) has tainted (attacker controlled) size that can be 0 or negative}}437}438 439// Tainted-sanitized VLAs.440void testTaintedSanitizedVLASize(void) {441 int x;442 scanf("%d", &x);443 if (x<1)444 return;445 int vla[x]; // no-warning446}447 448int testTaintedAllocaMem() {449 char x;450 void * p;451 scanf("%c", &x);452 p = __builtin_alloca(1);453 __builtin_memcpy(p, &x, 1);454 return 5 / *(char*)p; // expected-warning {{Division by a tainted value, possibly zero}}455}456 457int testTaintedMallocMem() {458 char x;459 void * p;460 scanf("%c", &x);461 p = malloc(1);462 __builtin_memcpy(p, &x, 1);463 return 5 / *(char*)p; // expected-warning {{Division by a tainted value, possibly zero}}464}465 466 467// This computation used to take a very long time.468#define longcmp(a,b,c) { \469 a -= c; a ^= c; c += b; b -= a; b ^= (a<<6) | (a >> (32-b)); a += c; c -= b; c ^= b; b += a; \470 a -= c; a ^= c; c += b; b -= a; b ^= a; a += c; c -= b; c ^= b; b += a; }471 472unsigned radar11369570_hanging(const unsigned char *arr, int l) {473 unsigned a, b, c;474 a = b = c = 0x9899e3 + l;475 while (l >= 6) {476 unsigned t;477 scanf("%d", &t);478 a += b;479 a ^= a;480 a += (arr[3] + ((unsigned) arr[2] << 8) + ((unsigned) arr[1] << 16) + ((unsigned) arr[0] << 24));481 longcmp(a, t, c);482 l -= 12;483 }484 return 5/a; // FIXME: Should be a "div by tainted" warning here.485}486 487// This computation used to take a very long time.488void complex_taint_queries(const int *p) {489 int tainted = 0;490 scanf("%d", &tainted);491 492 // Make "tmp" tainted.493 int tmp = tainted + tainted;494 clang_analyzer_isTainted_int(tmp); // expected-warning{{YES}}495 496 // Make "tmp" SymExpr a lot more complicated by applying computation.497 // This should balloon the symbol complexity.498 tmp += p[0] + p[0];499 tmp += p[1] + p[1];500 tmp += p[2] + p[2];501 clang_analyzer_dump_int(tmp); // expected-warning{{((((conj_}} symbol complexity: 8502 clang_analyzer_isTainted_int(tmp); // expected-warning{{YES}}503 504 tmp += p[3] + p[3];505 clang_analyzer_dump_int(tmp); // expected-warning{{(((((conj_}} symbol complexity: 10506 clang_analyzer_isTainted_int(tmp); // expected-warning{{NO}} 10 is already too complex to be traversed507 508 tmp += p[4] + p[4];509 tmp += p[5] + p[5];510 tmp += p[6] + p[6];511 tmp += p[7] + p[7];512 tmp += p[8] + p[8];513 tmp += p[9] + p[9];514 tmp += p[10] + p[10];515 tmp += p[11] + p[11];516 tmp += p[12] + p[12];517 tmp += p[13] + p[13];518 tmp += p[14] + p[14];519 tmp += p[15] + p[15];520 521 // The SymExpr still holds the full history of the computation, yet, "isTainted" doesn't traverse the tree as the complexity is over the threshold.522 clang_analyzer_dump_int(tmp);523 // expected-warning@-1{{(((((((((((((((((conj_}} symbol complexity: 34524 clang_analyzer_isTainted_int(tmp); // expected-warning{{NO}} FIXME: Ideally, this should still result in "tainted".525 526 // By making it even one step more complex, then it would hit the "max-symbol-complexity"527 // threshold and the engine would cut the SymExpr and replace it by a new conjured symbol.528 tmp += p[16];529 clang_analyzer_dump_int(tmp); // expected-warning{{conj_}} symbol complexity: 1530 clang_analyzer_isTainted_int(tmp); // expected-warning{{NO}}531}532 533// Check that we do not assert of the following code.534int SymSymExprWithDiffTypes(void* p) {535 int i;536 scanf("%d", &i);537 int j = (i % (int)(long)p);538 return 5/j; // expected-warning {{Division by a tainted value, possibly zero}}539}540 541 542void constraintManagerShouldTreatAsOpaque(int rhs) {543 int i;544 scanf("%d", &i);545 // This comparison used to hit an assertion in the constraint manager,546 // which didn't handle NonLoc sym-sym comparisons.547 if (i < rhs)548 return;549 if (i < rhs)550 *(volatile int *) 0; // no-warning551}552 553int testSprintf_is_not_a_source(char *buf, char *msg) {554 int x = sprintf(buf, "%s", msg); // no-warning555 return 1 / x; // no-warning: 'sprintf' is not a taint source556}557 558int testSprintf_propagates_taint(char *buf, char *msg) {559 scanf("%s", msg);560 int x = sprintf(buf, "%s", msg); // propagate taint!561 return 1 / x; // expected-warning {{Division by a tainted value, possibly zero}}562}563 564void test_wchar_apis_dont_propagate(const char *path) {565 // strlen, wcslen, strnlen and alike intentionally don't propagate taint.566 // See the details here: https://github.com/llvm/llvm-project/pull/66086567 // This isn't ideal, but this is only what we have now.568 569 FILE *f = fopen(path, "r");570 clang_analyzer_isTainted_charp((char*)f); // expected-warning {{YES}}571 wchar_t wbuf[10];572 fgetws(wbuf, sizeof(wbuf)/sizeof(*wbuf), f);573 clang_analyzer_isTainted_wchar(*wbuf); // expected-warning {{YES}}574 int n = wcslen(wbuf);575 clang_analyzer_isTainted_int(n); // expected-warning {{NO}}576 577 wchar_t dst[100] = L"ABC";578 clang_analyzer_isTainted_wchar(*dst); // expected-warning {{NO}}579 wcsncat(dst, wbuf, sizeof(wbuf)/sizeof(*wbuf));580 clang_analyzer_isTainted_wchar(*dst); // expected-warning {{YES}}581 582 int m = wcslen(dst);583 clang_analyzer_isTainted_int(m); // expected-warning {{NO}}584}585 586int scanf_s(const char *format, ...);587int testScanf_s_(int *out) {588 scanf_s("%d", out);589 return 1 / *out; // expected-warning {{Division by a tainted value, possibly zero}}590}591 592#define _IO_FILE FILE593int _IO_getc(_IO_FILE *__fp);594int testUnderscoreIO_getc(_IO_FILE *fp) {595 char c = _IO_getc(fp);596 return 1 / c; // expected-warning {{Division by a tainted value, possibly zero}}597}598 599char *getcwd(char *buf, size_t size);600int testGetcwd(char *buf, size_t size) {601 char *c = getcwd(buf, size);602 return system(c); // expected-warning {{Untrusted data is passed to a system call}}603}604 605char *getwd(char *buf);606int testGetwd(char *buf) {607 char *c = getwd(buf);608 return system(c); // expected-warning {{Untrusted data is passed to a system call}}609}610 611ssize_t readlink(const char *path, char *buf, size_t bufsiz);612int testReadlink(char *path, char *buf, size_t bufsiz) {613 ssize_t s = readlink(path, buf, bufsiz);614 system(buf); // expected-warning {{Untrusted data is passed to a system call}}615 // readlink never returns 0616 return 1 / (s + 1); // expected-warning {{Division by a tainted value, possibly zero}}617}618 619ssize_t readlinkat(int dirfd, const char *pathname, char *buf, size_t bufsiz);620int testReadlinkat(int dirfd, char *path, char *buf, size_t bufsiz) {621 ssize_t s = readlinkat(dirfd, path, buf, bufsiz);622 system(buf); // expected-warning {{Untrusted data is passed to a system call}}623 (void)(1 / dirfd); // arg 0 is not tainted624 system(path); // arg 1 is not tainted625 (void)(1 / bufsiz); // arg 3 is not tainted626 // readlinkat never returns 0627 return 1 / (s + 1); // expected-warning {{Division by a tainted value, possibly zero}}628}629 630char *get_current_dir_name(void);631int testGet_current_dir_name() {632 char *d = get_current_dir_name();633 return system(d); // expected-warning {{Untrusted data is passed to a system call}}634}635 636int gethostname(char *name, size_t len);637int testGethostname(char *name, size_t len) {638 gethostname(name, len);639 return system(name); // expected-warning {{Untrusted data is passed to a system call}}640}641 642int getnameinfo(const struct sockaddr *restrict addr, socklen_t addrlen,643 char *restrict host, socklen_t hostlen,644 char *restrict serv, socklen_t servlen, int flags);645int testGetnameinfo(const struct sockaddr *restrict addr, socklen_t addrlen,646 char *restrict host, socklen_t hostlen,647 char *restrict serv, socklen_t servlen, int flags) {648 getnameinfo(addr, addrlen, host, hostlen, serv, servlen, flags);649 650 system(host); // expected-warning {{Untrusted data is passed to a system call}}651 return system(serv); // expected-warning {{Untrusted data is passed to a system call}}652}653 654int getseuserbyname(const char *linuxuser, char **selinuxuser, char **level);655int testGetseuserbyname(const char *linuxuser, char **selinuxuser, char **level) {656 getseuserbyname(linuxuser, selinuxuser, level);657 system(selinuxuser[0]); // expected-warning {{Untrusted data is passed to a system call}}658 return system(level[0]); // expected-warning {{Untrusted data is passed to a system call}}659}660 661typedef int gid_t;662int getgroups(int size, gid_t list[]);663int testGetgroups(int size, gid_t list[], bool flag) {664 int result = getgroups(size, list);665 if (flag)666 return 1 / list[0]; // expected-warning {{Division by a tainted value, possibly zero}}667 668 return 1 / (result + 1); // expected-warning {{Division by a tainted value, possibly zero}}669}670 671char *getlogin(void);672int testGetlogin() {673 char *n = getlogin();674 return system(n); // expected-warning {{Untrusted data is passed to a system call}}675}676 677int getlogin_r(char *buf, size_t bufsize);678int testGetlogin_r(char *buf, size_t bufsize) {679 getlogin_r(buf, bufsize);680 return system(buf); // expected-warning {{Untrusted data is passed to a system call}}681}682 683int fscanf_s(FILE *stream, const char *format, ...);684void testFscanf_s(const char *fname, int *d) {685 FILE *f = fopen(fname, "r");686 fscanf_s(f, "%d", d);687 clang_analyzer_isTainted_int(*d); // expected-warning {{YES}}688}689 690int fread(void *buffer, size_t size, size_t count, FILE *stream);691void testFread(const char *fname, int *buffer, size_t size, size_t count) {692 FILE *f = fopen(fname, "r");693 size_t read = fread(buffer, size, count, f);694 695 clang_analyzer_isTainted_int(*buffer); // expected-warning {{YES}}696 clang_analyzer_isTainted_int(read); // expected-warning {{YES}}697}698 699ssize_t recv(int sockfd, void *buf, size_t len, int flags);700int accept(int fd, struct sockaddr *addr, socklen_t *addrlen);701int bind(int fd, const struct sockaddr *addr, socklen_t addrlen);702int listen(int fd, int backlog);703 704void testRecv(int *buf, size_t len, int flags) {705 int fd;706 scanf("%d", &fd); // fake a tainted a file descriptor707 708 size_t read = recv(fd, buf, len, flags);709 clang_analyzer_isTainted_int(*buf); // expected-warning {{YES}}710 clang_analyzer_isTainted_int(read); // expected-warning {{YES}}711}712 713ssize_t recvfrom(int sockfd, void *restrict buf, size_t len, int flags,714 struct sockaddr *restrict src_addr,715 socklen_t *restrict addrlen);716void testRecvfrom(int *restrict buf, size_t len, int flags,717 struct sockaddr *restrict src_addr,718 socklen_t *restrict addrlen) {719 int fd;720 scanf("%d", &fd); // fake a tainted a file descriptor721 722 size_t read = recvfrom(fd, buf, len, flags, src_addr, addrlen);723 clang_analyzer_isTainted_int(*buf); // expected-warning {{YES}}724 clang_analyzer_isTainted_int(read); // expected-warning {{YES}}725}726 727char *ttyname(int fd);728void testTtyname() {729 int fd;730 scanf("%d", &fd); // fake a tainted a file descriptor731 732 char *name = ttyname(fd);733 clang_analyzer_isTainted_charp(name); // expected-warning {{YES}}734}735 736int ttyname_r(int fd, char *buf, size_t buflen);737void testTtyname_r(char *buf, size_t buflen) {738 int fd;739 scanf("%d", &fd); // fake a tainted a file descriptor740 741 int result = ttyname_r(fd, buf, buflen);742 clang_analyzer_isTainted_char(*buf); // expected-warning {{YES}}743 clang_analyzer_isTainted_int(result); // expected-warning {{YES}}744}745 746char *dirname(char *path);747void testDirname() {748 char buf[10];749 scanf("%9s", buf);750 751 char *name = dirname(buf);752 clang_analyzer_isTainted_charp(name); // expected-warning {{YES}}753}754 755char *basename(char *path);756void testBasename() {757 char buf[10];758 scanf("%9s", buf);759 760 char *name = basename(buf);761 clang_analyzer_isTainted_charp(name); // expected-warning {{YES}}762}763 764int fnmatch(const char *pattern, const char *string, int flags);765void testFnmatch(const char *pattern, int flags) {766 char string[10];767 scanf("%9s", string);768 769 int result = fnmatch(pattern, string, flags);770 clang_analyzer_isTainted_int(result); // expected-warning {{YES}}771}772 773void *memchr(const void *s, int c, size_t n);774void testMemchr(int c, size_t n) {775 char buf[10];776 scanf("%9s", buf);777 778 char *result = memchr(buf, c, n);779 clang_analyzer_isTainted_charp(result); // expected-warning {{YES}}780}781 782void *memrchr(const void *s, int c, size_t n);783void testMemrchr(int c, size_t n) {784 char buf[10];785 scanf("%9s", buf);786 787 char *result = memrchr(buf, c, n);788 clang_analyzer_isTainted_charp(result); // expected-warning {{YES}}789}790 791void *rawmemchr(const void *s, int c);792void testRawmemchr(int c) {793 char buf[10];794 scanf("%9s", buf);795 796 char *result = rawmemchr(buf, c);797 clang_analyzer_isTainted_charp(result); // expected-warning {{YES}}798}799 800int mbtowc(wchar_t *pwc, const char *s, size_t n);801void testMbtowc(wchar_t *pwc, size_t n) {802 char buf[10];803 scanf("%9s", buf);804 805 int result = mbtowc(pwc, buf, n);806 clang_analyzer_isTainted_char(*pwc); // expected-warning {{YES}}807 clang_analyzer_isTainted_int(result); // expected-warning {{YES}}808}809 810int wctomb(char *s, wchar_t wc);811void testWctomb(char *buf) {812 wchar_t wc = getchar();813 814 int result = wctomb(buf, wc);815 clang_analyzer_isTainted_char(*buf); // expected-warning {{YES}}816 clang_analyzer_isTainted_int(result); // expected-warning {{YES}}817}818 819int wcwidth(wchar_t c);820void testWcwidth() {821 wchar_t wc = getchar();822 823 int width = wcwidth(wc);824 clang_analyzer_isTainted_int(width); // expected-warning {{YES}}825}826 827int memcmp(const void *s1, const void *s2, size_t n);828void testMemcmpWithLHSTainted(size_t n, char *rhs) {829 char lhs[10];830 scanf("%9s", lhs);831 832 int cmp_result = memcmp(lhs, rhs, n);833 clang_analyzer_isTainted_int(cmp_result); // expected-warning {{YES}}834}835 836void testMemcmpWithRHSTainted(size_t n, char *lhs) {837 char rhs[10];838 scanf("%9s", rhs);839 840 int cmp_result = memcmp(lhs, rhs, n);841 clang_analyzer_isTainted_int(cmp_result); // expected-warning {{YES}}842}843 844void *memcpy(void *restrict dest, const void *restrict src, size_t n);845void testMemcpy(char *dst, size_t n) {846 char src[10];847 scanf("%9s", src);848 849 char *result = memcpy(dst, src, n);850 851 clang_analyzer_isTainted_char(*dst); // expected-warning {{YES}}852 clang_analyzer_isTainted_charp(result); // expected-warning {{YES}}853}854 855void *memmove(void *dest, const void *src, size_t n);856void testMemmove(char *dst, size_t n) {857 char src[10];858 scanf("%9s", src);859 860 char *result = memmove(dst, src, n);861 862 clang_analyzer_isTainted_char(*dst); // expected-warning {{YES}}863 clang_analyzer_isTainted_charp(result); // expected-warning {{YES}}864}865 866void *memmem(const void *haystack, size_t haystacklen, const void *needle, size_t needlelen);867void testMemmem(const void *needle, size_t needlelen) {868 char haystack[10];869 scanf("%9s", haystack);870 871 char *result = memmem(haystack, 9, needle, needlelen);872 clang_analyzer_isTainted_charp(result); // expected-warning {{YES}}873}874 875char *strstr(const char *haystack, const char *needle);876void testStrstr(const char *needle) {877 char haystack[10];878 scanf("%9s", haystack);879 880 char *result = strstr(haystack, needle);881 clang_analyzer_isTainted_charp(result); // expected-warning {{YES}}882}883 884char *strcasestr(const char *haystack, const char *needle);885void testStrcasestr(const char *needle) {886 char haystack[10];887 scanf("%9s", haystack);888 889 char *result = strcasestr(haystack, needle);890 clang_analyzer_isTainted_charp(result); // expected-warning {{YES}}891}892 893char *strchrnul(const char *s, int c);894void testStrchrnul() {895 char s[10];896 scanf("%9s", s);897 898 char *result = strchrnul(s, 9);899 clang_analyzer_isTainted_charp(result); // expected-warning {{YES}}900}901 902char *index(const char *s, int c);903void testIndex() {904 char s[10];905 scanf("%9s", s);906 907 char *result = index(s, 9);908 clang_analyzer_isTainted_charp(result); // expected-warning {{YES}}909}910 911char *rindex(const char *s, int c);912void testRindex() {913 char s[10];914 scanf("%9s", s);915 916 char *result = rindex(s, 9);917 clang_analyzer_isTainted_charp(result); // expected-warning {{YES}}918}919 920int strcmp(const char *s1, const char *s2);921void testStrcmpWithLHSTainted(char *rhs) {922 char lhs[10];923 scanf("%9s", lhs);924 925 int cmp_result = strcmp(lhs, rhs);926 clang_analyzer_isTainted_int(cmp_result); // expected-warning {{YES}}927}928 929void testStrcmpWithRHSTainted(char *lhs) {930 char rhs[10];931 scanf("%9s", rhs);932 933 int cmp_result = strcmp(lhs, rhs);934 clang_analyzer_isTainted_int(cmp_result); // expected-warning {{YES}}935}936int strcasecmp(const char *s1, const char *s2);937void testStrcasecmpWithLHSTainted(char *rhs) {938 char lhs[10];939 scanf("%9s", lhs);940 941 int cmp_result = strcasecmp(lhs, rhs);942 clang_analyzer_isTainted_int(cmp_result); // expected-warning {{YES}}943}944 945void testStrcasecmpWithRHSTainted(char *lhs) {946 char rhs[10];947 scanf("%9s", rhs);948 949 int cmp_result = strcasecmp(lhs, rhs);950 clang_analyzer_isTainted_int(cmp_result); // expected-warning {{YES}}951}952int strncmp(const char *s1, const char *s2, size_t n);953void testStrncmpWithLHSTainted(char *rhs, size_t n) {954 char lhs[10];955 scanf("%9s", lhs);956 957 int cmp_result = strncmp(lhs, rhs, n);958 clang_analyzer_isTainted_int(cmp_result); // expected-warning {{YES}}959}960 961void testStrncmpWithRHSTainted(char *lhs, size_t n) {962 char rhs[10];963 scanf("%9s", rhs);964 965 int cmp_result = strncmp(lhs, rhs, n);966 clang_analyzer_isTainted_int(cmp_result); // expected-warning {{YES}}967}968 969void testStrncmpWithNTainted(char *lhs, char *rhs) {970 int n;971 scanf("%d", &n);972 973 int cmp_result = strncmp(lhs, rhs, n);974 clang_analyzer_isTainted_int(cmp_result); // expected-warning {{YES}}975}976 977int strncasecmp(const char *s1, const char *s2, size_t n);978void testStrncasecmpWithLHSTainted(char *rhs, size_t n) {979 char lhs[10];980 scanf("%9s", lhs);981 982 int cmp_result = strncmp(lhs, rhs, n);983 clang_analyzer_isTainted_int(cmp_result); // expected-warning {{YES}}984}985 986void testStrncasecmpWithRHSTainted(char *lhs, size_t n) {987 char rhs[10];988 scanf("%9s", rhs);989 990 int cmp_result = strncmp(lhs, rhs, n);991 clang_analyzer_isTainted_int(cmp_result); // expected-warning {{YES}}992}993 994void testStrncasecmpWithNTainted(char *lhs, char *rhs) {995 int n;996 scanf("%d", &n);997 998 int cmp_result = strncmp(lhs, rhs, n);999 clang_analyzer_isTainted_int(cmp_result); // expected-warning {{YES}}1000}1001 1002size_t strspn(const char *s, const char *accept);1003void testStrspnFirstArgTainted(const char *accept) {1004 char s[10];1005 scanf("%9s", s);1006 1007 size_t result = strspn(s, accept);1008 clang_analyzer_isTainted_int(result); // expected-warning {{YES}}1009}1010 1011void testStrspnSecondArgTainted(const char *s) {1012 char accept[10];1013 scanf("%9s", accept);1014 1015 size_t result = strspn(s, accept);1016 clang_analyzer_isTainted_int(result); // expected-warning {{YES}}1017}1018 1019size_t strcspn(const char *s, const char *reject);1020void testStrcspnFirstArgTainted(const char *reject) {1021 char s[10];1022 scanf("%9s", s);1023 1024 size_t result = strcspn(s, reject);1025 clang_analyzer_isTainted_int(result); // expected-warning {{YES}}1026}1027 1028void testStrcspnSecondArgTainted(const char *s) {1029 char reject[10];1030 scanf("%9s", reject);1031 1032 size_t result = strcspn(s, reject);1033 clang_analyzer_isTainted_int(result); // expected-warning {{YES}}1034}1035 1036char *strpbrk(const char *s, const char *accept);1037void testStrpbrk(const char *accept) {1038 char s[10];1039 scanf("%9s", s);1040 1041 char *result = strpbrk(s, accept);1042 clang_analyzer_isTainted_charp(result); // expected-warning {{YES}}1043}1044 1045char *strndup(const char *s, size_t n);1046void testStrndup(size_t n) {1047 char s[10];1048 scanf("%9s", s);1049 1050 char *result = strndup(s, n);1051 clang_analyzer_isTainted_charp(result); // expected-warning {{YES}}1052}1053 1054char *strdupa(const char *s);1055void testStrdupa() {1056 char s[10];1057 scanf("%9s", s);1058 1059 char *result = strdupa(s);1060 clang_analyzer_isTainted_charp(result); // expected-warning {{YES}}1061}1062 1063char *strndupa(const char *s, size_t n);1064void testStrndupa(size_t n) {1065 char s[10];1066 scanf("%9s", s);1067 1068 char *result = strndupa(s, n);1069 clang_analyzer_isTainted_charp(result); // expected-warning {{YES}}1070}1071 1072size_t strlen(const char *s);1073void testStrlen_dont_propagate() {1074 // strlen, wcslen, strnlen and alike intentionally don't propagate taint.1075 // See the details here: https://github.com/llvm/llvm-project/pull/660861076 // This isn't ideal, but this is only what we have now.1077 char s[10];1078 scanf("%9s", s);1079 1080 size_t result = strlen(s);1081 // strlen propagating taint would bring in many false positives1082 clang_analyzer_isTainted_int(result); // expected-warning {{NO}}1083}1084 1085size_t strnlen(const char *s, size_t maxlen);1086void testStrnlen_dont_propagate(size_t maxlen) {1087 // strlen, wcslen, strnlen and alike intentionally don't propagate taint.1088 // See the details here: https://github.com/llvm/llvm-project/pull/660861089 // This isn't ideal, but this is only what we have now.1090 char s[10];1091 scanf("%9s", s);1092 size_t result = strnlen(s, maxlen);1093 clang_analyzer_isTainted_int(result); // expected-warning {{NO}}1094}1095 1096long strtol(const char *restrict nptr, char **restrict endptr, int base);1097long long strtoll(const char *restrict nptr, char **restrict endptr, int base);1098unsigned long int strtoul(const char *nptr, char **endptr, int base);1099unsigned long long int strtoull(const char *nptr, char **endptr, int base);1100void testStrtolVariants(char **restrict endptr, int base) {1101 char s[10];1102 scanf("%9s", s);1103 1104 long result_l = strtol(s, endptr, base);1105 clang_analyzer_isTainted_int(result_l); // expected-warning {{YES}}1106 1107 long long result_ll = strtoll(s, endptr, base);1108 clang_analyzer_isTainted_int(result_ll); // expected-warning {{YES}}1109 1110 unsigned long result_ul = strtoul(s, endptr, base);1111 clang_analyzer_isTainted_int(result_ul); // expected-warning {{YES}}1112 1113 unsigned long long result_ull = strtoull(s, endptr, base);1114 clang_analyzer_isTainted_int(result_ull); // expected-warning {{YES}}1115}1116 1117int isalnum(int c);1118int isalpha(int c);1119int isascii(int c);1120int isblank(int c);1121int iscntrl(int c);1122int isdigit(int c);1123int isgraph(int c);1124int islower(int c);1125int isprint(int c);1126int ispunct(int c);1127int isspace(int c);1128int isupper(int c);1129int isxdigit(int c);1130 1131void testIsFunctions() {1132 char c;1133 scanf("%c", &c);1134 1135 int alnum = isalnum(c);1136 clang_analyzer_isTainted_int(alnum); // expected-warning {{YES}}1137 1138 int alpha = isalpha(c);1139 clang_analyzer_isTainted_int(alpha); // expected-warning {{YES}}1140 1141 int ascii = isascii(c);1142 clang_analyzer_isTainted_int(ascii); // expected-warning {{YES}}1143 1144 int blank = isblank(c);1145 clang_analyzer_isTainted_int(blank); // expected-warning {{YES}}1146 1147 int cntrl = iscntrl(c);1148 clang_analyzer_isTainted_int(cntrl); // expected-warning {{YES}}1149 1150 int digit = isdigit(c);1151 clang_analyzer_isTainted_int(digit); // expected-warning {{YES}}1152 1153 int graph = isgraph(c);1154 clang_analyzer_isTainted_int(graph); // expected-warning {{YES}}1155 1156 int lower = islower(c);1157 clang_analyzer_isTainted_int(lower); // expected-warning {{YES}}1158 1159 int print = isprint(c);1160 clang_analyzer_isTainted_int(print); // expected-warning {{YES}}1161 1162 int punct = ispunct(c);1163 clang_analyzer_isTainted_int(punct); // expected-warning {{YES}}1164 1165 int space = isspace(c);1166 clang_analyzer_isTainted_int(space); // expected-warning {{YES}}1167 1168 int upper = isupper(c);1169 clang_analyzer_isTainted_int(upper); // expected-warning {{YES}}1170 1171 int xdigit = isxdigit(c);1172 clang_analyzer_isTainted_int(xdigit); // expected-warning {{YES}}1173}1174 1175void qsort(void *base, size_t nmemb, size_t size, int (*compar)(const void *, const void *));1176void qsort_r(void *base, size_t nmemb, size_t size, int (*compar)(const void *, const void *, void *), void *arg);1177void testQsort() {1178 int data[1];1179 scanf("%d", data);1180 1181 qsort(data, sizeof(data), sizeof(data[0]), NULL);1182 clang_analyzer_isTainted_int(data[0]); // expected-warning {{YES}}1183 qsort_r(data, sizeof(data), sizeof(data[0]), NULL, NULL);1184 clang_analyzer_isTainted_int(data[0]); // expected-warning {{YES}}1185}1186 1187// Test configuration1188int mySource1(void);1189void mySource2(int*);1190void myScanf(const char*, ...);1191int myPropagator(int, int*);1192int mySnprintf(char*, size_t, const char*, ...);1193bool isOutOfRange(const int*); // const filter function1194void sanitizeCmd(char*); // non-const filter function1195void mySink(int, int, int);1196 1197void testConfigurationSources1(void) {1198 int x = mySource1();1199 Buffer[x] = 1; // expected-warning {{Potential out of bound access }}1200}1201 1202void testConfigurationSources2(void) {1203 int x;1204 mySource2(&x);1205 Buffer[x] = 1; // expected-warning {{Potential out of bound access }}1206}1207 1208void testConfigurationSources3(void) {1209 int x, y;1210 myScanf("%d %d", &x, &y);1211 Buffer[y] = 1; // expected-warning {{Potential out of bound access }}1212}1213 1214void testConfigurationPropagation(void) {1215 int x = mySource1();1216 int y;1217 myPropagator(x, &y);1218 Buffer[y] = 1; // expected-warning {{Potential out of bound access }}1219}1220 1221void testConfigurationFilter(void) {1222 int x = mySource1();1223 if (isOutOfRange(&x)) // the filter function1224 return;1225 Buffer[x] = 1; // no-warning1226}1227 1228void testConfigurationFilterNonConst(void) {1229 char buffer[1000];1230 myScanf("%s", buffer); // makes buffer tainted1231 system(buffer); // expected-warning {{Untrusted data is passed to a system call}}1232}1233 1234void testConfigurationFilterNonConst2(void) {1235 char buffer[1000];1236 myScanf("%s", buffer); // makes buffer tainted1237 sanitizeCmd(buffer); // removes taintedness1238 system(buffer); // no-warning1239}1240 1241void testConfigurationSinks(void) {1242 int x = mySource1();1243 mySink(x, 1, 2);1244 // expected-warning@-1 {{Untrusted data is passed to a user-defined sink}}1245 mySink(1, x, 2); // no-warning1246 mySink(1, 2, x);1247 // expected-warning@-1 {{Untrusted data is passed to a user-defined sink}}1248}1249 1250int test_exec_like_functions() {1251 char buf[100] = {0};1252 scanf("%99s", buf);1253 clang_analyzer_isTainted_char(buf[0]); // expected-warning {{YES}}1254 1255 char *cleanArray[] = {"ENV1=V1", "ENV2=V2", NULL};1256 char *taintedArray[] = {buf, "ENV2=V2", NULL};1257 clang_analyzer_isTainted_char(taintedArray[0][0]); // expected-warning {{YES}}1258 clang_analyzer_isTainted_char(*(char*)taintedArray[0]); // expected-warning {{YES}}1259 clang_analyzer_isTainted_char(*(char*)taintedArray); // expected-warning {{NO}} We should have YES here.1260 // FIXME: Above the triple pointer indirection will confuse the checker,1261 // as we only check two levels. The results would be worse, if the tainted1262 // subobject ("buf") would not be at the beginning of the enclosing object,1263 // for the same reason.1264 1265 switch (coin()) {1266 default: break;1267 // Execute `path` with all arguments after `path` until a NULL pointer1268 // and environment from `environ'.1269 case 0: return execl("path", "arg0", "arg1", "arg2", NULL); // no-warning1270 case 1: return execl(buf, "arg0", "arg1", "arg2", NULL); // expected-warning {{Untrusted data is passed to a system call}}1271 case 2: return execl("path", buf, "arg1", "arg2", NULL); // expected-warning {{Untrusted data is passed to a system call}}1272 case 3: return execl("path", "arg0", buf, "arg2", NULL); // expected-warning {{Untrusted data is passed to a system call}}1273 case 4: return execl("path", "arg0", "arg1", buf, NULL); // expected-warning {{Untrusted data is passed to a system call}}1274 }1275 1276 switch (coin()) {1277 default: break;1278 // Execute `path` with all arguments after `PATH` until a NULL pointer,1279 // and the argument after that for environment.1280 case 0: return execle("path", "arg0", "arg1", NULL, cleanArray); // no-warning1281 case 1: return execle( buf, "arg0", "arg1", NULL, cleanArray); // expected-warning {{Untrusted data is passed to a system call}}1282 case 2: return execle("path", buf, "arg1", NULL, cleanArray); // expected-warning {{Untrusted data is passed to a system call}}1283 case 3: return execle("path", "arg0", buf, NULL, cleanArray); // expected-warning {{Untrusted data is passed to a system call}}1284 case 4: return execle("path", "arg0", "arg1", NULL, buf); // expected-warning {{Untrusted data is passed to a system call}}1285 case 5: return execle("path", "arg0", "arg1", NULL, taintedArray); // FIXME: We might wanna have a report here.1286 }1287 1288 switch (coin()) {1289 default: break;1290 // Execute `file`, searching in the `PATH' environment variable if it1291 // contains no slashes, with all arguments after `file` until a NULL1292 // pointer and environment from `environ'.1293 case 0: return execlp("file", "arg0", "arg1", "arg2", NULL); // no-warning1294 case 1: return execlp( buf, "arg0", "arg1", "arg2", NULL); // expected-warning {{Untrusted data is passed to a system call}}1295 case 2: return execlp("file", buf, "arg1", "arg2", NULL); // expected-warning {{Untrusted data is passed to a system call}}1296 case 3: return execlp("file", "arg0", buf, "arg2", NULL); // expected-warning {{Untrusted data is passed to a system call}}1297 case 4: return execlp("file", "arg0", "arg1", buf, NULL); // expected-warning {{Untrusted data is passed to a system call}}1298 }1299 1300 switch (coin()) {1301 default: break;1302 // Execute `path` with arguments `ARGV` and environment from `environ'.1303 case 0: return execv("path", /*argv=*/ cleanArray); // no-warning1304 case 1: return execv( buf, /*argv=*/ cleanArray); // expected-warning {{Untrusted data is passed to a system call}}1305 case 2: return execv("path", /*argv=*/taintedArray); // FIXME: We might wanna have a report here.1306 }1307 1308 switch (coin()) {1309 default: break;1310 // Replace the current process, executing `path` with arguments `ARGV`1311 // and environment `ENVP`. `ARGV` and `ENVP` are terminated by NULL pointers.1312 case 0: return execve("path", /*argv=*/ cleanArray, /*envp=*/cleanArray); // no-warning1313 case 1: return execve( buf, /*argv=*/ cleanArray, /*envp=*/cleanArray); // expected-warning {{Untrusted data is passed to a system call}}1314 case 2: return execve("path", /*argv=*/taintedArray, /*envp=*/cleanArray); // FIXME: We might wanna have a report here.1315 case 3: return execve("path", /*argv=*/cleanArray, /*envp=*/taintedArray); // FIXME: We might wanna have a report here.1316 }1317 1318 switch (coin()) {1319 default: break;1320 // Execute `file`, searching in the `PATH' environment variable if it1321 // contains no slashes, with arguments `ARGV` and environment from `environ'.1322 case 0: return execvp("file", /*argv=*/ cleanArray); // no-warning1323 case 1: return execvp( buf, /*argv=*/ cleanArray); // expected-warning {{Untrusted data is passed to a system call}}1324 case 2: return execvp("file", /*argv=*/taintedArray); // FIXME: We might wanna have a report here.1325 }1326 1327 // execvpe1328 switch (coin()) {1329 default: break;1330 // Execute `file`, searching in the `PATH' environment variable if it1331 // contains no slashes, with arguments `ARGV` and environment `ENVP`.1332 // `ARGV` and `ENVP` are terminated by NULL pointers.1333 case 0: return execvpe("file", /*argv=*/ cleanArray, /*envp=*/ cleanArray); // no-warning1334 case 1: return execvpe( buf, /*argv=*/ cleanArray, /*envp=*/ cleanArray); // expected-warning {{Untrusted data is passed to a system call}}1335 case 2: return execvpe("file", /*argv=*/taintedArray, /*envp=*/ cleanArray); // FIXME: We might wanna have a report here.1336 case 3: return execvpe("file", /*argv=*/ cleanArray, /*envp=*/taintedArray); // FIXME: We might wanna have a report here.1337 }1338 1339 int cleanFD = coin();1340 int taintedFD;1341 scanf("%d", &taintedFD);1342 clang_analyzer_isTainted_int(taintedFD); // expected-warning {{YES}}1343 1344 switch (coin()) {1345 default: break;1346 // Execute the file `FD` refers to, overlaying the running program image.1347 // `ARGV` and `ENVP` are passed to the new program, as for `execve'.1348 case 0: return fexecve( cleanFD, /*argv=*/ cleanArray, /*envp=*/ cleanArray); // no-warning1349 case 1: return fexecve(taintedFD, /*argv=*/ cleanArray, /*envp=*/ cleanArray); // expected-warning {{Untrusted data is passed to a system call}}1350 case 2: return fexecve( cleanFD, /*argv=*/taintedArray, /*envp=*/ cleanArray); // FIXME: We might wanna have a report here.1351 case 3: return fexecve( cleanFD, /*argv=*/ cleanArray, /*envp=*/taintedArray); // FIXME: We might wanna have a report here.1352 }1353 1354 switch (coin()) {1355 default: break;1356 // Create a new stream connected to a pipe running the given `command`.1357 case 0: return pclose(popen("command", /*mode=*/"r")); // no-warning1358 case 1: return pclose(popen( buf, /*mode=*/"r")); // expected-warning {{Untrusted data is passed to a system call}}1359 case 2: return pclose(popen("command", /*mode=*/buf)); // 'mode' is not a taint sink.1360 }1361 1362 switch (coin()) {1363 default: break;1364 // Execute the given line as a shell command.1365 case 0: return system("command"); // no-warning1366 case 1: return system( buf); // expected-warning {{Untrusted data is passed to a system call}}1367 }1368 1369 return 0;1370}1371 1372void testUnknownFunction(void (*foo)(void)) {1373 foo(); // no-crash1374}1375 1376void testProctitleFalseNegative(void) {1377 char flag[80];1378 fscanf(stdin, "%79s", flag);1379 char *argv[] = {"myapp", flag};1380 // FIXME: We should have a warning below: Untrusted data passed to sink.1381 setproctitle_init(1, argv, 0);1382}1383 1384void testProctitle2(char *real_argv[]) {1385 char *app = getenv("APP_NAME");1386 if (!app)1387 return;1388 char *argv[] = {app, "--foobar"};1389 setproctitle_init(1, argv, 0); // expected-warning {{Untrusted data is passed to a user-defined sink}}1390 setproctitle_init(1, real_argv, argv); // expected-warning {{Untrusted data is passed to a user-defined sink}}1391}1392 1393void testAcceptPropagates() {1394 int listenSocket = socket(2, 1, 6);1395 clang_analyzer_isTainted_int(listenSocket); // expected-warning {{YES}}1396 int acceptSocket = accept(listenSocket, 0, 0);1397 clang_analyzer_isTainted_int(acceptSocket); // expected-warning {{YES}}1398}1399