@@ -74,13 +74,14 @@ class WalkAST : public StmtVisitor<WalkAST> {
7474
7575 const bool CheckRand;
7676 const ChecksFilter &filter;
77+ llvm::StringSet<> WarnFunctions;
7778
7879public:
79- WalkAST (BugReporter &br, AnalysisDeclContext* ac ,
80- const ChecksFilter &f )
81- : BR(br), AC(ac), II_setid(),
82- CheckRand (isArc4RandomAvailable(BR.getContext())),
83- filter(f ) {}
80+ WalkAST (BugReporter &br, AnalysisDeclContext *ac, const ChecksFilter &f ,
81+ llvm::StringSet<> wf )
82+ : BR(br), AC(ac), II_setid(),
83+ CheckRand (isArc4RandomAvailable(BR.getContext())), filter(f ),
84+ WarnFunctions(wf ) {}
8485
8586 // Statement visitor methods.
8687 void VisitCallExpr (CallExpr *CE);
@@ -101,6 +102,7 @@ class WalkAST : public StmtVisitor<WalkAST> {
101102 void checkLoopConditionForFloat (const ForStmt *FS);
102103 void checkCall_bcmp (const CallExpr *CE, const FunctionDecl *FD);
103104 void checkCall_bcopy (const CallExpr *CE, const FunctionDecl *FD);
105+ void checkCall_custom (const CallExpr *CE, const FunctionDecl *FD);
104106 void checkCall_bzero (const CallExpr *CE, const FunctionDecl *FD);
105107 void checkCall_gets (const CallExpr *CE, const FunctionDecl *FD);
106108 void checkCall_getpw (const CallExpr *CE, const FunctionDecl *FD);
@@ -175,12 +177,10 @@ void WalkAST::VisitCallExpr(CallExpr *CE) {
175177 .Case (" rand_r" , &WalkAST::checkCall_rand)
176178 .Case (" random" , &WalkAST::checkCall_random)
177179 .Case (" vfork" , &WalkAST::checkCall_vfork)
178- .Default (nullptr );
180+ .Default (&WalkAST::checkCall_custom );
179181
180- // If the callee isn't defined, it is not of security concern.
181182 // Check and evaluate the call.
182- if (evalFunction)
183- (this ->*evalFunction)(CE, FD);
183+ (this ->*evalFunction)(CE, FD);
184184
185185 // Recurse and check children.
186186 VisitChildren (CE);
@@ -542,6 +542,29 @@ void WalkAST::checkCall_getpw(const CallExpr *CE, const FunctionDecl *FD) {
542542 CELoc, CE->getCallee ()->getSourceRange ());
543543}
544544
545+ // ===----------------------------------------------------------------------===//
546+ // Check: Any use of a function from the user-provided list.
547+ // ===----------------------------------------------------------------------===//
548+
549+ void WalkAST::checkCall_custom (const CallExpr *CE, const FunctionDecl *FD) {
550+ IdentifierInfo *II = FD->getIdentifier ();
551+ if (!II) // if no identifier, not a simple C function
552+ return ;
553+ StringRef Name = II->getName ();
554+ Name.consume_front (" __builtin_" );
555+
556+ if (!(this ->WarnFunctions .contains (Name)))
557+ return ;
558+
559+ // Issue a warning.
560+ std::string Msg = (" Call to user-defined function '" + Name + " '." ).str ();
561+ PathDiagnosticLocation CELoc =
562+ PathDiagnosticLocation::createBegin (CE, BR.getSourceManager (), AC);
563+ BR.EmitBasicReport (AC->getDecl (), filter.checkName_getpw ,
564+ " User-provided function to be warned about" , " Security" ,
565+ Msg, CELoc, CE->getCallee ()->getSourceRange ());
566+ }
567+
545568// ===----------------------------------------------------------------------===//
546569// Check: Any use of 'mktemp' is insecure. It is obsoleted by mkstemp().
547570// CWE-377: Insecure Temporary File
@@ -1075,17 +1098,30 @@ namespace {
10751098class SecuritySyntaxChecker : public Checker <check::ASTCodeBody> {
10761099public:
10771100 ChecksFilter filter;
1101+ llvm::StringSet<> WarnFunctions;
10781102
10791103 void checkASTCodeBody (const Decl *D, AnalysisManager& mgr,
10801104 BugReporter &BR) const {
1081- WalkAST walker (BR, mgr.getAnalysisDeclContext (D), filter);
1105+ WalkAST walker (BR, mgr.getAnalysisDeclContext (D), filter, WarnFunctions );
10821106 walker.Visit (D->getBody ());
10831107 }
1108+
1109+ void setWarnFunctions (StringRef Input) {
1110+ StringRef CurrentStr = Input;
1111+ while (!CurrentStr.empty ()) {
1112+ auto SplitResult = CurrentStr.split (' ' );
1113+ WarnFunctions.insert (SplitResult.first );
1114+ CurrentStr = SplitResult.second ;
1115+ }
1116+ }
10841117};
10851118}
10861119
10871120void ento::registerSecuritySyntaxChecker (CheckerManager &mgr) {
1088- mgr.registerChecker <SecuritySyntaxChecker>();
1121+ SecuritySyntaxChecker *checker = mgr.registerChecker <SecuritySyntaxChecker>();
1122+ StringRef WarnOption =
1123+ mgr.getAnalyzerOptions ().getCheckerStringOption (checker, " Warn" );
1124+ checker->setWarnFunctions (WarnOption);
10891125}
10901126
10911127bool ento::shouldRegisterSecuritySyntaxChecker (const CheckerManager &mgr) {
0 commit comments