Skip to content

Commit 7287d96

Browse files
committed
[clang][analyzer] Add new option to specify functions SecuritySyntaxChecker warns about
1 parent ea3dbb8 commit 7287d96

File tree

3 files changed

+56
-11
lines changed

3 files changed

+56
-11
lines changed

clang/include/clang/StaticAnalyzer/Checkers/Checkers.td

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -841,6 +841,14 @@ let ParentPackage = InsecureAPI in {
841841

842842
def SecuritySyntaxChecker : Checker<"SecuritySyntaxChecker">,
843843
HelpText<"Base of various security function related checkers">,
844+
CheckerOptions<[
845+
CmdLineOption<String,
846+
"Warn",
847+
"List of space-separated function name to be warned about. "
848+
"Defaults to an empty list.",
849+
"",
850+
InAlpha>
851+
]>,
844852
Documentation<NotDocumented>,
845853
Hidden;
846854

clang/lib/StaticAnalyzer/Checkers/CheckSecuritySyntaxOnly.cpp

Lines changed: 47 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -74,13 +74,14 @@ class WalkAST : public StmtVisitor<WalkAST> {
7474

7575
const bool CheckRand;
7676
const ChecksFilter &filter;
77+
llvm::StringSet<> WarnFunctions;
7778

7879
public:
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 {
10751098
class SecuritySyntaxChecker : public Checker<check::ASTCodeBody> {
10761099
public:
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

10871120
void 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

10911127
bool ento::shouldRegisterSecuritySyntaxChecker(const CheckerManager &mgr) {

clang/test/Analysis/analyzer-config.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,7 @@
121121
// CHECK-NEXT: region-store-small-struct-limit = 2
122122
// CHECK-NEXT: report-in-main-source-file = false
123123
// CHECK-NEXT: security.cert.env.InvalidPtr:InvalidatingGetEnv = false
124+
// CHECK-NEXT: security.insecureAPI.SecuritySyntaxChecker:Warn = ""
124125
// CHECK-NEXT: serialize-stats = false
125126
// CHECK-NEXT: silence-checkers = ""
126127
// CHECK-NEXT: stable-report-filename = false

0 commit comments

Comments
 (0)