diff options
| author | Dimitry Andric <dim@FreeBSD.org> | 2020-01-17 20:45:01 +0000 | 
|---|---|---|
| committer | Dimitry Andric <dim@FreeBSD.org> | 2020-01-17 20:45:01 +0000 | 
| commit | 706b4fc47bbc608932d3b491ae19a3b9cde9497b (patch) | |
| tree | 4adf86a776049cbf7f69a1929c4babcbbef925eb /clang/lib/StaticAnalyzer/Checkers/CheckSecuritySyntaxOnly.cpp | |
| parent | 7cc9cf2bf09f069cb2dd947ead05d0b54301fb71 (diff) | |
Notes
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 260a2896e78c8..d9ffa562c0aaa 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)  | 
