Skip to content

Commit e7f5f14

Browse files
committed
[clang][analyzer] Add new option to specify functions SecuritySyntaxChecker warns about
1 parent 4454157 commit e7f5f14

File tree

3 files changed

+57
-11
lines changed

3 files changed

+57
-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: 48 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -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

7880
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) {}
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 {
10751099
class SecuritySyntaxChecker : public Checker<check::ASTCodeBody> {
10761100
public:
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

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

10911128
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)