clang  14.0.0git
ChrootChecker.cpp
Go to the documentation of this file.
1 //===-- ChrootChecker.cpp - chroot usage checks ---------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // This file defines chroot checker, which checks improper use of chroot.
10 //
11 //===----------------------------------------------------------------------===//
12 
22 
23 using namespace clang;
24 using namespace ento;
25 
26 namespace {
27 
28 // enum value that represent the jail state
29 enum Kind { NO_CHROOT, ROOT_CHANGED, JAIL_ENTERED };
30 
31 bool isRootChanged(intptr_t k) { return k == ROOT_CHANGED; }
32 //bool isJailEntered(intptr_t k) { return k == JAIL_ENTERED; }
33 
34 // This checker checks improper use of chroot.
35 // The state transition:
36 // NO_CHROOT ---chroot(path)--> ROOT_CHANGED ---chdir(/) --> JAIL_ENTERED
37 // | |
38 // ROOT_CHANGED<--chdir(..)-- JAIL_ENTERED<--chdir(..)--
39 // | |
40 // bug<--foo()-- JAIL_ENTERED<--foo()--
41 class ChrootChecker : public Checker<eval::Call, check::PreCall> {
42  // This bug refers to possibly break out of a chroot() jail.
43  mutable std::unique_ptr<BuiltinBug> BT_BreakJail;
44 
45  const CallDescription Chroot{"chroot", 1}, Chdir{"chdir", 1};
46 
47 public:
48  ChrootChecker() {}
49 
50  static void *getTag() {
51  static int x;
52  return &x;
53  }
54 
55  bool evalCall(const CallEvent &Call, CheckerContext &C) const;
56  void checkPreCall(const CallEvent &Call, CheckerContext &C) const;
57 
58 private:
59  void evalChroot(const CallEvent &Call, CheckerContext &C) const;
60  void evalChdir(const CallEvent &Call, CheckerContext &C) const;
61 };
62 
63 } // end anonymous namespace
64 
65 bool ChrootChecker::evalCall(const CallEvent &Call, CheckerContext &C) const {
66  if (Call.isCalled(Chroot)) {
67  evalChroot(Call, C);
68  return true;
69  }
70  if (Call.isCalled(Chdir)) {
71  evalChdir(Call, C);
72  return true;
73  }
74 
75  return false;
76 }
77 
78 void ChrootChecker::evalChroot(const CallEvent &Call, CheckerContext &C) const {
79  ProgramStateRef state = C.getState();
80  ProgramStateManager &Mgr = state->getStateManager();
81 
82  // Once encouter a chroot(), set the enum value ROOT_CHANGED directly in
83  // the GDM.
84  state = Mgr.addGDM(state, ChrootChecker::getTag(), (void*) ROOT_CHANGED);
85  C.addTransition(state);
86 }
87 
88 void ChrootChecker::evalChdir(const CallEvent &Call, CheckerContext &C) const {
89  ProgramStateRef state = C.getState();
90  ProgramStateManager &Mgr = state->getStateManager();
91 
92  // If there are no jail state in the GDM, just return.
93  const void *k = state->FindGDM(ChrootChecker::getTag());
94  if (!k)
95  return;
96 
97  // After chdir("/"), enter the jail, set the enum value JAIL_ENTERED.
98  const Expr *ArgExpr = Call.getArgExpr(0);
99  SVal ArgVal = C.getSVal(ArgExpr);
100 
101  if (const MemRegion *R = ArgVal.getAsRegion()) {
102  R = R->StripCasts();
103  if (const StringRegion* StrRegion= dyn_cast<StringRegion>(R)) {
104  const StringLiteral* Str = StrRegion->getStringLiteral();
105  if (Str->getString() == "/")
106  state = Mgr.addGDM(state, ChrootChecker::getTag(),
107  (void*) JAIL_ENTERED);
108  }
109  }
110 
111  C.addTransition(state);
112 }
113 
114 // Check the jail state before any function call except chroot and chdir().
115 void ChrootChecker::checkPreCall(const CallEvent &Call,
116  CheckerContext &C) const {
117  // Ignore chroot and chdir.
118  if (Call.isCalled(Chroot) || Call.isCalled(Chdir))
119  return;
120 
121  // If jail state is ROOT_CHANGED, generate BugReport.
122  void *const* k = C.getState()->FindGDM(ChrootChecker::getTag());
123  if (k)
124  if (isRootChanged((intptr_t) *k))
125  if (ExplodedNode *N = C.generateNonFatalErrorNode()) {
126  if (!BT_BreakJail)
127  BT_BreakJail.reset(new BuiltinBug(
128  this, "Break out of jail", "No call of chdir(\"/\") immediately "
129  "after chroot"));
130  C.emitReport(std::make_unique<PathSensitiveBugReport>(
131  *BT_BreakJail, BT_BreakJail->getDescription(), N));
132  }
133 }
134 
135 void ento::registerChrootChecker(CheckerManager &mgr) {
136  mgr.registerChecker<ChrootChecker>();
137 }
138 
139 bool ento::shouldRegisterChrootChecker(const CheckerManager &mgr) {
140  return true;
141 }
clang::ento::ProgramStateRef
IntrusiveRefCntPtr< const ProgramState > ProgramStateRef
Definition: ProgramState_Fwd.h:37
AttributeLangSupport::C
@ C
Definition: SemaDeclAttr.cpp:54
SymbolManager.h
clang::index::SymbolRole::Call
@ Call
CallEvent.h
BuiltinCheckerRegistration.h
CheckerManager.h
intptr_t
__INTPTR_TYPE__ intptr_t
A signed integer type with the property that any valid pointer to void can be converted to this type,...
Definition: opencl-c-base.h:117
clang::StringLiteral
StringLiteral - This represents a string literal expression, e.g.
Definition: Expr.h:1761
x
IRgen optimization opportunities The common pattern of short x
Definition: README.txt:7
state
and static some checkers Checker The latter are built on top of the former via the Checker and CheckerVisitor and attempts to isolate them from much of the gore of the internal analysis the analyzer is basically a source code simulator that traces out possible paths of execution The state of the and the combination of state and program point is a node in an exploded which has the entry program point and initial state
Definition: README.txt:30
BugType.h
CheckerContext.h
clang::ObjCPropertyAttribute::Kind
Kind
Definition: DeclObjCCommon.h:22
ProgramState.h
Checker.h
clang
Definition: CalledOnceCheck.h:17
ProgramStateTrait.h
clang::Expr
This represents one expression.
Definition: Expr.h:109
clang::StringLiteral::getString
StringRef getString() const
Definition: Expr.h:1844