//==- CheckSecuritySyntaxOnly.cpp - Basic security checks --------*- C++ -*-==// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // // This file defines a set of flow-insensitive security checks. // //===----------------------------------------------------------------------===// #include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h" #include "clang/AST/StmtVisitor.h" #include "clang/Analysis/AnalysisDeclContext.h" #include "clang/Basic/TargetInfo.h" #include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h" #include "clang/StaticAnalyzer/Core/Checker.h" #include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringSwitch.h" #include "llvm/Support/raw_ostream.h" usingnamespaceclang; usingnamespaceento; static bool isArc4RandomAvailable(const ASTContext &Ctx) { … } namespace { struct ChecksFilter { … }; class WalkAST : public StmtVisitor<WalkAST> { … }; } // end anonymous namespace //===----------------------------------------------------------------------===// // AST walking. //===----------------------------------------------------------------------===// void WalkAST::VisitChildren(Stmt *S) { … } void WalkAST::VisitCallExpr(CallExpr *CE) { … } void WalkAST::VisitObjCMessageExpr(ObjCMessageExpr *ME) { … } void WalkAST::VisitCompoundStmt(CompoundStmt *S) { … } void WalkAST::VisitForStmt(ForStmt *FS) { … } //===----------------------------------------------------------------------===// // Check: floating point variable used as loop counter. // Implements: CERT security coding advisory FLP-30. //===----------------------------------------------------------------------===// // Returns either 'x' or 'y', depending on which one of them is incremented // in 'expr', or nullptr if none of them is incremented. static const DeclRefExpr* getIncrementedVar(const Expr *expr, const VarDecl *x, const VarDecl *y) { … } /// CheckLoopConditionForFloat - This check looks for 'for' statements that /// use a floating point variable as a loop counter. /// CERT: FLP30-C, FLP30-CPP. /// void WalkAST::checkLoopConditionForFloat(const ForStmt *FS) { … } //===----------------------------------------------------------------------===// // Check: Any use of bcmp. // CWE-477: Use of Obsolete Functions // bcmp was deprecated in POSIX.1-2008 //===----------------------------------------------------------------------===// void WalkAST::checkCall_bcmp(const CallExpr *CE, const FunctionDecl *FD) { … } //===----------------------------------------------------------------------===// // Check: Any use of bcopy. // CWE-477: Use of Obsolete Functions // bcopy was deprecated in POSIX.1-2008 //===----------------------------------------------------------------------===// void WalkAST::checkCall_bcopy(const CallExpr *CE, const FunctionDecl *FD) { … } //===----------------------------------------------------------------------===// // Check: Any use of bzero. // CWE-477: Use of Obsolete Functions // bzero was deprecated in POSIX.1-2008 //===----------------------------------------------------------------------===// void WalkAST::checkCall_bzero(const CallExpr *CE, const FunctionDecl *FD) { … } //===----------------------------------------------------------------------===// // Check: Any use of 'gets' is insecure. Most man pages literally says this. // // Implements (part of): 300-BSI (buildsecurityin.us-cert.gov) // CWE-242: Use of Inherently Dangerous Function //===----------------------------------------------------------------------===// void WalkAST::checkCall_gets(const CallExpr *CE, const FunctionDecl *FD) { … } //===----------------------------------------------------------------------===// // Check: Any use of 'getpwd' is insecure. // CWE-477: Use of Obsolete Functions //===----------------------------------------------------------------------===// void WalkAST::checkCall_getpw(const CallExpr *CE, const FunctionDecl *FD) { … } //===----------------------------------------------------------------------===// // Check: Any use of 'mktemp' is insecure. It is obsoleted by mkstemp(). // CWE-377: Insecure Temporary File //===----------------------------------------------------------------------===// void WalkAST::checkCall_mktemp(const CallExpr *CE, const FunctionDecl *FD) { … } //===----------------------------------------------------------------------===// // Check: Use of 'mkstemp', 'mktemp', 'mkdtemp' should contain at least 6 X's. //===----------------------------------------------------------------------===// void WalkAST::checkCall_mkstemp(const CallExpr *CE, const FunctionDecl *FD) { … } //===----------------------------------------------------------------------===// // Check: Any use of 'strcpy' is insecure. // // CWE-119: Improper Restriction of Operations within // the Bounds of a Memory Buffer //===----------------------------------------------------------------------===// void WalkAST::checkCall_strcpy(const CallExpr *CE, const FunctionDecl *FD) { … } //===----------------------------------------------------------------------===// // Check: Any use of 'strcat' is insecure. // // CWE-119: Improper Restriction of Operations within // the Bounds of a Memory Buffer //===----------------------------------------------------------------------===// void WalkAST::checkCall_strcat(const CallExpr *CE, const FunctionDecl *FD) { … } //===----------------------------------------------------------------------===// // Check: Any use of 'sprintf', 'vsprintf', 'scanf', 'wscanf', 'fscanf', // 'fwscanf', 'vscanf', 'vwscanf', 'vfscanf', 'vfwscanf', 'sscanf', // 'swscanf', 'vsscanf', 'vswscanf', 'swprintf', 'snprintf', 'vswprintf', // 'vsnprintf', 'memcpy', 'memmove', 'strncpy', 'strncat', 'memset', // 'fprintf' is deprecated since C11. // // Use of 'sprintf', 'fprintf', 'vsprintf', 'scanf', 'wscanf', 'fscanf', // 'fwscanf', 'vscanf', 'vwscanf', 'vfscanf', 'vfwscanf', 'sscanf', // 'swscanf', 'vsscanf', 'vswscanf' without buffer limitations // is insecure. // // CWE-119: Improper Restriction of Operations within // the Bounds of a Memory Buffer //===----------------------------------------------------------------------===// void WalkAST::checkDeprecatedOrUnsafeBufferHandling(const CallExpr *CE, const FunctionDecl *FD) { … } //===----------------------------------------------------------------------===// // Common check for str* functions with no bounds parameters. //===----------------------------------------------------------------------===// bool WalkAST::checkCall_strCommon(const CallExpr *CE, const FunctionDecl *FD) { … } //===----------------------------------------------------------------------===// // Check: Linear congruent random number generators should not be used, // i.e. rand(), random(). // // E. Bach, "Efficient prediction of Marsaglia-Zaman random number generators," // in IEEE Transactions on Information Theory, vol. 44, no. 3, pp. 1253-1257, // May 1998, https://doi.org/10.1109/18.669305 // // CWE-338: Use of cryptographically weak prng //===----------------------------------------------------------------------===// void WalkAST::checkCall_rand(const CallExpr *CE, const FunctionDecl *FD) { … } // See justification for rand(). void WalkAST::checkCall_random(const CallExpr *CE, const FunctionDecl *FD) { … } //===----------------------------------------------------------------------===// // Check: 'vfork' should not be used. // POS33-C: Do not use vfork(). //===----------------------------------------------------------------------===// void WalkAST::checkCall_vfork(const CallExpr *CE, const FunctionDecl *FD) { … } //===----------------------------------------------------------------------===// // Check: '-decodeValueOfObjCType:at:' should not be used. // It is deprecated in favor of '-decodeValueOfObjCType:at:size:' due to // likelihood of buffer overflows. //===----------------------------------------------------------------------===// void WalkAST::checkMsg_decodeValueOfObjCType(const ObjCMessageExpr *ME) { … } //===----------------------------------------------------------------------===// // Check: The caller should always verify that the privileges // were dropped successfully. // // Some library functions, like setuid() and setgid(), should always be used // with a check of the return value to verify that the function completed // successfully. If the drop fails, the software will continue to run // with the raised privileges, which might provide additional access // to unprivileged users. // // (Note that this check predates __attribute__((warn_unused_result)). // Do we still need it now that we have a compiler warning for this? // Are these standard functions already annotated this way?) //===----------------------------------------------------------------------===// void WalkAST::checkUncheckedReturnValue(CallExpr *CE) { … } //===----------------------------------------------------------------------===// // SecuritySyntaxChecker //===----------------------------------------------------------------------===// namespace { class SecuritySyntaxChecker : public Checker<check::ASTCodeBody> { … }; } void ento::registerSecuritySyntaxChecker(CheckerManager &mgr) { … } bool ento::shouldRegisterSecuritySyntaxChecker(const CheckerManager &mgr) { … } #define REGISTER_CHECKER(name) … REGISTER_CHECKER(bcmp) REGISTER_CHECKER(bcopy) REGISTER_CHECKER(bzero) REGISTER_CHECKER(gets) REGISTER_CHECKER(getpw) REGISTER_CHECKER(mkstemp) REGISTER_CHECKER(mktemp) REGISTER_CHECKER(strcpy) REGISTER_CHECKER(rand) REGISTER_CHECKER(vfork) REGISTER_CHECKER(FloatLoopCounter) REGISTER_CHECKER(UncheckedReturn) REGISTER_CHECKER(DeprecatedOrUnsafeBufferHandling) REGISTER_CHECKER(decodeValueOfObjCType)