1ceeb02db9ad4232ea248a44192180d5bc7fe2653Zhongxing Xu//== ReturnPointerRangeChecker.cpp ------------------------------*- C++ -*--==// 2ceeb02db9ad4232ea248a44192180d5bc7fe2653Zhongxing Xu// 3ceeb02db9ad4232ea248a44192180d5bc7fe2653Zhongxing Xu// The LLVM Compiler Infrastructure 4ceeb02db9ad4232ea248a44192180d5bc7fe2653Zhongxing Xu// 5ceeb02db9ad4232ea248a44192180d5bc7fe2653Zhongxing Xu// This file is distributed under the University of Illinois Open Source 6ceeb02db9ad4232ea248a44192180d5bc7fe2653Zhongxing Xu// License. See LICENSE.TXT for details. 7ceeb02db9ad4232ea248a44192180d5bc7fe2653Zhongxing Xu// 8ceeb02db9ad4232ea248a44192180d5bc7fe2653Zhongxing Xu//===----------------------------------------------------------------------===// 9ceeb02db9ad4232ea248a44192180d5bc7fe2653Zhongxing Xu// 10ceeb02db9ad4232ea248a44192180d5bc7fe2653Zhongxing Xu// This file defines ReturnPointerRangeChecker, which is a path-sensitive check 11ceeb02db9ad4232ea248a44192180d5bc7fe2653Zhongxing Xu// which looks for an out-of-bound pointer being returned to callers. 12ceeb02db9ad4232ea248a44192180d5bc7fe2653Zhongxing Xu// 13ceeb02db9ad4232ea248a44192180d5bc7fe2653Zhongxing Xu//===----------------------------------------------------------------------===// 14ceeb02db9ad4232ea248a44192180d5bc7fe2653Zhongxing Xu 1569355798abdbe5e78d1185af7d4600b9355b5814Argyrios Kyrtzidis#include "ClangSACheckers.h" 1655fc873017f10f6f566b182b70f6fc22aefa3464Chandler Carruth#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" 17ec8605f1d7ec846dbf51047bfd5c56d32d1ff91cArgyrios Kyrtzidis#include "clang/StaticAnalyzer/Core/Checker.h" 1869355798abdbe5e78d1185af7d4600b9355b5814Argyrios Kyrtzidis#include "clang/StaticAnalyzer/Core/CheckerManager.h" 1969355798abdbe5e78d1185af7d4600b9355b5814Argyrios Kyrtzidis#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" 209b663716449b618ba0390b1dbebc54fa8e971124Ted Kremenek#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h" 21ceeb02db9ad4232ea248a44192180d5bc7fe2653Zhongxing Xu 22ceeb02db9ad4232ea248a44192180d5bc7fe2653Zhongxing Xuusing namespace clang; 239ef6537a894c33003359b1f9b9676e9178e028b7Ted Kremenekusing namespace ento; 24ceeb02db9ad4232ea248a44192180d5bc7fe2653Zhongxing Xu 25ceeb02db9ad4232ea248a44192180d5bc7fe2653Zhongxing Xunamespace { 26ba5fb5a955c896815c439289fc51c03cf0635129Kovarththanan Rajaratnamclass ReturnPointerRangeChecker : 27ec8605f1d7ec846dbf51047bfd5c56d32d1ff91cArgyrios Kyrtzidis public Checker< check::PreStmt<ReturnStmt> > { 28651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines mutable std::unique_ptr<BuiltinBug> BT; 29651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines 30ceeb02db9ad4232ea248a44192180d5bc7fe2653Zhongxing Xupublic: 3169355798abdbe5e78d1185af7d4600b9355b5814Argyrios Kyrtzidis void checkPreStmt(const ReturnStmt *RS, CheckerContext &C) const; 32ceeb02db9ad4232ea248a44192180d5bc7fe2653Zhongxing Xu}; 33ceeb02db9ad4232ea248a44192180d5bc7fe2653Zhongxing Xu} 34ceeb02db9ad4232ea248a44192180d5bc7fe2653Zhongxing Xu 3569355798abdbe5e78d1185af7d4600b9355b5814Argyrios Kyrtzidisvoid ReturnPointerRangeChecker::checkPreStmt(const ReturnStmt *RS, 3669355798abdbe5e78d1185af7d4600b9355b5814Argyrios Kyrtzidis CheckerContext &C) const { 378bef8238181a30e52dea380789a7e2d760eac532Ted Kremenek ProgramStateRef state = C.getState(); 38ceeb02db9ad4232ea248a44192180d5bc7fe2653Zhongxing Xu 39ceeb02db9ad4232ea248a44192180d5bc7fe2653Zhongxing Xu const Expr *RetE = RS->getRetValue(); 40ceeb02db9ad4232ea248a44192180d5bc7fe2653Zhongxing Xu if (!RetE) 41ceeb02db9ad4232ea248a44192180d5bc7fe2653Zhongxing Xu return; 42ceeb02db9ad4232ea248a44192180d5bc7fe2653Zhongxing Xu 435eca482fe895ea57bc82410222e6426c09e63284Ted Kremenek SVal V = state->getSVal(RetE, C.getLocationContext()); 44ceeb02db9ad4232ea248a44192180d5bc7fe2653Zhongxing Xu const MemRegion *R = V.getAsRegion(); 45ceeb02db9ad4232ea248a44192180d5bc7fe2653Zhongxing Xu 46ceeb02db9ad4232ea248a44192180d5bc7fe2653Zhongxing Xu const ElementRegion *ER = dyn_cast_or_null<ElementRegion>(R); 47ceeb02db9ad4232ea248a44192180d5bc7fe2653Zhongxing Xu if (!ER) 486f516f50e53b621613d281ef186c76c5160d9d35Ted Kremenek return; 49ceeb02db9ad4232ea248a44192180d5bc7fe2653Zhongxing Xu 507a95de68c093991047ed8d339479ccad51b88663David Blaikie DefinedOrUnknownSVal Idx = ER->getIndex().castAs<DefinedOrUnknownSVal>(); 51b1dbe0ee0d2e766067ab5a30daf89b2743ebbe43Zhongxing Xu // Zero index is always in bound, this also passes ElementRegions created for 52b1dbe0ee0d2e766067ab5a30daf89b2743ebbe43Zhongxing Xu // pointer casts. 53b1dbe0ee0d2e766067ab5a30daf89b2743ebbe43Zhongxing Xu if (Idx.isZeroConstant()) 54b1dbe0ee0d2e766067ab5a30daf89b2743ebbe43Zhongxing Xu return; 55b991f48ccff0567d581cf95e4eda1bffd5bbada3Zhongxing Xu // FIXME: All of this out-of-bounds checking should eventually be refactored 56b991f48ccff0567d581cf95e4eda1bffd5bbada3Zhongxing Xu // into a common place. 57ceeb02db9ad4232ea248a44192180d5bc7fe2653Zhongxing Xu 58e884ff88baa1bd61db273baf107862a2110058edZhongxing Xu DefinedOrUnknownSVal NumElements 593ed04d37573c566205d965d2e91d54ccae898d0aZhongxing Xu = C.getStoreManager().getSizeInElements(state, ER->getSuperRegion(), 60018220c343c103b7dfaa117a7a474c7a7fd6d068Zhongxing Xu ER->getValueType()); 61ceeb02db9ad4232ea248a44192180d5bc7fe2653Zhongxing Xu 628bef8238181a30e52dea380789a7e2d760eac532Ted Kremenek ProgramStateRef StInBound = state->assumeInBound(Idx, NumElements, true); 638bef8238181a30e52dea380789a7e2d760eac532Ted Kremenek ProgramStateRef StOutBound = state->assumeInBound(Idx, NumElements, false); 64ceeb02db9ad4232ea248a44192180d5bc7fe2653Zhongxing Xu if (StOutBound && !StInBound) { 65d048c6ef5b6cfaa0cecb8cc1d4bdace32ed21d07Ted Kremenek ExplodedNode *N = C.generateSink(StOutBound); 66ceeb02db9ad4232ea248a44192180d5bc7fe2653Zhongxing Xu 67ceeb02db9ad4232ea248a44192180d5bc7fe2653Zhongxing Xu if (!N) 68ceeb02db9ad4232ea248a44192180d5bc7fe2653Zhongxing Xu return; 69ceeb02db9ad4232ea248a44192180d5bc7fe2653Zhongxing Xu 70b991f48ccff0567d581cf95e4eda1bffd5bbada3Zhongxing Xu // FIXME: This bug correspond to CWE-466. Eventually we should have bug 71b991f48ccff0567d581cf95e4eda1bffd5bbada3Zhongxing Xu // types explicitly reference such exploit categories (when applicable). 72ceeb02db9ad4232ea248a44192180d5bc7fe2653Zhongxing Xu if (!BT) 73651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines BT.reset(new BuiltinBug( 74651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines this, "Return of pointer value outside of expected range", 75651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines "Returned pointer value points outside the original object " 76651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines "(potential buffer overflow)")); 776f516f50e53b621613d281ef186c76c5160d9d35Ted Kremenek 78b991f48ccff0567d581cf95e4eda1bffd5bbada3Zhongxing Xu // FIXME: It would be nice to eventually make this diagnostic more clear, 79b991f48ccff0567d581cf95e4eda1bffd5bbada3Zhongxing Xu // e.g., by referencing the original declaration or by saying *why* this 80b991f48ccff0567d581cf95e4eda1bffd5bbada3Zhongxing Xu // reference is outside the range. 816f516f50e53b621613d281ef186c76c5160d9d35Ted Kremenek 82ceeb02db9ad4232ea248a44192180d5bc7fe2653Zhongxing Xu // Generate a report for this bug. 83e172e8b9e7fc67d7d03589af7e92fe777afcf33aAnna Zaks BugReport *report = 84e172e8b9e7fc67d7d03589af7e92fe777afcf33aAnna Zaks new BugReport(*BT, BT->getDescription(), N); 85ceeb02db9ad4232ea248a44192180d5bc7fe2653Zhongxing Xu 866f516f50e53b621613d281ef186c76c5160d9d35Ted Kremenek report->addRange(RetE->getSourceRange()); 87785950e59424dca7ce0081bebf13c0acd2c4fff6Jordan Rose C.emitReport(report); 88ceeb02db9ad4232ea248a44192180d5bc7fe2653Zhongxing Xu } 89ceeb02db9ad4232ea248a44192180d5bc7fe2653Zhongxing Xu} 9069355798abdbe5e78d1185af7d4600b9355b5814Argyrios Kyrtzidis 9169355798abdbe5e78d1185af7d4600b9355b5814Argyrios Kyrtzidisvoid ento::registerReturnPointerRangeChecker(CheckerManager &mgr) { 9269355798abdbe5e78d1185af7d4600b9355b5814Argyrios Kyrtzidis mgr.registerChecker<ReturnPointerRangeChecker>(); 9369355798abdbe5e78d1185af7d4600b9355b5814Argyrios Kyrtzidis} 94