1 //== GenericTaintChecker.cpp ----------------------------------- -*- C++ -*--=//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 // This checker defines the attack surface for generic taint propagation.
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.
16 //===----------------------------------------------------------------------===//
17 #include "ClangSACheckers.h"
18 #include "clang/AST/Attr.h"
19 #include "clang/Basic/Builtins.h"
20 #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
21 #include "clang/StaticAnalyzer/Core/Checker.h"
22 #include "clang/StaticAnalyzer/Core/CheckerManager.h"
23 #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
24 #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h"
27 using namespace clang;
31 class GenericTaintChecker : public Checker< check::PostStmt<CallExpr>,
32 check::PreStmt<CallExpr> > {
34 static void *getTag() { static int Tag; return &Tag; }
36 void checkPostStmt(const CallExpr *CE, CheckerContext &C) const;
38 void checkPreStmt(const CallExpr *CE, CheckerContext &C) const;
41 static const unsigned InvalidArgIndex = UINT_MAX;
42 /// Denotes the return vale.
43 static const unsigned ReturnValueIndex = UINT_MAX - 1;
45 mutable std::unique_ptr<BugType> BT;
46 inline void initBugType() const {
48 BT.reset(new BugType(this, "Use of Untrusted Data", "Untrusted Data"));
51 /// \brief Catch taint related bugs. Check if tainted data is passed to a
53 bool checkPre(const CallExpr *CE, CheckerContext &C) const;
55 /// \brief Add taint sources on a pre-visit.
56 void addSourcesPre(const CallExpr *CE, CheckerContext &C) const;
58 /// \brief Propagate taint generated at pre-visit.
59 bool propagateFromPre(const CallExpr *CE, CheckerContext &C) const;
61 /// \brief Add taint sources on a post visit.
62 void addSourcesPost(const CallExpr *CE, CheckerContext &C) const;
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);
68 /// \brief Given a pointer argument, return the value it points to.
69 static Optional<SVal> getPointedToSVal(CheckerContext &C, const Expr *Arg);
71 /// Functions defining the attack surface.
72 typedef ProgramStateRef (GenericTaintChecker::*FnCheck)(const CallExpr *,
73 CheckerContext &C) const;
74 ProgramStateRef postScanf(const CallExpr *CE, CheckerContext &C) const;
75 ProgramStateRef postSocket(const CallExpr *CE, CheckerContext &C) const;
76 ProgramStateRef postRetTaint(const CallExpr *CE, CheckerContext &C) const;
78 /// Taint the scanned input if the file is tainted.
79 ProgramStateRef preFscanf(const CallExpr *CE, CheckerContext &C) const;
81 /// Check for CWE-134: Uncontrolled Format String.
82 static const char MsgUncontrolledFormatString[];
83 bool checkUncontrolledFormatString(const CallExpr *CE,
84 CheckerContext &C) const;
87 /// CERT/STR02-C. "Sanitize data passed to complex subsystems"
88 /// CWE-78, "Failure to Sanitize Data into an OS Command"
89 static const char MsgSanitizeSystemArgs[];
90 bool checkSystemCall(const CallExpr *CE, StringRef Name,
91 CheckerContext &C) const;
93 /// Check if tainted data is used as a buffer size ins strn.. functions,
95 static const char MsgTaintedBufferSize[];
96 bool checkTaintedBufferSize(const CallExpr *CE, const FunctionDecl *FDecl,
97 CheckerContext &C) const;
99 /// Generate a report if the expression is tainted or points to tainted data.
100 bool generateReportIfTainted(const Expr *E, const char Msg[],
101 CheckerContext &C) const;
103 /// The bug visitor prints a diagnostic message at the location where a given
104 /// variable was tainted.
105 class TaintBugVisitor
106 : public BugReporterVisitorImpl<TaintBugVisitor> {
111 TaintBugVisitor(const SVal V) : V(V) {}
112 void Profile(llvm::FoldingSetNodeID &ID) const override { ID.Add(V); }
114 std::shared_ptr<PathDiagnosticPiece> VisitNode(const ExplodedNode *N,
115 const ExplodedNode *PrevN,
116 BugReporterContext &BRC,
117 BugReport &BR) override;
120 typedef SmallVector<unsigned, 2> ArgVector;
122 /// \brief A struct used to specify taint propagation rules for a function.
124 /// If any of the possible taint source arguments is tainted, all of the
125 /// destination arguments should also be tainted. Use InvalidArgIndex in the
126 /// src list to specify that all of the arguments can introduce taint. Use
127 /// InvalidArgIndex in the dst arguments to signify that all the non-const
128 /// pointer and reference arguments might be tainted on return. If
129 /// ReturnValueIndex is added to the dst list, the return value will be
131 struct TaintPropagationRule {
132 /// List of arguments which can be taint sources and should be checked.
134 /// List of arguments which should be tainted on function return.
136 // TODO: Check if using other data structures would be more optimal.
138 TaintPropagationRule() {}
140 TaintPropagationRule(unsigned SArg,
141 unsigned DArg, bool TaintRet = false) {
142 SrcArgs.push_back(SArg);
143 DstArgs.push_back(DArg);
145 DstArgs.push_back(ReturnValueIndex);
148 TaintPropagationRule(unsigned SArg1, unsigned SArg2,
149 unsigned DArg, bool TaintRet = false) {
150 SrcArgs.push_back(SArg1);
151 SrcArgs.push_back(SArg2);
152 DstArgs.push_back(DArg);
154 DstArgs.push_back(ReturnValueIndex);
157 /// Get the propagation rule for a given function.
158 static TaintPropagationRule
159 getTaintPropagationRule(const FunctionDecl *FDecl,
163 inline void addSrcArg(unsigned A) { SrcArgs.push_back(A); }
164 inline void addDstArg(unsigned A) { DstArgs.push_back(A); }
166 inline bool isNull() const { return SrcArgs.empty(); }
168 inline bool isDestinationArgument(unsigned ArgNum) const {
169 return (std::find(DstArgs.begin(),
170 DstArgs.end(), ArgNum) != DstArgs.end());
173 static inline bool isTaintedOrPointsToTainted(const Expr *E,
174 ProgramStateRef State,
176 if (State->isTainted(E, C.getLocationContext()) || isStdin(E, C))
179 if (!E->getType().getTypePtr()->isPointerType())
182 Optional<SVal> V = getPointedToSVal(C, E);
183 return (V && State->isTainted(*V));
186 /// \brief Pre-process a function which propagates taint according to the
188 ProgramStateRef process(const CallExpr *CE, CheckerContext &C) const;
193 const unsigned GenericTaintChecker::ReturnValueIndex;
194 const unsigned GenericTaintChecker::InvalidArgIndex;
196 const char GenericTaintChecker::MsgUncontrolledFormatString[] =
197 "Untrusted data is used as a format string "
198 "(CWE-134: Uncontrolled Format String)";
200 const char GenericTaintChecker::MsgSanitizeSystemArgs[] =
201 "Untrusted data is passed to a system call "
202 "(CERT/STR02-C. Sanitize data passed to complex subsystems)";
204 const char GenericTaintChecker::MsgTaintedBufferSize[] =
205 "Untrusted data is used to specify the buffer size "
206 "(CERT/STR31-C. Guarantee that storage for strings has sufficient space for "
207 "character data and the null terminator)";
209 } // end of anonymous namespace
211 /// A set which is used to pass information from call pre-visit instruction
212 /// to the call post-visit. The values are unsigned integers, which are either
213 /// ReturnValueIndex, or indexes of the pointer/reference argument, which
214 /// points to data, which should be tainted on return.
215 REGISTER_SET_WITH_PROGRAMSTATE(TaintArgsOnPostVisit, unsigned)
217 std::shared_ptr<PathDiagnosticPiece>
218 GenericTaintChecker::TaintBugVisitor::VisitNode(const ExplodedNode *N,
219 const ExplodedNode *PrevN, BugReporterContext &BRC, BugReport &BR) {
221 // Find the ExplodedNode where the taint was first introduced
222 if (!N->getState()->isTainted(V) || PrevN->getState()->isTainted(V))
225 const Stmt *S = PathDiagnosticLocation::getStmt(N);
229 const LocationContext *NCtx = N->getLocationContext();
230 PathDiagnosticLocation L =
231 PathDiagnosticLocation::createBegin(S, BRC.getSourceManager(), NCtx);
232 if (!L.isValid() || !L.asLocation().isValid())
235 return std::make_shared<PathDiagnosticEventPiece>(
236 L, "Taint originated here");
239 GenericTaintChecker::TaintPropagationRule
240 GenericTaintChecker::TaintPropagationRule::getTaintPropagationRule(
241 const FunctionDecl *FDecl,
244 // TODO: Currently, we might lose precision here: we always mark a return
245 // value as tainted even if it's just a pointer, pointing to tainted data.
247 // Check for exact name match for functions without builtin substitutes.
248 TaintPropagationRule Rule = llvm::StringSwitch<TaintPropagationRule>(Name)
249 .Case("atoi", TaintPropagationRule(0, ReturnValueIndex))
250 .Case("atol", TaintPropagationRule(0, ReturnValueIndex))
251 .Case("atoll", TaintPropagationRule(0, ReturnValueIndex))
252 .Case("getc", TaintPropagationRule(0, ReturnValueIndex))
253 .Case("fgetc", TaintPropagationRule(0, ReturnValueIndex))
254 .Case("getc_unlocked", TaintPropagationRule(0, ReturnValueIndex))
255 .Case("getw", TaintPropagationRule(0, ReturnValueIndex))
256 .Case("toupper", TaintPropagationRule(0, ReturnValueIndex))
257 .Case("tolower", TaintPropagationRule(0, ReturnValueIndex))
258 .Case("strchr", TaintPropagationRule(0, ReturnValueIndex))
259 .Case("strrchr", TaintPropagationRule(0, ReturnValueIndex))
260 .Case("read", TaintPropagationRule(0, 2, 1, true))
261 .Case("pread", TaintPropagationRule(InvalidArgIndex, 1, true))
262 .Case("gets", TaintPropagationRule(InvalidArgIndex, 0, true))
263 .Case("fgets", TaintPropagationRule(2, 0, true))
264 .Case("getline", TaintPropagationRule(2, 0))
265 .Case("getdelim", TaintPropagationRule(3, 0))
266 .Case("fgetln", TaintPropagationRule(0, ReturnValueIndex))
267 .Default(TaintPropagationRule());
272 // Check if it's one of the memory setting/copying functions.
273 // This check is specialized but faster then calling isCLibraryFunction.
275 if ( (BId = FDecl->getMemoryFunctionKind()) )
277 case Builtin::BImemcpy:
278 case Builtin::BImemmove:
279 case Builtin::BIstrncpy:
280 case Builtin::BIstrncat:
281 return TaintPropagationRule(1, 2, 0, true);
282 case Builtin::BIstrlcpy:
283 case Builtin::BIstrlcat:
284 return TaintPropagationRule(1, 2, 0, false);
285 case Builtin::BIstrndup:
286 return TaintPropagationRule(0, 1, ReturnValueIndex);
292 // Process all other functions which could be defined as builtins.
294 if (C.isCLibraryFunction(FDecl, "snprintf") ||
295 C.isCLibraryFunction(FDecl, "sprintf"))
296 return TaintPropagationRule(InvalidArgIndex, 0, true);
297 else if (C.isCLibraryFunction(FDecl, "strcpy") ||
298 C.isCLibraryFunction(FDecl, "stpcpy") ||
299 C.isCLibraryFunction(FDecl, "strcat"))
300 return TaintPropagationRule(1, 0, true);
301 else if (C.isCLibraryFunction(FDecl, "bcopy"))
302 return TaintPropagationRule(0, 2, 1, false);
303 else if (C.isCLibraryFunction(FDecl, "strdup") ||
304 C.isCLibraryFunction(FDecl, "strdupa"))
305 return TaintPropagationRule(0, ReturnValueIndex);
306 else if (C.isCLibraryFunction(FDecl, "wcsdup"))
307 return TaintPropagationRule(0, ReturnValueIndex);
310 // Skipping the following functions, since they might be used for cleansing
311 // or smart memory copy:
312 // - memccpy - copying until hitting a special character.
314 return TaintPropagationRule();
317 void GenericTaintChecker::checkPreStmt(const CallExpr *CE,
318 CheckerContext &C) const {
319 // Check for errors first.
324 addSourcesPre(CE, C);
327 void GenericTaintChecker::checkPostStmt(const CallExpr *CE,
328 CheckerContext &C) const {
329 if (propagateFromPre(CE, C))
331 addSourcesPost(CE, C);
334 void GenericTaintChecker::addSourcesPre(const CallExpr *CE,
335 CheckerContext &C) const {
336 ProgramStateRef State = nullptr;
337 const FunctionDecl *FDecl = C.getCalleeDecl(CE);
338 if (!FDecl || FDecl->getKind() != Decl::Function)
341 StringRef Name = C.getCalleeName(FDecl);
345 // First, try generating a propagation rule for this function.
346 TaintPropagationRule Rule =
347 TaintPropagationRule::getTaintPropagationRule(FDecl, Name, C);
348 if (!Rule.isNull()) {
349 State = Rule.process(CE, C);
352 C.addTransition(State);
356 // Otherwise, check if we have custom pre-processing implemented.
357 FnCheck evalFunction = llvm::StringSwitch<FnCheck>(Name)
358 .Case("fscanf", &GenericTaintChecker::preFscanf)
360 // Check and evaluate the call.
362 State = (this->*evalFunction)(CE, C);
365 C.addTransition(State);
369 bool GenericTaintChecker::propagateFromPre(const CallExpr *CE,
370 CheckerContext &C) const {
371 ProgramStateRef State = C.getState();
373 // Depending on what was tainted at pre-visit, we determined a set of
374 // arguments which should be tainted after the function returns. These are
375 // stored in the state as TaintArgsOnPostVisit set.
376 TaintArgsOnPostVisitTy TaintArgs = State->get<TaintArgsOnPostVisit>();
377 if (TaintArgs.isEmpty())
380 for (llvm::ImmutableSet<unsigned>::iterator
381 I = TaintArgs.begin(), E = TaintArgs.end(); I != E; ++I) {
382 unsigned ArgNum = *I;
384 // Special handling for the tainted return value.
385 if (ArgNum == ReturnValueIndex) {
386 State = State->addTaint(CE, C.getLocationContext());
390 // The arguments are pointer arguments. The data they are pointing at is
391 // tainted after the call.
392 if (CE->getNumArgs() < (ArgNum + 1))
394 const Expr* Arg = CE->getArg(ArgNum);
395 Optional<SVal> V = getPointedToSVal(C, Arg);
397 State = State->addTaint(*V);
400 // Clear up the taint info from the state.
401 State = State->remove<TaintArgsOnPostVisit>();
403 if (State != C.getState()) {
404 C.addTransition(State);
410 void GenericTaintChecker::addSourcesPost(const CallExpr *CE,
411 CheckerContext &C) const {
412 // Define the attack surface.
413 // Set the evaluation function by switching on the callee name.
414 const FunctionDecl *FDecl = C.getCalleeDecl(CE);
415 if (!FDecl || FDecl->getKind() != Decl::Function)
418 StringRef Name = C.getCalleeName(FDecl);
421 FnCheck evalFunction = llvm::StringSwitch<FnCheck>(Name)
422 .Case("scanf", &GenericTaintChecker::postScanf)
423 // TODO: Add support for vfscanf & family.
424 .Case("getchar", &GenericTaintChecker::postRetTaint)
425 .Case("getchar_unlocked", &GenericTaintChecker::postRetTaint)
426 .Case("getenv", &GenericTaintChecker::postRetTaint)
427 .Case("fopen", &GenericTaintChecker::postRetTaint)
428 .Case("fdopen", &GenericTaintChecker::postRetTaint)
429 .Case("freopen", &GenericTaintChecker::postRetTaint)
430 .Case("getch", &GenericTaintChecker::postRetTaint)
431 .Case("wgetch", &GenericTaintChecker::postRetTaint)
432 .Case("socket", &GenericTaintChecker::postSocket)
435 // If the callee isn't defined, it is not of security concern.
436 // Check and evaluate the call.
437 ProgramStateRef State = nullptr;
439 State = (this->*evalFunction)(CE, C);
443 C.addTransition(State);
446 bool GenericTaintChecker::checkPre(const CallExpr *CE, CheckerContext &C) const{
448 if (checkUncontrolledFormatString(CE, C))
451 const FunctionDecl *FDecl = C.getCalleeDecl(CE);
452 if (!FDecl || FDecl->getKind() != Decl::Function)
455 StringRef Name = C.getCalleeName(FDecl);
459 if (checkSystemCall(CE, Name, C))
462 if (checkTaintedBufferSize(CE, FDecl, C))
468 Optional<SVal> GenericTaintChecker::getPointedToSVal(CheckerContext &C,
470 ProgramStateRef State = C.getState();
471 SVal AddrVal = State->getSVal(Arg->IgnoreParens(), C.getLocationContext());
472 if (AddrVal.isUnknownOrUndef())
475 Optional<Loc> AddrLoc = AddrVal.getAs<Loc>();
479 QualType ArgTy = Arg->getType().getCanonicalType();
480 if (!ArgTy->isPointerType())
483 QualType ValTy = ArgTy->getPointeeType();
485 // Do not dereference void pointers. Treat them as byte pointers instead.
486 // FIXME: we might want to consider more than just the first byte.
487 if (ValTy->isVoidType())
488 ValTy = C.getASTContext().CharTy;
490 return State->getSVal(*AddrLoc, ValTy);
494 GenericTaintChecker::TaintPropagationRule::process(const CallExpr *CE,
495 CheckerContext &C) const {
496 ProgramStateRef State = C.getState();
498 // Check for taint in arguments.
499 bool IsTainted = false;
500 for (ArgVector::const_iterator I = SrcArgs.begin(),
501 E = SrcArgs.end(); I != E; ++I) {
502 unsigned ArgNum = *I;
504 if (ArgNum == InvalidArgIndex) {
505 // Check if any of the arguments is tainted, but skip the
506 // destination arguments.
507 for (unsigned int i = 0; i < CE->getNumArgs(); ++i) {
508 if (isDestinationArgument(i))
510 if ((IsTainted = isTaintedOrPointsToTainted(CE->getArg(i), State, C)))
516 if (CE->getNumArgs() < (ArgNum + 1))
518 if ((IsTainted = isTaintedOrPointsToTainted(CE->getArg(ArgNum), State, C)))
524 // Mark the arguments which should be tainted after the function returns.
525 for (ArgVector::const_iterator I = DstArgs.begin(),
526 E = DstArgs.end(); I != E; ++I) {
527 unsigned ArgNum = *I;
529 // Should we mark all arguments as tainted?
530 if (ArgNum == InvalidArgIndex) {
531 // For all pointer and references that were passed in:
532 // If they are not pointing to const data, mark data as tainted.
533 // TODO: So far we are just going one level down; ideally we'd need to
535 for (unsigned int i = 0; i < CE->getNumArgs(); ++i) {
536 const Expr *Arg = CE->getArg(i);
537 // Process pointer argument.
538 const Type *ArgTy = Arg->getType().getTypePtr();
539 QualType PType = ArgTy->getPointeeType();
540 if ((!PType.isNull() && !PType.isConstQualified())
541 || (ArgTy->isReferenceType() && !Arg->getType().isConstQualified()))
542 State = State->add<TaintArgsOnPostVisit>(i);
547 // Should mark the return value?
548 if (ArgNum == ReturnValueIndex) {
549 State = State->add<TaintArgsOnPostVisit>(ReturnValueIndex);
553 // Mark the given argument.
554 assert(ArgNum < CE->getNumArgs());
555 State = State->add<TaintArgsOnPostVisit>(ArgNum);
562 // If argument 0 (file descriptor) is tainted, all arguments except for arg 0
563 // and arg 1 should get taint.
564 ProgramStateRef GenericTaintChecker::preFscanf(const CallExpr *CE,
565 CheckerContext &C) const {
566 assert(CE->getNumArgs() >= 2);
567 ProgramStateRef State = C.getState();
569 // Check is the file descriptor is tainted.
570 if (State->isTainted(CE->getArg(0), C.getLocationContext()) ||
571 isStdin(CE->getArg(0), C)) {
572 // All arguments except for the first two should get taint.
573 for (unsigned int i = 2; i < CE->getNumArgs(); ++i)
574 State = State->add<TaintArgsOnPostVisit>(i);
582 // If argument 0(protocol domain) is network, the return value should get taint.
583 ProgramStateRef GenericTaintChecker::postSocket(const CallExpr *CE,
584 CheckerContext &C) const {
585 ProgramStateRef State = C.getState();
586 if (CE->getNumArgs() < 3)
589 SourceLocation DomLoc = CE->getArg(0)->getExprLoc();
590 StringRef DomName = C.getMacroNameOrSpelling(DomLoc);
591 // White list the internal communication protocols.
592 if (DomName.equals("AF_SYSTEM") || DomName.equals("AF_LOCAL") ||
593 DomName.equals("AF_UNIX") || DomName.equals("AF_RESERVED_36"))
595 State = State->addTaint(CE, C.getLocationContext());
599 ProgramStateRef GenericTaintChecker::postScanf(const CallExpr *CE,
600 CheckerContext &C) const {
601 ProgramStateRef State = C.getState();
602 if (CE->getNumArgs() < 2)
605 // All arguments except for the very first one should get taint.
606 for (unsigned int i = 1; i < CE->getNumArgs(); ++i) {
607 // The arguments are pointer arguments. The data they are pointing at is
608 // tainted after the call.
609 const Expr* Arg = CE->getArg(i);
610 Optional<SVal> V = getPointedToSVal(C, Arg);
612 State = State->addTaint(*V);
617 ProgramStateRef GenericTaintChecker::postRetTaint(const CallExpr *CE,
618 CheckerContext &C) const {
619 return C.getState()->addTaint(CE, C.getLocationContext());
622 bool GenericTaintChecker::isStdin(const Expr *E, CheckerContext &C) {
623 ProgramStateRef State = C.getState();
624 SVal Val = State->getSVal(E, C.getLocationContext());
626 // stdin is a pointer, so it would be a region.
627 const MemRegion *MemReg = Val.getAsRegion();
629 // The region should be symbolic, we do not know it's value.
630 const SymbolicRegion *SymReg = dyn_cast_or_null<SymbolicRegion>(MemReg);
634 // Get it's symbol and find the declaration region it's pointing to.
635 const SymbolRegionValue *Sm =dyn_cast<SymbolRegionValue>(SymReg->getSymbol());
638 const DeclRegion *DeclReg = dyn_cast_or_null<DeclRegion>(Sm->getRegion());
642 // This region corresponds to a declaration, find out if it's a global/extern
643 // variable named stdin with the proper type.
644 if (const VarDecl *D = dyn_cast_or_null<VarDecl>(DeclReg->getDecl())) {
645 D = D->getCanonicalDecl();
646 if ((D->getName().find("stdin") != StringRef::npos) && D->isExternC())
647 if (const PointerType * PtrTy =
648 dyn_cast<PointerType>(D->getType().getTypePtr()))
649 if (PtrTy->getPointeeType() == C.getASTContext().getFILEType())
655 static bool getPrintfFormatArgumentNum(const CallExpr *CE,
656 const CheckerContext &C,
657 unsigned int &ArgNum) {
658 // Find if the function contains a format string argument.
659 // Handles: fprintf, printf, sprintf, snprintf, vfprintf, vprintf, vsprintf,
660 // vsnprintf, syslog, custom annotated functions.
661 const FunctionDecl *FDecl = C.getCalleeDecl(CE);
664 for (const auto *Format : FDecl->specific_attrs<FormatAttr>()) {
665 ArgNum = Format->getFormatIdx() - 1;
666 if ((Format->getType()->getName() == "printf") &&
667 CE->getNumArgs() > ArgNum)
671 // Or if a function is named setproctitle (this is a heuristic).
672 if (C.getCalleeName(CE).find("setproctitle") != StringRef::npos) {
680 bool GenericTaintChecker::generateReportIfTainted(const Expr *E,
682 CheckerContext &C) const {
686 ProgramStateRef State = C.getState();
687 Optional<SVal> PointedToSVal = getPointedToSVal(C, E);
689 if (PointedToSVal && State->isTainted(*PointedToSVal))
690 TaintedSVal = *PointedToSVal;
691 else if (State->isTainted(E, C.getLocationContext()))
692 TaintedSVal = C.getSVal(E);
696 // Generate diagnostic.
697 if (ExplodedNode *N = C.generateNonFatalErrorNode()) {
699 auto report = llvm::make_unique<BugReport>(*BT, Msg, N);
700 report->addRange(E->getSourceRange());
701 report->addVisitor(llvm::make_unique<TaintBugVisitor>(TaintedSVal));
702 C.emitReport(std::move(report));
708 bool GenericTaintChecker::checkUncontrolledFormatString(const CallExpr *CE,
709 CheckerContext &C) const{
710 // Check if the function contains a format string argument.
711 unsigned int ArgNum = 0;
712 if (!getPrintfFormatArgumentNum(CE, C, ArgNum))
715 // If either the format string content or the pointer itself are tainted, warn.
716 return generateReportIfTainted(CE->getArg(ArgNum),
717 MsgUncontrolledFormatString, C);
720 bool GenericTaintChecker::checkSystemCall(const CallExpr *CE,
722 CheckerContext &C) const {
723 // TODO: It might make sense to run this check on demand. In some cases,
724 // we should check if the environment has been cleansed here. We also might
725 // need to know if the user was reset before these calls(seteuid).
726 unsigned ArgNum = llvm::StringSwitch<unsigned>(Name)
739 if (ArgNum == UINT_MAX || CE->getNumArgs() < (ArgNum + 1))
742 return generateReportIfTainted(CE->getArg(ArgNum), MsgSanitizeSystemArgs, C);
745 // TODO: Should this check be a part of the CString checker?
746 // If yes, should taint be a global setting?
747 bool GenericTaintChecker::checkTaintedBufferSize(const CallExpr *CE,
748 const FunctionDecl *FDecl,
749 CheckerContext &C) const {
750 // If the function has a buffer size argument, set ArgNum.
751 unsigned ArgNum = InvalidArgIndex;
753 if ( (BId = FDecl->getMemoryFunctionKind()) )
755 case Builtin::BImemcpy:
756 case Builtin::BImemmove:
757 case Builtin::BIstrncpy:
760 case Builtin::BIstrndup:
767 if (ArgNum == InvalidArgIndex) {
768 if (C.isCLibraryFunction(FDecl, "malloc") ||
769 C.isCLibraryFunction(FDecl, "calloc") ||
770 C.isCLibraryFunction(FDecl, "alloca"))
772 else if (C.isCLibraryFunction(FDecl, "memccpy"))
774 else if (C.isCLibraryFunction(FDecl, "realloc"))
776 else if (C.isCLibraryFunction(FDecl, "bcopy"))
780 return ArgNum != InvalidArgIndex && CE->getNumArgs() > ArgNum &&
781 generateReportIfTainted(CE->getArg(ArgNum), MsgTaintedBufferSize, C);
784 void ento::registerGenericTaintChecker(CheckerManager &mgr) {
785 mgr.registerChecker<GenericTaintChecker>();