[analyzer] Mark output of fscanf and fopen as tainted.

llvm-svn: 146533
This commit is contained in:
Anna Zaks 2011-12-14 00:56:02 +00:00
parent d6bb3227de
commit eefc0e9342
2 changed files with 65 additions and 1 deletions

View File

@ -39,6 +39,7 @@ class GenericTaintChecker : public Checker< check::PostStmt<CallExpr> > {
typedef void (GenericTaintChecker::*FnCheck)(const CallExpr *,
CheckerContext &C) const;
void processScanf(const CallExpr *CE, CheckerContext &C) const;
void processFscanf(const CallExpr *CE, CheckerContext &C) const;
void processRetTaint(const CallExpr *CE, CheckerContext &C) const;
public:
@ -62,8 +63,14 @@ void GenericTaintChecker::checkPostStmt(const CallExpr *CE,
// Set the evaluation function by switching on the callee name.
FnCheck evalFunction = llvm::StringSwitch<FnCheck>(Name)
.Case("scanf", &GenericTaintChecker::processScanf)
.Case("fscanf", &GenericTaintChecker::processFscanf)
.Case("sscanf", &GenericTaintChecker::processFscanf)
// TODO: Add support for vfscanf & family.
.Case("getchar", &GenericTaintChecker::processRetTaint)
.Case("getenv", &GenericTaintChecker::processRetTaint)
.Case("fopen", &GenericTaintChecker::processRetTaint)
.Case("fdopen", &GenericTaintChecker::processRetTaint)
.Case("freopen", &GenericTaintChecker::processRetTaint)
.Default(NULL);
// If the callee isn't defined, it is not of security concern.
@ -108,7 +115,7 @@ SymbolRef GenericTaintChecker::getPointedToSymbol(CheckerContext &C,
void GenericTaintChecker::processScanf(const CallExpr *CE,
CheckerContext &C) const {
const ProgramState *State = C.getState();
assert(CE->getNumArgs() == 2);
assert(CE->getNumArgs() >= 2);
SVal x = State->getSVal(CE->getArg(1));
// All arguments except for the very first one should get taint.
for (unsigned int i = 1; i < CE->getNumArgs(); ++i) {
@ -120,7 +127,29 @@ void GenericTaintChecker::processScanf(const CallExpr *CE,
State = State->addTaint(Sym);
}
C.addTransition(State);
}
/// If argument 0 (file descriptor) is tainted, all arguments except for arg 0
/// and arg 1 should get taint.
void GenericTaintChecker::processFscanf(const CallExpr *CE,
CheckerContext &C) const {
const ProgramState *State = C.getState();
assert(CE->getNumArgs() >= 2);
// Check is the file descriptor is tainted.
if (!State->isTainted(CE->getArg(0)))
return;
// All arguments except for the first two should get taint.
for (unsigned int i = 2; i < CE->getNumArgs(); ++i) {
// The arguments are pointer arguments. The data they are pointing at is
// tainted after the call.
const Expr* Arg = CE->getArg(i);
SymbolRef Sym = getPointedToSymbol(C, Arg);
if (Sym)
State = State->addTaint(Sym);
}
C.addTransition(State);
}
void GenericTaintChecker::processRetTaint(const CallExpr *CE,

View File

@ -54,6 +54,10 @@ void taintTracking(int 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) {
@ -80,3 +84,34 @@ void getenvTest(char *home) {
}
}
struct _IO_FILE {
unsigned fakeField1;
char fakeField2;
};
typedef struct _IO_FILE FILE;
extern struct _IO_FILE *stdin;
extern struct _IO_FILE *stdout;
extern struct _IO_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;
if((fp=fopen("test", "w")) == 0) // expected-warning 3 {{tainted}}
return 1;
// TODO: Have to mark stdin as tainted.
fscanf(stdin, "%s%d", s, &t);
fprintf(fp, "%s %d", s, t); // expected-warning 1 {{tainted}}
fclose(fp); // expected-warning 1 {{tainted}}
if((fp=fopen("test","r")) == 0) // expected-warning 3 {{tainted}}
return 1;
fscanf(fp, "%s%d", s, &t); // expected-warning 1 {{tainted}}
fprintf(stdout, "%s %d", s, t); // expected-warning 1 {{tainted}}
return 0;
}