clang  6.0.0svn
VforkChecker.cpp
Go to the documentation of this file.
1 //===- VforkChecker.cpp -------- Vfork usage 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 vfork checker which checks for dangerous uses of vfork.
11 // Vforked process shares memory (including stack) with parent so it's
12 // range of actions is significantly limited: can't write variables,
13 // can't call functions not in whitelist, etc. For more details, see
14 // http://man7.org/linux/man-pages/man2/vfork.2.html
15 //
16 // This checker checks for prohibited constructs in vforked process.
17 // The state transition diagram:
18 // PARENT ---(vfork() == 0)--> CHILD
19 // |
20 // --(*p = ...)--> bug
21 // |
22 // --foo()--> bug
23 // |
24 // --return--> bug
25 //
26 //===----------------------------------------------------------------------===//
27 
28 #include "ClangSACheckers.h"
38 #include "clang/AST/ParentMap.h"
39 
40 using namespace clang;
41 using namespace ento;
42 
43 namespace {
44 
45 class VforkChecker : public Checker<check::PreCall, check::PostCall,
46  check::Bind, check::PreStmt<ReturnStmt>> {
47  mutable std::unique_ptr<BuiltinBug> BT;
48  mutable llvm::SmallSet<const IdentifierInfo *, 10> VforkWhitelist;
49  mutable const IdentifierInfo *II_vfork;
50 
51  static bool isChildProcess(const ProgramStateRef State);
52 
53  bool isVforkCall(const Decl *D, CheckerContext &C) const;
54  bool isCallWhitelisted(const IdentifierInfo *II, CheckerContext &C) const;
55 
56  void reportBug(const char *What, CheckerContext &C,
57  const char *Details = nullptr) const;
58 
59 public:
60  VforkChecker() : II_vfork(nullptr) {}
61 
62  void checkPreCall(const CallEvent &Call, CheckerContext &C) const;
63  void checkPostCall(const CallEvent &Call, CheckerContext &C) const;
64  void checkBind(SVal L, SVal V, const Stmt *S, CheckerContext &C) const;
65  void checkPreStmt(const ReturnStmt *RS, CheckerContext &C) const;
66 };
67 
68 } // end anonymous namespace
69 
70 // This trait holds region of variable that is assigned with vfork's
71 // return value (this is the only region child is allowed to write).
72 // VFORK_RESULT_INVALID means that we are in parent process.
73 // VFORK_RESULT_NONE means that vfork's return value hasn't been assigned.
74 // Other values point to valid regions.
75 REGISTER_TRAIT_WITH_PROGRAMSTATE(VforkResultRegion, const void *)
76 #define VFORK_RESULT_INVALID 0
77 #define VFORK_RESULT_NONE ((void *)(uintptr_t)1)
78 
79 bool VforkChecker::isChildProcess(const ProgramStateRef State) {
80  return State->get<VforkResultRegion>() != VFORK_RESULT_INVALID;
81 }
82 
83 bool VforkChecker::isVforkCall(const Decl *D, CheckerContext &C) const {
84  auto FD = dyn_cast_or_null<FunctionDecl>(D);
85  if (!FD || !C.isCLibraryFunction(FD))
86  return false;
87 
88  if (!II_vfork) {
89  ASTContext &AC = C.getASTContext();
90  II_vfork = &AC.Idents.get("vfork");
91  }
92 
93  return FD->getIdentifier() == II_vfork;
94 }
95 
96 // Returns true iff ok to call function after successful vfork.
97 bool VforkChecker::isCallWhitelisted(const IdentifierInfo *II,
98  CheckerContext &C) const {
99  if (VforkWhitelist.empty()) {
100  // According to manpage.
101  const char *ids[] = {
102  "_exit",
103  "_Exit",
104  "execl",
105  "execlp",
106  "execle",
107  "execv",
108  "execvp",
109  "execvpe",
110  nullptr
111  };
112 
113  ASTContext &AC = C.getASTContext();
114  for (const char **id = ids; *id; ++id)
115  VforkWhitelist.insert(&AC.Idents.get(*id));
116  }
117 
118  return VforkWhitelist.count(II);
119 }
120 
121 void VforkChecker::reportBug(const char *What, CheckerContext &C,
122  const char *Details) const {
123  if (ExplodedNode *N = C.generateErrorNode(C.getState())) {
124  if (!BT)
125  BT.reset(new BuiltinBug(this,
126  "Dangerous construct in a vforked process"));
127 
128  SmallString<256> buf;
129  llvm::raw_svector_ostream os(buf);
130 
131  os << What << " is prohibited after a successful vfork";
132 
133  if (Details)
134  os << "; " << Details;
135 
136  auto Report = llvm::make_unique<BugReport>(*BT, os.str(), N);
137  // TODO: mark vfork call in BugReportVisitor
138  C.emitReport(std::move(Report));
139  }
140 }
141 
142 // Detect calls to vfork and split execution appropriately.
143 void VforkChecker::checkPostCall(const CallEvent &Call,
144  CheckerContext &C) const {
145  // We can't call vfork in child so don't bother
146  // (corresponding warning has already been emitted in checkPreCall).
148  if (isChildProcess(State))
149  return;
150 
151  if (!isVforkCall(Call.getDecl(), C))
152  return;
153 
154  // Get return value of vfork.
155  SVal VforkRetVal = Call.getReturnValue();
157  VforkRetVal.getAs<DefinedOrUnknownSVal>();
158  if (!DVal)
159  return;
160 
161  // Get assigned variable.
162  const ParentMap &PM = C.getLocationContext()->getParentMap();
163  const Stmt *P = PM.getParentIgnoreParenCasts(Call.getOriginExpr());
164  const VarDecl *LhsDecl;
165  std::tie(LhsDecl, std::ignore) = parseAssignment(P);
166 
167  // Get assigned memory region.
169  const MemRegion *LhsDeclReg =
170  LhsDecl
171  ? M.getVarRegion(LhsDecl, C.getLocationContext())
172  : (const MemRegion *)VFORK_RESULT_NONE;
173 
174  // Parent branch gets nonzero return value (according to manpage).
175  ProgramStateRef ParentState, ChildState;
176  std::tie(ParentState, ChildState) = C.getState()->assume(*DVal);
177  C.addTransition(ParentState);
178  ChildState = ChildState->set<VforkResultRegion>(LhsDeclReg);
179  C.addTransition(ChildState);
180 }
181 
182 // Prohibit calls to non-whitelist functions in child process.
183 void VforkChecker::checkPreCall(const CallEvent &Call,
184  CheckerContext &C) const {
186  if (isChildProcess(State)
187  && !isCallWhitelisted(Call.getCalleeIdentifier(), C))
188  reportBug("This function call", C);
189 }
190 
191 // Prohibit writes in child process (except for vfork's lhs).
192 void VforkChecker::checkBind(SVal L, SVal V, const Stmt *S,
193  CheckerContext &C) const {
195  if (!isChildProcess(State))
196  return;
197 
198  const MemRegion *VforkLhs =
199  static_cast<const MemRegion *>(State->get<VforkResultRegion>());
200  const MemRegion *MR = L.getAsRegion();
201 
202  // Child is allowed to modify only vfork's lhs.
203  if (!MR || MR == VforkLhs)
204  return;
205 
206  reportBug("This assignment", C);
207 }
208 
209 // Prohibit return from function in child process.
210 void VforkChecker::checkPreStmt(const ReturnStmt *RS, CheckerContext &C) const {
212  if (isChildProcess(State))
213  reportBug("Return", C, "call _exit() instead");
214 }
215 
216 void ento::registerVforkChecker(CheckerManager &mgr) {
217  mgr.registerChecker<VforkChecker>();
218 }
MemRegion - The root abstract class for all memory regions.
Definition: MemRegion.h:79
ExplodedNode * generateErrorNode(ProgramStateRef State=nullptr, const ProgramPointTag *Tag=nullptr)
Generate a transition to a node that will be used to report an error.
Stmt - This represents one statement.
Definition: Stmt.h:66
ExplodedNode * addTransition(ProgramStateRef State=nullptr, const ProgramPointTag *Tag=nullptr)
Generates a new transition in the program state graph (ExplodedGraph).
Decl - This represents one declaration (or definition), e.g.
Definition: DeclBase.h:86
StringRef P
const Expr * getOriginExpr() const
Returns the expression whose value will be the result of this call.
Definition: CallEvent.h:225
VarDecl - An instance of this class is created to represent a variable declaration or definition...
Definition: Decl.h:806
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:149
LineState State
IdentifierTable & Idents
Definition: ASTContext.h:537
SVal getReturnValue() const
Returns the return value of the call.
Definition: CallEvent.cpp:242
std::pair< const clang::VarDecl *, const clang::Expr * > parseAssignment(const Stmt *S)
static bool isCLibraryFunction(const FunctionDecl *FD, StringRef Name=StringRef())
Returns true if the callee is an externally-visible function in the top-level namespace, such as malloc.
const IdentifierInfo * getCalleeIdentifier() const
Returns the name of the callee, if its name is a simple identifier.
Definition: CallEvent.h:335
internal::Matcher< T > id(StringRef ID, const internal::BindableMatcher< T > &InnerMatcher)
If the provided matcher matches a node, binds the node to ID.
Definition: ASTMatchers.h:137
virtual const Decl * getDecl() const
Returns the declaration of the function or method that will be called.
Definition: CallEvent.h:205
ReturnStmt - This represents a return, optionally of an expression: return; return 4;...
Definition: Stmt.h:1413
#define VFORK_RESULT_INVALID
ParentMap & getParentMap() const
Optional< T > getAs() const
Convert to the specified SVal type, returning None if this SVal is not of the desired type...
Definition: SVals.h:100
void emitReport(std::unique_ptr< BugReport > R)
Emit the diagnostics report.
#define REGISTER_TRAIT_WITH_PROGRAMSTATE(Name, Type)
Declares a program state trait for type Type called Name, and introduce a typedef named NameTy...
CHECKER * registerChecker()
Used to register checkers.
StoreManager & getStoreManager()
IdentifierInfo & get(StringRef Name)
Return the identifier token info for the specified named identifier.
const MemRegion * getAsRegion() const
Definition: SVals.cpp:140
SVal - This represents a symbolic expression, which can be either an L-value or an R-value...
Definition: SVals.h:63
#define VFORK_RESULT_NONE
Dataflow Directional Tag Classes.
const VarRegion * getVarRegion(const VarDecl *D, const LocationContext *LC)
getVarRegion - Retrieve or create the memory region associated with a specified VarDecl and LocationC...
Definition: MemRegion.cpp:783
Represents an abstract call to a function or method along a particular path.
Definition: CallEvent.h:140
MemRegionManager & getRegionManager()
getRegionManager - Returns the internal RegionManager object that is used to query and manipulate Mem...
Definition: Store.h:108
const ProgramStateRef & getState() const
Stmt * getParentIgnoreParenCasts(Stmt *) const
Definition: ParentMap.cpp:133
const LocationContext * getLocationContext() const