summaryrefslogtreecommitdiffstats
path: root/clang/lib/StaticAnalyzer/Checkers/CheckSecuritySyntaxOnly.cpp
diff options
context:
space:
mode:
authorArtem Dergachev <artem.dergachev@gmail.com>2019-12-19 14:21:02 -0800
committerArtem Dergachev <artem.dergachev@gmail.com>2019-12-19 14:54:29 -0800
commitb284005072122fe4af879725e3c8090009f89ca0 (patch)
tree1cb978a8a8fbd7c92f247812d293f478bba5a1f1 /clang/lib/StaticAnalyzer/Checkers/CheckSecuritySyntaxOnly.cpp
parent047186cc986f5bb53ce716dfe363ba517b7d0ed8 (diff)
downloadbcm5719-llvm-b284005072122fe4af879725e3c8090009f89ca0.tar.gz
bcm5719-llvm-b284005072122fe4af879725e3c8090009f89ca0.zip
[analyzer] Add a syntactic security check for ObjC NSCoder API.
Method '-[NSCoder decodeValueOfObjCType:at:]' is not only deprecated but also a security hazard, hence a loud check. Differential Revision: https://reviews.llvm.org/D71728
Diffstat (limited to 'clang/lib/StaticAnalyzer/Checkers/CheckSecuritySyntaxOnly.cpp')
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/CheckSecuritySyntaxOnly.cpp68
1 files changed, 68 insertions, 0 deletions
diff --git a/clang/lib/StaticAnalyzer/Checkers/CheckSecuritySyntaxOnly.cpp b/clang/lib/StaticAnalyzer/Checkers/CheckSecuritySyntaxOnly.cpp
index 260a2896e78..d9ffa562c0a 100644
--- a/clang/lib/StaticAnalyzer/Checkers/CheckSecuritySyntaxOnly.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/CheckSecuritySyntaxOnly.cpp
@@ -49,6 +49,7 @@ struct ChecksFilter {
DefaultBool check_vfork;
DefaultBool check_FloatLoopCounter;
DefaultBool check_UncheckedReturn;
+ DefaultBool check_decodeValueOfObjCType;
CheckerNameRef checkName_bcmp;
CheckerNameRef checkName_bcopy;
@@ -63,6 +64,7 @@ struct ChecksFilter {
CheckerNameRef checkName_vfork;
CheckerNameRef checkName_FloatLoopCounter;
CheckerNameRef checkName_UncheckedReturn;
+ CheckerNameRef checkName_decodeValueOfObjCType;
};
class WalkAST : public StmtVisitor<WalkAST> {
@@ -83,6 +85,7 @@ public:
// Statement visitor methods.
void VisitCallExpr(CallExpr *CE);
+ void VisitObjCMessageExpr(ObjCMessageExpr *CE);
void VisitForStmt(ForStmt *S);
void VisitCompoundStmt (CompoundStmt *S);
void VisitStmt(Stmt *S) { VisitChildren(S); }
@@ -93,6 +96,7 @@ public:
bool checkCall_strCommon(const CallExpr *CE, const FunctionDecl *FD);
typedef void (WalkAST::*FnCheck)(const CallExpr *, const FunctionDecl *);
+ typedef void (WalkAST::*MsgCheck)(const ObjCMessageExpr *);
// Checker-specific methods.
void checkLoopConditionForFloat(const ForStmt *FS);
@@ -110,6 +114,7 @@ public:
void checkCall_rand(const CallExpr *CE, const FunctionDecl *FD);
void checkCall_random(const CallExpr *CE, const FunctionDecl *FD);
void checkCall_vfork(const CallExpr *CE, const FunctionDecl *FD);
+ void checkMsg_decodeValueOfObjCType(const ObjCMessageExpr *ME);
void checkUncheckedReturnValue(CallExpr *CE);
};
} // end anonymous namespace
@@ -182,6 +187,20 @@ void WalkAST::VisitCallExpr(CallExpr *CE) {
VisitChildren(CE);
}
+void WalkAST::VisitObjCMessageExpr(ObjCMessageExpr *ME) {
+ MsgCheck evalFunction =
+ llvm::StringSwitch<MsgCheck>(ME->getSelector().getAsString())
+ .Case("decodeValueOfObjCType:at:",
+ &WalkAST::checkMsg_decodeValueOfObjCType)
+ .Default(nullptr);
+
+ if (evalFunction)
+ (this->*evalFunction)(ME);
+
+ // Recurse and check children.
+ VisitChildren(ME);
+}
+
void WalkAST::VisitCompoundStmt(CompoundStmt *S) {
for (Stmt *Child : S->children())
if (Child) {
@@ -924,6 +943,54 @@ 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) {
+ if (!filter.check_decodeValueOfObjCType)
+ return;
+
+ // Check availability of the secure alternative:
+ // iOS 11+, macOS 10.13+, tvOS 11+, and watchOS 4.0+
+ // FIXME: We probably shouldn't register the check if it's not available.
+ const TargetInfo &TI = AC->getASTContext().getTargetInfo();
+ const llvm::Triple &T = TI.getTriple();
+ const VersionTuple &VT = TI.getPlatformMinVersion();
+ switch (T.getOS()) {
+ case llvm::Triple::IOS:
+ if (VT < VersionTuple(11, 0))
+ return;
+ break;
+ case llvm::Triple::MacOSX:
+ if (VT < VersionTuple(10, 13))
+ return;
+ break;
+ case llvm::Triple::WatchOS:
+ if (VT < VersionTuple(4, 0))
+ return;
+ break;
+ case llvm::Triple::TvOS:
+ if (VT < VersionTuple(11, 0))
+ return;
+ break;
+ default:
+ return;
+ }
+
+ PathDiagnosticLocation MELoc =
+ PathDiagnosticLocation::createBegin(ME, BR.getSourceManager(), AC);
+ BR.EmitBasicReport(
+ AC->getDecl(), filter.checkName_decodeValueOfObjCType,
+ "Potential buffer overflow in '-decodeValueOfObjCType:at:'", "Security",
+ "Deprecated method '-decodeValueOfObjCType:at:' is insecure "
+ "as it can lead to potential buffer overflows. Use the safer "
+ "'-decodeValueOfObjCType:at:size:' method.",
+ MELoc, ME->getSourceRange());
+}
+
+//===----------------------------------------------------------------------===//
// Check: Should check whether privileges are dropped successfully.
// Originally: <rdar://problem/6337132>
//===----------------------------------------------------------------------===//
@@ -1035,3 +1102,4 @@ REGISTER_CHECKER(vfork)
REGISTER_CHECKER(FloatLoopCounter)
REGISTER_CHECKER(UncheckedReturn)
REGISTER_CHECKER(DeprecatedOrUnsafeBufferHandling)
+REGISTER_CHECKER(decodeValueOfObjCType)
OpenPOWER on IntegriCloud