void iOSAppSecLeakingWebCachesChecker::checkASTDecl(const ObjCMethodDecl *pMD, AnalysisManager &rMgr, BugReporter &rBR) const
{
  MSEC_DEBUG_FUNC( "redwud: ", "ENTER (Method)" ) ;

  do
  {
    if ( !pMD )
    {
      break ;
    }
    
    Selector S = pMD ->getSelector() ;

    //There is no point of checking if you can't report it   
    if ( !m_pInsecureInstBugType )
    {
      MSEC_DEBUG("redwud: ","Reporting will fail!" ) ;
      break ;
    }

    // connection:
    if ( S.getIdentifierInfoForSlot( 0 ) != m_piiConnection)
    {
      //MSEC_DEBUG("redwud: ","!connection: " << S.getAsString() ) ;
      break ;
    }

    ASTContext &Ctx = rBR.getContext() ; 

    // Two arguments
    if ( S.getNumArgs() != 2 )
    {
      break ;
    }
    
    // willCacheResponse:
    if ( S.getIdentifierInfoForSlot(1) != m_piiWillCacheResponse )
    {
      break ;
    }

    //Note: Intentionally made it common for both
    if ( !checkWillCacheResponse( pMD, Ctx ) )
    {
      break ;
    } 
    
    CMSecCommon::reportInsecureInstance( *m_pInsecureInstBugType
      , m_szReportDesc, rBR, pMD ) ; 
      
  } while(_PASSING_) ;

  MSEC_DEBUG_FUNC( "redwud: ", "EXIT (Method)" ) ;
}
Beispiel #2
0
ObjCInstanceTypeFamily Selector::getInstTypeMethodFamily(Selector sel) {
  IdentifierInfo *first = sel.getIdentifierInfoForSlot(0);
  if (!first) return OIT_None;
  
  StringRef name = first->getName();
  
  if (name.empty()) return OIT_None;
  switch (name.front()) {
    case 'a':
      if (startsWithWord(name, "array")) return OIT_Array;
      break;
    case 'd':
      if (startsWithWord(name, "default")) return OIT_ReturnsSelf;
      if (startsWithWord(name, "dictionary")) return OIT_Dictionary;
      break;
    case 's':
      if (startsWithWord(name, "shared")) return OIT_ReturnsSelf;
      if (startsWithWord(name, "standard")) return OIT_Singleton;
    case 'i':
      if (startsWithWord(name, "init")) return OIT_Init;
    default:
      break;
  }
  return OIT_None;
}
Beispiel #3
0
void ObjCMigrateASTConsumer::migrateObjCInterfaceDecl(ASTContext &Ctx,
                                                      ObjCInterfaceDecl *D) {
  for (ObjCContainerDecl::method_iterator M = D->meth_begin(), MEnd = D->meth_end();
       M != MEnd; ++M) {
    ObjCMethodDecl *Method = (*M);
    if (Method->isPropertyAccessor() ||  Method->param_size() != 0)
      continue;
    // Is this method candidate to be a getter?
    QualType GRT = Method->getResultType();
    if (GRT->isVoidType())
      continue;
    Selector GetterSelector = Method->getSelector();
    IdentifierInfo *getterName = GetterSelector.getIdentifierInfoForSlot(0);
    Selector SetterSelector =
      SelectorTable::constructSetterSelector(PP.getIdentifierTable(),
                                             PP.getSelectorTable(),
                                             getterName);
    if (ObjCMethodDecl *SetterMethod = D->lookupMethod(SetterSelector, true)) {
      // Is this a valid setter, matching the target getter?
      QualType SRT = SetterMethod->getResultType();
      if (!SRT->isVoidType())
        continue;
      const ParmVarDecl *argDecl = *SetterMethod->param_begin();
      QualType ArgType = argDecl->getType();
      if (!Ctx.hasSameType(ArgType, GRT))
          continue;
        edit::Commit commit(*Editor);
        edit::rewriteToObjCProperty(Method, SetterMethod, *NSAPIObj, commit);
        Editor->commit(commit);
      }
  }
}
Beispiel #4
0
ObjCStringFormatFamily Selector::getStringFormatFamilyImpl(Selector sel) {
  IdentifierInfo *first = sel.getIdentifierInfoForSlot(0);
  if (!first) return SFF_None;
  
  StringRef name = first->getName();
  
  switch (name.front()) {
    case 'a':
      if (name == "appendFormat") return SFF_NSString;
      break;
      
    case 'i':
      if (name == "initWithFormat") return SFF_NSString;
      break;
      
    case 'l':
      if (name == "localizedStringWithFormat") return SFF_NSString;
      break;
      
    case 's':
      if (name == "stringByAppendingFormat" ||
          name == "stringWithFormat") return SFF_NSString;
      break;
  }
  return SFF_None;
}
Beispiel #5
0
ObjCInstanceTypeFamily Selector::getInstTypeMethodFamily(Selector sel) {
  IdentifierInfo *first = sel.getIdentifierInfoForSlot(0);
  if (!first) return OIT_None;
  
  StringRef name = first->getName();
  
  if (name.empty()) return OIT_None;
  switch (name.front()) {
    case 'a':
      if (startsWithWord(name, "alloc")) return OIT_MemManage;
      else
        if (startsWithWord(name, "array")) return OIT_Array;
      break;
    case 'd':
      if (startsWithWord(name, "dictionary")) return OIT_Dictionary;
      break;
    case 'i':
      if (startsWithWord(name, "init")) return OIT_MemManage;
      break;
    case 's':
      if (startsWithWord(name, "string")) return OIT_NSString;
      else
        if (startsWithWord(name, "set")) return OIT_NSSet;
      break;
    case 'U':
      if (startsWithWord(name, "URL")) return OIT_NSURL;
      break;
    default:
      break;
  }
  return OIT_None;
}
Beispiel #6
0
bool operator<(DeclarationName LHS, DeclarationName RHS) {
  if (LHS.getNameKind() != RHS.getNameKind())
    return LHS.getNameKind() < RHS.getNameKind();
  
  switch (LHS.getNameKind()) {
  case DeclarationName::Identifier:
    return LHS.getAsIdentifierInfo()->getName() < 
                                         RHS.getAsIdentifierInfo()->getName();

  case DeclarationName::ObjCZeroArgSelector:
  case DeclarationName::ObjCOneArgSelector:
  case DeclarationName::ObjCMultiArgSelector: {
    Selector LHSSelector = LHS.getObjCSelector();
    Selector RHSSelector = RHS.getObjCSelector();
    for (unsigned I = 0, 
               N = std::min(LHSSelector.getNumArgs(), RHSSelector.getNumArgs());
         I != N; ++I) {
      IdentifierInfo *LHSId = LHSSelector.getIdentifierInfoForSlot(I);
      IdentifierInfo *RHSId = RHSSelector.getIdentifierInfoForSlot(I);
      if (!LHSId || !RHSId)
        return LHSId && !RHSId;
        
      switch (LHSId->getName().compare(RHSId->getName())) {
      case -1: return true;
      case 1: return false;
      default: break;
      }
    }
    
    return LHSSelector.getNumArgs() < RHSSelector.getNumArgs();
  }
  
  case DeclarationName::CXXConstructorName:
  case DeclarationName::CXXDestructorName:
  case DeclarationName::CXXConversionFunctionName:
    return QualTypeOrdering()(LHS.getCXXNameType(), RHS.getCXXNameType());
              
  case DeclarationName::CXXOperatorName:
    return LHS.getCXXOverloadedOperator() < RHS.getCXXOverloadedOperator();
              
  case DeclarationName::CXXUsingDirective:
    return false;
  }
              
  return false;
}
Beispiel #7
0
void ODRHash::AddDeclarationName(DeclarationName Name) {
  // Index all DeclarationName and use index numbers to refer to them.
  auto Result = DeclNameMap.insert(std::make_pair(Name, DeclNameMap.size()));
  ID.AddInteger(Result.first->second);
  if (!Result.second) {
    // If found in map, the the DeclarationName has previously been processed.
    return;
  }

  // First time processing each DeclarationName, also process its details.
  AddBoolean(Name.isEmpty());
  if (Name.isEmpty())
    return;

  auto Kind = Name.getNameKind();
  ID.AddInteger(Kind);
  switch (Kind) {
  case DeclarationName::Identifier:
    AddIdentifierInfo(Name.getAsIdentifierInfo());
    break;
  case DeclarationName::ObjCZeroArgSelector:
  case DeclarationName::ObjCOneArgSelector:
  case DeclarationName::ObjCMultiArgSelector: {
    Selector S = Name.getObjCSelector();
    AddBoolean(S.isNull());
    AddBoolean(S.isKeywordSelector());
    AddBoolean(S.isUnarySelector());
    unsigned NumArgs = S.getNumArgs();
    for (unsigned i = 0; i < NumArgs; ++i) {
      AddIdentifierInfo(S.getIdentifierInfoForSlot(i));
    }
    break;
  }
  case DeclarationName::CXXConstructorName:
  case DeclarationName::CXXDestructorName:
    AddQualType(Name.getCXXNameType());
    break;
  case DeclarationName::CXXOperatorName:
    ID.AddInteger(Name.getCXXOverloadedOperator());
    break;
  case DeclarationName::CXXLiteralOperatorName:
    AddIdentifierInfo(Name.getCXXLiteralIdentifier());
    break;
  case DeclarationName::CXXConversionFunctionName:
    AddQualType(Name.getCXXNameType());
    break;
  case DeclarationName::CXXUsingDirective:
    break;
  case DeclarationName::CXXDeductionGuideName: {
    auto *Template = Name.getCXXDeductionGuideTemplate();
    AddBoolean(Template);
    if (Template) {
      AddDecl(Template);
    }
  }
  }
}
unsigned serialization::ComputeHash(Selector Sel) {
  unsigned N = Sel.getNumArgs();
  if (N == 0)
    ++N;
  unsigned R = 5381;
  for (unsigned I = 0; I != N; ++I)
    if (IdentifierInfo *II = Sel.getIdentifierInfoForSlot(I))
      R = llvm::HashString(II->getName(), R);
  return R;
}
Beispiel #9
0
bool ObjCMethodCall::argumentsMayEscape() const {
  if (isInSystemHeader() && !isInstanceMessage()) {
    Selector Sel = getSelector();
    if (Sel.getNumArgs() == 1 &&
        Sel.getIdentifierInfoForSlot(0)->isStr("valueWithPointer"))
      return true;
  }

  return CallEvent::argumentsMayEscape();
}
bool ObjCLoopChecker::isCollectionCountMethod(const ObjCMethodCall &M,
                                              CheckerContext &C) const {
  Selector S = M.getSelector();
  // Initialize the identifiers on first use.
  if (!CountSelectorII)
    CountSelectorII = &C.getASTContext().Idents.get("count");

  // If the method returns collection count, record the value.
  return S.isUnarySelector() &&
         (S.getIdentifierInfoForSlot(0) == CountSelectorII);
}
Beispiel #11
0
void ODRHash::AddDeclarationName(DeclarationName Name) {
  AddBoolean(Name.isEmpty());
  if (Name.isEmpty())
    return;

  auto Kind = Name.getNameKind();
  ID.AddInteger(Kind);
  switch (Kind) {
  case DeclarationName::Identifier:
    AddIdentifierInfo(Name.getAsIdentifierInfo());
    break;
  case DeclarationName::ObjCZeroArgSelector:
  case DeclarationName::ObjCOneArgSelector:
  case DeclarationName::ObjCMultiArgSelector: {
    Selector S = Name.getObjCSelector();
    AddBoolean(S.isNull());
    AddBoolean(S.isKeywordSelector());
    AddBoolean(S.isUnarySelector());
    unsigned NumArgs = S.getNumArgs();
    for (unsigned i = 0; i < NumArgs; ++i) {
      AddIdentifierInfo(S.getIdentifierInfoForSlot(i));
    }
    break;
  }
  case DeclarationName::CXXConstructorName:
  case DeclarationName::CXXDestructorName:
    AddQualType(Name.getCXXNameType());
    break;
  case DeclarationName::CXXOperatorName:
    ID.AddInteger(Name.getCXXOverloadedOperator());
    break;
  case DeclarationName::CXXLiteralOperatorName:
    AddIdentifierInfo(Name.getCXXLiteralIdentifier());
    break;
  case DeclarationName::CXXConversionFunctionName:
    AddQualType(Name.getCXXNameType());
    break;
  case DeclarationName::CXXUsingDirective:
    break;
  case DeclarationName::CXXDeductionGuideName: {
    auto *Template = Name.getCXXDeductionGuideTemplate();
    AddBoolean(Template);
    if (Template) {
      AddDecl(Template);
    }
  }
  }
}
Beispiel #12
0
ObjCMethodFamily Selector::getMethodFamilyImpl(Selector sel) {
  IdentifierInfo *first = sel.getIdentifierInfoForSlot(0);
  if (!first) return OMF_None;

  StringRef name = first->getName();
  if (sel.isUnarySelector()) {
    if (name == "autorelease") return OMF_autorelease;
    if (name == "dealloc") return OMF_dealloc;
    if (name == "finalize") return OMF_finalize;
    if (name == "release") return OMF_release;
    if (name == "retain") return OMF_retain;
    if (name == "retainCount") return OMF_retainCount;
    if (name == "self") return OMF_self;
    if (name == "initialize") return OMF_initialize;
  }

  if (name == "performSelector" || name == "performSelectorInBackground" ||
      name == "performSelectorOnMainThread")
    return OMF_performSelector;

  // The other method families may begin with a prefix of underscores.
  while (!name.empty() && name.front() == '_')
    name = name.substr(1);

  if (name.empty()) return OMF_None;
  switch (name.front()) {
  case 'a':
    if (startsWithWord(name, "alloc")) return OMF_alloc;
    break;
  case 'c':
    if (startsWithWord(name, "copy")) return OMF_copy;
    break;
  case 'i':
    if (startsWithWord(name, "init")) return OMF_init;
    break;
  case 'm':
    if (startsWithWord(name, "mutableCopy")) return OMF_mutableCopy;
    break;
  case 'n':
    if (startsWithWord(name, "new")) return OMF_new;
    break;
  default:
    break;
  }

  return OMF_None;
}
Beispiel #13
0
/// \brief Get the ASTContext-specific selector.
Selector GlobalSelector::getSelector(ASTContext &AST) const {
  if (isInvalid())
    return Selector();

  Selector GlobSel = Selector(reinterpret_cast<uintptr_t>(Val));

  llvm::SmallVector<IdentifierInfo *, 8> Ids;
  for (unsigned i = 0, e = GlobSel.isUnarySelector() ? 1 : GlobSel.getNumArgs();
         i != e; ++i) {
    IdentifierInfo *GlobII = GlobSel.getIdentifierInfoForSlot(i);
    IdentifierInfo *II = &AST.Idents.get(GlobII->getName(),
                                       GlobII->getName() + GlobII->getLength());
    Ids.push_back(II);
  }

  return AST.Selectors.getSelector(GlobSel.getNumArgs(), Ids.data());
}
Beispiel #14
0
/// \brief Get a GlobalSelector for the ASTContext-specific selector.
GlobalSelector GlobalSelector::get(Selector Sel, Program &Prog) {
  if (Sel.isNull())
    return GlobalSelector();

  ProgramImpl &ProgImpl = *static_cast<ProgramImpl*>(Prog.Impl);

  llvm::SmallVector<IdentifierInfo *, 8> Ids;
  for (unsigned i = 0, e = Sel.isUnarySelector() ? 1 : Sel.getNumArgs();
         i != e; ++i) {
    IdentifierInfo *II = Sel.getIdentifierInfoForSlot(i);
    IdentifierInfo *GlobII = &ProgImpl.getIdents().get(II->getName(),
                                               II->getName() + II->getLength());
    Ids.push_back(GlobII);
  }

  Selector GlobSel = ProgImpl.getSelectors().getSelector(Sel.getNumArgs(),
                                                         Ids.data());
  return GlobalSelector(GlobSel.getAsOpaquePtr());
}
void iOSAppSecAbusingURLSchemesChecker::checkASTDecl(const ObjCMethodDecl *pMD, AnalysisManager &rMgr, BugReporter &rBR) const
{
  MSEC_DEBUG_FUNC( "redwud: ", "ENTER (Method)" ) ;

  do
  {
    if ( !pMD )
    {
      break ;
    }
    
    Selector S = pMD ->getSelector() ;

    //There is no point of checking if you can't report it   
    if ( !m_pInsecureInstBugType )
    {
      MSEC_DEBUG("redwud: ","Reporting will fail!" ) ;
      break ;
    }

    // application:
    if ( S.getIdentifierInfoForSlot( 0 ) != m_piiApplication )
    {
      //MSEC_DEBUG("redwud: ","!application: " << S.getAsString() ) ;
      break ;
    }

    unsigned iArgs = S.getNumArgs() ;
    ASTContext &Ctx = rBR.getContext() ; 

    //
    //openURL:
    //

    do
    {
      if ( iArgs != 4 )
      {
        break ;
      }
      
      if ( (S.getIdentifierInfoForSlot(1) != m_piiOpenURL) 
           || (S.getIdentifierInfoForSlot(2) != m_piiSourceApplication)
           || (S.getIdentifierInfoForSlot(3) != m_piiAnnotation ) )
      {
        break ;
      }
          
      if ( !checkOpenURL( pMD, Ctx ) )
      {
        break ;
      } 
      
      CMSecCommon::reportInsecureInstance( *m_pInsecureInstBugType
        , m_szReportDesc 
        , rBR, pMD ) ; 
    
    } while(_PASSING_) ;

    //
    //handleOpenURL:
    //

    do
    {
      if ( iArgs != 2 )
      {
        break ;
      }
      
      if ( S.getIdentifierInfoForSlot(1) != m_piiHandleOpenURL )
      {
        break ;
      }
      
      //Note: Intentionally made it common for both
      if ( !checkOpenURL( pMD, Ctx ) )
      {
        break ;
      } 
      
      CMSecCommon::reportInsecureInstance( *m_pInsecureInstBugType
        , m_szReportDesc, rBR, pMD ) ;
    
    } while(_PASSING_) ; //handleOpenURL:
  
  } while(_PASSING_) ;

  MSEC_DEBUG_FUNC( "redwud: ", "EXIT (Method)" ) ;
}
//FIXME: Consider other methods than setObject like dictionaryWithObjectsAndKeys
/// Process call to NSMutableArray:setObject:forKey: 
void iOSAppSecInsecureKeyChainStorageChecker::checkPreObjCMessage 
  (const ObjCMethodCall &M, CheckerContext &C) const
{
  MSEC_DEBUG_FUNC("redwud:","ENTER") ;

  do
  {
    const ObjCInterfaceDecl *pRxInterface = M.getReceiverInterface() ;
    
    if ( !pRxInterface )
    {
      break ;
    }

    ASTContext &Ctx = C.getASTContext() ;
    Selector selCurr = M.getSelector() ; 

    initIdentifierInfo( Ctx ) ;

    //TODO: Check this with property, this might not work on it    
    //NSMutableDictionary 
    if ( pRxInterface ->getIdentifier() != m_piiNSMutableDictionary )
    {
      break ;
    } 

    //setObject 
    IdentifierInfo *piiSetObject = selCurr.getIdentifierInfoForSlot(0) ;  

    if ( piiSetObject != m_piiSetObject )
    {
       break ;
    }
    
    //forKey
    IdentifierInfo *piiForKey = selCurr.getIdentifierInfoForSlot(1) ;

    if ( piiForKey != m_piiForKey )
    {
       break ;
    }
    
    // MSEC_DEBUG("redwud: ", "'" << selCurr.getAsString() << "' num args: " << selCurr.getNumArgs() ) ;
    if ( selCurr.getNumArgs() != 2 )
    {
      // Unlikely to be of concerned 
      break ;
    }

    ProgramStateRef pProgState = C.getState() ;
    const LocationContext *pLCtx = C.getLocationContext() ; 

    //Get the value for "aKey" parameter (2nd)
    // Checking this first because checking the first parameter takes a bit longer    
    const Expr *pKeyExpr = M.getArgExpr(1) ;
    SVal argValKey = pProgState ->getSVal( pKeyExpr, pLCtx ) ;

    if ( !CMSecCommon::isSValContains( argValKey, "kSecAttrAccessible" ) )
    {
      // Not of concern
      break ; 
    }

    //Get the value for "anObject" parameter (1st)
    const Expr *pObjExpr = M.getArgExpr(0) ;
    SVal argValAnObject = pProgState ->getSVal( pObjExpr, pLCtx ) ;

    //Get receiver as symbol, should be used in either condition
    SymbolRef pSymQuery = M.getReceiverSVal().getAsSymbol() ;

    if ( !pSymQuery )
    {
      // redwud: Can't save empty receiver symbol,
      // so there is no point of moving on, 
      // there must be something wrong with this
      break ;
    }

    //Idea: if [query] is currently being tracked change it to different status, e.g. secure
    //      if not tracked add new secure state

    bool bInsecureObject = isInsecureObject( argValAnObject ) ; 

    pProgState = pProgState ->set <StreamMap>( pSymQuery, bInsecureObject ? 
      KeyChainState::getNotSecure() : KeyChainState::getSecure() ) ;   

    // Add transition of state
    //redwud: it seems that the states are transitioned at some point
    C.addTransition( pProgState ) ;

    MSEC_DEBUG( "redwud: ", "Finish checking!" ) ; 
  } while (_PASSING_) ;


  MSEC_DEBUG_FUNC("redwud:","EXIT") ;
}