1*0b57cec5SDimitry Andric //== GenericTaintChecker.cpp ----------------------------------- -*- C++ -*--=// 2*0b57cec5SDimitry Andric // 3*0b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4*0b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5*0b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6*0b57cec5SDimitry Andric // 7*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 8*0b57cec5SDimitry Andric // 9*0b57cec5SDimitry Andric // This checker defines the attack surface for generic taint propagation. 10*0b57cec5SDimitry Andric // 11*0b57cec5SDimitry Andric // The taint information produced by it might be useful to other checkers. For 12*0b57cec5SDimitry Andric // example, checkers should report errors which involve tainted data more 13*0b57cec5SDimitry Andric // aggressively, even if the involved symbols are under constrained. 14*0b57cec5SDimitry Andric // 15*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 16*0b57cec5SDimitry Andric 17*0b57cec5SDimitry Andric #include "Taint.h" 18*0b57cec5SDimitry Andric #include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h" 19*0b57cec5SDimitry Andric #include "clang/AST/Attr.h" 20*0b57cec5SDimitry Andric #include "clang/Basic/Builtins.h" 21*0b57cec5SDimitry Andric #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" 22*0b57cec5SDimitry Andric #include "clang/StaticAnalyzer/Core/Checker.h" 23*0b57cec5SDimitry Andric #include "clang/StaticAnalyzer/Core/CheckerManager.h" 24*0b57cec5SDimitry Andric #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" 25*0b57cec5SDimitry Andric #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h" 26*0b57cec5SDimitry Andric #include <climits> 27*0b57cec5SDimitry Andric #include <initializer_list> 28*0b57cec5SDimitry Andric #include <utility> 29*0b57cec5SDimitry Andric 30*0b57cec5SDimitry Andric using namespace clang; 31*0b57cec5SDimitry Andric using namespace ento; 32*0b57cec5SDimitry Andric using namespace taint; 33*0b57cec5SDimitry Andric 34*0b57cec5SDimitry Andric namespace { 35*0b57cec5SDimitry Andric class GenericTaintChecker 36*0b57cec5SDimitry Andric : public Checker<check::PostStmt<CallExpr>, check::PreStmt<CallExpr>> { 37*0b57cec5SDimitry Andric public: 38*0b57cec5SDimitry Andric static void *getTag() { 39*0b57cec5SDimitry Andric static int Tag; 40*0b57cec5SDimitry Andric return &Tag; 41*0b57cec5SDimitry Andric } 42*0b57cec5SDimitry Andric 43*0b57cec5SDimitry Andric void checkPostStmt(const CallExpr *CE, CheckerContext &C) const; 44*0b57cec5SDimitry Andric 45*0b57cec5SDimitry Andric void checkPreStmt(const CallExpr *CE, CheckerContext &C) const; 46*0b57cec5SDimitry Andric 47*0b57cec5SDimitry Andric void printState(raw_ostream &Out, ProgramStateRef State, 48*0b57cec5SDimitry Andric const char *NL, const char *Sep) const override; 49*0b57cec5SDimitry Andric 50*0b57cec5SDimitry Andric private: 51*0b57cec5SDimitry Andric static const unsigned InvalidArgIndex = UINT_MAX; 52*0b57cec5SDimitry Andric /// Denotes the return vale. 53*0b57cec5SDimitry Andric static const unsigned ReturnValueIndex = UINT_MAX - 1; 54*0b57cec5SDimitry Andric 55*0b57cec5SDimitry Andric mutable std::unique_ptr<BugType> BT; 56*0b57cec5SDimitry Andric void initBugType() const { 57*0b57cec5SDimitry Andric if (!BT) 58*0b57cec5SDimitry Andric BT.reset(new BugType(this, "Use of Untrusted Data", "Untrusted Data")); 59*0b57cec5SDimitry Andric } 60*0b57cec5SDimitry Andric 61*0b57cec5SDimitry Andric /// Catch taint related bugs. Check if tainted data is passed to a 62*0b57cec5SDimitry Andric /// system call etc. 63*0b57cec5SDimitry Andric bool checkPre(const CallExpr *CE, CheckerContext &C) const; 64*0b57cec5SDimitry Andric 65*0b57cec5SDimitry Andric /// Add taint sources on a pre-visit. 66*0b57cec5SDimitry Andric void addSourcesPre(const CallExpr *CE, CheckerContext &C) const; 67*0b57cec5SDimitry Andric 68*0b57cec5SDimitry Andric /// Propagate taint generated at pre-visit. 69*0b57cec5SDimitry Andric bool propagateFromPre(const CallExpr *CE, CheckerContext &C) const; 70*0b57cec5SDimitry Andric 71*0b57cec5SDimitry Andric /// Check if the region the expression evaluates to is the standard input, 72*0b57cec5SDimitry Andric /// and thus, is tainted. 73*0b57cec5SDimitry Andric static bool isStdin(const Expr *E, CheckerContext &C); 74*0b57cec5SDimitry Andric 75*0b57cec5SDimitry Andric /// Given a pointer argument, return the value it points to. 76*0b57cec5SDimitry Andric static Optional<SVal> getPointedToSVal(CheckerContext &C, const Expr *Arg); 77*0b57cec5SDimitry Andric 78*0b57cec5SDimitry Andric /// Check for CWE-134: Uncontrolled Format String. 79*0b57cec5SDimitry Andric static const char MsgUncontrolledFormatString[]; 80*0b57cec5SDimitry Andric bool checkUncontrolledFormatString(const CallExpr *CE, 81*0b57cec5SDimitry Andric CheckerContext &C) const; 82*0b57cec5SDimitry Andric 83*0b57cec5SDimitry Andric /// Check for: 84*0b57cec5SDimitry Andric /// CERT/STR02-C. "Sanitize data passed to complex subsystems" 85*0b57cec5SDimitry Andric /// CWE-78, "Failure to Sanitize Data into an OS Command" 86*0b57cec5SDimitry Andric static const char MsgSanitizeSystemArgs[]; 87*0b57cec5SDimitry Andric bool checkSystemCall(const CallExpr *CE, StringRef Name, 88*0b57cec5SDimitry Andric CheckerContext &C) const; 89*0b57cec5SDimitry Andric 90*0b57cec5SDimitry Andric /// Check if tainted data is used as a buffer size ins strn.. functions, 91*0b57cec5SDimitry Andric /// and allocators. 92*0b57cec5SDimitry Andric static const char MsgTaintedBufferSize[]; 93*0b57cec5SDimitry Andric bool checkTaintedBufferSize(const CallExpr *CE, const FunctionDecl *FDecl, 94*0b57cec5SDimitry Andric CheckerContext &C) const; 95*0b57cec5SDimitry Andric 96*0b57cec5SDimitry Andric /// Generate a report if the expression is tainted or points to tainted data. 97*0b57cec5SDimitry Andric bool generateReportIfTainted(const Expr *E, const char Msg[], 98*0b57cec5SDimitry Andric CheckerContext &C) const; 99*0b57cec5SDimitry Andric 100*0b57cec5SDimitry Andric using ArgVector = SmallVector<unsigned, 2>; 101*0b57cec5SDimitry Andric 102*0b57cec5SDimitry Andric /// A struct used to specify taint propagation rules for a function. 103*0b57cec5SDimitry Andric /// 104*0b57cec5SDimitry Andric /// If any of the possible taint source arguments is tainted, all of the 105*0b57cec5SDimitry Andric /// destination arguments should also be tainted. Use InvalidArgIndex in the 106*0b57cec5SDimitry Andric /// src list to specify that all of the arguments can introduce taint. Use 107*0b57cec5SDimitry Andric /// InvalidArgIndex in the dst arguments to signify that all the non-const 108*0b57cec5SDimitry Andric /// pointer and reference arguments might be tainted on return. If 109*0b57cec5SDimitry Andric /// ReturnValueIndex is added to the dst list, the return value will be 110*0b57cec5SDimitry Andric /// tainted. 111*0b57cec5SDimitry Andric struct TaintPropagationRule { 112*0b57cec5SDimitry Andric enum class VariadicType { None, Src, Dst }; 113*0b57cec5SDimitry Andric 114*0b57cec5SDimitry Andric using PropagationFuncType = bool (*)(bool IsTainted, const CallExpr *, 115*0b57cec5SDimitry Andric CheckerContext &C); 116*0b57cec5SDimitry Andric 117*0b57cec5SDimitry Andric /// List of arguments which can be taint sources and should be checked. 118*0b57cec5SDimitry Andric ArgVector SrcArgs; 119*0b57cec5SDimitry Andric /// List of arguments which should be tainted on function return. 120*0b57cec5SDimitry Andric ArgVector DstArgs; 121*0b57cec5SDimitry Andric /// Index for the first variadic parameter if exist. 122*0b57cec5SDimitry Andric unsigned VariadicIndex; 123*0b57cec5SDimitry Andric /// Show when a function has variadic parameters. If it has, it marks all 124*0b57cec5SDimitry Andric /// of them as source or destination. 125*0b57cec5SDimitry Andric VariadicType VarType; 126*0b57cec5SDimitry Andric /// Special function for tainted source determination. If defined, it can 127*0b57cec5SDimitry Andric /// override the default behavior. 128*0b57cec5SDimitry Andric PropagationFuncType PropagationFunc; 129*0b57cec5SDimitry Andric 130*0b57cec5SDimitry Andric TaintPropagationRule() 131*0b57cec5SDimitry Andric : VariadicIndex(InvalidArgIndex), VarType(VariadicType::None), 132*0b57cec5SDimitry Andric PropagationFunc(nullptr) {} 133*0b57cec5SDimitry Andric 134*0b57cec5SDimitry Andric TaintPropagationRule(std::initializer_list<unsigned> &&Src, 135*0b57cec5SDimitry Andric std::initializer_list<unsigned> &&Dst, 136*0b57cec5SDimitry Andric VariadicType Var = VariadicType::None, 137*0b57cec5SDimitry Andric unsigned VarIndex = InvalidArgIndex, 138*0b57cec5SDimitry Andric PropagationFuncType Func = nullptr) 139*0b57cec5SDimitry Andric : SrcArgs(std::move(Src)), DstArgs(std::move(Dst)), 140*0b57cec5SDimitry Andric VariadicIndex(VarIndex), VarType(Var), PropagationFunc(Func) {} 141*0b57cec5SDimitry Andric 142*0b57cec5SDimitry Andric /// Get the propagation rule for a given function. 143*0b57cec5SDimitry Andric static TaintPropagationRule 144*0b57cec5SDimitry Andric getTaintPropagationRule(const FunctionDecl *FDecl, StringRef Name, 145*0b57cec5SDimitry Andric CheckerContext &C); 146*0b57cec5SDimitry Andric 147*0b57cec5SDimitry Andric void addSrcArg(unsigned A) { SrcArgs.push_back(A); } 148*0b57cec5SDimitry Andric void addDstArg(unsigned A) { DstArgs.push_back(A); } 149*0b57cec5SDimitry Andric 150*0b57cec5SDimitry Andric bool isNull() const { 151*0b57cec5SDimitry Andric return SrcArgs.empty() && DstArgs.empty() && 152*0b57cec5SDimitry Andric VariadicType::None == VarType; 153*0b57cec5SDimitry Andric } 154*0b57cec5SDimitry Andric 155*0b57cec5SDimitry Andric bool isDestinationArgument(unsigned ArgNum) const { 156*0b57cec5SDimitry Andric return (llvm::find(DstArgs, ArgNum) != DstArgs.end()); 157*0b57cec5SDimitry Andric } 158*0b57cec5SDimitry Andric 159*0b57cec5SDimitry Andric static bool isTaintedOrPointsToTainted(const Expr *E, ProgramStateRef State, 160*0b57cec5SDimitry Andric CheckerContext &C) { 161*0b57cec5SDimitry Andric if (isTainted(State, E, C.getLocationContext()) || isStdin(E, C)) 162*0b57cec5SDimitry Andric return true; 163*0b57cec5SDimitry Andric 164*0b57cec5SDimitry Andric if (!E->getType().getTypePtr()->isPointerType()) 165*0b57cec5SDimitry Andric return false; 166*0b57cec5SDimitry Andric 167*0b57cec5SDimitry Andric Optional<SVal> V = getPointedToSVal(C, E); 168*0b57cec5SDimitry Andric return (V && isTainted(State, *V)); 169*0b57cec5SDimitry Andric } 170*0b57cec5SDimitry Andric 171*0b57cec5SDimitry Andric /// Pre-process a function which propagates taint according to the 172*0b57cec5SDimitry Andric /// taint rule. 173*0b57cec5SDimitry Andric ProgramStateRef process(const CallExpr *CE, CheckerContext &C) const; 174*0b57cec5SDimitry Andric 175*0b57cec5SDimitry Andric // Functions for custom taintedness propagation. 176*0b57cec5SDimitry Andric static bool postSocket(bool IsTainted, const CallExpr *CE, 177*0b57cec5SDimitry Andric CheckerContext &C); 178*0b57cec5SDimitry Andric }; 179*0b57cec5SDimitry Andric }; 180*0b57cec5SDimitry Andric 181*0b57cec5SDimitry Andric const unsigned GenericTaintChecker::ReturnValueIndex; 182*0b57cec5SDimitry Andric const unsigned GenericTaintChecker::InvalidArgIndex; 183*0b57cec5SDimitry Andric 184*0b57cec5SDimitry Andric const char GenericTaintChecker::MsgUncontrolledFormatString[] = 185*0b57cec5SDimitry Andric "Untrusted data is used as a format string " 186*0b57cec5SDimitry Andric "(CWE-134: Uncontrolled Format String)"; 187*0b57cec5SDimitry Andric 188*0b57cec5SDimitry Andric const char GenericTaintChecker::MsgSanitizeSystemArgs[] = 189*0b57cec5SDimitry Andric "Untrusted data is passed to a system call " 190*0b57cec5SDimitry Andric "(CERT/STR02-C. Sanitize data passed to complex subsystems)"; 191*0b57cec5SDimitry Andric 192*0b57cec5SDimitry Andric const char GenericTaintChecker::MsgTaintedBufferSize[] = 193*0b57cec5SDimitry Andric "Untrusted data is used to specify the buffer size " 194*0b57cec5SDimitry Andric "(CERT/STR31-C. Guarantee that storage for strings has sufficient space " 195*0b57cec5SDimitry Andric "for character data and the null terminator)"; 196*0b57cec5SDimitry Andric 197*0b57cec5SDimitry Andric } // end of anonymous namespace 198*0b57cec5SDimitry Andric 199*0b57cec5SDimitry Andric /// A set which is used to pass information from call pre-visit instruction 200*0b57cec5SDimitry Andric /// to the call post-visit. The values are unsigned integers, which are either 201*0b57cec5SDimitry Andric /// ReturnValueIndex, or indexes of the pointer/reference argument, which 202*0b57cec5SDimitry Andric /// points to data, which should be tainted on return. 203*0b57cec5SDimitry Andric REGISTER_SET_WITH_PROGRAMSTATE(TaintArgsOnPostVisit, unsigned) 204*0b57cec5SDimitry Andric 205*0b57cec5SDimitry Andric GenericTaintChecker::TaintPropagationRule 206*0b57cec5SDimitry Andric GenericTaintChecker::TaintPropagationRule::getTaintPropagationRule( 207*0b57cec5SDimitry Andric const FunctionDecl *FDecl, StringRef Name, CheckerContext &C) { 208*0b57cec5SDimitry Andric // TODO: Currently, we might lose precision here: we always mark a return 209*0b57cec5SDimitry Andric // value as tainted even if it's just a pointer, pointing to tainted data. 210*0b57cec5SDimitry Andric 211*0b57cec5SDimitry Andric // Check for exact name match for functions without builtin substitutes. 212*0b57cec5SDimitry Andric TaintPropagationRule Rule = 213*0b57cec5SDimitry Andric llvm::StringSwitch<TaintPropagationRule>(Name) 214*0b57cec5SDimitry Andric // Source functions 215*0b57cec5SDimitry Andric // TODO: Add support for vfscanf & family. 216*0b57cec5SDimitry Andric .Case("fdopen", TaintPropagationRule({}, {ReturnValueIndex})) 217*0b57cec5SDimitry Andric .Case("fopen", TaintPropagationRule({}, {ReturnValueIndex})) 218*0b57cec5SDimitry Andric .Case("freopen", TaintPropagationRule({}, {ReturnValueIndex})) 219*0b57cec5SDimitry Andric .Case("getch", TaintPropagationRule({}, {ReturnValueIndex})) 220*0b57cec5SDimitry Andric .Case("getchar", TaintPropagationRule({}, {ReturnValueIndex})) 221*0b57cec5SDimitry Andric .Case("getchar_unlocked", TaintPropagationRule({}, {ReturnValueIndex})) 222*0b57cec5SDimitry Andric .Case("getenv", TaintPropagationRule({}, {ReturnValueIndex})) 223*0b57cec5SDimitry Andric .Case("gets", TaintPropagationRule({}, {0, ReturnValueIndex})) 224*0b57cec5SDimitry Andric .Case("scanf", TaintPropagationRule({}, {}, VariadicType::Dst, 1)) 225*0b57cec5SDimitry Andric .Case("socket", 226*0b57cec5SDimitry Andric TaintPropagationRule({}, {ReturnValueIndex}, VariadicType::None, 227*0b57cec5SDimitry Andric InvalidArgIndex, 228*0b57cec5SDimitry Andric &TaintPropagationRule::postSocket)) 229*0b57cec5SDimitry Andric .Case("wgetch", TaintPropagationRule({}, {ReturnValueIndex})) 230*0b57cec5SDimitry Andric // Propagating functions 231*0b57cec5SDimitry Andric .Case("atoi", TaintPropagationRule({0}, {ReturnValueIndex})) 232*0b57cec5SDimitry Andric .Case("atol", TaintPropagationRule({0}, {ReturnValueIndex})) 233*0b57cec5SDimitry Andric .Case("atoll", TaintPropagationRule({0}, {ReturnValueIndex})) 234*0b57cec5SDimitry Andric .Case("fgetc", TaintPropagationRule({0}, {ReturnValueIndex})) 235*0b57cec5SDimitry Andric .Case("fgetln", TaintPropagationRule({0}, {ReturnValueIndex})) 236*0b57cec5SDimitry Andric .Case("fgets", TaintPropagationRule({2}, {0, ReturnValueIndex})) 237*0b57cec5SDimitry Andric .Case("fscanf", TaintPropagationRule({0}, {}, VariadicType::Dst, 2)) 238*0b57cec5SDimitry Andric .Case("getc", TaintPropagationRule({0}, {ReturnValueIndex})) 239*0b57cec5SDimitry Andric .Case("getc_unlocked", TaintPropagationRule({0}, {ReturnValueIndex})) 240*0b57cec5SDimitry Andric .Case("getdelim", TaintPropagationRule({3}, {0})) 241*0b57cec5SDimitry Andric .Case("getline", TaintPropagationRule({2}, {0})) 242*0b57cec5SDimitry Andric .Case("getw", TaintPropagationRule({0}, {ReturnValueIndex})) 243*0b57cec5SDimitry Andric .Case("pread", 244*0b57cec5SDimitry Andric TaintPropagationRule({0, 1, 2, 3}, {1, ReturnValueIndex})) 245*0b57cec5SDimitry Andric .Case("read", TaintPropagationRule({0, 2}, {1, ReturnValueIndex})) 246*0b57cec5SDimitry Andric .Case("strchr", TaintPropagationRule({0}, {ReturnValueIndex})) 247*0b57cec5SDimitry Andric .Case("strrchr", TaintPropagationRule({0}, {ReturnValueIndex})) 248*0b57cec5SDimitry Andric .Case("tolower", TaintPropagationRule({0}, {ReturnValueIndex})) 249*0b57cec5SDimitry Andric .Case("toupper", TaintPropagationRule({0}, {ReturnValueIndex})) 250*0b57cec5SDimitry Andric .Default(TaintPropagationRule()); 251*0b57cec5SDimitry Andric 252*0b57cec5SDimitry Andric if (!Rule.isNull()) 253*0b57cec5SDimitry Andric return Rule; 254*0b57cec5SDimitry Andric 255*0b57cec5SDimitry Andric // Check if it's one of the memory setting/copying functions. 256*0b57cec5SDimitry Andric // This check is specialized but faster then calling isCLibraryFunction. 257*0b57cec5SDimitry Andric unsigned BId = 0; 258*0b57cec5SDimitry Andric if ((BId = FDecl->getMemoryFunctionKind())) 259*0b57cec5SDimitry Andric switch (BId) { 260*0b57cec5SDimitry Andric case Builtin::BImemcpy: 261*0b57cec5SDimitry Andric case Builtin::BImemmove: 262*0b57cec5SDimitry Andric case Builtin::BIstrncpy: 263*0b57cec5SDimitry Andric case Builtin::BIstrncat: 264*0b57cec5SDimitry Andric return TaintPropagationRule({1, 2}, {0, ReturnValueIndex}); 265*0b57cec5SDimitry Andric case Builtin::BIstrlcpy: 266*0b57cec5SDimitry Andric case Builtin::BIstrlcat: 267*0b57cec5SDimitry Andric return TaintPropagationRule({1, 2}, {0}); 268*0b57cec5SDimitry Andric case Builtin::BIstrndup: 269*0b57cec5SDimitry Andric return TaintPropagationRule({0, 1}, {ReturnValueIndex}); 270*0b57cec5SDimitry Andric 271*0b57cec5SDimitry Andric default: 272*0b57cec5SDimitry Andric break; 273*0b57cec5SDimitry Andric }; 274*0b57cec5SDimitry Andric 275*0b57cec5SDimitry Andric // Process all other functions which could be defined as builtins. 276*0b57cec5SDimitry Andric if (Rule.isNull()) { 277*0b57cec5SDimitry Andric if (C.isCLibraryFunction(FDecl, "snprintf")) 278*0b57cec5SDimitry Andric return TaintPropagationRule({1}, {0, ReturnValueIndex}, VariadicType::Src, 279*0b57cec5SDimitry Andric 3); 280*0b57cec5SDimitry Andric else if (C.isCLibraryFunction(FDecl, "sprintf")) 281*0b57cec5SDimitry Andric return TaintPropagationRule({}, {0, ReturnValueIndex}, VariadicType::Src, 282*0b57cec5SDimitry Andric 2); 283*0b57cec5SDimitry Andric else if (C.isCLibraryFunction(FDecl, "strcpy") || 284*0b57cec5SDimitry Andric C.isCLibraryFunction(FDecl, "stpcpy") || 285*0b57cec5SDimitry Andric C.isCLibraryFunction(FDecl, "strcat")) 286*0b57cec5SDimitry Andric return TaintPropagationRule({1}, {0, ReturnValueIndex}); 287*0b57cec5SDimitry Andric else if (C.isCLibraryFunction(FDecl, "bcopy")) 288*0b57cec5SDimitry Andric return TaintPropagationRule({0, 2}, {1}); 289*0b57cec5SDimitry Andric else if (C.isCLibraryFunction(FDecl, "strdup") || 290*0b57cec5SDimitry Andric C.isCLibraryFunction(FDecl, "strdupa")) 291*0b57cec5SDimitry Andric return TaintPropagationRule({0}, {ReturnValueIndex}); 292*0b57cec5SDimitry Andric else if (C.isCLibraryFunction(FDecl, "wcsdup")) 293*0b57cec5SDimitry Andric return TaintPropagationRule({0}, {ReturnValueIndex}); 294*0b57cec5SDimitry Andric } 295*0b57cec5SDimitry Andric 296*0b57cec5SDimitry Andric // Skipping the following functions, since they might be used for cleansing 297*0b57cec5SDimitry Andric // or smart memory copy: 298*0b57cec5SDimitry Andric // - memccpy - copying until hitting a special character. 299*0b57cec5SDimitry Andric 300*0b57cec5SDimitry Andric return TaintPropagationRule(); 301*0b57cec5SDimitry Andric } 302*0b57cec5SDimitry Andric 303*0b57cec5SDimitry Andric void GenericTaintChecker::checkPreStmt(const CallExpr *CE, 304*0b57cec5SDimitry Andric CheckerContext &C) const { 305*0b57cec5SDimitry Andric // Check for taintedness related errors first: system call, uncontrolled 306*0b57cec5SDimitry Andric // format string, tainted buffer size. 307*0b57cec5SDimitry Andric if (checkPre(CE, C)) 308*0b57cec5SDimitry Andric return; 309*0b57cec5SDimitry Andric 310*0b57cec5SDimitry Andric // Marks the function's arguments and/or return value tainted if it present in 311*0b57cec5SDimitry Andric // the list. 312*0b57cec5SDimitry Andric addSourcesPre(CE, C); 313*0b57cec5SDimitry Andric } 314*0b57cec5SDimitry Andric 315*0b57cec5SDimitry Andric void GenericTaintChecker::checkPostStmt(const CallExpr *CE, 316*0b57cec5SDimitry Andric CheckerContext &C) const { 317*0b57cec5SDimitry Andric // Set the marked values as tainted. The return value only accessible from 318*0b57cec5SDimitry Andric // checkPostStmt. 319*0b57cec5SDimitry Andric propagateFromPre(CE, C); 320*0b57cec5SDimitry Andric } 321*0b57cec5SDimitry Andric 322*0b57cec5SDimitry Andric void GenericTaintChecker::printState(raw_ostream &Out, ProgramStateRef State, 323*0b57cec5SDimitry Andric const char *NL, const char *Sep) const { 324*0b57cec5SDimitry Andric printTaint(State, Out, NL, Sep); 325*0b57cec5SDimitry Andric } 326*0b57cec5SDimitry Andric 327*0b57cec5SDimitry Andric void GenericTaintChecker::addSourcesPre(const CallExpr *CE, 328*0b57cec5SDimitry Andric CheckerContext &C) const { 329*0b57cec5SDimitry Andric ProgramStateRef State = nullptr; 330*0b57cec5SDimitry Andric const FunctionDecl *FDecl = C.getCalleeDecl(CE); 331*0b57cec5SDimitry Andric if (!FDecl || FDecl->getKind() != Decl::Function) 332*0b57cec5SDimitry Andric return; 333*0b57cec5SDimitry Andric 334*0b57cec5SDimitry Andric StringRef Name = C.getCalleeName(FDecl); 335*0b57cec5SDimitry Andric if (Name.empty()) 336*0b57cec5SDimitry Andric return; 337*0b57cec5SDimitry Andric 338*0b57cec5SDimitry Andric // First, try generating a propagation rule for this function. 339*0b57cec5SDimitry Andric TaintPropagationRule Rule = 340*0b57cec5SDimitry Andric TaintPropagationRule::getTaintPropagationRule(FDecl, Name, C); 341*0b57cec5SDimitry Andric if (!Rule.isNull()) { 342*0b57cec5SDimitry Andric State = Rule.process(CE, C); 343*0b57cec5SDimitry Andric if (!State) 344*0b57cec5SDimitry Andric return; 345*0b57cec5SDimitry Andric C.addTransition(State); 346*0b57cec5SDimitry Andric return; 347*0b57cec5SDimitry Andric } 348*0b57cec5SDimitry Andric 349*0b57cec5SDimitry Andric if (!State) 350*0b57cec5SDimitry Andric return; 351*0b57cec5SDimitry Andric C.addTransition(State); 352*0b57cec5SDimitry Andric } 353*0b57cec5SDimitry Andric 354*0b57cec5SDimitry Andric bool GenericTaintChecker::propagateFromPre(const CallExpr *CE, 355*0b57cec5SDimitry Andric CheckerContext &C) const { 356*0b57cec5SDimitry Andric ProgramStateRef State = C.getState(); 357*0b57cec5SDimitry Andric 358*0b57cec5SDimitry Andric // Depending on what was tainted at pre-visit, we determined a set of 359*0b57cec5SDimitry Andric // arguments which should be tainted after the function returns. These are 360*0b57cec5SDimitry Andric // stored in the state as TaintArgsOnPostVisit set. 361*0b57cec5SDimitry Andric TaintArgsOnPostVisitTy TaintArgs = State->get<TaintArgsOnPostVisit>(); 362*0b57cec5SDimitry Andric if (TaintArgs.isEmpty()) 363*0b57cec5SDimitry Andric return false; 364*0b57cec5SDimitry Andric 365*0b57cec5SDimitry Andric for (unsigned ArgNum : TaintArgs) { 366*0b57cec5SDimitry Andric // Special handling for the tainted return value. 367*0b57cec5SDimitry Andric if (ArgNum == ReturnValueIndex) { 368*0b57cec5SDimitry Andric State = addTaint(State, CE, C.getLocationContext()); 369*0b57cec5SDimitry Andric continue; 370*0b57cec5SDimitry Andric } 371*0b57cec5SDimitry Andric 372*0b57cec5SDimitry Andric // The arguments are pointer arguments. The data they are pointing at is 373*0b57cec5SDimitry Andric // tainted after the call. 374*0b57cec5SDimitry Andric if (CE->getNumArgs() < (ArgNum + 1)) 375*0b57cec5SDimitry Andric return false; 376*0b57cec5SDimitry Andric const Expr *Arg = CE->getArg(ArgNum); 377*0b57cec5SDimitry Andric Optional<SVal> V = getPointedToSVal(C, Arg); 378*0b57cec5SDimitry Andric if (V) 379*0b57cec5SDimitry Andric State = addTaint(State, *V); 380*0b57cec5SDimitry Andric } 381*0b57cec5SDimitry Andric 382*0b57cec5SDimitry Andric // Clear up the taint info from the state. 383*0b57cec5SDimitry Andric State = State->remove<TaintArgsOnPostVisit>(); 384*0b57cec5SDimitry Andric 385*0b57cec5SDimitry Andric if (State != C.getState()) { 386*0b57cec5SDimitry Andric C.addTransition(State); 387*0b57cec5SDimitry Andric return true; 388*0b57cec5SDimitry Andric } 389*0b57cec5SDimitry Andric return false; 390*0b57cec5SDimitry Andric } 391*0b57cec5SDimitry Andric 392*0b57cec5SDimitry Andric bool GenericTaintChecker::checkPre(const CallExpr *CE, 393*0b57cec5SDimitry Andric CheckerContext &C) const { 394*0b57cec5SDimitry Andric 395*0b57cec5SDimitry Andric if (checkUncontrolledFormatString(CE, C)) 396*0b57cec5SDimitry Andric return true; 397*0b57cec5SDimitry Andric 398*0b57cec5SDimitry Andric const FunctionDecl *FDecl = C.getCalleeDecl(CE); 399*0b57cec5SDimitry Andric if (!FDecl || FDecl->getKind() != Decl::Function) 400*0b57cec5SDimitry Andric return false; 401*0b57cec5SDimitry Andric 402*0b57cec5SDimitry Andric StringRef Name = C.getCalleeName(FDecl); 403*0b57cec5SDimitry Andric if (Name.empty()) 404*0b57cec5SDimitry Andric return false; 405*0b57cec5SDimitry Andric 406*0b57cec5SDimitry Andric if (checkSystemCall(CE, Name, C)) 407*0b57cec5SDimitry Andric return true; 408*0b57cec5SDimitry Andric 409*0b57cec5SDimitry Andric if (checkTaintedBufferSize(CE, FDecl, C)) 410*0b57cec5SDimitry Andric return true; 411*0b57cec5SDimitry Andric 412*0b57cec5SDimitry Andric return false; 413*0b57cec5SDimitry Andric } 414*0b57cec5SDimitry Andric 415*0b57cec5SDimitry Andric Optional<SVal> GenericTaintChecker::getPointedToSVal(CheckerContext &C, 416*0b57cec5SDimitry Andric const Expr *Arg) { 417*0b57cec5SDimitry Andric ProgramStateRef State = C.getState(); 418*0b57cec5SDimitry Andric SVal AddrVal = C.getSVal(Arg->IgnoreParens()); 419*0b57cec5SDimitry Andric if (AddrVal.isUnknownOrUndef()) 420*0b57cec5SDimitry Andric return None; 421*0b57cec5SDimitry Andric 422*0b57cec5SDimitry Andric Optional<Loc> AddrLoc = AddrVal.getAs<Loc>(); 423*0b57cec5SDimitry Andric if (!AddrLoc) 424*0b57cec5SDimitry Andric return None; 425*0b57cec5SDimitry Andric 426*0b57cec5SDimitry Andric QualType ArgTy = Arg->getType().getCanonicalType(); 427*0b57cec5SDimitry Andric if (!ArgTy->isPointerType()) 428*0b57cec5SDimitry Andric return None; 429*0b57cec5SDimitry Andric 430*0b57cec5SDimitry Andric QualType ValTy = ArgTy->getPointeeType(); 431*0b57cec5SDimitry Andric 432*0b57cec5SDimitry Andric // Do not dereference void pointers. Treat them as byte pointers instead. 433*0b57cec5SDimitry Andric // FIXME: we might want to consider more than just the first byte. 434*0b57cec5SDimitry Andric if (ValTy->isVoidType()) 435*0b57cec5SDimitry Andric ValTy = C.getASTContext().CharTy; 436*0b57cec5SDimitry Andric 437*0b57cec5SDimitry Andric return State->getSVal(*AddrLoc, ValTy); 438*0b57cec5SDimitry Andric } 439*0b57cec5SDimitry Andric 440*0b57cec5SDimitry Andric ProgramStateRef 441*0b57cec5SDimitry Andric GenericTaintChecker::TaintPropagationRule::process(const CallExpr *CE, 442*0b57cec5SDimitry Andric CheckerContext &C) const { 443*0b57cec5SDimitry Andric ProgramStateRef State = C.getState(); 444*0b57cec5SDimitry Andric 445*0b57cec5SDimitry Andric // Check for taint in arguments. 446*0b57cec5SDimitry Andric bool IsTainted = true; 447*0b57cec5SDimitry Andric for (unsigned ArgNum : SrcArgs) { 448*0b57cec5SDimitry Andric if (ArgNum >= CE->getNumArgs()) 449*0b57cec5SDimitry Andric return State; 450*0b57cec5SDimitry Andric if ((IsTainted = isTaintedOrPointsToTainted(CE->getArg(ArgNum), State, C))) 451*0b57cec5SDimitry Andric break; 452*0b57cec5SDimitry Andric } 453*0b57cec5SDimitry Andric 454*0b57cec5SDimitry Andric // Check for taint in variadic arguments. 455*0b57cec5SDimitry Andric if (!IsTainted && VariadicType::Src == VarType) { 456*0b57cec5SDimitry Andric // Check if any of the arguments is tainted 457*0b57cec5SDimitry Andric for (unsigned int i = VariadicIndex; i < CE->getNumArgs(); ++i) { 458*0b57cec5SDimitry Andric if ((IsTainted = isTaintedOrPointsToTainted(CE->getArg(i), State, C))) 459*0b57cec5SDimitry Andric break; 460*0b57cec5SDimitry Andric } 461*0b57cec5SDimitry Andric } 462*0b57cec5SDimitry Andric 463*0b57cec5SDimitry Andric if (PropagationFunc) 464*0b57cec5SDimitry Andric IsTainted = PropagationFunc(IsTainted, CE, C); 465*0b57cec5SDimitry Andric 466*0b57cec5SDimitry Andric if (!IsTainted) 467*0b57cec5SDimitry Andric return State; 468*0b57cec5SDimitry Andric 469*0b57cec5SDimitry Andric // Mark the arguments which should be tainted after the function returns. 470*0b57cec5SDimitry Andric for (unsigned ArgNum : DstArgs) { 471*0b57cec5SDimitry Andric // Should mark the return value? 472*0b57cec5SDimitry Andric if (ArgNum == ReturnValueIndex) { 473*0b57cec5SDimitry Andric State = State->add<TaintArgsOnPostVisit>(ReturnValueIndex); 474*0b57cec5SDimitry Andric continue; 475*0b57cec5SDimitry Andric } 476*0b57cec5SDimitry Andric 477*0b57cec5SDimitry Andric // Mark the given argument. 478*0b57cec5SDimitry Andric assert(ArgNum < CE->getNumArgs()); 479*0b57cec5SDimitry Andric State = State->add<TaintArgsOnPostVisit>(ArgNum); 480*0b57cec5SDimitry Andric } 481*0b57cec5SDimitry Andric 482*0b57cec5SDimitry Andric // Mark all variadic arguments tainted if present. 483*0b57cec5SDimitry Andric if (VariadicType::Dst == VarType) { 484*0b57cec5SDimitry Andric // For all pointer and references that were passed in: 485*0b57cec5SDimitry Andric // If they are not pointing to const data, mark data as tainted. 486*0b57cec5SDimitry Andric // TODO: So far we are just going one level down; ideally we'd need to 487*0b57cec5SDimitry Andric // recurse here. 488*0b57cec5SDimitry Andric for (unsigned int i = VariadicIndex; i < CE->getNumArgs(); ++i) { 489*0b57cec5SDimitry Andric const Expr *Arg = CE->getArg(i); 490*0b57cec5SDimitry Andric // Process pointer argument. 491*0b57cec5SDimitry Andric const Type *ArgTy = Arg->getType().getTypePtr(); 492*0b57cec5SDimitry Andric QualType PType = ArgTy->getPointeeType(); 493*0b57cec5SDimitry Andric if ((!PType.isNull() && !PType.isConstQualified()) || 494*0b57cec5SDimitry Andric (ArgTy->isReferenceType() && !Arg->getType().isConstQualified())) 495*0b57cec5SDimitry Andric State = State->add<TaintArgsOnPostVisit>(i); 496*0b57cec5SDimitry Andric } 497*0b57cec5SDimitry Andric } 498*0b57cec5SDimitry Andric 499*0b57cec5SDimitry Andric return State; 500*0b57cec5SDimitry Andric } 501*0b57cec5SDimitry Andric 502*0b57cec5SDimitry Andric // If argument 0(protocol domain) is network, the return value should get taint. 503*0b57cec5SDimitry Andric bool GenericTaintChecker::TaintPropagationRule::postSocket(bool /*IsTainted*/, 504*0b57cec5SDimitry Andric const CallExpr *CE, 505*0b57cec5SDimitry Andric CheckerContext &C) { 506*0b57cec5SDimitry Andric SourceLocation DomLoc = CE->getArg(0)->getExprLoc(); 507*0b57cec5SDimitry Andric StringRef DomName = C.getMacroNameOrSpelling(DomLoc); 508*0b57cec5SDimitry Andric // White list the internal communication protocols. 509*0b57cec5SDimitry Andric if (DomName.equals("AF_SYSTEM") || DomName.equals("AF_LOCAL") || 510*0b57cec5SDimitry Andric DomName.equals("AF_UNIX") || DomName.equals("AF_RESERVED_36")) 511*0b57cec5SDimitry Andric return false; 512*0b57cec5SDimitry Andric 513*0b57cec5SDimitry Andric return true; 514*0b57cec5SDimitry Andric } 515*0b57cec5SDimitry Andric 516*0b57cec5SDimitry Andric bool GenericTaintChecker::isStdin(const Expr *E, CheckerContext &C) { 517*0b57cec5SDimitry Andric ProgramStateRef State = C.getState(); 518*0b57cec5SDimitry Andric SVal Val = C.getSVal(E); 519*0b57cec5SDimitry Andric 520*0b57cec5SDimitry Andric // stdin is a pointer, so it would be a region. 521*0b57cec5SDimitry Andric const MemRegion *MemReg = Val.getAsRegion(); 522*0b57cec5SDimitry Andric 523*0b57cec5SDimitry Andric // The region should be symbolic, we do not know it's value. 524*0b57cec5SDimitry Andric const SymbolicRegion *SymReg = dyn_cast_or_null<SymbolicRegion>(MemReg); 525*0b57cec5SDimitry Andric if (!SymReg) 526*0b57cec5SDimitry Andric return false; 527*0b57cec5SDimitry Andric 528*0b57cec5SDimitry Andric // Get it's symbol and find the declaration region it's pointing to. 529*0b57cec5SDimitry Andric const SymbolRegionValue *Sm = 530*0b57cec5SDimitry Andric dyn_cast<SymbolRegionValue>(SymReg->getSymbol()); 531*0b57cec5SDimitry Andric if (!Sm) 532*0b57cec5SDimitry Andric return false; 533*0b57cec5SDimitry Andric const DeclRegion *DeclReg = dyn_cast_or_null<DeclRegion>(Sm->getRegion()); 534*0b57cec5SDimitry Andric if (!DeclReg) 535*0b57cec5SDimitry Andric return false; 536*0b57cec5SDimitry Andric 537*0b57cec5SDimitry Andric // This region corresponds to a declaration, find out if it's a global/extern 538*0b57cec5SDimitry Andric // variable named stdin with the proper type. 539*0b57cec5SDimitry Andric if (const auto *D = dyn_cast_or_null<VarDecl>(DeclReg->getDecl())) { 540*0b57cec5SDimitry Andric D = D->getCanonicalDecl(); 541*0b57cec5SDimitry Andric if ((D->getName().find("stdin") != StringRef::npos) && D->isExternC()) { 542*0b57cec5SDimitry Andric const auto *PtrTy = dyn_cast<PointerType>(D->getType().getTypePtr()); 543*0b57cec5SDimitry Andric if (PtrTy && PtrTy->getPointeeType().getCanonicalType() == 544*0b57cec5SDimitry Andric C.getASTContext().getFILEType().getCanonicalType()) 545*0b57cec5SDimitry Andric return true; 546*0b57cec5SDimitry Andric } 547*0b57cec5SDimitry Andric } 548*0b57cec5SDimitry Andric return false; 549*0b57cec5SDimitry Andric } 550*0b57cec5SDimitry Andric 551*0b57cec5SDimitry Andric static bool getPrintfFormatArgumentNum(const CallExpr *CE, 552*0b57cec5SDimitry Andric const CheckerContext &C, 553*0b57cec5SDimitry Andric unsigned int &ArgNum) { 554*0b57cec5SDimitry Andric // Find if the function contains a format string argument. 555*0b57cec5SDimitry Andric // Handles: fprintf, printf, sprintf, snprintf, vfprintf, vprintf, vsprintf, 556*0b57cec5SDimitry Andric // vsnprintf, syslog, custom annotated functions. 557*0b57cec5SDimitry Andric const FunctionDecl *FDecl = C.getCalleeDecl(CE); 558*0b57cec5SDimitry Andric if (!FDecl) 559*0b57cec5SDimitry Andric return false; 560*0b57cec5SDimitry Andric for (const auto *Format : FDecl->specific_attrs<FormatAttr>()) { 561*0b57cec5SDimitry Andric ArgNum = Format->getFormatIdx() - 1; 562*0b57cec5SDimitry Andric if ((Format->getType()->getName() == "printf") && CE->getNumArgs() > ArgNum) 563*0b57cec5SDimitry Andric return true; 564*0b57cec5SDimitry Andric } 565*0b57cec5SDimitry Andric 566*0b57cec5SDimitry Andric // Or if a function is named setproctitle (this is a heuristic). 567*0b57cec5SDimitry Andric if (C.getCalleeName(CE).find("setproctitle") != StringRef::npos) { 568*0b57cec5SDimitry Andric ArgNum = 0; 569*0b57cec5SDimitry Andric return true; 570*0b57cec5SDimitry Andric } 571*0b57cec5SDimitry Andric 572*0b57cec5SDimitry Andric return false; 573*0b57cec5SDimitry Andric } 574*0b57cec5SDimitry Andric 575*0b57cec5SDimitry Andric bool GenericTaintChecker::generateReportIfTainted(const Expr *E, 576*0b57cec5SDimitry Andric const char Msg[], 577*0b57cec5SDimitry Andric CheckerContext &C) const { 578*0b57cec5SDimitry Andric assert(E); 579*0b57cec5SDimitry Andric 580*0b57cec5SDimitry Andric // Check for taint. 581*0b57cec5SDimitry Andric ProgramStateRef State = C.getState(); 582*0b57cec5SDimitry Andric Optional<SVal> PointedToSVal = getPointedToSVal(C, E); 583*0b57cec5SDimitry Andric SVal TaintedSVal; 584*0b57cec5SDimitry Andric if (PointedToSVal && isTainted(State, *PointedToSVal)) 585*0b57cec5SDimitry Andric TaintedSVal = *PointedToSVal; 586*0b57cec5SDimitry Andric else if (isTainted(State, E, C.getLocationContext())) 587*0b57cec5SDimitry Andric TaintedSVal = C.getSVal(E); 588*0b57cec5SDimitry Andric else 589*0b57cec5SDimitry Andric return false; 590*0b57cec5SDimitry Andric 591*0b57cec5SDimitry Andric // Generate diagnostic. 592*0b57cec5SDimitry Andric if (ExplodedNode *N = C.generateNonFatalErrorNode()) { 593*0b57cec5SDimitry Andric initBugType(); 594*0b57cec5SDimitry Andric auto report = llvm::make_unique<BugReport>(*BT, Msg, N); 595*0b57cec5SDimitry Andric report->addRange(E->getSourceRange()); 596*0b57cec5SDimitry Andric report->addVisitor(llvm::make_unique<TaintBugVisitor>(TaintedSVal)); 597*0b57cec5SDimitry Andric C.emitReport(std::move(report)); 598*0b57cec5SDimitry Andric return true; 599*0b57cec5SDimitry Andric } 600*0b57cec5SDimitry Andric return false; 601*0b57cec5SDimitry Andric } 602*0b57cec5SDimitry Andric 603*0b57cec5SDimitry Andric bool GenericTaintChecker::checkUncontrolledFormatString( 604*0b57cec5SDimitry Andric const CallExpr *CE, CheckerContext &C) const { 605*0b57cec5SDimitry Andric // Check if the function contains a format string argument. 606*0b57cec5SDimitry Andric unsigned int ArgNum = 0; 607*0b57cec5SDimitry Andric if (!getPrintfFormatArgumentNum(CE, C, ArgNum)) 608*0b57cec5SDimitry Andric return false; 609*0b57cec5SDimitry Andric 610*0b57cec5SDimitry Andric // If either the format string content or the pointer itself are tainted, 611*0b57cec5SDimitry Andric // warn. 612*0b57cec5SDimitry Andric return generateReportIfTainted(CE->getArg(ArgNum), 613*0b57cec5SDimitry Andric MsgUncontrolledFormatString, C); 614*0b57cec5SDimitry Andric } 615*0b57cec5SDimitry Andric 616*0b57cec5SDimitry Andric bool GenericTaintChecker::checkSystemCall(const CallExpr *CE, StringRef Name, 617*0b57cec5SDimitry Andric CheckerContext &C) const { 618*0b57cec5SDimitry Andric // TODO: It might make sense to run this check on demand. In some cases, 619*0b57cec5SDimitry Andric // we should check if the environment has been cleansed here. We also might 620*0b57cec5SDimitry Andric // need to know if the user was reset before these calls(seteuid). 621*0b57cec5SDimitry Andric unsigned ArgNum = llvm::StringSwitch<unsigned>(Name) 622*0b57cec5SDimitry Andric .Case("system", 0) 623*0b57cec5SDimitry Andric .Case("popen", 0) 624*0b57cec5SDimitry Andric .Case("execl", 0) 625*0b57cec5SDimitry Andric .Case("execle", 0) 626*0b57cec5SDimitry Andric .Case("execlp", 0) 627*0b57cec5SDimitry Andric .Case("execv", 0) 628*0b57cec5SDimitry Andric .Case("execvp", 0) 629*0b57cec5SDimitry Andric .Case("execvP", 0) 630*0b57cec5SDimitry Andric .Case("execve", 0) 631*0b57cec5SDimitry Andric .Case("dlopen", 0) 632*0b57cec5SDimitry Andric .Default(UINT_MAX); 633*0b57cec5SDimitry Andric 634*0b57cec5SDimitry Andric if (ArgNum == UINT_MAX || CE->getNumArgs() < (ArgNum + 1)) 635*0b57cec5SDimitry Andric return false; 636*0b57cec5SDimitry Andric 637*0b57cec5SDimitry Andric return generateReportIfTainted(CE->getArg(ArgNum), MsgSanitizeSystemArgs, C); 638*0b57cec5SDimitry Andric } 639*0b57cec5SDimitry Andric 640*0b57cec5SDimitry Andric // TODO: Should this check be a part of the CString checker? 641*0b57cec5SDimitry Andric // If yes, should taint be a global setting? 642*0b57cec5SDimitry Andric bool GenericTaintChecker::checkTaintedBufferSize(const CallExpr *CE, 643*0b57cec5SDimitry Andric const FunctionDecl *FDecl, 644*0b57cec5SDimitry Andric CheckerContext &C) const { 645*0b57cec5SDimitry Andric // If the function has a buffer size argument, set ArgNum. 646*0b57cec5SDimitry Andric unsigned ArgNum = InvalidArgIndex; 647*0b57cec5SDimitry Andric unsigned BId = 0; 648*0b57cec5SDimitry Andric if ((BId = FDecl->getMemoryFunctionKind())) 649*0b57cec5SDimitry Andric switch (BId) { 650*0b57cec5SDimitry Andric case Builtin::BImemcpy: 651*0b57cec5SDimitry Andric case Builtin::BImemmove: 652*0b57cec5SDimitry Andric case Builtin::BIstrncpy: 653*0b57cec5SDimitry Andric ArgNum = 2; 654*0b57cec5SDimitry Andric break; 655*0b57cec5SDimitry Andric case Builtin::BIstrndup: 656*0b57cec5SDimitry Andric ArgNum = 1; 657*0b57cec5SDimitry Andric break; 658*0b57cec5SDimitry Andric default: 659*0b57cec5SDimitry Andric break; 660*0b57cec5SDimitry Andric }; 661*0b57cec5SDimitry Andric 662*0b57cec5SDimitry Andric if (ArgNum == InvalidArgIndex) { 663*0b57cec5SDimitry Andric if (C.isCLibraryFunction(FDecl, "malloc") || 664*0b57cec5SDimitry Andric C.isCLibraryFunction(FDecl, "calloc") || 665*0b57cec5SDimitry Andric C.isCLibraryFunction(FDecl, "alloca")) 666*0b57cec5SDimitry Andric ArgNum = 0; 667*0b57cec5SDimitry Andric else if (C.isCLibraryFunction(FDecl, "memccpy")) 668*0b57cec5SDimitry Andric ArgNum = 3; 669*0b57cec5SDimitry Andric else if (C.isCLibraryFunction(FDecl, "realloc")) 670*0b57cec5SDimitry Andric ArgNum = 1; 671*0b57cec5SDimitry Andric else if (C.isCLibraryFunction(FDecl, "bcopy")) 672*0b57cec5SDimitry Andric ArgNum = 2; 673*0b57cec5SDimitry Andric } 674*0b57cec5SDimitry Andric 675*0b57cec5SDimitry Andric return ArgNum != InvalidArgIndex && CE->getNumArgs() > ArgNum && 676*0b57cec5SDimitry Andric generateReportIfTainted(CE->getArg(ArgNum), MsgTaintedBufferSize, C); 677*0b57cec5SDimitry Andric } 678*0b57cec5SDimitry Andric 679*0b57cec5SDimitry Andric void ento::registerGenericTaintChecker(CheckerManager &mgr) { 680*0b57cec5SDimitry Andric mgr.registerChecker<GenericTaintChecker>(); 681*0b57cec5SDimitry Andric } 682*0b57cec5SDimitry Andric 683*0b57cec5SDimitry Andric bool ento::shouldRegisterGenericTaintChecker(const LangOptions &LO) { 684*0b57cec5SDimitry Andric return true; 685*0b57cec5SDimitry Andric } 686