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