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