UnixAPIChecker.cpp 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510
  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/STLExtras.h"
  20. #include "llvm/ADT/SmallString.h"
  21. #include "llvm/ADT/StringExtras.h"
  22. #include "llvm/Support/raw_ostream.h"
  23. #include <optional>
  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 std::optional<uint64_t> Val_O_CREAT;
  38. public:
  39. void checkPreStmt(const CallExpr *CE, CheckerContext &C) const;
  40. void CheckOpen(CheckerContext &C, const CallExpr *CE) const;
  41. void CheckOpenAt(CheckerContext &C, const CallExpr *CE) const;
  42. void CheckPthreadOnce(CheckerContext &C, const CallExpr *CE) const;
  43. void CheckOpenVariant(CheckerContext &C,
  44. const CallExpr *CE, OpenVariant Variant) const;
  45. void ReportOpenBug(CheckerContext &C,
  46. ProgramStateRef State,
  47. const char *Msg,
  48. SourceRange SR) const;
  49. };
  50. class UnixAPIPortabilityChecker : public Checker< check::PreStmt<CallExpr> > {
  51. public:
  52. void checkPreStmt(const CallExpr *CE, CheckerContext &C) const;
  53. private:
  54. mutable std::unique_ptr<BugType> BT_mallocZero;
  55. void CheckCallocZero(CheckerContext &C, const CallExpr *CE) const;
  56. void CheckMallocZero(CheckerContext &C, const CallExpr *CE) const;
  57. void CheckReallocZero(CheckerContext &C, const CallExpr *CE) const;
  58. void CheckReallocfZero(CheckerContext &C, const CallExpr *CE) const;
  59. void CheckAllocaZero(CheckerContext &C, const CallExpr *CE) const;
  60. void CheckAllocaWithAlignZero(CheckerContext &C, const CallExpr *CE) const;
  61. void CheckVallocZero(CheckerContext &C, const CallExpr *CE) const;
  62. bool ReportZeroByteAllocation(CheckerContext &C,
  63. ProgramStateRef falseState,
  64. const Expr *arg,
  65. const char *fn_name) const;
  66. void BasicAllocationCheck(CheckerContext &C,
  67. const CallExpr *CE,
  68. const unsigned numArgs,
  69. const unsigned sizeArg,
  70. const char *fn) const;
  71. };
  72. } //end anonymous namespace
  73. static void LazyInitialize(const CheckerBase *Checker,
  74. std::unique_ptr<BugType> &BT,
  75. const char *name) {
  76. if (BT)
  77. return;
  78. BT.reset(new BugType(Checker, name, categories::UnixAPI));
  79. }
  80. //===----------------------------------------------------------------------===//
  81. // "open" (man 2 open)
  82. //===----------------------------------------------------------------------===/
  83. void UnixAPIMisuseChecker::checkPreStmt(const CallExpr *CE,
  84. CheckerContext &C) const {
  85. const FunctionDecl *FD = C.getCalleeDecl(CE);
  86. if (!FD || FD->getKind() != Decl::Function)
  87. return;
  88. // Don't treat functions in namespaces with the same name a Unix function
  89. // as a call to the Unix function.
  90. const DeclContext *NamespaceCtx = FD->getEnclosingNamespaceContext();
  91. if (isa_and_nonnull<NamespaceDecl>(NamespaceCtx))
  92. return;
  93. StringRef FName = C.getCalleeName(FD);
  94. if (FName.empty())
  95. return;
  96. if (FName == "open")
  97. CheckOpen(C, CE);
  98. else if (FName == "openat")
  99. CheckOpenAt(C, CE);
  100. else if (FName == "pthread_once")
  101. CheckPthreadOnce(C, CE);
  102. }
  103. void UnixAPIMisuseChecker::ReportOpenBug(CheckerContext &C,
  104. ProgramStateRef State,
  105. const char *Msg,
  106. SourceRange SR) const {
  107. ExplodedNode *N = C.generateErrorNode(State);
  108. if (!N)
  109. return;
  110. LazyInitialize(this, BT_open, "Improper use of 'open'");
  111. auto Report = std::make_unique<PathSensitiveBugReport>(*BT_open, Msg, N);
  112. Report->addRange(SR);
  113. C.emitReport(std::move(Report));
  114. }
  115. void UnixAPIMisuseChecker::CheckOpen(CheckerContext &C,
  116. const CallExpr *CE) const {
  117. CheckOpenVariant(C, CE, OpenVariant::Open);
  118. }
  119. void UnixAPIMisuseChecker::CheckOpenAt(CheckerContext &C,
  120. const CallExpr *CE) const {
  121. CheckOpenVariant(C, CE, OpenVariant::OpenAt);
  122. }
  123. void UnixAPIMisuseChecker::CheckOpenVariant(CheckerContext &C,
  124. const CallExpr *CE,
  125. OpenVariant Variant) const {
  126. // The index of the argument taking the flags open flags (O_RDONLY,
  127. // O_WRONLY, O_CREAT, etc.),
  128. unsigned int FlagsArgIndex;
  129. const char *VariantName;
  130. switch (Variant) {
  131. case OpenVariant::Open:
  132. FlagsArgIndex = 1;
  133. VariantName = "open";
  134. break;
  135. case OpenVariant::OpenAt:
  136. FlagsArgIndex = 2;
  137. VariantName = "openat";
  138. break;
  139. };
  140. // All calls should at least provide arguments up to the 'flags' parameter.
  141. unsigned int MinArgCount = FlagsArgIndex + 1;
  142. // If the flags has O_CREAT set then open/openat() require an additional
  143. // argument specifying the file mode (permission bits) for the created file.
  144. unsigned int CreateModeArgIndex = FlagsArgIndex + 1;
  145. // The create mode argument should be the last argument.
  146. unsigned int MaxArgCount = CreateModeArgIndex + 1;
  147. ProgramStateRef state = C.getState();
  148. if (CE->getNumArgs() < MinArgCount) {
  149. // The frontend should issue a warning for this case. Just return.
  150. return;
  151. } else if (CE->getNumArgs() == MaxArgCount) {
  152. const Expr *Arg = CE->getArg(CreateModeArgIndex);
  153. QualType QT = Arg->getType();
  154. if (!QT->isIntegerType()) {
  155. SmallString<256> SBuf;
  156. llvm::raw_svector_ostream OS(SBuf);
  157. OS << "The " << CreateModeArgIndex + 1
  158. << llvm::getOrdinalSuffix(CreateModeArgIndex + 1)
  159. << " argument to '" << VariantName << "' is not an integer";
  160. ReportOpenBug(C, state,
  161. SBuf.c_str(),
  162. Arg->getSourceRange());
  163. return;
  164. }
  165. } else if (CE->getNumArgs() > MaxArgCount) {
  166. SmallString<256> SBuf;
  167. llvm::raw_svector_ostream OS(SBuf);
  168. OS << "Call to '" << VariantName << "' with more than " << MaxArgCount
  169. << " arguments";
  170. ReportOpenBug(C, state,
  171. SBuf.c_str(),
  172. CE->getArg(MaxArgCount)->getSourceRange());
  173. return;
  174. }
  175. // The definition of O_CREAT is platform specific. We need a better way
  176. // of querying this information from the checking environment.
  177. if (!Val_O_CREAT) {
  178. if (C.getASTContext().getTargetInfo().getTriple().getVendor()
  179. == llvm::Triple::Apple)
  180. Val_O_CREAT = 0x0200;
  181. else {
  182. // FIXME: We need a more general way of getting the O_CREAT value.
  183. // We could possibly grovel through the preprocessor state, but
  184. // that would require passing the Preprocessor object to the ExprEngine.
  185. // See also: MallocChecker.cpp / M_ZERO.
  186. return;
  187. }
  188. }
  189. // Now check if oflags has O_CREAT set.
  190. const Expr *oflagsEx = CE->getArg(FlagsArgIndex);
  191. const SVal V = C.getSVal(oflagsEx);
  192. if (!isa<NonLoc>(V)) {
  193. // The case where 'V' can be a location can only be due to a bad header,
  194. // so in this case bail out.
  195. return;
  196. }
  197. NonLoc oflags = V.castAs<NonLoc>();
  198. NonLoc ocreateFlag = C.getSValBuilder()
  199. .makeIntVal(*Val_O_CREAT, oflagsEx->getType())
  200. .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)