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