clang  9.0.0svn
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 
21 
22 using namespace clang;
23 using namespace ento;
24 
25 namespace {
26 
27 // enum value that represent the jail state
28 enum Kind { NO_CHROOT, ROOT_CHANGED, JAIL_ENTERED };
29 
30 bool isRootChanged(intptr_t k) { return k == ROOT_CHANGED; }
31 //bool isJailEntered(intptr_t k) { return k == JAIL_ENTERED; }
32 
33 // This checker checks improper use of chroot.
34 // The state transition:
35 // NO_CHROOT ---chroot(path)--> ROOT_CHANGED ---chdir(/) --> JAIL_ENTERED
36 // | |
37 // ROOT_CHANGED<--chdir(..)-- JAIL_ENTERED<--chdir(..)--
38 // | |
39 // bug<--foo()-- JAIL_ENTERED<--foo()--
40 class ChrootChecker : public Checker<eval::Call, check::PreStmt<CallExpr> > {
41  mutable IdentifierInfo *II_chroot, *II_chdir;
42  // This bug refers to possibly break out of a chroot() jail.
43  mutable std::unique_ptr<BuiltinBug> BT_BreakJail;
44 
45 public:
46  ChrootChecker() : II_chroot(nullptr), II_chdir(nullptr) {}
47 
48  static void *getTag() {
49  static int x;
50  return &x;
51  }
52 
53  bool evalCall(const CallExpr *CE, CheckerContext &C) const;
54  void checkPreStmt(const CallExpr *CE, CheckerContext &C) const;
55 
56 private:
57  void Chroot(CheckerContext &C, const CallExpr *CE) const;
58  void Chdir(CheckerContext &C, const CallExpr *CE) const;
59 };
60 
61 } // end anonymous namespace
62 
63 bool ChrootChecker::evalCall(const CallExpr *CE, CheckerContext &C) const {
64  const FunctionDecl *FD = C.getCalleeDecl(CE);
65  if (!FD)
66  return false;
67 
68  ASTContext &Ctx = C.getASTContext();
69  if (!II_chroot)
70  II_chroot = &Ctx.Idents.get("chroot");
71  if (!II_chdir)
72  II_chdir = &Ctx.Idents.get("chdir");
73 
74  if (FD->getIdentifier() == II_chroot) {
75  Chroot(C, CE);
76  return true;
77  }
78  if (FD->getIdentifier() == II_chdir) {
79  Chdir(C, CE);
80  return true;
81  }
82 
83  return false;
84 }
85 
86 void ChrootChecker::Chroot(CheckerContext &C, const CallExpr *CE) const {
87  ProgramStateRef state = C.getState();
88  ProgramStateManager &Mgr = state->getStateManager();
89 
90  // Once encouter a chroot(), set the enum value ROOT_CHANGED directly in
91  // the GDM.
92  state = Mgr.addGDM(state, ChrootChecker::getTag(), (void*) ROOT_CHANGED);
93  C.addTransition(state);
94 }
95 
96 void ChrootChecker::Chdir(CheckerContext &C, const CallExpr *CE) const {
97  ProgramStateRef state = C.getState();
98  ProgramStateManager &Mgr = state->getStateManager();
99 
100  // If there are no jail state in the GDM, just return.
101  const void *k = state->FindGDM(ChrootChecker::getTag());
102  if (!k)
103  return;
104 
105  // After chdir("/"), enter the jail, set the enum value JAIL_ENTERED.
106  const Expr *ArgExpr = CE->getArg(0);
107  SVal ArgVal = C.getSVal(ArgExpr);
108 
109  if (const MemRegion *R = ArgVal.getAsRegion()) {
110  R = R->StripCasts();
111  if (const StringRegion* StrRegion= dyn_cast<StringRegion>(R)) {
112  const StringLiteral* Str = StrRegion->getStringLiteral();
113  if (Str->getString() == "/")
114  state = Mgr.addGDM(state, ChrootChecker::getTag(),
115  (void*) JAIL_ENTERED);
116  }
117  }
118 
119  C.addTransition(state);
120 }
121 
122 // Check the jail state before any function call except chroot and chdir().
123 void ChrootChecker::checkPreStmt(const CallExpr *CE, CheckerContext &C) const {
124  const FunctionDecl *FD = C.getCalleeDecl(CE);
125  if (!FD)
126  return;
127 
128  ASTContext &Ctx = C.getASTContext();
129  if (!II_chroot)
130  II_chroot = &Ctx.Idents.get("chroot");
131  if (!II_chdir)
132  II_chdir = &Ctx.Idents.get("chdir");
133 
134  // Ignore chroot and chdir.
135  if (FD->getIdentifier() == II_chroot || FD->getIdentifier() == II_chdir)
136  return;
137 
138  // If jail state is ROOT_CHANGED, generate BugReport.
139  void *const* k = C.getState()->FindGDM(ChrootChecker::getTag());
140  if (k)
141  if (isRootChanged((intptr_t) *k))
142  if (ExplodedNode *N = C.generateNonFatalErrorNode()) {
143  if (!BT_BreakJail)
144  BT_BreakJail.reset(new BuiltinBug(
145  this, "Break out of jail", "No call of chdir(\"/\") immediately "
146  "after chroot"));
147  C.emitReport(llvm::make_unique<BugReport>(
148  *BT_BreakJail, BT_BreakJail->getDescription(), N));
149  }
150 }
151 
152 void ento::registerChrootChecker(CheckerManager &mgr) {
153  mgr.registerChecker<ChrootChecker>();
154 }
155 
156 bool ento::shouldRegisterChrootChecker(const LangOptions &LO) {
157  return true;
158 }
Represents a function declaration or definition.
Definition: Decl.h:1737
Expr * getArg(unsigned Arg)
getArg - Return the specified argument.
Definition: Expr.h:2586
IntrusiveRefCntPtr< const ProgramState > ProgramStateRef
IdentifierInfo * getIdentifier() const
Get the identifier that names this declaration, if there is one.
Definition: Decl.h:269
One of these records is kept for each identifier that is lexed.
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
Definition: ASTContext.h:154
Keeps track of the various options that can be enabled, which controls the dialect of C or C++ that i...
Definition: LangOptions.h:49
i32 captured_struct **param SharedsTy A type which contains references the shared variables *param Shareds Context with the list of shared variables from the p *TaskFunction *param Data Additional data for task generation like final * state
IdentifierTable & Idents
Definition: ASTContext.h:565
__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.h:82
StringRef getString() const
Definition: Expr.h:1682
This represents one expression.
Definition: Expr.h:108
Kind
IdentifierInfo & get(StringRef Name)
Return the identifier token info for the specified named identifier.
Dataflow Directional Tag Classes.
StringLiteral - This represents a string literal expression, e.g.
Definition: Expr.h:1599
CallExpr - Represents a function call (C99 6.5.2.2, C++ [expr.call]).
Definition: Expr.h:2429