1 //== ReturnPointerRangeChecker.cpp ------------------------------*- C++ -*--==// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 // 10 // This file defines ReturnPointerRangeChecker, which is a path-sensitive check 11 // which looks for an out-of-bound pointer being returned to callers. 12 // 13 //===----------------------------------------------------------------------===// 14 15 #include "ClangSACheckers.h" 16 #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" 17 #include "clang/StaticAnalyzer/Core/Checker.h" 18 #include "clang/StaticAnalyzer/Core/CheckerManager.h" 19 #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" 20 #include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h" 21 22 using namespace clang; 23 using namespace ento; 24 25 namespace { 26 class ReturnPointerRangeChecker : 27 public Checker< check::PreStmt<ReturnStmt> > { 28 mutable OwningPtr<BuiltinBug> BT; 29 public: 30 void checkPreStmt(const ReturnStmt *RS, CheckerContext &C) const; 31 }; 32 } 33 34 void ReturnPointerRangeChecker::checkPreStmt(const ReturnStmt *RS, 35 CheckerContext &C) const { 36 ProgramStateRef state = C.getState(); 37 38 const Expr *RetE = RS->getRetValue(); 39 if (!RetE) 40 return; 41 42 SVal V = state->getSVal(RetE, C.getLocationContext()); 43 const MemRegion *R = V.getAsRegion(); 44 45 const ElementRegion *ER = dyn_cast_or_null<ElementRegion>(R); 46 if (!ER) 47 return; 48 49 DefinedOrUnknownSVal Idx = ER->getIndex().castAs<DefinedOrUnknownSVal>(); 50 // Zero index is always in bound, this also passes ElementRegions created for 51 // pointer casts. 52 if (Idx.isZeroConstant()) 53 return; 54 // FIXME: All of this out-of-bounds checking should eventually be refactored 55 // into a common place. 56 57 DefinedOrUnknownSVal NumElements 58 = C.getStoreManager().getSizeInElements(state, ER->getSuperRegion(), 59 ER->getValueType()); 60 61 ProgramStateRef StInBound = state->assumeInBound(Idx, NumElements, true); 62 ProgramStateRef StOutBound = state->assumeInBound(Idx, NumElements, false); 63 if (StOutBound && !StInBound) { 64 ExplodedNode *N = C.generateSink(StOutBound); 65 66 if (!N) 67 return; 68 69 // FIXME: This bug correspond to CWE-466. Eventually we should have bug 70 // types explicitly reference such exploit categories (when applicable). 71 if (!BT) 72 BT.reset(new BuiltinBug("Return of pointer value outside of expected range", 73 "Returned pointer value points outside the original object " 74 "(potential buffer overflow)")); 75 76 // FIXME: It would be nice to eventually make this diagnostic more clear, 77 // e.g., by referencing the original declaration or by saying *why* this 78 // reference is outside the range. 79 80 // Generate a report for this bug. 81 BugReport *report = 82 new BugReport(*BT, BT->getDescription(), N); 83 84 report->addRange(RetE->getSourceRange()); 85 C.emitReport(report); 86 } 87 } 88 89 void ento::registerReturnPointerRangeChecker(CheckerManager &mgr) { 90 mgr.registerChecker<ReturnPointerRangeChecker>(); 91 } 92