// TODO: Should this check be a part of the CString checker? // If yes, should taint be a global setting? bool GenericTaintChecker::checkTaintedBufferSize(const CallExpr *CE, const FunctionDecl *FDecl, CheckerContext &C) const { // If the function has a buffer size argument, set ArgNum. unsigned ArgNum = InvalidArgIndex; unsigned BId = 0; if ( (BId = FDecl->getMemoryFunctionKind()) ) switch(BId) { case Builtin::BImemcpy: case Builtin::BImemmove: case Builtin::BIstrncpy: ArgNum = 2; break; case Builtin::BIstrndup: ArgNum = 1; break; default: break; }; if (ArgNum == InvalidArgIndex) { if (C.isCLibraryFunction(FDecl, "malloc") || C.isCLibraryFunction(FDecl, "calloc") || C.isCLibraryFunction(FDecl, "alloca")) ArgNum = 0; else if (C.isCLibraryFunction(FDecl, "memccpy")) ArgNum = 3; else if (C.isCLibraryFunction(FDecl, "realloc")) ArgNum = 1; else if (C.isCLibraryFunction(FDecl, "bcopy")) ArgNum = 2; } if (ArgNum != InvalidArgIndex && CE->getNumArgs() > ArgNum && generateReportIfTainted(CE->getArg(ArgNum), MsgTaintedBufferSize, C)) return true; return false; }
GenericTaintChecker::TaintPropagationRule GenericTaintChecker::TaintPropagationRule::getTaintPropagationRule( const FunctionDecl *FDecl, StringRef Name, CheckerContext &C) { // TODO: Currently, we might lose precision here: we always mark a return // value as tainted even if it's just a pointer, pointing to tainted data. // Check for exact name match for functions without builtin substitutes. TaintPropagationRule Rule = llvm::StringSwitch<TaintPropagationRule>(Name) .Case("atoi", TaintPropagationRule(0, ReturnValueIndex)) .Case("atol", TaintPropagationRule(0, ReturnValueIndex)) .Case("atoll", TaintPropagationRule(0, ReturnValueIndex)) .Case("getc", TaintPropagationRule(0, ReturnValueIndex)) .Case("fgetc", TaintPropagationRule(0, ReturnValueIndex)) .Case("getc_unlocked", TaintPropagationRule(0, ReturnValueIndex)) .Case("getw", TaintPropagationRule(0, ReturnValueIndex)) .Case("toupper", TaintPropagationRule(0, ReturnValueIndex)) .Case("tolower", TaintPropagationRule(0, ReturnValueIndex)) .Case("strchr", TaintPropagationRule(0, ReturnValueIndex)) .Case("strrchr", TaintPropagationRule(0, ReturnValueIndex)) .Case("read", TaintPropagationRule(0, 2, 1, true)) .Case("pread", TaintPropagationRule(InvalidArgIndex, 1, true)) .Case("gets", TaintPropagationRule(InvalidArgIndex, 0, true)) .Case("fgets", TaintPropagationRule(2, 0, true)) .Case("getline", TaintPropagationRule(2, 0)) .Case("getdelim", TaintPropagationRule(3, 0)) .Case("fgetln", TaintPropagationRule(0, ReturnValueIndex)) .Default(TaintPropagationRule()); if (!Rule.isNull()) return Rule; // Check if it's one of the memory setting/copying functions. // This check is specialized but faster then calling isCLibraryFunction. unsigned BId = 0; if ( (BId = FDecl->getMemoryFunctionKind()) ) switch(BId) { case Builtin::BImemcpy: case Builtin::BImemmove: case Builtin::BIstrncpy: case Builtin::BIstrncat: return TaintPropagationRule(1, 2, 0, true); case Builtin::BIstrlcpy: case Builtin::BIstrlcat: return TaintPropagationRule(1, 2, 0, false); case Builtin::BIstrndup: return TaintPropagationRule(0, 1, ReturnValueIndex); default: break; }; // Process all other functions which could be defined as builtins. if (Rule.isNull()) { if (C.isCLibraryFunction(FDecl, "snprintf") || C.isCLibraryFunction(FDecl, "sprintf")) return TaintPropagationRule(InvalidArgIndex, 0, true); else if (C.isCLibraryFunction(FDecl, "strcpy") || C.isCLibraryFunction(FDecl, "stpcpy") || C.isCLibraryFunction(FDecl, "strcat")) return TaintPropagationRule(1, 0, true); else if (C.isCLibraryFunction(FDecl, "bcopy")) return TaintPropagationRule(0, 2, 1, false); else if (C.isCLibraryFunction(FDecl, "strdup") || C.isCLibraryFunction(FDecl, "strdupa")) return TaintPropagationRule(0, ReturnValueIndex); else if (C.isCLibraryFunction(FDecl, "wcsdup")) return TaintPropagationRule(0, ReturnValueIndex); } // Skipping the following functions, since they might be used for cleansing // or smart memory copy: // - memccpy - copying until hitting a special character. return TaintPropagationRule(); }