[cfe-commits] r136659 - in /cfe/trunk: lib/StaticAnalyzer/Checkers/CMakeLists.txt lib/StaticAnalyzer/Checkers/Checkers.td lib/StaticAnalyzer/Checkers/MacOSKeychainAPIChecker.cpp test/Analysis/keychainAPI.m

Anna Zaks ganna at apple.com
Mon Aug 1 15:40:02 PDT 2011


Author: zaks
Date: Mon Aug  1 17:40:01 2011
New Revision: 136659

URL: http://llvm.org/viewvc/llvm-project?rev=136659&view=rev
Log:
Add a skeleton for the Keychain Services API Checker. Register it as OSX experimental for now. Note, the checker still does not handle tracking of escaped values, taking into account the return value of the allocator functions, nor the actual bug reporting.. 

Added:
    cfe/trunk/lib/StaticAnalyzer/Checkers/MacOSKeychainAPIChecker.cpp
    cfe/trunk/test/Analysis/keychainAPI.m
Modified:
    cfe/trunk/lib/StaticAnalyzer/Checkers/CMakeLists.txt
    cfe/trunk/lib/StaticAnalyzer/Checkers/Checkers.td

Modified: cfe/trunk/lib/StaticAnalyzer/Checkers/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Checkers/CMakeLists.txt?rev=136659&r1=136658&r2=136659&view=diff
==============================================================================
--- cfe/trunk/lib/StaticAnalyzer/Checkers/CMakeLists.txt (original)
+++ cfe/trunk/lib/StaticAnalyzer/Checkers/CMakeLists.txt Mon Aug  1 17:40:01 2011
@@ -31,6 +31,7 @@
   IdempotentOperationChecker.cpp
   IteratorsChecker.cpp
   LLVMConventionsChecker.cpp
+  MacOSKeychainAPIChecker.cpp
   MacOSXAPIChecker.cpp
   MallocChecker.cpp
   NSAutoreleasePoolChecker.cpp

Modified: cfe/trunk/lib/StaticAnalyzer/Checkers/Checkers.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Checkers/Checkers.td?rev=136659&r1=136658&r2=136659&view=diff
==============================================================================
--- cfe/trunk/lib/StaticAnalyzer/Checkers/Checkers.td (original)
+++ cfe/trunk/lib/StaticAnalyzer/Checkers/Checkers.td Mon Aug  1 17:40:01 2011
@@ -42,6 +42,8 @@
   InGroup<AllExperimental>, Hidden;
 
 def OSX : Package<"osx">;
+def OSXExperimental : Package<"experimental">, InPackage<OSX>,
+  InGroup<AllExperimental>, Hidden;
 def Cocoa : Package<"cocoa">, InPackage<OSX>;
 def CocoaExperimental : Package<"experimental">, InPackage<Cocoa>,
   InGroup<AllExperimental>, Hidden;
@@ -276,6 +278,15 @@
 
 } // end "macosx"
 
+let ParentPackage = OSXExperimental in {
+
+def MacOSKeychainAPIChecker : Checker<"KeychainAPI">,
+  InPackage<OSX>,
+  HelpText<"Check for proper uses of Secure Keychain APIs">,
+  DescFile<"MacOSKeychainAPIChecker.cpp">;
+
+} // end "osx.experimental"
+
 let ParentPackage = Cocoa in {
 
 def ObjCAtSyncChecker : Checker<"AtSync">,

Added: cfe/trunk/lib/StaticAnalyzer/Checkers/MacOSKeychainAPIChecker.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Checkers/MacOSKeychainAPIChecker.cpp?rev=136659&view=auto
==============================================================================
--- cfe/trunk/lib/StaticAnalyzer/Checkers/MacOSKeychainAPIChecker.cpp (added)
+++ cfe/trunk/lib/StaticAnalyzer/Checkers/MacOSKeychainAPIChecker.cpp Mon Aug  1 17:40:01 2011
@@ -0,0 +1,160 @@
+//==--- MacOSKeychainAPIChecker.cpp -----------------------------------*- C++ -*-==//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+// This checker flags misuses of KeyChainAPI. In particular, the password data
+// allocated/returned by SecKeychainItemCopyContent,
+// SecKeychainFindGenericPassword, SecKeychainFindInternetPassword functions has
+// to be freed using a call to SecKeychainItemFreeContent.
+//===----------------------------------------------------------------------===//
+
+#include "ClangSACheckers.h"
+#include "clang/StaticAnalyzer/Core/Checker.h"
+#include "clang/StaticAnalyzer/Core/CheckerManager.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/GRState.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/GRStateTrait.h"
+
+using namespace clang;
+using namespace ento;
+
+namespace {
+class MacOSKeychainAPIChecker : public Checker<check::PreStmt<CallExpr>,
+                                               check::PreStmt<ReturnStmt>,
+                                               check::PostStmt<CallExpr>,
+                                               check::EndPath > {
+public:
+  void checkPreStmt(const CallExpr *S, CheckerContext &C) const;
+  void checkPreStmt(const ReturnStmt *S, CheckerContext &C) const;
+  void checkPostStmt(const CallExpr *S, CheckerContext &C) const;
+
+  void checkEndPath(EndOfFunctionNodeBuilder &B, ExprEngine &Eng) const;
+
+private:
+  static const unsigned InvalidParamVal = 100000;
+
+  /// Given the function name, returns the index of the parameter which will
+  /// be allocated as a result of the call.
+  unsigned getAllocatingFunctionParam(StringRef Name) const {
+    if (Name == "SecKeychainItemCopyContent")
+      return 4;
+    if (Name == "SecKeychainFindGenericPassword")
+      return 6;
+    if (Name == "SecKeychainFindInternetPassword")
+      return 13;
+    return InvalidParamVal;
+  }
+
+  /// Given the function name, returns the index of the parameter which will
+  /// be freed by the function.
+  unsigned getDeallocatingFunctionParam(StringRef Name) const {
+    if (Name == "SecKeychainItemFreeContent")
+      return 1;
+    return InvalidParamVal;
+  }
+};
+}
+
+// GRState traits to store the currently allocated (and not yet freed) symbols.
+typedef llvm::ImmutableSet<SymbolRef> AllocatedSetTy;
+
+namespace { struct AllocatedData {}; }
+namespace clang { namespace ento {
+template<> struct GRStateTrait<AllocatedData>
+    :  public GRStatePartialTrait<AllocatedSetTy > {
+  static void *GDMIndex() { static int index = 0; return &index; }
+};
+}}
+
+void MacOSKeychainAPIChecker::checkPreStmt(const CallExpr *CE,
+                                           CheckerContext &C) const {
+  const GRState *State = C.getState();
+  const Expr *Callee = CE->getCallee();
+  SVal L = State->getSVal(Callee);
+
+  const FunctionDecl *funDecl = L.getAsFunctionDecl();
+  if (!funDecl)
+    return;
+  IdentifierInfo *funI = funDecl->getIdentifier();
+  if (!funI)
+    return;
+  StringRef funName = funI->getName();
+
+  // If a value has been freed, remove from the list.
+  unsigned idx = getDeallocatingFunctionParam(funName);
+  if (idx != InvalidParamVal) {
+    SymbolRef Param = State->getSVal(CE->getArg(idx)).getAsSymbol();
+    if (!Param)
+      return;
+    if (!State->contains<AllocatedData>(Param)) {
+      // TODO: do we care about this?
+      assert(0 && "Trying to free data which has not been allocated yet.");
+    }
+    State = State->remove<AllocatedData>(Param);
+    C.addTransition(State);
+  }
+}
+
+void MacOSKeychainAPIChecker::checkPostStmt(const CallExpr *CE,
+                                            CheckerContext &C) const {
+  const GRState *State = C.getState();
+  const Expr *Callee = CE->getCallee();
+  SVal L = State->getSVal(Callee);
+  StoreManager& SM = C.getStoreManager();
+
+  const FunctionDecl *funDecl = L.getAsFunctionDecl();
+  if (!funDecl)
+    return;
+  IdentifierInfo *funI = funDecl->getIdentifier();
+  if (!funI)
+    return;
+  StringRef funName = funI->getName();
+
+  // If a value has been allocated, add it to the set for tracking.
+  unsigned idx = getAllocatingFunctionParam(funName);
+  if (idx != InvalidParamVal) {
+    SVal Param = State->getSVal(CE->getArg(idx));
+    if (const loc::MemRegionVal *X = dyn_cast<loc::MemRegionVal>(&Param)) {
+      SymbolRef V = SM.Retrieve (State->getStore(), *X).getAsSymbol();
+      if (!V)
+        return;
+      State = State->add<AllocatedData>(V);
+      C.addTransition(State);
+    }
+  }
+}
+
+void MacOSKeychainAPIChecker::checkPreStmt(const ReturnStmt *S,
+                                           CheckerContext &C) const {
+  const Expr *retExpr = S->getRetValue();
+  if (!retExpr)
+    return;
+
+  // Check  if the value is escaping through the return.
+  const GRState *state = C.getState();
+  SymbolRef V = state->getSVal(retExpr).getAsSymbol();
+  if (!V)
+    return;
+  state->remove<AllocatedData>(V);
+
+}
+
+void MacOSKeychainAPIChecker::checkEndPath(EndOfFunctionNodeBuilder &B,
+                                 ExprEngine &Eng) const {
+  const GRState *state = B.getState();
+  AllocatedSetTy AS = state->get<AllocatedData>();
+
+  // Anything which has been allocated but not freed (nor escaped) will be
+  // found here, so report it.
+  if (!AS.isEmpty()) {
+    assert(0 && "TODO: Report the bug here.");
+  }
+}
+
+void ento::registerMacOSKeychainAPIChecker(CheckerManager &mgr) {
+  mgr.registerChecker<MacOSKeychainAPIChecker>();
+}

Added: cfe/trunk/test/Analysis/keychainAPI.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/keychainAPI.m?rev=136659&view=auto
==============================================================================
--- cfe/trunk/test/Analysis/keychainAPI.m (added)
+++ cfe/trunk/test/Analysis/keychainAPI.m Mon Aug  1 17:40:01 2011
@@ -0,0 +1,71 @@
+// RUN: %clang_cc1 -analyze -analyzer-checker=osx.experimental.KeychainAPI %s -verify
+
+// Fake typedefs.
+typedef unsigned int OSStatus;
+typedef unsigned int SecKeychainAttributeList;
+typedef unsigned int SecKeychainItemRef;
+typedef unsigned int SecItemClass;
+typedef unsigned int UInt32;
+typedef unsigned int CFTypeRef;
+typedef unsigned int UInt16;
+typedef unsigned int SecProtocolType;
+typedef unsigned int SecAuthenticationType;
+enum {
+  noErr                      = 0,
+  GenericError               = 1
+};
+
+// Functions that allocate data.
+OSStatus SecKeychainItemCopyContent (
+    SecKeychainItemRef itemRef,
+    SecItemClass *itemClass,
+    SecKeychainAttributeList *attrList,
+    UInt32 *length,
+    void **outData
+);
+OSStatus SecKeychainFindGenericPassword (
+    CFTypeRef keychainOrArray,
+    UInt32 serviceNameLength,
+    const char *serviceName,
+    UInt32 accountNameLength,
+    const char *accountName,
+    UInt32 *passwordLength,
+    void **passwordData,
+    SecKeychainItemRef *itemRef
+);
+OSStatus SecKeychainFindInternetPassword (
+    CFTypeRef keychainOrArray,
+    UInt32 serverNameLength,
+    const char *serverName,
+    UInt32 securityDomainLength,
+    const char *securityDomain,
+    UInt32 accountNameLength,
+    const char *accountName,
+    UInt32 pathLength,
+    const char *path,
+    UInt16 port,
+    SecProtocolType protocol,
+    SecAuthenticationType authenticationType,
+    UInt32 *passwordLength,
+    void **passwordData,
+    SecKeychainItemRef *itemRef
+);
+
+// Function which frees data.
+OSStatus SecKeychainItemFreeContent (
+    SecKeychainAttributeList *attrList,
+    void *data
+);
+
+int foo () {
+  unsigned int *ptr = 0;
+  OSStatus st = 0;
+
+  UInt32 length;
+  void *outData;
+
+  st = SecKeychainItemCopyContent(2, ptr, ptr, &length, &outData);
+  SecKeychainItemFreeContent(ptr, outData);
+
+  return 0;
+}





More information about the cfe-commits mailing list