clang  3.9.0
ChrootChecker.cpp
Go to the documentation of this file.
1 //===- Chrootchecker.cpp -------- Basic security checks ---------*- C++ -*-===//
2 //
3 // The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 //
10 // This file defines chroot checker, which checks improper use of chroot.
11 //
12 //===----------------------------------------------------------------------===//
13 
14 #include "ClangSACheckers.h"
22 #include "llvm/ADT/ImmutableMap.h"
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::PreStmt<CallExpr> > {
43  mutable IdentifierInfo *II_chroot, *II_chdir;
44  // This bug refers to possibly break out of a chroot() jail.
45  mutable std::unique_ptr<BuiltinBug> BT_BreakJail;
46 
47 public:
48  ChrootChecker() : II_chroot(nullptr), II_chdir(nullptr) {}
49 
50  static void *getTag() {
51  static int x;
52  return &x;
53  }
54 
55  bool evalCall(const CallExpr *CE, CheckerContext &C) const;
56  void checkPreStmt(const CallExpr *CE, CheckerContext &C) const;
57 
58 private:
59  void Chroot(CheckerContext &C, const CallExpr *CE) const;
60  void Chdir(CheckerContext &C, const CallExpr *CE) const;
61 };
62 
63 } // end anonymous namespace
64 
65 bool ChrootChecker::evalCall(const CallExpr *CE, CheckerContext &C) const {
66  const FunctionDecl *FD = C.getCalleeDecl(CE);
67  if (!FD)
68  return false;
69 
70  ASTContext &Ctx = C.getASTContext();
71  if (!II_chroot)
72  II_chroot = &Ctx.Idents.get("chroot");
73  if (!II_chdir)
74  II_chdir = &Ctx.Idents.get("chdir");
75 
76  if (FD->getIdentifier() == II_chroot) {
77  Chroot(C, CE);
78  return true;
79  }
80  if (FD->getIdentifier() == II_chdir) {
81  Chdir(C, CE);
82  return true;
83  }
84 
85  return false;
86 }
87 
88 void ChrootChecker::Chroot(CheckerContext &C, const CallExpr *CE) const {
90  ProgramStateManager &Mgr = state->getStateManager();
91 
92  // Once encouter a chroot(), set the enum value ROOT_CHANGED directly in
93  // the GDM.
94  state = Mgr.addGDM(state, ChrootChecker::getTag(), (void*) ROOT_CHANGED);
95  C.addTransition(state);
96 }
97 
98 void ChrootChecker::Chdir(CheckerContext &C, const CallExpr *CE) const {
99  ProgramStateRef state = C.getState();
100  ProgramStateManager &Mgr = state->getStateManager();
101 
102  // If there are no jail state in the GDM, just return.
103  const void *k = state->FindGDM(ChrootChecker::getTag());
104  if (!k)
105  return;
106 
107  // After chdir("/"), enter the jail, set the enum value JAIL_ENTERED.
108  const Expr *ArgExpr = CE->getArg(0);
109  SVal ArgVal = state->getSVal(ArgExpr, C.getLocationContext());
110 
111  if (const MemRegion *R = ArgVal.getAsRegion()) {
112  R = R->StripCasts();
113  if (const StringRegion* StrRegion= dyn_cast<StringRegion>(R)) {
114  const StringLiteral* Str = StrRegion->getStringLiteral();
115  if (Str->getString() == "/")
116  state = Mgr.addGDM(state, ChrootChecker::getTag(),
117  (void*) JAIL_ENTERED);
118  }
119  }
120 
121  C.addTransition(state);
122 }
123 
124 // Check the jail state before any function call except chroot and chdir().
125 void ChrootChecker::checkPreStmt(const CallExpr *CE, CheckerContext &C) const {
126  const FunctionDecl *FD = C.getCalleeDecl(CE);
127  if (!FD)
128  return;
129 
130  ASTContext &Ctx = C.getASTContext();
131  if (!II_chroot)
132  II_chroot = &Ctx.Idents.get("chroot");
133  if (!II_chdir)
134  II_chdir = &Ctx.Idents.get("chdir");
135 
136  // Ingnore chroot and chdir.
137  if (FD->getIdentifier() == II_chroot || FD->getIdentifier() == II_chdir)
138  return;
139 
140  // If jail state is ROOT_CHANGED, generate BugReport.
141  void *const* k = C.getState()->FindGDM(ChrootChecker::getTag());
142  if (k)
143  if (isRootChanged((intptr_t) *k))
145  if (!BT_BreakJail)
146  BT_BreakJail.reset(new BuiltinBug(
147  this, "Break out of jail", "No call of chdir(\"/\") immediately "
148  "after chroot"));
149  C.emitReport(llvm::make_unique<BugReport>(
150  *BT_BreakJail, BT_BreakJail->getDescription(), N));
151  }
152 }
153 
154 void ento::registerChrootChecker(CheckerManager &mgr) {
155  mgr.registerChecker<ChrootChecker>();
156 }
ProgramStateRef addGDM(ProgramStateRef St, void *Key, void *Data)
FunctionDecl - An instance of this class is created to represent a function declaration or definition...
Definition: Decl.h:1561
MemRegion - The root abstract class for all memory regions.
Definition: MemRegion.h:79
Expr * getArg(unsigned Arg)
getArg - Return the specified argument.
Definition: Expr.h:2217
IdentifierInfo * getIdentifier() const
getIdentifier - Get the identifier that names this declaration, if there is one.
Definition: Decl.h:232
ExplodedNode * addTransition(ProgramStateRef State=nullptr, const ProgramPointTag *Tag=nullptr)
Generates a new transition in the program state graph (ExplodedGraph).
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:92
const FunctionDecl * getCalleeDecl(const CallExpr *CE) const
Get the declaration of the called function (path-sensitive).
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:459
__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:68
Expr - This represents one expression.
Definition: Expr.h:105
const ProgramStateRef & getState() const
ExplodedNode * generateNonFatalErrorNode(ProgramStateRef State=nullptr, const ProgramPointTag *Tag=nullptr)
Generate a transition to a node that will be used to report an error.
void emitReport(std::unique_ptr< BugReport > R)
Emit the diagnostics report.
Kind
CHECKER * registerChecker()
Used to register checkers.
IdentifierInfo & get(StringRef Name)
Return the identifier token info for the specified named identifier.
SVal - This represents a symbolic expression, which can be either an L-value or an R-value...
Definition: SVals.h:46
StringRef getString() const
Definition: Expr.h:1514
const MemRegion * getAsRegion() const
Definition: SVals.cpp:135
StringLiteral - This represents a string literal expression, e.g.
Definition: Expr.h:1466
CallExpr - Represents a function call (C99 6.5.2.2, C++ [expr.call]).
Definition: Expr.h:2148
StringRegion - Region associated with a StringLiteral.
Definition: MemRegion.h:737
const LocationContext * getLocationContext() const