// RUN: %clang_cc1 -analyze -analyzer-checker=experimental.security.taint,debug.TaintTest %s -verify #include int scanf(const char *restrict format, ...); int getchar(void); typedef __typeof(sizeof(int)) size_t; #define BUFSIZE 10 int Buffer[BUFSIZE]; struct XYStruct { int x; int y; char z; }; void taintTracking(int x) { int n; int *addr = &Buffer[0]; scanf("%d", &n); addr += n;// expected-warning + {{tainted}} *addr = n; // expected-warning + {{tainted}} double tdiv = n / 30; // expected-warning+ {{tainted}} char *loc_cast = (char *) n; // expected-warning +{{tainted}} char tinc = tdiv++; // expected-warning + {{tainted}} int tincdec = (char)tinc--; // expected-warning+{{tainted}} // Tainted ptr arithmetic/array element address. int tprtarithmetic1 = *(addr+1); // expected-warning + {{tainted}} // Dereference. int *ptr; scanf("%p", &ptr); int ptrDeref = *ptr; // expected-warning + {{tainted}} int _ptrDeref = ptrDeref + 13; // expected-warning + {{tainted}} // Pointer arithmetic + dereferencing. // FIXME: We fail to propagate the taint here because RegionStore does not // handle ElementRegions with symbolic indexes. int addrDeref = *addr; // expected-warning + {{tainted}} int _addrDeref = addrDeref; // expected-warning + {{tainted}} // Tainted struct address, casts. struct XYStruct *xyPtr = 0; scanf("%p", &xyPtr); void *tXYStructPtr = xyPtr; // expected-warning + {{tainted}} struct XYStruct *xyPtrCopy = tXYStructPtr; // expected-warning + {{tainted}} int ptrtx = xyPtr->x;// expected-warning + {{tainted}} int ptrty = xyPtr->y;// expected-warning + {{tainted}} // Taint on fields of a struct. struct XYStruct xy = {2, 3, 11}; scanf("%d", &xy.y); scanf("%d", &xy.x); int tx = xy.x; // expected-warning + {{tainted}} int ty = xy.y; // FIXME: This should be tainted as well. char ntz = xy.z;// no warning // Now, scanf scans both. scanf("%d %d", &xy.y, &xy.x); int ttx = xy.x; // expected-warning + {{tainted}} int tty = xy.y; // expected-warning + {{tainted}} } void BitwiseOp(int in, char inn) { // Taint on bitwise operations, integer to integer cast. int m; int x = 0; scanf("%d", &x); int y = (in << (x << in)) * 5;// expected-warning + {{tainted}} // The next line tests integer to integer cast. int z = y & inn; // expected-warning + {{tainted}} if (y == 5) // expected-warning + {{tainted}} m = z | z;// expected-warning + {{tainted}} else m = inn; int mm = m; // expected-warning + {{tainted}} } // Test getenv. char *getenv(const char *name); void getenvTest(char *home) { home = getenv("HOME"); // expected-warning + {{tainted}} if (home != 0) { // expected-warning + {{tainted}} char d = home[0]; // expected-warning + {{tainted}} } } typedef struct _FILE FILE; extern FILE *stdin; extern FILE *stdout; extern FILE *stderr; int fscanf(FILE *restrict stream, const char *restrict format, ...); int fprintf(FILE *stream, const char *format, ...); int fclose(FILE *stream); FILE *fopen(const char *path, const char *mode); int fscanfTest(void) { FILE *fp; char s[80]; int t; // Check if stdin is treated as tainted. fscanf(stdin, "%s %d", s, &t); // Note, here, s is not tainted, but the data s points to is tainted. char *ts = s; char tss = s[0]; // expected-warning + {{tainted}} int tt = t; // expected-warning + {{tainted}} if((fp=fopen("test", "w")) == 0) // expected-warning + {{tainted}} return 1; fprintf(fp, "%s %d", s, t); // expected-warning + {{tainted}} fclose(fp); // expected-warning + {{tainted}} // Test fscanf and fopen. if((fp=fopen("test","r")) == 0) // expected-warning + {{tainted}} return 1; fscanf(fp, "%s%d", s, &t); // expected-warning + {{tainted}} fprintf(stdout, "%s %d", s, t); // expected-warning + {{tainted}} return 0; } // Check if we propagate taint from stdin when it's used in an assignment. void stdinTest1() { int i; fscanf(stdin, "%d", &i); int j = i; // expected-warning + {{tainted}} } void stdinTest2(FILE *pIn) { FILE *p = stdin; FILE *pp = p; int ii; fscanf(pp, "%d", &ii); int jj = ii;// expected-warning + {{tainted}} fscanf(p, "%d", &ii); int jj2 = ii;// expected-warning + {{tainted}} ii = 3; int jj3 = ii;// no warning p = pIn; fscanf(p, "%d", &ii); int jj4 = ii;// no warning } void stdinTest3() { FILE **ppp = &stdin; int iii; fscanf(*ppp, "%d", &iii); int jjj = iii;// expected-warning + {{tainted}} } // Test that stdin does not get invalidated by calls. void foo(); void stdinTest4() { int i; fscanf(stdin, "%d", &i); foo(); int j = i; // expected-warning + {{tainted}} } int getw(FILE *); void getwTest() { int i = getw(stdin); // expected-warning + {{tainted}} } typedef long ssize_t; ssize_t getline(char ** __restrict, size_t * __restrict, FILE * __restrict); int printf(const char * __restrict, ...); void free(void *ptr); void getlineTest(void) { FILE *fp; char *line = 0; size_t len = 0; ssize_t read; while ((read = getline(&line, &len, stdin)) != -1) { printf("%s", line); // expected-warning + {{tainted}} } free(line); // expected-warning + {{tainted}} } // Test propagation functions - the ones that propagate taint from arguments to // return value, ptr arguments. int atoi(const char *nptr); long atol(const char *nptr); long long atoll(const char *nptr); void atoiTest() { char s[80]; scanf("%s", s); int d = atoi(s); // expected-warning + {{tainted}} int td = d; // expected-warning + {{tainted}} long l = atol(s); // expected-warning + {{tainted}} int tl = l; // expected-warning + {{tainted}} long long ll = atoll(s); // expected-warning + {{tainted}} int tll = ll; // expected-warning + {{tainted}} }