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); }
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_ ) ; }