@@ -53,6 +53,7 @@ struct ChecksFilter {
5353 CheckerNameRef checkName_bcmp;
5454 CheckerNameRef checkName_bcopy;
5555 CheckerNameRef checkName_bzero;
56+ CheckerNameRef checkName_custom;
5657 CheckerNameRef checkName_gets;
5758 CheckerNameRef checkName_getpw;
5859 CheckerNameRef checkName_mktemp;
@@ -74,13 +75,14 @@ class WalkAST : public StmtVisitor<WalkAST> {
7475
7576 const bool CheckRand;
7677 const ChecksFilter &filter;
78+ llvm::StringSet<> WarnFunctions;
7779
7880public:
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 ) {}
81+ WalkAST (BugReporter &br, AnalysisDeclContext *ac, const ChecksFilter &f ,
82+ llvm::StringSet<> wf )
83+ : BR(br), AC(ac), II_setid(),
84+ CheckRand (isArc4RandomAvailable(BR.getContext())), filter(f ),
85+ WarnFunctions(wf ) {}
8486
8587 // Statement visitor methods.
8688 void VisitCallExpr (CallExpr *CE);
@@ -101,6 +103,7 @@ class WalkAST : public StmtVisitor<WalkAST> {
101103 void checkLoopConditionForFloat (const ForStmt *FS);
102104 void checkCall_bcmp (const CallExpr *CE, const FunctionDecl *FD);
103105 void checkCall_bcopy (const CallExpr *CE, const FunctionDecl *FD);
106+ void checkCall_custom (const CallExpr *CE, const FunctionDecl *FD);
104107 void checkCall_bzero (const CallExpr *CE, const FunctionDecl *FD);
105108 void checkCall_gets (const CallExpr *CE, const FunctionDecl *FD);
106109 void checkCall_getpw (const CallExpr *CE, const FunctionDecl *FD);
@@ -175,12 +178,10 @@ void WalkAST::VisitCallExpr(CallExpr *CE) {
175178 .Case (" rand_r" , &WalkAST::checkCall_rand)
176179 .Case (" random" , &WalkAST::checkCall_random)
177180 .Case (" vfork" , &WalkAST::checkCall_vfork)
178- .Default (nullptr );
181+ .Default (&WalkAST::checkCall_custom );
179182
180- // If the callee isn't defined, it is not of security concern.
181183 // Check and evaluate the call.
182- if (evalFunction)
183- (this ->*evalFunction)(CE, FD);
184+ (this ->*evalFunction)(CE, FD);
184185
185186 // Recurse and check children.
186187 VisitChildren (CE);
@@ -542,6 +543,29 @@ void WalkAST::checkCall_getpw(const CallExpr *CE, const FunctionDecl *FD) {
542543 CELoc, CE->getCallee ()->getSourceRange ());
543544}
544545
546+ // ===----------------------------------------------------------------------===//
547+ // Check: Any use of a function from the user-provided list.
548+ // ===----------------------------------------------------------------------===//
549+
550+ void WalkAST::checkCall_custom (const CallExpr *CE, const FunctionDecl *FD) {
551+ IdentifierInfo *II = FD->getIdentifier ();
552+ if (!II) // if no identifier, not a simple C function
553+ return ;
554+ StringRef Name = II->getName ();
555+ Name.consume_front (" __builtin_" );
556+
557+ if (!(this ->WarnFunctions .contains (Name)))
558+ return ;
559+
560+ // Issue a warning.
561+ std::string Msg = (" Call to user-defined function '" + Name + " '." ).str ();
562+ PathDiagnosticLocation CELoc =
563+ PathDiagnosticLocation::createBegin (CE, BR.getSourceManager (), AC);
564+ BR.EmitBasicReport (AC->getDecl (), filter.checkName_custom ,
565+ " User-provided function to be warned about" , " Security" ,
566+ Msg, CELoc, CE->getCallee ()->getSourceRange ());
567+ }
568+
545569// ===----------------------------------------------------------------------===//
546570// Check: Any use of 'mktemp' is insecure. It is obsoleted by mkstemp().
547571// CWE-377: Insecure Temporary File
@@ -1075,17 +1099,30 @@ namespace {
10751099class SecuritySyntaxChecker : public Checker <check::ASTCodeBody> {
10761100public:
10771101 ChecksFilter filter;
1102+ llvm::StringSet<> WarnFunctions;
10781103
10791104 void checkASTCodeBody (const Decl *D, AnalysisManager& mgr,
10801105 BugReporter &BR) const {
1081- WalkAST walker (BR, mgr.getAnalysisDeclContext (D), filter);
1106+ WalkAST walker (BR, mgr.getAnalysisDeclContext (D), filter, WarnFunctions );
10821107 walker.Visit (D->getBody ());
10831108 }
1109+
1110+ void setWarnFunctions (StringRef Input) {
1111+ StringRef CurrentStr = Input;
1112+ while (!CurrentStr.empty ()) {
1113+ auto SplitResult = CurrentStr.split (' ' );
1114+ WarnFunctions.insert (SplitResult.first );
1115+ CurrentStr = SplitResult.second ;
1116+ }
1117+ }
10841118};
10851119}
10861120
10871121void ento::registerSecuritySyntaxChecker (CheckerManager &mgr) {
1088- mgr.registerChecker <SecuritySyntaxChecker>();
1122+ SecuritySyntaxChecker *checker = mgr.registerChecker <SecuritySyntaxChecker>();
1123+ StringRef WarnOption =
1124+ mgr.getAnalyzerOptions ().getCheckerStringOption (checker, " Warn" );
1125+ checker->setWarnFunctions (WarnOption);
10891126}
10901127
10911128bool ento::shouldRegisterSecuritySyntaxChecker (const CheckerManager &mgr) {
0 commit comments