diff options
Diffstat (limited to 'clang/lib/StaticAnalyzer/Checkers/CheckSecuritySyntaxOnly.cpp')
-rw-r--r-- | clang/lib/StaticAnalyzer/Checkers/CheckSecuritySyntaxOnly.cpp | 68 |
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) |