clang  15.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 
23 
24 using namespace clang;
25 using namespace ento;
26 
27 namespace {
28 
29 // enum value that represent the jail state
30 enum Kind { NO_CHROOT, ROOT_CHANGED, JAIL_ENTERED };
31 
32 bool isRootChanged(intptr_t k) { return k == ROOT_CHANGED; }
33 //bool isJailEntered(intptr_t k) { return k == JAIL_ENTERED; }
34 
35 // This checker checks improper use of chroot.
36 // The state transition:
37 // NO_CHROOT ---chroot(path)--> ROOT_CHANGED ---chdir(/) --> JAIL_ENTERED
38 // | |
39 // ROOT_CHANGED<--chdir(..)-- JAIL_ENTERED<--chdir(..)--
40 // | |
41 // bug<--foo()-- JAIL_ENTERED<--foo()--
42 class ChrootChecker : public Checker<eval::Call, check::PreCall> {
43  // This bug refers to possibly break out of a chroot() jail.
44  mutable std::unique_ptr<BuiltinBug> BT_BreakJail;
45 
46  const CallDescription Chroot{"chroot", 1}, Chdir{"chdir", 1};
47 
48 public:
49  ChrootChecker() {}
50 
51  static void *getTag() {
52  static int x;
53  return &x;
54  }
55 
56  bool evalCall(const CallEvent &Call, CheckerContext &C) const;
57  void checkPreCall(const CallEvent &Call, CheckerContext &C) const;
58 
59 private:
60  void evalChroot(const CallEvent &Call, CheckerContext &C) const;
61  void evalChdir(const CallEvent &Call, CheckerContext &C) const;
62 };
63 
64 } // end anonymous namespace
65 
66 bool ChrootChecker::evalCall(const CallEvent &Call, CheckerContext &C) const {
67  if (Chroot.matches(Call)) {
68  evalChroot(Call, C);
69  return true;
70  }
71  if (Chdir.matches(Call)) {
72  evalChdir(Call, C);
73  return true;
74  }
75 
76  return false;
77 }
78 
79 void ChrootChecker::evalChroot(const CallEvent &Call, CheckerContext &C) const {
80  ProgramStateRef state = C.getState();
81  ProgramStateManager &Mgr = state->getStateManager();
82 
83  // Once encouter a chroot(), set the enum value ROOT_CHANGED directly in
84  // the GDM.
85  state = Mgr.addGDM(state, ChrootChecker::getTag(), (void*) ROOT_CHANGED);
86  C.addTransition(state);
87 }
88 
89 void ChrootChecker::evalChdir(const CallEvent &Call, CheckerContext &C) const {
90  ProgramStateRef state = C.getState();
91  ProgramStateManager &Mgr = state->getStateManager();
92 
93  // If there are no jail state in the GDM, just return.
94  const void *k = state->FindGDM(ChrootChecker::getTag());
95  if (!k)
96  return;
97 
98  // After chdir("/"), enter the jail, set the enum value JAIL_ENTERED.
99  const Expr *ArgExpr = Call.getArgExpr(0);
100  SVal ArgVal = C.getSVal(ArgExpr);
101 
102  if (const MemRegion *R = ArgVal.getAsRegion()) {
103  R = R->StripCasts();
104  if (const StringRegion* StrRegion= dyn_cast<StringRegion>(R)) {
105  const StringLiteral* Str = StrRegion->getStringLiteral();
106  if (Str->getString() == "/")
107  state = Mgr.addGDM(state, ChrootChecker::getTag(),
108  (void*) JAIL_ENTERED);
109  }
110  }
111 
112  C.addTransition(state);
113 }
114 
115 // Check the jail state before any function call except chroot and chdir().
116 void ChrootChecker::checkPreCall(const CallEvent &Call,
117  CheckerContext &C) const {
118  // Ignore chroot and chdir.
119  if (matchesAny(Call, Chroot, Chdir))
120  return;
121 
122  // If jail state is ROOT_CHANGED, generate BugReport.
123  void *const* k = C.getState()->FindGDM(ChrootChecker::getTag());
124  if (k)
125  if (isRootChanged((intptr_t) *k))
126  if (ExplodedNode *N = C.generateNonFatalErrorNode()) {
127  if (!BT_BreakJail)
128  BT_BreakJail.reset(new BuiltinBug(
129  this, "Break out of jail", "No call of chdir(\"/\") immediately "
130  "after chroot"));
131  C.emitReport(std::make_unique<PathSensitiveBugReport>(
132  *BT_BreakJail, BT_BreakJail->getDescription(), N));
133  }
134 }
135 
136 void ento::registerChrootChecker(CheckerManager &mgr) {
137  mgr.registerChecker<ChrootChecker>();
138 }
139 
140 bool ento::shouldRegisterChrootChecker(const CheckerManager &mgr) {
141  return true;
142 }
CallDescription.h
clang::ento::ProgramStateRef
IntrusiveRefCntPtr< const ProgramState > ProgramStateRef
Definition: ProgramState_Fwd.h:37
AttributeLangSupport::C
@ C
Definition: SemaDeclAttr.cpp:55
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:133
clang::StringLiteral
StringLiteral - This represents a string literal expression, e.g.
Definition: Expr.h:1767
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:1850