Home | History | Annotate | Line # | Download | only in Checkers
      1 //= UnixAPIChecker.h - Checks preconditions for various Unix APIs --*- C++ -*-//
      2 //
      3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
      4 // See https://llvm.org/LICENSE.txt for license information.
      5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
      6 //
      7 //===----------------------------------------------------------------------===//
      8 //
      9 // This defines UnixAPIChecker, which is an assortment of checks on calls
     10 // to various, widely used UNIX/Posix functions.
     11 //
     12 //===----------------------------------------------------------------------===//
     13 
     14 #include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
     15 #include "clang/Basic/TargetInfo.h"
     16 #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
     17 #include "clang/StaticAnalyzer/Core/Checker.h"
     18 #include "clang/StaticAnalyzer/Core/CheckerManager.h"
     19 #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
     20 #include "llvm/ADT/Optional.h"
     21 #include "llvm/ADT/STLExtras.h"
     22 #include "llvm/ADT/SmallString.h"
     23 #include "llvm/ADT/StringExtras.h"
     24 #include "llvm/Support/raw_ostream.h"
     25 
     26 using namespace clang;
     27 using namespace ento;
     28 
     29 enum class OpenVariant {
     30   /// The standard open() call:
     31   ///    int open(const char *path, int oflag, ...);
     32   Open,
     33 
     34   /// The variant taking a directory file descriptor and a relative path:
     35   ///    int openat(int fd, const char *path, int oflag, ...);
     36   OpenAt
     37 };
     38 
     39 namespace {
     40 
     41 class UnixAPIMisuseChecker : public Checker< check::PreStmt<CallExpr> > {
     42   mutable std::unique_ptr<BugType> BT_open, BT_pthreadOnce;
     43   mutable Optional<uint64_t> Val_O_CREAT;
     44 
     45 public:
     46   DefaultBool CheckMisuse, CheckPortability;
     47 
     48   void checkPreStmt(const CallExpr *CE, CheckerContext &C) const;
     49 
     50   void CheckOpen(CheckerContext &C, const CallExpr *CE) const;
     51   void CheckOpenAt(CheckerContext &C, const CallExpr *CE) const;
     52   void CheckPthreadOnce(CheckerContext &C, const CallExpr *CE) const;
     53 
     54   void CheckOpenVariant(CheckerContext &C,
     55                         const CallExpr *CE, OpenVariant Variant) const;
     56 
     57   void ReportOpenBug(CheckerContext &C,
     58                      ProgramStateRef State,
     59                      const char *Msg,
     60                      SourceRange SR) const;
     61 
     62 };
     63 
     64 class UnixAPIPortabilityChecker : public Checker< check::PreStmt<CallExpr> > {
     65 public:
     66   void checkPreStmt(const CallExpr *CE, CheckerContext &C) const;
     67 
     68 private:
     69   mutable std::unique_ptr<BugType> BT_mallocZero;
     70 
     71   void CheckCallocZero(CheckerContext &C, const CallExpr *CE) const;
     72   void CheckMallocZero(CheckerContext &C, const CallExpr *CE) const;
     73   void CheckReallocZero(CheckerContext &C, const CallExpr *CE) const;
     74   void CheckReallocfZero(CheckerContext &C, const CallExpr *CE) const;
     75   void CheckAllocaZero(CheckerContext &C, const CallExpr *CE) const;
     76   void CheckAllocaWithAlignZero(CheckerContext &C, const CallExpr *CE) const;
     77   void CheckVallocZero(CheckerContext &C, const CallExpr *CE) const;
     78 
     79   bool ReportZeroByteAllocation(CheckerContext &C,
     80                                 ProgramStateRef falseState,
     81                                 const Expr *arg,
     82                                 const char *fn_name) const;
     83   void BasicAllocationCheck(CheckerContext &C,
     84                             const CallExpr *CE,
     85                             const unsigned numArgs,
     86                             const unsigned sizeArg,
     87                             const char *fn) const;
     88 };
     89 
     90 } //end anonymous namespace
     91 
     92 static void LazyInitialize(const CheckerBase *Checker,
     93                            std::unique_ptr<BugType> &BT,
     94                            const char *name) {
     95   if (BT)
     96     return;
     97   BT.reset(new BugType(Checker, name, categories::UnixAPI));
     98 }
     99 
    100 //===----------------------------------------------------------------------===//
    101 // "open" (man 2 open)
    102 //===----------------------------------------------------------------------===/
    103 
    104 void UnixAPIMisuseChecker::checkPreStmt(const CallExpr *CE,
    105                                         CheckerContext &C) const {
    106   const FunctionDecl *FD = C.getCalleeDecl(CE);
    107   if (!FD || FD->getKind() != Decl::Function)
    108     return;
    109 
    110   // Don't treat functions in namespaces with the same name a Unix function
    111   // as a call to the Unix function.
    112   const DeclContext *NamespaceCtx = FD->getEnclosingNamespaceContext();
    113   if (NamespaceCtx && isa<NamespaceDecl>(NamespaceCtx))
    114     return;
    115 
    116   StringRef FName = C.getCalleeName(FD);
    117   if (FName.empty())
    118     return;
    119 
    120   if (FName == "open")
    121     CheckOpen(C, CE);
    122 
    123   else if (FName == "openat")
    124     CheckOpenAt(C, CE);
    125 
    126   else if (FName == "pthread_once")
    127     CheckPthreadOnce(C, CE);
    128 }
    129 void UnixAPIMisuseChecker::ReportOpenBug(CheckerContext &C,
    130                                          ProgramStateRef State,
    131                                          const char *Msg,
    132                                          SourceRange SR) const {
    133   ExplodedNode *N = C.generateErrorNode(State);
    134   if (!N)
    135     return;
    136 
    137   LazyInitialize(this, BT_open, "Improper use of 'open'");
    138 
    139   auto Report = std::make_unique<PathSensitiveBugReport>(*BT_open, Msg, N);
    140   Report->addRange(SR);
    141   C.emitReport(std::move(Report));
    142 }
    143 
    144 void UnixAPIMisuseChecker::CheckOpen(CheckerContext &C,
    145                                      const CallExpr *CE) const {
    146   CheckOpenVariant(C, CE, OpenVariant::Open);
    147 }
    148 
    149 void UnixAPIMisuseChecker::CheckOpenAt(CheckerContext &C,
    150                                        const CallExpr *CE) const {
    151   CheckOpenVariant(C, CE, OpenVariant::OpenAt);
    152 }
    153 
    154 void UnixAPIMisuseChecker::CheckOpenVariant(CheckerContext &C,
    155                                             const CallExpr *CE,
    156                                             OpenVariant Variant) const {
    157   // The index of the argument taking the flags open flags (O_RDONLY,
    158   // O_WRONLY, O_CREAT, etc.),
    159   unsigned int FlagsArgIndex;
    160   const char *VariantName;
    161   switch (Variant) {
    162   case OpenVariant::Open:
    163     FlagsArgIndex = 1;
    164     VariantName = "open";
    165     break;
    166   case OpenVariant::OpenAt:
    167     FlagsArgIndex = 2;
    168     VariantName = "openat";
    169     break;
    170   };
    171 
    172   // All calls should at least provide arguments up to the 'flags' parameter.
    173   unsigned int MinArgCount = FlagsArgIndex + 1;
    174 
    175   // If the flags has O_CREAT set then open/openat() require an additional
    176   // argument specifying the file mode (permission bits) for the created file.
    177   unsigned int CreateModeArgIndex = FlagsArgIndex + 1;
    178 
    179   // The create mode argument should be the last argument.
    180   unsigned int MaxArgCount = CreateModeArgIndex + 1;
    181 
    182   ProgramStateRef state = C.getState();
    183 
    184   if (CE->getNumArgs() < MinArgCount) {
    185     // The frontend should issue a warning for this case, so this is a sanity
    186     // check.
    187     return;
    188   } else if (CE->getNumArgs() == MaxArgCount) {
    189     const Expr *Arg = CE->getArg(CreateModeArgIndex);
    190     QualType QT = Arg->getType();
    191     if (!QT->isIntegerType()) {
    192       SmallString<256> SBuf;
    193       llvm::raw_svector_ostream OS(SBuf);
    194       OS << "The " << CreateModeArgIndex + 1
    195          << llvm::getOrdinalSuffix(CreateModeArgIndex + 1)
    196          << " argument to '" << VariantName << "' is not an integer";
    197 
    198       ReportOpenBug(C, state,
    199                     SBuf.c_str(),
    200                     Arg->getSourceRange());
    201       return;
    202     }
    203   } else if (CE->getNumArgs() > MaxArgCount) {
    204     SmallString<256> SBuf;
    205     llvm::raw_svector_ostream OS(SBuf);
    206     OS << "Call to '" << VariantName << "' with more than " << MaxArgCount
    207        << " arguments";
    208 
    209     ReportOpenBug(C, state,
    210                   SBuf.c_str(),
    211                   CE->getArg(MaxArgCount)->getSourceRange());
    212     return;
    213   }
    214 
    215   // The definition of O_CREAT is platform specific.  We need a better way
    216   // of querying this information from the checking environment.
    217   if (!Val_O_CREAT.hasValue()) {
    218     if (C.getASTContext().getTargetInfo().getTriple().getVendor()
    219                                                       == llvm::Triple::Apple)
    220       Val_O_CREAT = 0x0200;
    221     else {
    222       // FIXME: We need a more general way of getting the O_CREAT value.
    223       // We could possibly grovel through the preprocessor state, but
    224       // that would require passing the Preprocessor object to the ExprEngine.
    225       // See also: MallocChecker.cpp / M_ZERO.
    226       return;
    227     }
    228   }
    229 
    230   // Now check if oflags has O_CREAT set.
    231   const Expr *oflagsEx = CE->getArg(FlagsArgIndex);
    232   const SVal V = C.getSVal(oflagsEx);
    233   if (!V.getAs<NonLoc>()) {
    234     // The case where 'V' can be a location can only be due to a bad header,
    235     // so in this case bail out.
    236     return;
    237   }
    238   NonLoc oflags = V.castAs<NonLoc>();
    239   NonLoc ocreateFlag = C.getSValBuilder()
    240       .makeIntVal(Val_O_CREAT.getValue(), oflagsEx->getType()).castAs<NonLoc>();
    241   SVal maskedFlagsUC = C.getSValBuilder().evalBinOpNN(state, BO_And,
    242                                                       oflags, ocreateFlag,
    243                                                       oflagsEx->getType());
    244   if (maskedFlagsUC.isUnknownOrUndef())
    245     return;
    246   DefinedSVal maskedFlags = maskedFlagsUC.castAs<DefinedSVal>();
    247 
    248   // Check if maskedFlags is non-zero.
    249   ProgramStateRef trueState, falseState;
    250   std::tie(trueState, falseState) = state->assume(maskedFlags);
    251 
    252   // Only emit an error if the value of 'maskedFlags' is properly
    253   // constrained;
    254   if (!(trueState && !falseState))
    255     return;
    256 
    257   if (CE->getNumArgs() < MaxArgCount) {
    258     SmallString<256> SBuf;
    259     llvm::raw_svector_ostream OS(SBuf);
    260     OS << "Call to '" << VariantName << "' requires a "
    261        << CreateModeArgIndex + 1
    262        << llvm::getOrdinalSuffix(CreateModeArgIndex + 1)
    263        << " argument when the 'O_CREAT' flag is set";
    264     ReportOpenBug(C, trueState,
    265                   SBuf.c_str(),
    266                   oflagsEx->getSourceRange());
    267   }
    268 }
    269 
    270 //===----------------------------------------------------------------------===//
    271 // pthread_once
    272 //===----------------------------------------------------------------------===//
    273 
    274 void UnixAPIMisuseChecker::CheckPthreadOnce(CheckerContext &C,
    275                                       const CallExpr *CE) const {
    276 
    277   // This is similar to 'CheckDispatchOnce' in the MacOSXAPIChecker.
    278   // They can possibly be refactored.
    279 
    280   if (CE->getNumArgs() < 1)
    281     return;
    282 
    283   // Check if the first argument is stack allocated.  If so, issue a warning
    284   // because that's likely to be bad news.
    285   ProgramStateRef state = C.getState();
    286   const MemRegion *R = C.getSVal(CE->getArg(0)).getAsRegion();
    287   if (!R || !isa<StackSpaceRegion>(R->getMemorySpace()))
    288     return;
    289 
    290   ExplodedNode *N = C.generateErrorNode(state);
    291   if (!N)
    292     return;
    293 
    294   SmallString<256> S;
    295   llvm::raw_svector_ostream os(S);
    296   os << "Call to 'pthread_once' uses";
    297   if (const VarRegion *VR = dyn_cast<VarRegion>(R))
    298     os << " the local variable '" << VR->getDecl()->getName() << '\'';
    299   else
    300     os << " stack allocated memory";
    301   os << " for the \"control\" value.  Using such transient memory for "
    302   "the control value is potentially dangerous.";
    303   if (isa<VarRegion>(R) && isa<StackLocalsSpaceRegion>(R->getMemorySpace()))
    304     os << "  Perhaps you intended to declare the variable as 'static'?";
    305 
    306   LazyInitialize(this, BT_pthreadOnce, "Improper use of 'pthread_once'");
    307 
    308   auto report =
    309       std::make_unique<PathSensitiveBugReport>(*BT_pthreadOnce, os.str(), N);
    310   report->addRange(CE->getArg(0)->getSourceRange());
    311   C.emitReport(std::move(report));
    312 }
    313 
    314 //===----------------------------------------------------------------------===//
    315 // "calloc", "malloc", "realloc", "reallocf", "alloca" and "valloc"
    316 // with allocation size 0
    317 //===----------------------------------------------------------------------===//
    318 
    319 // FIXME: Eventually these should be rolled into the MallocChecker, but right now
    320 // they're more basic and valuable for widespread use.
    321 
    322 // Returns true if we try to do a zero byte allocation, false otherwise.
    323 // Fills in trueState and falseState.
    324 static bool IsZeroByteAllocation(ProgramStateRef state,
    325                                  const SVal argVal,
    326                                  ProgramStateRef *trueState,
    327                                  ProgramStateRef *falseState) {
    328   std::tie(*trueState, *falseState) =
    329     state->assume(argVal.castAs<DefinedSVal>());
    330 
    331   return (*falseState && !*trueState);
    332 }
    333 
    334 // Generates an error report, indicating that the function whose name is given
    335 // will perform a zero byte allocation.
    336 // Returns false if an error occurred, true otherwise.
    337 bool UnixAPIPortabilityChecker::ReportZeroByteAllocation(
    338                                                     CheckerContext &C,
    339                                                     ProgramStateRef falseState,
    340                                                     const Expr *arg,
    341                                                     const char *fn_name) const {
    342   ExplodedNode *N = C.generateErrorNode(falseState);
    343   if (!N)
    344     return false;
    345 
    346   LazyInitialize(this, BT_mallocZero,
    347                  "Undefined allocation of 0 bytes (CERT MEM04-C; CWE-131)");
    348 
    349   SmallString<256> S;
    350   llvm::raw_svector_ostream os(S);
    351   os << "Call to '" << fn_name << "' has an allocation size of 0 bytes";
    352   auto report =
    353       std::make_unique<PathSensitiveBugReport>(*BT_mallocZero, os.str(), N);
    354 
    355   report->addRange(arg->getSourceRange());
    356   bugreporter::trackExpressionValue(N, arg, *report);
    357   C.emitReport(std::move(report));
    358 
    359   return true;
    360 }
    361 
    362 // Does a basic check for 0-sized allocations suitable for most of the below
    363 // functions (modulo "calloc")
    364 void UnixAPIPortabilityChecker::BasicAllocationCheck(CheckerContext &C,
    365                                                      const CallExpr *CE,
    366                                                      const unsigned numArgs,
    367                                                      const unsigned sizeArg,
    368                                                      const char *fn) const {
    369   // Sanity check for the correct number of arguments
    370   if (CE->getNumArgs() != numArgs)
    371     return;
    372 
    373   // Check if the allocation size is 0.
    374   ProgramStateRef state = C.getState();
    375   ProgramStateRef trueState = nullptr, falseState = nullptr;
    376   const Expr *arg = CE->getArg(sizeArg);
    377   SVal argVal = C.getSVal(arg);
    378 
    379   if (argVal.isUnknownOrUndef())
    380     return;
    381 
    382   // Is the value perfectly constrained to zero?
    383   if (IsZeroByteAllocation(state, argVal, &trueState, &falseState)) {
    384     (void) ReportZeroByteAllocation(C, falseState, arg, fn);
    385     return;
    386   }
    387   // Assume the value is non-zero going forward.
    388   assert(trueState);
    389   if (trueState != state)
    390     C.addTransition(trueState);
    391 }
    392 
    393 void UnixAPIPortabilityChecker::CheckCallocZero(CheckerContext &C,
    394                                                 const CallExpr *CE) const {
    395   unsigned int nArgs = CE->getNumArgs();
    396   if (nArgs != 2)
    397     return;
    398 
    399   ProgramStateRef state = C.getState();
    400   ProgramStateRef trueState = nullptr, falseState = nullptr;
    401 
    402   unsigned int i;
    403   for (i = 0; i < nArgs; i++) {
    404     const Expr *arg = CE->getArg(i);
    405     SVal argVal = C.getSVal(arg);
    406     if (argVal.isUnknownOrUndef()) {
    407       if (i == 0)
    408         continue;
    409       else
    410         return;
    411     }
    412 
    413     if (IsZeroByteAllocation(state, argVal, &trueState, &falseState)) {
    414       if (ReportZeroByteAllocation(C, falseState, arg, "calloc"))
    415         return;
    416       else if (i == 0)
    417         continue;
    418       else
    419         return;
    420     }
    421   }
    422 
    423   // Assume the value is non-zero going forward.
    424   assert(trueState);
    425   if (trueState != state)
    426     C.addTransition(trueState);
    427 }
    428 
    429 void UnixAPIPortabilityChecker::CheckMallocZero(CheckerContext &C,
    430                                                 const CallExpr *CE) const {
    431   BasicAllocationCheck(C, CE, 1, 0, "malloc");
    432 }
    433 
    434 void UnixAPIPortabilityChecker::CheckReallocZero(CheckerContext &C,
    435                                                  const CallExpr *CE) const {
    436   BasicAllocationCheck(C, CE, 2, 1, "realloc");
    437 }
    438 
    439 void UnixAPIPortabilityChecker::CheckReallocfZero(CheckerContext &C,
    440                                                   const CallExpr *CE) const {
    441   BasicAllocationCheck(C, CE, 2, 1, "reallocf");
    442 }
    443 
    444 void UnixAPIPortabilityChecker::CheckAllocaZero(CheckerContext &C,
    445                                                 const CallExpr *CE) const {
    446   BasicAllocationCheck(C, CE, 1, 0, "alloca");
    447 }
    448 
    449 void UnixAPIPortabilityChecker::CheckAllocaWithAlignZero(
    450                                                      CheckerContext &C,
    451                                                      const CallExpr *CE) const {
    452   BasicAllocationCheck(C, CE, 2, 0, "__builtin_alloca_with_align");
    453 }
    454 
    455 void UnixAPIPortabilityChecker::CheckVallocZero(CheckerContext &C,
    456                                                 const CallExpr *CE) const {
    457   BasicAllocationCheck(C, CE, 1, 0, "valloc");
    458 }
    459 
    460 void UnixAPIPortabilityChecker::checkPreStmt(const CallExpr *CE,
    461                                              CheckerContext &C) const {
    462   const FunctionDecl *FD = C.getCalleeDecl(CE);
    463   if (!FD || FD->getKind() != Decl::Function)
    464     return;
    465 
    466   // Don't treat functions in namespaces with the same name a Unix function
    467   // as a call to the Unix function.
    468   const DeclContext *NamespaceCtx = FD->getEnclosingNamespaceContext();
    469   if (NamespaceCtx && isa<NamespaceDecl>(NamespaceCtx))
    470     return;
    471 
    472   StringRef FName = C.getCalleeName(FD);
    473   if (FName.empty())
    474     return;
    475 
    476   if (FName == "calloc")
    477     CheckCallocZero(C, CE);
    478 
    479   else if (FName == "malloc")
    480     CheckMallocZero(C, CE);
    481 
    482   else if (FName == "realloc")
    483     CheckReallocZero(C, CE);
    484 
    485   else if (FName == "reallocf")
    486     CheckReallocfZero(C, CE);
    487 
    488   else if (FName == "alloca" || FName ==  "__builtin_alloca")
    489     CheckAllocaZero(C, CE);
    490 
    491   else if (FName == "__builtin_alloca_with_align")
    492     CheckAllocaWithAlignZero(C, CE);
    493 
    494   else if (FName == "valloc")
    495     CheckVallocZero(C, CE);
    496 }
    497 
    498 //===----------------------------------------------------------------------===//
    499 // Registration.
    500 //===----------------------------------------------------------------------===//
    501 
    502 #define REGISTER_CHECKER(CHECKERNAME)                                          \
    503   void ento::register##CHECKERNAME(CheckerManager &mgr) {                      \
    504     mgr.registerChecker<CHECKERNAME>();                                        \
    505   }                                                                            \
    506                                                                                \
    507   bool ento::shouldRegister##CHECKERNAME(const CheckerManager &mgr) {              \
    508     return true;                                                               \
    509   }
    510 
    511 REGISTER_CHECKER(UnixAPIMisuseChecker)
    512 REGISTER_CHECKER(UnixAPIPortabilityChecker)
    513