void ReturnPointerRangeChecker::PreVisitReturnStmt(CheckerContext &C, const ReturnStmt *RS) { const GRState *state = C.getState(); const Expr *RetE = RS->getRetValue(); if (!RetE) return; SVal V = state->getSVal(RetE); const MemRegion *R = V.getAsRegion(); if (!R) return; R = R->StripCasts(); if (!R) return; const ElementRegion *ER = dyn_cast_or_null<ElementRegion>(R); if (!ER) return; DefinedOrUnknownSVal &Idx = cast<DefinedOrUnknownSVal>(ER->getIndex()); // FIXME: All of this out-of-bounds checking should eventually be refactored // into a common place. DefinedOrUnknownSVal NumElements = C.getStoreManager().getSizeInElements(state, ER->getSuperRegion(), ER->getValueType()); const GRState *StInBound = state->AssumeInBound(Idx, NumElements, true); const GRState *StOutBound = state->AssumeInBound(Idx, NumElements, false); if (StOutBound && !StInBound) { ExplodedNode *N = C.GenerateSink(StOutBound); if (!N) return; // FIXME: This bug correspond to CWE-466. Eventually we should have bug // types explicitly reference such exploit categories (when applicable). if (!BT) BT = new BuiltinBug("Return of pointer value outside of expected range", "Returned pointer value points outside the original object " "(potential buffer overflow)"); // FIXME: It would be nice to eventually make this diagnostic more clear, // e.g., by referencing the original declaration or by saying *why* this // reference is outside the range. // Generate a report for this bug. RangedBugReport *report = new RangedBugReport(*BT, BT->getDescription(), N); report->addRange(RetE->getSourceRange()); C.EmitReport(report); } }
void ArrayBoundChecker::checkLocation(SVal l, bool isLoad, CheckerContext &C) const { // Check for out of bound array element access. const MemRegion *R = l.getAsRegion(); if (!R) return; const ElementRegion *ER = dyn_cast<ElementRegion>(R); if (!ER) return; // Get the index of the accessed element. DefinedOrUnknownSVal Idx = cast<DefinedOrUnknownSVal>(ER->getIndex()); // Zero index is always in bound, this also passes ElementRegions created for // pointer casts. if (Idx.isZeroConstant()) return; const GRState *state = C.getState(); // Get the size of the array. DefinedOrUnknownSVal NumElements = C.getStoreManager().getSizeInElements(state, ER->getSuperRegion(), ER->getValueType()); const GRState *StInBound = state->assumeInBound(Idx, NumElements, true); const GRState *StOutBound = state->assumeInBound(Idx, NumElements, false); if (StOutBound && !StInBound) { ExplodedNode *N = C.generateSink(StOutBound); if (!N) return; if (!BT) BT.reset(new BuiltinBug("Out-of-bound array access", "Access out-of-bound array element (buffer overflow)")); // FIXME: It would be nice to eventually make this diagnostic more clear, // e.g., by referencing the original declaration or by saying *why* this // reference is outside the range. // Generate a report for this bug. RangedBugReport *report = new RangedBugReport(*BT, BT->getDescription(), N); report->addRange(C.getStmt()->getSourceRange()); C.EmitReport(report); return; } // Array bound check succeeded. From this point forward the array bound // should always succeed. assert(StInBound); C.addTransition(StInBound); }
void ReturnPointerRangeChecker::checkPreStmt(const ReturnStmt *RS, CheckerContext &C) const { ProgramStateRef state = C.getState(); const Expr *RetE = RS->getRetValue(); if (!RetE) return; SVal V = state->getSVal(RetE, C.getLocationContext()); const MemRegion *R = V.getAsRegion(); const ElementRegion *ER = dyn_cast_or_null<ElementRegion>(R); if (!ER) return; DefinedOrUnknownSVal Idx = ER->getIndex().castAs<DefinedOrUnknownSVal>(); // Zero index is always in bound, this also passes ElementRegions created for // pointer casts. if (Idx.isZeroConstant()) return; // FIXME: All of this out-of-bounds checking should eventually be refactored // into a common place. DefinedOrUnknownSVal NumElements = C.getStoreManager().getSizeInElements(state, ER->getSuperRegion(), ER->getValueType()); ProgramStateRef StInBound = state->assumeInBound(Idx, NumElements, true); ProgramStateRef StOutBound = state->assumeInBound(Idx, NumElements, false); if (StOutBound && !StInBound) { ExplodedNode *N = C.generateSink(StOutBound); if (!N) return; // FIXME: This bug correspond to CWE-466. Eventually we should have bug // types explicitly reference such exploit categories (when applicable). if (!BT) BT.reset(new BuiltinBug( this, "Return of pointer value outside of expected range", "Returned pointer value points outside the original object " "(potential buffer overflow)")); // FIXME: It would be nice to eventually make this diagnostic more clear, // e.g., by referencing the original declaration or by saying *why* this // reference is outside the range. // Generate a report for this bug. auto report = llvm::make_unique<BugReport>(*BT, BT->getDescription(), N); report->addRange(RetE->getSourceRange()); C.emitReport(std::move(report)); } }
bool IntegerOverflowChecker::hasGlobalVariablesOrMembers(const Stmt *S, CheckerContext &C) const { if (S == NULL || S->getStmtClass() == Stmt::IntegerLiteralClass) return false; ProgramStateRef State = C.getState(); const LocationContext *LCtx = C.getLocationContext(); if ((S->getStmtClass() != Stmt::ImplicitCastExprClass) && isInWhiteList(S, State, LCtx)) return true; if (const MemberExpr *MExpr = dyn_cast<MemberExpr>(S)) { if (MExpr->getMemberDecl()->isFunctionOrFunctionTemplate()) return hasGlobalVariablesOrMembers(MExpr->getMemberDecl()->getBody(), C); // We found member usage! return true; } if (const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(S)) if (isa<DeclRefExpr>(ICE->getSubExpr()) && isInWhiteList(C.getSVal(ICE), State)) return true; if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(S)) if (const VarDecl *VarD = dyn_cast<VarDecl>(DRE->getDecl())) { Loc VLoc = C.getStoreManager().getLValueVar(VarD, LCtx); SVal VVal = C.getStoreManager().getBinding(State->getStore(), VLoc); if (isInWhiteList(VVal, State)) return true; } // We will not surrender! for (auto I = S->child_begin(); I != S->child_end(); I++) if (hasGlobalVariablesOrMembers(*I, C)) return true; return false; }
/// Given the address expression, retrieve the value it's pointing to. Assume /// that value is itself an address, and return the corresponding symbol. static SymbolRef getAsPointeeSymbol(const Expr *Expr, CheckerContext &C) { ProgramStateRef State = C.getState(); SVal ArgV = State->getSVal(Expr, C.getLocationContext()); if (Optional<loc::MemRegionVal> X = ArgV.getAs<loc::MemRegionVal>()) { StoreManager& SM = C.getStoreManager(); SymbolRef sym = SM.getBinding(State->getStore(), *X).getAsLocSymbol(); if (sym) return sym; } return 0; }
/// Given the address expression, retrieve the value it's pointing to. Assume /// that value is itself an address, and return the corresponding symbol. static SymbolRef getAsPointeeSymbol(const Expr *Expr, CheckerContext &C) { const ProgramState *State = C.getState(); SVal ArgV = State->getSVal(Expr); if (const loc::MemRegionVal *X = dyn_cast<loc::MemRegionVal>(&ArgV)) { StoreManager& SM = C.getStoreManager(); const MemRegion *V = SM.Retrieve(State->getStore(), *X).getAsRegion(); if (V) return getSymbolForRegion(C, V); } return 0; }
bool BuiltinFunctionChecker::evalCall(const CallExpr *CE, CheckerContext &C) const { ProgramStateRef state = C.getState(); const FunctionDecl *FD = C.getCalleeDecl(CE); const LocationContext *LCtx = C.getLocationContext(); if (!FD) return false; unsigned id = FD->getBuiltinID(); if (!id) return false; switch (id) { case Builtin::BI__builtin_expect: { // For __builtin_expect, just return the value of the subexpression. assert (CE->arg_begin() != CE->arg_end()); SVal X = state->getSVal(*(CE->arg_begin()), LCtx); C.addTransition(state->BindExpr(CE, LCtx, X)); return true; } case Builtin::BI__builtin_alloca: { // FIXME: Refactor into StoreManager itself? MemRegionManager& RM = C.getStoreManager().getRegionManager(); const AllocaRegion* R = RM.getAllocaRegion(CE, C.blockCount(), C.getLocationContext()); // Set the extent of the region in bytes. This enables us to use the // SVal of the argument directly. If we save the extent in bits, we // cannot represent values like symbol*8. DefinedOrUnknownSVal Size = state->getSVal(*(CE->arg_begin()), LCtx).castAs<DefinedOrUnknownSVal>(); SValBuilder& svalBuilder = C.getSValBuilder(); DefinedOrUnknownSVal Extent = R->getExtent(svalBuilder); DefinedOrUnknownSVal extentMatchesSizeArg = svalBuilder.evalEQ(state, Extent, Size); state = state->assume(extentMatchesSizeArg, true); assert(state && "The region should not have any previous constraints"); C.addTransition(state->BindExpr(CE, LCtx, loc::MemRegionVal(R))); return true; } } return false; }
void MPIChecker::allRegionsUsedByWait( llvm::SmallVector<const MemRegion *, 2> &ReqRegions, const MemRegion *const MR, const CallEvent &CE, CheckerContext &Ctx) const { MemRegionManager *const RegionManager = MR->getMemRegionManager(); if (FuncClassifier->isMPI_Waitall(CE.getCalleeIdentifier())) { const MemRegion *SuperRegion{nullptr}; if (const ElementRegion *const ER = MR->getAs<ElementRegion>()) { SuperRegion = ER->getSuperRegion(); } // A single request is passed to MPI_Waitall. if (!SuperRegion) { ReqRegions.push_back(MR); return; } const auto &Size = Ctx.getStoreManager().getSizeInElements( Ctx.getState(), SuperRegion, CE.getArgExpr(1)->getType()->getPointeeType()); const llvm::APSInt &ArrSize = Size.getAs<nonloc::ConcreteInt>()->getValue(); for (size_t i = 0; i < ArrSize; ++i) { const NonLoc Idx = Ctx.getSValBuilder().makeArrayIndex(i); const ElementRegion *const ER = RegionManager->getElementRegion( CE.getArgExpr(1)->getType()->getPointeeType(), Idx, SuperRegion, Ctx.getASTContext()); ReqRegions.push_back(ER->getAs<MemRegion>()); } } else if (FuncClassifier->isMPI_Wait(CE.getCalleeIdentifier())) { ReqRegions.push_back(MR); } }
bool BuiltinFunctionChecker::evalCall(const CallExpr *CE, CheckerContext &C) const { ProgramStateRef state = C.getState(); const FunctionDecl *FD = C.getCalleeDecl(CE); const LocationContext *LCtx = C.getLocationContext(); if (!FD) return false; switch (FD->getBuiltinID()) { default: return false; case Builtin::BI__builtin_unpredictable: case Builtin::BI__builtin_expect: case Builtin::BI__builtin_assume_aligned: case Builtin::BI__builtin_addressof: { // For __builtin_unpredictable, __builtin_expect, and // __builtin_assume_aligned, just return the value of the subexpression. // __builtin_addressof is going from a reference to a pointer, but those // are represented the same way in the analyzer. assert (CE->arg_begin() != CE->arg_end()); SVal X = state->getSVal(*(CE->arg_begin()), LCtx); C.addTransition(state->BindExpr(CE, LCtx, X)); return true; } case Builtin::BI__builtin_alloca_with_align: case Builtin::BI__builtin_alloca: { // FIXME: Refactor into StoreManager itself? MemRegionManager& RM = C.getStoreManager().getRegionManager(); const AllocaRegion* R = RM.getAllocaRegion(CE, C.blockCount(), C.getLocationContext()); // Set the extent of the region in bytes. This enables us to use the // SVal of the argument directly. If we save the extent in bits, we // cannot represent values like symbol*8. DefinedOrUnknownSVal Size = state->getSVal(*(CE->arg_begin()), LCtx).castAs<DefinedOrUnknownSVal>(); SValBuilder& svalBuilder = C.getSValBuilder(); DefinedOrUnknownSVal Extent = R->getExtent(svalBuilder); DefinedOrUnknownSVal extentMatchesSizeArg = svalBuilder.evalEQ(state, Extent, Size); state = state->assume(extentMatchesSizeArg, true); assert(state && "The region should not have any previous constraints"); C.addTransition(state->BindExpr(CE, LCtx, loc::MemRegionVal(R))); return true; } case Builtin::BI__builtin_object_size: { // This must be resolvable at compile time, so we defer to the constant // evaluator for a value. SVal V = UnknownVal(); llvm::APSInt Result; if (CE->EvaluateAsInt(Result, C.getASTContext(), Expr::SE_NoSideEffects)) { // Make sure the result has the correct type. SValBuilder &SVB = C.getSValBuilder(); BasicValueFactory &BVF = SVB.getBasicValueFactory(); BVF.getAPSIntType(CE->getType()).apply(Result); V = SVB.makeIntVal(Result); } C.addTransition(state->BindExpr(CE, LCtx, V)); return true; } } }