CheckSecuritySyntaxOnly.cpp 36 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037
  1. //==- CheckSecuritySyntaxOnly.cpp - Basic security checks --------*- 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 file defines a set of flow-insensitive security checks.
  10. //
  11. //===----------------------------------------------------------------------===//
  12. #include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
  13. #include "clang/AST/StmtVisitor.h"
  14. #include "clang/Analysis/AnalysisDeclContext.h"
  15. #include "clang/Basic/TargetInfo.h"
  16. #include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
  17. #include "clang/StaticAnalyzer/Core/Checker.h"
  18. #include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h"
  19. #include "llvm/ADT/SmallString.h"
  20. #include "llvm/ADT/StringSwitch.h"
  21. #include "llvm/Support/raw_ostream.h"
  22. using namespace clang;
  23. using namespace ento;
  24. static bool isArc4RandomAvailable(const ASTContext &Ctx) {
  25. const llvm::Triple &T = Ctx.getTargetInfo().getTriple();
  26. return T.getVendor() == llvm::Triple::Apple ||
  27. T.getOS() == llvm::Triple::CloudABI ||
  28. T.isOSFreeBSD() ||
  29. T.isOSNetBSD() ||
  30. T.isOSOpenBSD() ||
  31. T.isOSDragonFly();
  32. }
  33. namespace {
  34. struct ChecksFilter {
  35. DefaultBool check_bcmp;
  36. DefaultBool check_bcopy;
  37. DefaultBool check_bzero;
  38. DefaultBool check_gets;
  39. DefaultBool check_getpw;
  40. DefaultBool check_mktemp;
  41. DefaultBool check_mkstemp;
  42. DefaultBool check_strcpy;
  43. DefaultBool check_DeprecatedOrUnsafeBufferHandling;
  44. DefaultBool check_rand;
  45. DefaultBool check_vfork;
  46. DefaultBool check_FloatLoopCounter;
  47. DefaultBool check_UncheckedReturn;
  48. CheckerNameRef checkName_bcmp;
  49. CheckerNameRef checkName_bcopy;
  50. CheckerNameRef checkName_bzero;
  51. CheckerNameRef checkName_gets;
  52. CheckerNameRef checkName_getpw;
  53. CheckerNameRef checkName_mktemp;
  54. CheckerNameRef checkName_mkstemp;
  55. CheckerNameRef checkName_strcpy;
  56. CheckerNameRef checkName_DeprecatedOrUnsafeBufferHandling;
  57. CheckerNameRef checkName_rand;
  58. CheckerNameRef checkName_vfork;
  59. CheckerNameRef checkName_FloatLoopCounter;
  60. CheckerNameRef checkName_UncheckedReturn;
  61. };
  62. class WalkAST : public StmtVisitor<WalkAST> {
  63. BugReporter &BR;
  64. AnalysisDeclContext* AC;
  65. enum { num_setids = 6 };
  66. IdentifierInfo *II_setid[num_setids];
  67. const bool CheckRand;
  68. const ChecksFilter &filter;
  69. public:
  70. WalkAST(BugReporter &br, AnalysisDeclContext* ac,
  71. const ChecksFilter &f)
  72. : BR(br), AC(ac), II_setid(),
  73. CheckRand(isArc4RandomAvailable(BR.getContext())),
  74. filter(f) {}
  75. // Statement visitor methods.
  76. void VisitCallExpr(CallExpr *CE);
  77. void VisitForStmt(ForStmt *S);
  78. void VisitCompoundStmt (CompoundStmt *S);
  79. void VisitStmt(Stmt *S) { VisitChildren(S); }
  80. void VisitChildren(Stmt *S);
  81. // Helpers.
  82. bool checkCall_strCommon(const CallExpr *CE, const FunctionDecl *FD);
  83. typedef void (WalkAST::*FnCheck)(const CallExpr *, const FunctionDecl *);
  84. // Checker-specific methods.
  85. void checkLoopConditionForFloat(const ForStmt *FS);
  86. void checkCall_bcmp(const CallExpr *CE, const FunctionDecl *FD);
  87. void checkCall_bcopy(const CallExpr *CE, const FunctionDecl *FD);
  88. void checkCall_bzero(const CallExpr *CE, const FunctionDecl *FD);
  89. void checkCall_gets(const CallExpr *CE, const FunctionDecl *FD);
  90. void checkCall_getpw(const CallExpr *CE, const FunctionDecl *FD);
  91. void checkCall_mktemp(const CallExpr *CE, const FunctionDecl *FD);
  92. void checkCall_mkstemp(const CallExpr *CE, const FunctionDecl *FD);
  93. void checkCall_strcpy(const CallExpr *CE, const FunctionDecl *FD);
  94. void checkCall_strcat(const CallExpr *CE, const FunctionDecl *FD);
  95. void checkDeprecatedOrUnsafeBufferHandling(const CallExpr *CE,
  96. const FunctionDecl *FD);
  97. void checkCall_rand(const CallExpr *CE, const FunctionDecl *FD);
  98. void checkCall_random(const CallExpr *CE, const FunctionDecl *FD);
  99. void checkCall_vfork(const CallExpr *CE, const FunctionDecl *FD);
  100. void checkUncheckedReturnValue(CallExpr *CE);
  101. };
  102. } // end anonymous namespace
  103. //===----------------------------------------------------------------------===//
  104. // AST walking.
  105. //===----------------------------------------------------------------------===//
  106. void WalkAST::VisitChildren(Stmt *S) {
  107. for (Stmt *Child : S->children())
  108. if (Child)
  109. Visit(Child);
  110. }
  111. void WalkAST::VisitCallExpr(CallExpr *CE) {
  112. // Get the callee.
  113. const FunctionDecl *FD = CE->getDirectCallee();
  114. if (!FD)
  115. return;
  116. // Get the name of the callee. If it's a builtin, strip off the prefix.
  117. IdentifierInfo *II = FD->getIdentifier();
  118. if (!II) // if no identifier, not a simple C function
  119. return;
  120. StringRef Name = II->getName();
  121. if (Name.startswith("__builtin_"))
  122. Name = Name.substr(10);
  123. // Set the evaluation function by switching on the callee name.
  124. FnCheck evalFunction = llvm::StringSwitch<FnCheck>(Name)
  125. .Case("bcmp", &WalkAST::checkCall_bcmp)
  126. .Case("bcopy", &WalkAST::checkCall_bcopy)
  127. .Case("bzero", &WalkAST::checkCall_bzero)
  128. .Case("gets", &WalkAST::checkCall_gets)
  129. .Case("getpw", &WalkAST::checkCall_getpw)
  130. .Case("mktemp", &WalkAST::checkCall_mktemp)
  131. .Case("mkstemp", &WalkAST::checkCall_mkstemp)
  132. .Case("mkdtemp", &WalkAST::checkCall_mkstemp)
  133. .Case("mkstemps", &WalkAST::checkCall_mkstemp)
  134. .Cases("strcpy", "__strcpy_chk", &WalkAST::checkCall_strcpy)
  135. .Cases("strcat", "__strcat_chk", &WalkAST::checkCall_strcat)
  136. .Cases("sprintf", "vsprintf", "scanf", "wscanf", "fscanf", "fwscanf",
  137. "vscanf", "vwscanf", "vfscanf", "vfwscanf",
  138. &WalkAST::checkDeprecatedOrUnsafeBufferHandling)
  139. .Cases("sscanf", "swscanf", "vsscanf", "vswscanf", "swprintf",
  140. "snprintf", "vswprintf", "vsnprintf", "memcpy", "memmove",
  141. &WalkAST::checkDeprecatedOrUnsafeBufferHandling)
  142. .Cases("strncpy", "strncat", "memset",
  143. &WalkAST::checkDeprecatedOrUnsafeBufferHandling)
  144. .Case("drand48", &WalkAST::checkCall_rand)
  145. .Case("erand48", &WalkAST::checkCall_rand)
  146. .Case("jrand48", &WalkAST::checkCall_rand)
  147. .Case("lrand48", &WalkAST::checkCall_rand)
  148. .Case("mrand48", &WalkAST::checkCall_rand)
  149. .Case("nrand48", &WalkAST::checkCall_rand)
  150. .Case("lcong48", &WalkAST::checkCall_rand)
  151. .Case("rand", &WalkAST::checkCall_rand)
  152. .Case("rand_r", &WalkAST::checkCall_rand)
  153. .Case("random", &WalkAST::checkCall_random)
  154. .Case("vfork", &WalkAST::checkCall_vfork)
  155. .Default(nullptr);
  156. // If the callee isn't defined, it is not of security concern.
  157. // Check and evaluate the call.
  158. if (evalFunction)
  159. (this->*evalFunction)(CE, FD);
  160. // Recurse and check children.
  161. VisitChildren(CE);
  162. }
  163. void WalkAST::VisitCompoundStmt(CompoundStmt *S) {
  164. for (Stmt *Child : S->children())
  165. if (Child) {
  166. if (CallExpr *CE = dyn_cast<CallExpr>(Child))
  167. checkUncheckedReturnValue(CE);
  168. Visit(Child);
  169. }
  170. }
  171. void WalkAST::VisitForStmt(ForStmt *FS) {
  172. checkLoopConditionForFloat(FS);
  173. // Recurse and check children.
  174. VisitChildren(FS);
  175. }
  176. //===----------------------------------------------------------------------===//
  177. // Check: floating point variable used as loop counter.
  178. // Originally: <rdar://problem/6336718>
  179. // Implements: CERT security coding advisory FLP-30.
  180. //===----------------------------------------------------------------------===//
  181. // Returns either 'x' or 'y', depending on which one of them is incremented
  182. // in 'expr', or nullptr if none of them is incremented.
  183. static const DeclRefExpr*
  184. getIncrementedVar(const Expr *expr, const VarDecl *x, const VarDecl *y) {
  185. expr = expr->IgnoreParenCasts();
  186. if (const BinaryOperator *B = dyn_cast<BinaryOperator>(expr)) {
  187. if (!(B->isAssignmentOp() || B->isCompoundAssignmentOp() ||
  188. B->getOpcode() == BO_Comma))
  189. return nullptr;
  190. if (const DeclRefExpr *lhs = getIncrementedVar(B->getLHS(), x, y))
  191. return lhs;
  192. if (const DeclRefExpr *rhs = getIncrementedVar(B->getRHS(), x, y))
  193. return rhs;
  194. return nullptr;
  195. }
  196. if (const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(expr)) {
  197. const NamedDecl *ND = DR->getDecl();
  198. return ND == x || ND == y ? DR : nullptr;
  199. }
  200. if (const UnaryOperator *U = dyn_cast<UnaryOperator>(expr))
  201. return U->isIncrementDecrementOp()
  202. ? getIncrementedVar(U->getSubExpr(), x, y) : nullptr;
  203. return nullptr;
  204. }
  205. /// CheckLoopConditionForFloat - This check looks for 'for' statements that
  206. /// use a floating point variable as a loop counter.
  207. /// CERT: FLP30-C, FLP30-CPP.
  208. ///
  209. void WalkAST::checkLoopConditionForFloat(const ForStmt *FS) {
  210. if (!filter.check_FloatLoopCounter)
  211. return;
  212. // Does the loop have a condition?
  213. const Expr *condition = FS->getCond();
  214. if (!condition)
  215. return;
  216. // Does the loop have an increment?
  217. const Expr *increment = FS->getInc();
  218. if (!increment)
  219. return;
  220. // Strip away '()' and casts.
  221. condition = condition->IgnoreParenCasts();
  222. increment = increment->IgnoreParenCasts();
  223. // Is the loop condition a comparison?
  224. const BinaryOperator *B = dyn_cast<BinaryOperator>(condition);
  225. if (!B)
  226. return;
  227. // Is this a comparison?
  228. if (!(B->isRelationalOp() || B->isEqualityOp()))
  229. return;
  230. // Are we comparing variables?
  231. const DeclRefExpr *drLHS =
  232. dyn_cast<DeclRefExpr>(B->getLHS()->IgnoreParenLValueCasts());
  233. const DeclRefExpr *drRHS =
  234. dyn_cast<DeclRefExpr>(B->getRHS()->IgnoreParenLValueCasts());
  235. // Does at least one of the variables have a floating point type?
  236. drLHS = drLHS && drLHS->getType()->isRealFloatingType() ? drLHS : nullptr;
  237. drRHS = drRHS && drRHS->getType()->isRealFloatingType() ? drRHS : nullptr;
  238. if (!drLHS && !drRHS)
  239. return;
  240. const VarDecl *vdLHS = drLHS ? dyn_cast<VarDecl>(drLHS->getDecl()) : nullptr;
  241. const VarDecl *vdRHS = drRHS ? dyn_cast<VarDecl>(drRHS->getDecl()) : nullptr;
  242. if (!vdLHS && !vdRHS)
  243. return;
  244. // Does either variable appear in increment?
  245. const DeclRefExpr *drInc = getIncrementedVar(increment, vdLHS, vdRHS);
  246. if (!drInc)
  247. return;
  248. const VarDecl *vdInc = cast<VarDecl>(drInc->getDecl());
  249. assert(vdInc && (vdInc == vdLHS || vdInc == vdRHS));
  250. // Emit the error. First figure out which DeclRefExpr in the condition
  251. // referenced the compared variable.
  252. const DeclRefExpr *drCond = vdLHS == vdInc ? drLHS : drRHS;
  253. SmallVector<SourceRange, 2> ranges;
  254. SmallString<256> sbuf;
  255. llvm::raw_svector_ostream os(sbuf);
  256. os << "Variable '" << drCond->getDecl()->getName()
  257. << "' with floating point type '" << drCond->getType().getAsString()
  258. << "' should not be used as a loop counter";
  259. ranges.push_back(drCond->getSourceRange());
  260. ranges.push_back(drInc->getSourceRange());
  261. const char *bugType = "Floating point variable used as loop counter";
  262. PathDiagnosticLocation FSLoc =
  263. PathDiagnosticLocation::createBegin(FS, BR.getSourceManager(), AC);
  264. BR.EmitBasicReport(AC->getDecl(), filter.checkName_FloatLoopCounter,
  265. bugType, "Security", os.str(),
  266. FSLoc, ranges);
  267. }
  268. //===----------------------------------------------------------------------===//
  269. // Check: Any use of bcmp.
  270. // CWE-477: Use of Obsolete Functions
  271. // bcmp was deprecated in POSIX.1-2008
  272. //===----------------------------------------------------------------------===//
  273. void WalkAST::checkCall_bcmp(const CallExpr *CE, const FunctionDecl *FD) {
  274. if (!filter.check_bcmp)
  275. return;
  276. const FunctionProtoType *FPT = FD->getType()->getAs<FunctionProtoType>();
  277. if (!FPT)
  278. return;
  279. // Verify that the function takes three arguments.
  280. if (FPT->getNumParams() != 3)
  281. return;
  282. for (int i = 0; i < 2; i++) {
  283. // Verify the first and second argument type is void*.
  284. const PointerType *PT = FPT->getParamType(i)->getAs<PointerType>();
  285. if (!PT)
  286. return;
  287. if (PT->getPointeeType().getUnqualifiedType() != BR.getContext().VoidTy)
  288. return;
  289. }
  290. // Verify the third argument type is integer.
  291. if (!FPT->getParamType(2)->isIntegralOrUnscopedEnumerationType())
  292. return;
  293. // Issue a warning.
  294. PathDiagnosticLocation CELoc =
  295. PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC);
  296. BR.EmitBasicReport(AC->getDecl(), filter.checkName_bcmp,
  297. "Use of deprecated function in call to 'bcmp()'",
  298. "Security",
  299. "The bcmp() function is obsoleted by memcmp().",
  300. CELoc, CE->getCallee()->getSourceRange());
  301. }
  302. //===----------------------------------------------------------------------===//
  303. // Check: Any use of bcopy.
  304. // CWE-477: Use of Obsolete Functions
  305. // bcopy was deprecated in POSIX.1-2008
  306. //===----------------------------------------------------------------------===//
  307. void WalkAST::checkCall_bcopy(const CallExpr *CE, const FunctionDecl *FD) {
  308. if (!filter.check_bcopy)
  309. return;
  310. const FunctionProtoType *FPT = FD->getType()->getAs<FunctionProtoType>();
  311. if (!FPT)
  312. return;
  313. // Verify that the function takes three arguments.
  314. if (FPT->getNumParams() != 3)
  315. return;
  316. for (int i = 0; i < 2; i++) {
  317. // Verify the first and second argument type is void*.
  318. const PointerType *PT = FPT->getParamType(i)->getAs<PointerType>();
  319. if (!PT)
  320. return;
  321. if (PT->getPointeeType().getUnqualifiedType() != BR.getContext().VoidTy)
  322. return;
  323. }
  324. // Verify the third argument type is integer.
  325. if (!FPT->getParamType(2)->isIntegralOrUnscopedEnumerationType())
  326. return;
  327. // Issue a warning.
  328. PathDiagnosticLocation CELoc =
  329. PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC);
  330. BR.EmitBasicReport(AC->getDecl(), filter.checkName_bcopy,
  331. "Use of deprecated function in call to 'bcopy()'",
  332. "Security",
  333. "The bcopy() function is obsoleted by memcpy() "
  334. "or memmove().",
  335. CELoc, CE->getCallee()->getSourceRange());
  336. }
  337. //===----------------------------------------------------------------------===//
  338. // Check: Any use of bzero.
  339. // CWE-477: Use of Obsolete Functions
  340. // bzero was deprecated in POSIX.1-2008
  341. //===----------------------------------------------------------------------===//
  342. void WalkAST::checkCall_bzero(const CallExpr *CE, const FunctionDecl *FD) {
  343. if (!filter.check_bzero)
  344. return;
  345. const FunctionProtoType *FPT = FD->getType()->getAs<FunctionProtoType>();
  346. if (!FPT)
  347. return;
  348. // Verify that the function takes two arguments.
  349. if (FPT->getNumParams() != 2)
  350. return;
  351. // Verify the first argument type is void*.
  352. const PointerType *PT = FPT->getParamType(0)->getAs<PointerType>();
  353. if (!PT)
  354. return;
  355. if (PT->getPointeeType().getUnqualifiedType() != BR.getContext().VoidTy)
  356. return;
  357. // Verify the second argument type is integer.
  358. if (!FPT->getParamType(1)->isIntegralOrUnscopedEnumerationType())
  359. return;
  360. // Issue a warning.
  361. PathDiagnosticLocation CELoc =
  362. PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC);
  363. BR.EmitBasicReport(AC->getDecl(), filter.checkName_bzero,
  364. "Use of deprecated function in call to 'bzero()'",
  365. "Security",
  366. "The bzero() function is obsoleted by memset().",
  367. CELoc, CE->getCallee()->getSourceRange());
  368. }
  369. //===----------------------------------------------------------------------===//
  370. // Check: Any use of 'gets' is insecure.
  371. // Originally: <rdar://problem/6335715>
  372. // Implements (part of): 300-BSI (buildsecurityin.us-cert.gov)
  373. // CWE-242: Use of Inherently Dangerous Function
  374. //===----------------------------------------------------------------------===//
  375. void WalkAST::checkCall_gets(const CallExpr *CE, const FunctionDecl *FD) {
  376. if (!filter.check_gets)
  377. return;
  378. const FunctionProtoType *FPT = FD->getType()->getAs<FunctionProtoType>();
  379. if (!FPT)
  380. return;
  381. // Verify that the function takes a single argument.
  382. if (FPT->getNumParams() != 1)
  383. return;
  384. // Is the argument a 'char*'?
  385. const PointerType *PT = FPT->getParamType(0)->getAs<PointerType>();
  386. if (!PT)
  387. return;
  388. if (PT->getPointeeType().getUnqualifiedType() != BR.getContext().CharTy)
  389. return;
  390. // Issue a warning.
  391. PathDiagnosticLocation CELoc =
  392. PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC);
  393. BR.EmitBasicReport(AC->getDecl(), filter.checkName_gets,
  394. "Potential buffer overflow in call to 'gets'",
  395. "Security",
  396. "Call to function 'gets' is extremely insecure as it can "
  397. "always result in a buffer overflow",
  398. CELoc, CE->getCallee()->getSourceRange());
  399. }
  400. //===----------------------------------------------------------------------===//
  401. // Check: Any use of 'getpwd' is insecure.
  402. // CWE-477: Use of Obsolete Functions
  403. //===----------------------------------------------------------------------===//
  404. void WalkAST::checkCall_getpw(const CallExpr *CE, const FunctionDecl *FD) {
  405. if (!filter.check_getpw)
  406. return;
  407. const FunctionProtoType *FPT = FD->getType()->getAs<FunctionProtoType>();
  408. if (!FPT)
  409. return;
  410. // Verify that the function takes two arguments.
  411. if (FPT->getNumParams() != 2)
  412. return;
  413. // Verify the first argument type is integer.
  414. if (!FPT->getParamType(0)->isIntegralOrUnscopedEnumerationType())
  415. return;
  416. // Verify the second argument type is char*.
  417. const PointerType *PT = FPT->getParamType(1)->getAs<PointerType>();
  418. if (!PT)
  419. return;
  420. if (PT->getPointeeType().getUnqualifiedType() != BR.getContext().CharTy)
  421. return;
  422. // Issue a warning.
  423. PathDiagnosticLocation CELoc =
  424. PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC);
  425. BR.EmitBasicReport(AC->getDecl(), filter.checkName_getpw,
  426. "Potential buffer overflow in call to 'getpw'",
  427. "Security",
  428. "The getpw() function is dangerous as it may overflow the "
  429. "provided buffer. It is obsoleted by getpwuid().",
  430. CELoc, CE->getCallee()->getSourceRange());
  431. }
  432. //===----------------------------------------------------------------------===//
  433. // Check: Any use of 'mktemp' is insecure. It is obsoleted by mkstemp().
  434. // CWE-377: Insecure Temporary File
  435. //===----------------------------------------------------------------------===//
  436. void WalkAST::checkCall_mktemp(const CallExpr *CE, const FunctionDecl *FD) {
  437. if (!filter.check_mktemp) {
  438. // Fall back to the security check of looking for enough 'X's in the
  439. // format string, since that is a less severe warning.
  440. checkCall_mkstemp(CE, FD);
  441. return;
  442. }
  443. const FunctionProtoType *FPT = FD->getType()->getAs<FunctionProtoType>();
  444. if(!FPT)
  445. return;
  446. // Verify that the function takes a single argument.
  447. if (FPT->getNumParams() != 1)
  448. return;
  449. // Verify that the argument is Pointer Type.
  450. const PointerType *PT = FPT->getParamType(0)->getAs<PointerType>();
  451. if (!PT)
  452. return;
  453. // Verify that the argument is a 'char*'.
  454. if (PT->getPointeeType().getUnqualifiedType() != BR.getContext().CharTy)
  455. return;
  456. // Issue a warning.
  457. PathDiagnosticLocation CELoc =
  458. PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC);
  459. BR.EmitBasicReport(AC->getDecl(), filter.checkName_mktemp,
  460. "Potential insecure temporary file in call 'mktemp'",
  461. "Security",
  462. "Call to function 'mktemp' is insecure as it always "
  463. "creates or uses insecure temporary file. Use 'mkstemp' "
  464. "instead",
  465. CELoc, CE->getCallee()->getSourceRange());
  466. }
  467. //===----------------------------------------------------------------------===//
  468. // Check: Use of 'mkstemp', 'mktemp', 'mkdtemp' should contain at least 6 X's.
  469. //===----------------------------------------------------------------------===//
  470. void WalkAST::checkCall_mkstemp(const CallExpr *CE, const FunctionDecl *FD) {
  471. if (!filter.check_mkstemp)
  472. return;
  473. StringRef Name = FD->getIdentifier()->getName();
  474. std::pair<signed, signed> ArgSuffix =
  475. llvm::StringSwitch<std::pair<signed, signed> >(Name)
  476. .Case("mktemp", std::make_pair(0,-1))
  477. .Case("mkstemp", std::make_pair(0,-1))
  478. .Case("mkdtemp", std::make_pair(0,-1))
  479. .Case("mkstemps", std::make_pair(0,1))
  480. .Default(std::make_pair(-1, -1));
  481. assert(ArgSuffix.first >= 0 && "Unsupported function");
  482. // Check if the number of arguments is consistent with out expectations.
  483. unsigned numArgs = CE->getNumArgs();
  484. if ((signed) numArgs <= ArgSuffix.first)
  485. return;
  486. const StringLiteral *strArg =
  487. dyn_cast<StringLiteral>(CE->getArg((unsigned)ArgSuffix.first)
  488. ->IgnoreParenImpCasts());
  489. // Currently we only handle string literals. It is possible to do better,
  490. // either by looking at references to const variables, or by doing real
  491. // flow analysis.
  492. if (!strArg || strArg->getCharByteWidth() != 1)
  493. return;
  494. // Count the number of X's, taking into account a possible cutoff suffix.
  495. StringRef str = strArg->getString();
  496. unsigned numX = 0;
  497. unsigned n = str.size();
  498. // Take into account the suffix.
  499. unsigned suffix = 0;
  500. if (ArgSuffix.second >= 0) {
  501. const Expr *suffixEx = CE->getArg((unsigned)ArgSuffix.second);
  502. Expr::EvalResult EVResult;
  503. if (!suffixEx->EvaluateAsInt(EVResult, BR.getContext()))
  504. return;
  505. llvm::APSInt Result = EVResult.Val.getInt();
  506. // FIXME: Issue a warning.
  507. if (Result.isNegative())
  508. return;
  509. suffix = (unsigned) Result.getZExtValue();
  510. n = (n > suffix) ? n - suffix : 0;
  511. }
  512. for (unsigned i = 0; i < n; ++i)
  513. if (str[i] == 'X') ++numX;
  514. if (numX >= 6)
  515. return;
  516. // Issue a warning.
  517. PathDiagnosticLocation CELoc =
  518. PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC);
  519. SmallString<512> buf;
  520. llvm::raw_svector_ostream out(buf);
  521. out << "Call to '" << Name << "' should have at least 6 'X's in the"
  522. " format string to be secure (" << numX << " 'X'";
  523. if (numX != 1)
  524. out << 's';
  525. out << " seen";
  526. if (suffix) {
  527. out << ", " << suffix << " character";
  528. if (suffix > 1)
  529. out << 's';
  530. out << " used as a suffix";
  531. }
  532. out << ')';
  533. BR.EmitBasicReport(AC->getDecl(), filter.checkName_mkstemp,
  534. "Insecure temporary file creation", "Security",
  535. out.str(), CELoc, strArg->getSourceRange());
  536. }
  537. //===----------------------------------------------------------------------===//
  538. // Check: Any use of 'strcpy' is insecure.
  539. //
  540. // CWE-119: Improper Restriction of Operations within
  541. // the Bounds of a Memory Buffer
  542. //===----------------------------------------------------------------------===//
  543. void WalkAST::checkCall_strcpy(const CallExpr *CE, const FunctionDecl *FD) {
  544. if (!filter.check_strcpy)
  545. return;
  546. if (!checkCall_strCommon(CE, FD))
  547. return;
  548. const auto *Target = CE->getArg(0)->IgnoreImpCasts(),
  549. *Source = CE->getArg(1)->IgnoreImpCasts();
  550. if (const auto *Array = dyn_cast<ConstantArrayType>(Target->getType())) {
  551. uint64_t ArraySize = BR.getContext().getTypeSize(Array) / 8;
  552. if (const auto *String = dyn_cast<StringLiteral>(Source)) {
  553. if (ArraySize >= String->getLength() + 1)
  554. return;
  555. }
  556. }
  557. // Issue a warning.
  558. PathDiagnosticLocation CELoc =
  559. PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC);
  560. BR.EmitBasicReport(AC->getDecl(), filter.checkName_strcpy,
  561. "Potential insecure memory buffer bounds restriction in "
  562. "call 'strcpy'",
  563. "Security",
  564. "Call to function 'strcpy' is insecure as it does not "
  565. "provide bounding of the memory buffer. Replace "
  566. "unbounded copy functions with analogous functions that "
  567. "support length arguments such as 'strlcpy'. CWE-119.",
  568. CELoc, CE->getCallee()->getSourceRange());
  569. }
  570. //===----------------------------------------------------------------------===//
  571. // Check: Any use of 'strcat' is insecure.
  572. //
  573. // CWE-119: Improper Restriction of Operations within
  574. // the Bounds of a Memory Buffer
  575. //===----------------------------------------------------------------------===//
  576. void WalkAST::checkCall_strcat(const CallExpr *CE, const FunctionDecl *FD) {
  577. if (!filter.check_strcpy)
  578. return;
  579. if (!checkCall_strCommon(CE, FD))
  580. return;
  581. // Issue a warning.
  582. PathDiagnosticLocation CELoc =
  583. PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC);
  584. BR.EmitBasicReport(AC->getDecl(), filter.checkName_strcpy,
  585. "Potential insecure memory buffer bounds restriction in "
  586. "call 'strcat'",
  587. "Security",
  588. "Call to function 'strcat' is insecure as it does not "
  589. "provide bounding of the memory buffer. Replace "
  590. "unbounded copy functions with analogous functions that "
  591. "support length arguments such as 'strlcat'. CWE-119.",
  592. CELoc, CE->getCallee()->getSourceRange());
  593. }
  594. //===----------------------------------------------------------------------===//
  595. // Check: Any use of 'sprintf', 'vsprintf', 'scanf', 'wscanf', 'fscanf',
  596. // 'fwscanf', 'vscanf', 'vwscanf', 'vfscanf', 'vfwscanf', 'sscanf',
  597. // 'swscanf', 'vsscanf', 'vswscanf', 'swprintf', 'snprintf', 'vswprintf',
  598. // 'vsnprintf', 'memcpy', 'memmove', 'strncpy', 'strncat', 'memset'
  599. // is deprecated since C11.
  600. //
  601. // Use of 'sprintf', 'vsprintf', 'scanf', 'wscanf','fscanf',
  602. // 'fwscanf', 'vscanf', 'vwscanf', 'vfscanf', 'vfwscanf', 'sscanf',
  603. // 'swscanf', 'vsscanf', 'vswscanf' without buffer limitations
  604. // is insecure.
  605. //
  606. // CWE-119: Improper Restriction of Operations within
  607. // the Bounds of a Memory Buffer
  608. //===----------------------------------------------------------------------===//
  609. void WalkAST::checkDeprecatedOrUnsafeBufferHandling(const CallExpr *CE,
  610. const FunctionDecl *FD) {
  611. if (!filter.check_DeprecatedOrUnsafeBufferHandling)
  612. return;
  613. if (!BR.getContext().getLangOpts().C11)
  614. return;
  615. // Issue a warning. ArgIndex == -1: Deprecated but not unsafe (has size
  616. // restrictions).
  617. enum { DEPR_ONLY = -1, UNKNOWN_CALL = -2 };
  618. StringRef Name = FD->getIdentifier()->getName();
  619. if (Name.startswith("__builtin_"))
  620. Name = Name.substr(10);
  621. int ArgIndex =
  622. llvm::StringSwitch<int>(Name)
  623. .Cases("scanf", "wscanf", "vscanf", "vwscanf", 0)
  624. .Cases("sprintf", "vsprintf", "fscanf", "fwscanf", "vfscanf",
  625. "vfwscanf", "sscanf", "swscanf", "vsscanf", "vswscanf", 1)
  626. .Cases("swprintf", "snprintf", "vswprintf", "vsnprintf", "memcpy",
  627. "memmove", "memset", "strncpy", "strncat", DEPR_ONLY)
  628. .Default(UNKNOWN_CALL);
  629. assert(ArgIndex != UNKNOWN_CALL && "Unsupported function");
  630. bool BoundsProvided = ArgIndex == DEPR_ONLY;
  631. if (!BoundsProvided) {
  632. // Currently we only handle (not wide) string literals. It is possible to do
  633. // better, either by looking at references to const variables, or by doing
  634. // real flow analysis.
  635. auto FormatString =
  636. dyn_cast<StringLiteral>(CE->getArg(ArgIndex)->IgnoreParenImpCasts());
  637. if (FormatString &&
  638. FormatString->getString().find("%s") == StringRef::npos &&
  639. FormatString->getString().find("%[") == StringRef::npos)
  640. BoundsProvided = true;
  641. }
  642. SmallString<128> Buf1;
  643. SmallString<512> Buf2;
  644. llvm::raw_svector_ostream Out1(Buf1);
  645. llvm::raw_svector_ostream Out2(Buf2);
  646. Out1 << "Potential insecure memory buffer bounds restriction in call '"
  647. << Name << "'";
  648. Out2 << "Call to function '" << Name
  649. << "' is insecure as it does not provide ";
  650. if (!BoundsProvided) {
  651. Out2 << "bounding of the memory buffer or ";
  652. }
  653. Out2 << "security checks introduced "
  654. "in the C11 standard. Replace with analogous functions that "
  655. "support length arguments or provides boundary checks such as '"
  656. << Name << "_s' in case of C11";
  657. PathDiagnosticLocation CELoc =
  658. PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC);
  659. BR.EmitBasicReport(AC->getDecl(),
  660. filter.checkName_DeprecatedOrUnsafeBufferHandling,
  661. Out1.str(), "Security", Out2.str(), CELoc,
  662. CE->getCallee()->getSourceRange());
  663. }
  664. //===----------------------------------------------------------------------===//
  665. // Common check for str* functions with no bounds parameters.
  666. //===----------------------------------------------------------------------===//
  667. bool WalkAST::checkCall_strCommon(const CallExpr *CE, const FunctionDecl *FD) {
  668. const FunctionProtoType *FPT = FD->getType()->getAs<FunctionProtoType>();
  669. if (!FPT)
  670. return false;
  671. // Verify the function takes two arguments, three in the _chk version.
  672. int numArgs = FPT->getNumParams();
  673. if (numArgs != 2 && numArgs != 3)
  674. return false;
  675. // Verify the type for both arguments.
  676. for (int i = 0; i < 2; i++) {
  677. // Verify that the arguments are pointers.
  678. const PointerType *PT = FPT->getParamType(i)->getAs<PointerType>();
  679. if (!PT)
  680. return false;
  681. // Verify that the argument is a 'char*'.
  682. if (PT->getPointeeType().getUnqualifiedType() != BR.getContext().CharTy)
  683. return false;
  684. }
  685. return true;
  686. }
  687. //===----------------------------------------------------------------------===//
  688. // Check: Linear congruent random number generators should not be used
  689. // Originally: <rdar://problem/63371000>
  690. // CWE-338: Use of cryptographically weak prng
  691. //===----------------------------------------------------------------------===//
  692. void WalkAST::checkCall_rand(const CallExpr *CE, const FunctionDecl *FD) {
  693. if (!filter.check_rand || !CheckRand)
  694. return;
  695. const FunctionProtoType *FTP = FD->getType()->getAs<FunctionProtoType>();
  696. if (!FTP)
  697. return;
  698. if (FTP->getNumParams() == 1) {
  699. // Is the argument an 'unsigned short *'?
  700. // (Actually any integer type is allowed.)
  701. const PointerType *PT = FTP->getParamType(0)->getAs<PointerType>();
  702. if (!PT)
  703. return;
  704. if (! PT->getPointeeType()->isIntegralOrUnscopedEnumerationType())
  705. return;
  706. } else if (FTP->getNumParams() != 0)
  707. return;
  708. // Issue a warning.
  709. SmallString<256> buf1;
  710. llvm::raw_svector_ostream os1(buf1);
  711. os1 << '\'' << *FD << "' is a poor random number generator";
  712. SmallString<256> buf2;
  713. llvm::raw_svector_ostream os2(buf2);
  714. os2 << "Function '" << *FD
  715. << "' is obsolete because it implements a poor random number generator."
  716. << " Use 'arc4random' instead";
  717. PathDiagnosticLocation CELoc =
  718. PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC);
  719. BR.EmitBasicReport(AC->getDecl(), filter.checkName_rand, os1.str(),
  720. "Security", os2.str(), CELoc,
  721. CE->getCallee()->getSourceRange());
  722. }
  723. //===----------------------------------------------------------------------===//
  724. // Check: 'random' should not be used
  725. // Originally: <rdar://problem/63371000>
  726. //===----------------------------------------------------------------------===//
  727. void WalkAST::checkCall_random(const CallExpr *CE, const FunctionDecl *FD) {
  728. if (!CheckRand || !filter.check_rand)
  729. return;
  730. const FunctionProtoType *FTP = FD->getType()->getAs<FunctionProtoType>();
  731. if (!FTP)
  732. return;
  733. // Verify that the function takes no argument.
  734. if (FTP->getNumParams() != 0)
  735. return;
  736. // Issue a warning.
  737. PathDiagnosticLocation CELoc =
  738. PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC);
  739. BR.EmitBasicReport(AC->getDecl(), filter.checkName_rand,
  740. "'random' is not a secure random number generator",
  741. "Security",
  742. "The 'random' function produces a sequence of values that "
  743. "an adversary may be able to predict. Use 'arc4random' "
  744. "instead", CELoc, CE->getCallee()->getSourceRange());
  745. }
  746. //===----------------------------------------------------------------------===//
  747. // Check: 'vfork' should not be used.
  748. // POS33-C: Do not use vfork().
  749. //===----------------------------------------------------------------------===//
  750. void WalkAST::checkCall_vfork(const CallExpr *CE, const FunctionDecl *FD) {
  751. if (!filter.check_vfork)
  752. return;
  753. // All calls to vfork() are insecure, issue a warning.
  754. PathDiagnosticLocation CELoc =
  755. PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC);
  756. BR.EmitBasicReport(AC->getDecl(), filter.checkName_vfork,
  757. "Potential insecure implementation-specific behavior in "
  758. "call 'vfork'",
  759. "Security",
  760. "Call to function 'vfork' is insecure as it can lead to "
  761. "denial of service situations in the parent process. "
  762. "Replace calls to vfork with calls to the safer "
  763. "'posix_spawn' function",
  764. CELoc, CE->getCallee()->getSourceRange());
  765. }
  766. //===----------------------------------------------------------------------===//
  767. // Check: Should check whether privileges are dropped successfully.
  768. // Originally: <rdar://problem/6337132>
  769. //===----------------------------------------------------------------------===//
  770. void WalkAST::checkUncheckedReturnValue(CallExpr *CE) {
  771. if (!filter.check_UncheckedReturn)
  772. return;
  773. const FunctionDecl *FD = CE->getDirectCallee();
  774. if (!FD)
  775. return;
  776. if (II_setid[0] == nullptr) {
  777. static const char * const identifiers[num_setids] = {
  778. "setuid", "setgid", "seteuid", "setegid",
  779. "setreuid", "setregid"
  780. };
  781. for (size_t i = 0; i < num_setids; i++)
  782. II_setid[i] = &BR.getContext().Idents.get(identifiers[i]);
  783. }
  784. const IdentifierInfo *id = FD->getIdentifier();
  785. size_t identifierid;
  786. for (identifierid = 0; identifierid < num_setids; identifierid++)
  787. if (id == II_setid[identifierid])
  788. break;
  789. if (identifierid >= num_setids)
  790. return;
  791. const FunctionProtoType *FTP = FD->getType()->getAs<FunctionProtoType>();
  792. if (!FTP)
  793. return;
  794. // Verify that the function takes one or two arguments (depending on
  795. // the function).
  796. if (FTP->getNumParams() != (identifierid < 4 ? 1 : 2))
  797. return;
  798. // The arguments must be integers.
  799. for (unsigned i = 0; i < FTP->getNumParams(); i++)
  800. if (!FTP->getParamType(i)->isIntegralOrUnscopedEnumerationType())
  801. return;
  802. // Issue a warning.
  803. SmallString<256> buf1;
  804. llvm::raw_svector_ostream os1(buf1);
  805. os1 << "Return value is not checked in call to '" << *FD << '\'';
  806. SmallString<256> buf2;
  807. llvm::raw_svector_ostream os2(buf2);
  808. os2 << "The return value from the call to '" << *FD
  809. << "' is not checked. If an error occurs in '" << *FD
  810. << "', the following code may execute with unexpected privileges";
  811. PathDiagnosticLocation CELoc =
  812. PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC);
  813. BR.EmitBasicReport(AC->getDecl(), filter.checkName_UncheckedReturn, os1.str(),
  814. "Security", os2.str(), CELoc,
  815. CE->getCallee()->getSourceRange());
  816. }
  817. //===----------------------------------------------------------------------===//
  818. // SecuritySyntaxChecker
  819. //===----------------------------------------------------------------------===//
  820. namespace {
  821. class SecuritySyntaxChecker : public Checker<check::ASTCodeBody> {
  822. public:
  823. ChecksFilter filter;
  824. void checkASTCodeBody(const Decl *D, AnalysisManager& mgr,
  825. BugReporter &BR) const {
  826. WalkAST walker(BR, mgr.getAnalysisDeclContext(D), filter);
  827. walker.Visit(D->getBody());
  828. }
  829. };
  830. }
  831. void ento::registerSecuritySyntaxChecker(CheckerManager &mgr) {
  832. mgr.registerChecker<SecuritySyntaxChecker>();
  833. }
  834. bool ento::shouldRegisterSecuritySyntaxChecker(const LangOptions &LO) {
  835. return true;
  836. }
  837. #define REGISTER_CHECKER(name) \
  838. void ento::register##name(CheckerManager &mgr) { \
  839. SecuritySyntaxChecker *checker = mgr.getChecker<SecuritySyntaxChecker>(); \
  840. checker->filter.check_##name = true; \
  841. checker->filter.checkName_##name = mgr.getCurrentCheckerName(); \
  842. } \
  843. \
  844. bool ento::shouldRegister##name(const LangOptions &LO) { return true; }
  845. REGISTER_CHECKER(bcmp)
  846. REGISTER_CHECKER(bcopy)
  847. REGISTER_CHECKER(bzero)
  848. REGISTER_CHECKER(gets)
  849. REGISTER_CHECKER(getpw)
  850. REGISTER_CHECKER(mkstemp)
  851. REGISTER_CHECKER(mktemp)
  852. REGISTER_CHECKER(strcpy)
  853. REGISTER_CHECKER(rand)
  854. REGISTER_CHECKER(vfork)
  855. REGISTER_CHECKER(FloatLoopCounter)
  856. REGISTER_CHECKER(UncheckedReturn)
  857. REGISTER_CHECKER(DeprecatedOrUnsafeBufferHandling)