void SimpleStreamChecker::checkPreCall(const CallEvent &Call,
                                       CheckerContext &C) const {
  if (!Call.isGlobalCFunction())
    return;

  if (!Call.isCalled(CloseFn))
    return;

  // Get the symbolic value corresponding to the file handle.
  SymbolRef FileDesc = Call.getArgSVal(0).getAsSymbol();
  if (!FileDesc)
    return;

  // Check if the stream has already been closed.
  ProgramStateRef State = C.getState();
  const StreamState *SS = State->get<StreamMap>(FileDesc);
  if (SS && SS->isClosed()) {
    reportDoubleClose(FileDesc, Call, C);
    return;
  }

  // Generate the next transition, in which the stream is closed.
  State = State->set<StreamMap>(FileDesc, StreamState::getClosed());
  C.addTransition(State);
}
Example #2
0
void StackAddrEscapeChecker::checkPreCall(const CallEvent &Call,
                                          CheckerContext &C) const {
  if (!ChecksEnabled[CK_StackAddrAsyncEscapeChecker])
    return;
  if (!Call.isGlobalCFunction("dispatch_after") &&
      !Call.isGlobalCFunction("dispatch_async"))
    return;
  for (unsigned Idx = 0, NumArgs = Call.getNumArgs(); Idx < NumArgs; ++Idx) {
    if (const BlockDataRegion *B = dyn_cast_or_null<BlockDataRegion>(
            Call.getArgSVal(Idx).getAsRegion()))
      checkAsyncExecutedBlockCaptures(*B, C);
  }
}
void NoReturnFunctionChecker::checkPostCall(const CallEvent &CE,
        CheckerContext &C) const {
    ProgramStateRef state = C.getState();
    bool BuildSinks = false;

    if (const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(CE.getDecl()))
        BuildSinks = FD->getAttr<AnalyzerNoReturnAttr>() || FD->isNoReturn();

    const Expr *Callee = CE.getOriginExpr();
    if (!BuildSinks && Callee)
        BuildSinks = getFunctionExtInfo(Callee->getType()).getNoReturn();

    if (!BuildSinks && CE.isGlobalCFunction()) {
        if (const IdentifierInfo *II = CE.getCalleeIdentifier()) {
            // HACK: Some functions are not marked noreturn, and don't return.
            //  Here are a few hardwired ones.  If this takes too long, we can
            //  potentially cache these results.
            BuildSinks
                = llvm::StringSwitch<bool>(StringRef(II->getName()))
                  .Case("exit", true)
                  .Case("panic", true)
                  .Case("error", true)
                  .Case("Assert", true)
                  // FIXME: This is just a wrapper around throwing an exception.
                  //  Eventually inter-procedural analysis should handle this easily.
                  .Case("ziperr", true)
                  .Case("assfail", true)
                  .Case("db_error", true)
                  .Case("__assert", true)
                  // For the purpose of static analysis, we do not care that
                  //  this MSVC function will return if the user decides to continue.
                  .Case("_wassert", true)
                  .Case("__assert_rtn", true)
                  .Case("__assert_fail", true)
                  .Case("dtrace_assfail", true)
                  .Case("yy_fatal_error", true)
                  .Case("_XCAssertionFailureHandler", true)
                  .Case("_DTAssertionFailureHandler", true)
                  .Case("_TSAssertionFailureHandler", true)
                  .Default(false);
        }
    }

    if (BuildSinks)
        C.generateSink();
}
void SimpleStreamChecker::checkPostCall(const CallEvent &Call,
                                        CheckerContext &C) const {
  if (!Call.isGlobalCFunction())
    return;

  if (!Call.isCalled(OpenFn))
    return;

  // Get the symbolic value corresponding to the file handle.
  SymbolRef FileDesc = Call.getReturnValue().getAsSymbol();
  if (!FileDesc)
    return;

  // Generate the next transition (an edge in the exploded graph).
  ProgramStateRef State = C.getState();
  State = State->set<StreamMap>(FileDesc, StreamState::getOpened());
  C.addTransition(State);
}
void CFRetainReleaseChecker::checkPreCall(const CallEvent &Call,
                                          CheckerContext &C) const {
  // TODO: Make this check part of CallDescription.
  if (!Call.isGlobalCFunction())
    return;

  // Check if we called CFRetain/CFRelease/CFMakeCollectable/CFAutorelease.
  if (!(Call.isCalled(CFRetain) || Call.isCalled(CFRelease) ||
        Call.isCalled(CFMakeCollectable) || Call.isCalled(CFAutorelease)))
    return;

  // Get the argument's value.
  SVal ArgVal = Call.getArgSVal(0);
  Optional<DefinedSVal> DefArgVal = ArgVal.getAs<DefinedSVal>();
  if (!DefArgVal)
    return;

  // Is it null?
  ProgramStateRef state = C.getState();
  ProgramStateRef stateNonNull, stateNull;
  std::tie(stateNonNull, stateNull) = state->assume(*DefArgVal);

  if (!stateNonNull) {
    ExplodedNode *N = C.generateErrorNode(stateNull);
    if (!N)
      return;

    SmallString<64> Str;
    raw_svector_ostream OS(Str);
    OS << "Null pointer argument in call to "
       << cast<FunctionDecl>(Call.getDecl())->getName();

    auto report = llvm::make_unique<BugReport>(BT, OS.str(), N);
    report->addRange(Call.getArgSourceRange(0));
    bugreporter::trackExpressionValue(N, Call.getArgExpr(0), *report);
    C.emitReport(std::move(report));
    return;
  }

  // From here on, we know the argument is non-null.
  C.addTransition(stateNonNull);
}
void PHPZPPCheckerImpl::checkPreCall(const CallEvent &Call,
                                     CheckerContext &C) const {
  initIdentifierInfo(C.getASTContext());

  unsigned offset;

  if (!Call.isGlobalCFunction())
    return;

  if (Call.getCalleeIdentifier() == IIzpp) {
    offset = 1;
  } else if (Call.getCalleeIdentifier() == IIzpp_ex) {
    offset = 2;
  } else if (Call.getCalleeIdentifier() == IIzpmp) {
    offset = 2;
  } else if (Call.getCalleeIdentifier() == IIzpmp_ex) {
    offset = 3;
  } else {
    return;
  }

  if (TSRMBuild) {
    ++offset;
  }

  if (Call.getNumArgs() <= offset)
    // Something is really weird - this should be caught by the compiler
    return;

  const StringLiteral *format_spec_sl =
      getCStringLiteral(Call.getArgSVal(offset));
  if (!format_spec_sl) {
    // TODO need a good way to report this, even though this is no error
    std::cout << "Couldn't get format string looked at offset " << offset << std::endl;
    Call.dump();
    return;
  }
  const StringRef format_spec = format_spec_sl->getBytes();

  // Call.dump();
  for (StringRef::const_iterator modifier = format_spec.begin(),
                                 last_mod = format_spec.end();
       modifier != last_mod; ++modifier) {
//std::cout << "  I am checking for " << *modifier << std::endl;
    const PHPTypeRange range = map.equal_range(*modifier);

    if (range.first == range.second) {
      BugReport *R = new BugReport(
          *InvalidModifierBugType,
          std::string("Unknown modifier '") + *modifier + "'", C.addTransition());
      C.emitReport(R);
      return;
    }

    for (PHPTypeMap::const_iterator type = range.first; type != range.second;
         ++type) {
      if (!type->second) {
        // Current modifier doesn't need an argument, these are special things
        // like |, ! or /
        continue;
      }
      ++offset;
//std::cout << "    I need a " << *type->second << " (" << offset << ")" << std::endl;
      if (Call.getNumArgs() <= offset) {
        BugReport *R = new BugReport(*WrongArgumentNumberBugType,
                                     "Too few arguments for format specified",
                                     C.addTransition());
        C.emitReport(R);
//std::cout << "!!!!I am missing args! " << Call.getNumArgs() << "<=" << offset << std::endl;
        return;
      }

      SVal val = Call.getArgSVal(offset);
      if (!compareTypeWithSVal(val, *type->second, C)) {
        // TODO: Move error reporting here?

        // Even if there is a type mismatch we can continue, most of the time
        // this should be a simple mistake by the user, in rare cases the user
        // missed an argument and will get many subsequent errors
      }
    }
  }

  if (Call.getNumArgs() > 1 + offset) {
    BugReport *R = new BugReport(*WrongArgumentNumberBugType,
                                 "Too many arguments for format specified",
                                 C.addTransition());
    R->markInteresting(Call.getArgSVal(offset));
    C.emitReport(R);
  }
}
// Checking for SecItemAdd and SecItemUpdate, no particular reason for assigning it to PostCall
void iOSAppSecInsecureKeyChainStorageChecker::checkPostCall(const CallEvent &Call,
                                        CheckerContext &C) const 
{
  do
  {
    initIdentifierInfo( C.getASTContext() ) ;

    //redwud: Obviously it is what it is
    if ( !Call.isGlobalCFunction() )
    {
      break ;
    }

    const IdentifierInfo *pCalleeIdent = Call.getCalleeIdentifier() ; 

    // for SecITemAdd() by default
    unsigned int uiParam = 0 ; 
    
    //We do away with array because it's only two of them and it
    //will break the while..passing pattern  
    if ( pCalleeIdent != m_piiSecItemAdd )
    {  
      if ( (pCalleeIdent != m_piiSecItemUpdate) )
      {
        break ;
      }
      else
      {
        uiParam = 1 ;
      }
    }
    
    //Get the query parameter
    //Check if it was recorded as not secure
    //Then create a report
    //Else do nothing

    // Use new method to reuse for checking each parameters, 
    // 1st param for SecItemAdd(), 2nd param for SecItemUpdate() 

    // Get the symbolic value corresponding to the "attributes" parameter.
    SymbolRef pSymToCheck = Call.getArgSVal( uiParam ).getAsSymbol() ;

    //rewud: Not sure how to interpret this, it seems there are no
    //       no symbol for the first parameter 
    if ( !pSymToCheck )
    {
      break ;
    }

    ProgramStateRef pProgState = C.getState() ; 
    
    if ( !isInsecureSymbol( pSymToCheck, pProgState ) ) 
    {
      break ;
    }

    if ( !m_pInsecureInstBugType )
    {
      MSEC_DEBUG( "redwud: ", "!m_pInsecureInstBugType" ) ;
      break ;
    }
 
    //Report this instance
    CMSecCommon::reportInsecureInstance( pSymToCheck, C, C.addTransition( pProgState )
      , *m_pInsecureInstBugType, m_szReportDesc ) ;
  
  } while ( _PASSING_ ) ;

}
// Checking for SecItemAdd and SecItemUpdate, no particular reason for assigning it to PostCall
void iOSAppSecLeakingLogsChecker::checkPostCall(const CallEvent &Call,
                                        CheckerContext &C) const 
{
  do
  {
    if ( !m_pInsecureInstBugType )
    {
      MSEC_DEBUG( "redwud: ", "!m_pInsecureInstBugType" ) ;
      break ;
    }

    initIdentifierInfo( C.getASTContext() ) ;

    //redwud: Obviously it is what it is
    if ( !Call.isGlobalCFunction() )
    {
      MSEC_DEBUG( "redwud: ", "!Call.isGlobalCFunction" ) ;
      break ;
    }

    const IdentifierInfo *pCalleeIdent = Call.getCalleeIdentifier() ; 

    unsigned iNumArgs = Call.getNumArgs() ; 

    //We do away with array because it's only two of them and it
    //will break the while..passing pattern  
    if ( pCalleeIdent != m_piiNSLog )
    {  
      if ( (pCalleeIdent != m_piiNSLogv) )
      {
        break ;
      }
      //FIXME: Workaround to evade 2nd and onward parameters of NSLogv
      //  Idea: Use identifier for slot from s
      iNumArgs = 1 ;
    }

    CSensitiveInfo &rSenInfo = CSensitiveInfo::create() ;
    SymbolRef pSymToCheck = NULL ; 
   
    // Go through each parameter unless find some sensitive info in one of them
    for ( unsigned iCtr = 0; (iCtr < iNumArgs) && (!pSymToCheck); iCtr++ )
    {
      const Expr *pExpr = Call.getArgExpr( iCtr ) ;
      StringRef szString ;
      StringRef szVarName ;

      CMSecCommon::getStrFromExpr( szString, pExpr, &szVarName ) ; 

      if ( szString.empty() ) // Nil is supported here, so no need to check
      {
//        MSEC_DEBUG( "redwud: ", "Empty string" ) ;
        continue ;
      }

      if ( !rSenInfo.isSensitive( szString.str() ) && !rSenInfo.isSensitive( szVarName.str() ) )
      {
//        MSEC_DEBUG( "redwud: ", "!Sensitive :" << szString << "Var name: " << szVarName ) ;
        continue ; 
      }

      // Get the symbolic value corresponding to the target parameter.
      pSymToCheck = Call.getArgSVal( iCtr ).getAsSymbol() ;
     
      //Force the issue
      if ( !pSymToCheck )
      {
        pSymToCheck = CMSecCommon::conjureSymbolRef() ;
      }
    }

    if ( !pSymToCheck )
    {
      break ;
    }

    ProgramStateRef pProgState = C.getState() ; 

    //Report this instance
    CMSecCommon::reportInsecureInstance( pSymToCheck, C, C.addTransition( pProgState )
      , *m_pInsecureInstBugType, m_szReportDesc ) ;
  
  } while ( _PASSING_ ) ;

}