UnixAPIChecker.cpp 18 KB

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