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