45class VforkChecker :
public Checker<check::PreCall, check::PostCall,
46 check::Bind, check::PreStmt<ReturnStmt>> {
47 const BugType BT{
this,
"Dangerous construct in a vforked process"};
48 mutable llvm::SmallPtrSet<const IdentifierInfo *, 10> VforkAllowlist;
49 mutable const IdentifierInfo *II_vfork =
nullptr;
53 bool isVforkCall(
const Decl *D, CheckerContext &
C)
const;
54 bool isCallExplicitelyAllowed(
const IdentifierInfo *II,
55 CheckerContext &
C)
const;
57 void reportBug(
const char *What, CheckerContext &
C,
58 const char *Details =
nullptr)
const;
61 VforkChecker() =
default;
63 void checkPreCall(
const CallEvent &
Call, CheckerContext &
C)
const;
64 void checkPostCall(
const CallEvent &
Call, CheckerContext &
C)
const;
65 void checkBind(SVal L, SVal
V,
const Stmt *S,
bool AtDeclInit,
66 CheckerContext &
C)
const;
67 void checkPreStmt(
const ReturnStmt *RS, CheckerContext &
C)
const;
78#define VFORK_RESULT_INVALID 0
79#define VFORK_RESULT_NONE ((void *)(uintptr_t)1)
85bool VforkChecker::isVforkCall(
const Decl *D, CheckerContext &
C)
const {
86 auto FD = dyn_cast_or_null<FunctionDecl>(D);
87 if (!FD || !
C.isCLibraryFunction(FD))
91 ASTContext &AC =
C.getASTContext();
95 return FD->getIdentifier() == II_vfork;
99bool VforkChecker::isCallExplicitelyAllowed(
const IdentifierInfo *II,
100 CheckerContext &
C)
const {
101 if (VforkAllowlist.empty()) {
103 const char *ids[] = {
116 ASTContext &AC =
C.getASTContext();
117 for (
const char **
id = ids; *id; ++id)
118 VforkAllowlist.insert(&AC.
Idents.
get(*
id));
121 return VforkAllowlist.count(II);
124void VforkChecker::reportBug(
const char *What, CheckerContext &
C,
125 const char *Details)
const {
126 if (ExplodedNode *N =
C.generateErrorNode(
C.getState())) {
127 SmallString<256> buf;
128 llvm::raw_svector_ostream os(buf);
130 os << What <<
" is prohibited after a successful vfork";
133 os <<
"; " << Details;
135 auto Report = std::make_unique<PathSensitiveBugReport>(BT, os.str(), N);
137 C.emitReport(std::move(
Report));
142void VforkChecker::checkPostCall(
const CallEvent &
Call,
143 CheckerContext &
C)
const {
147 if (isChildProcess(State))
150 if (!isVforkCall(
Call.getDecl(),
C))
154 SVal VforkRetVal =
Call.getReturnValue();
155 std::optional<DefinedOrUnknownSVal> DVal =
156 VforkRetVal.
getAs<DefinedOrUnknownSVal>();
161 const ParentMap &PM =
C.getLocationContext()->getParentMap();
163 const VarDecl *LhsDecl;
167 MemRegionManager &M =
C.getStoreManager().getRegionManager();
168 const MemRegion *LhsDeclReg =
175 std::tie(ParentState, ChildState) =
C.getState()->assume(*DVal);
176 C.addTransition(ParentState);
177 ChildState = ChildState->set<VforkResultRegion>(LhsDeclReg);
178 C.addTransition(ChildState);
183void VforkChecker::checkPreCall(
const CallEvent &
Call,
184 CheckerContext &
C)
const {
186 if (isChildProcess(State) &&
187 !isCallExplicitelyAllowed(
Call.getCalleeIdentifier(),
C))
188 reportBug(
"This function call",
C);
192void VforkChecker::checkBind(SVal L, SVal
V,
const Stmt *S,
bool AtDeclInit,
193 CheckerContext &
C)
const {
195 if (!isChildProcess(State))
198 const MemRegion *VforkLhs =
199 static_cast<const MemRegion *
>(State->get<VforkResultRegion>());
203 if (!MR || MR == VforkLhs)
206 reportBug(
"This assignment",
C);
210void VforkChecker::checkPreStmt(
const ReturnStmt *RS, CheckerContext &
C)
const {
212 if (isChildProcess(State))
213 reportBug(
"Return",
C,
"call _exit() instead");
216void ento::registerVforkChecker(CheckerManager &mgr) {
220bool ento::shouldRegisterVforkChecker(
const CheckerManager &mgr) {
#define REGISTER_TRAIT_WITH_PROGRAMSTATE(Name, Type)
Declares a program state trait for type Type called Name, and introduce a type named NameTy.
#define VFORK_RESULT_INVALID
#define VFORK_RESULT_NONE
IdentifierInfo & get(StringRef Name)
Return the identifier token info for the specified named identifier.
Stmt * getParentIgnoreParenCasts(Stmt *) const
CHECKER * registerChecker(AT &&...Args)
Register a single-part checker (derived from Checker): construct its singleton instance,...
Simple checker classes that implement one frontend (i.e.
const VarRegion * getVarRegion(const VarDecl *VD, const LocationContext *LC)
getVarRegion - Retrieve or create the memory region associated with a specified VarDecl and LocationC...
std::optional< T > getAs() const
Convert to the specified SVal type, returning std::nullopt if this SVal is not of the desired type.
const MemRegion * getAsRegion() const
IntrusiveRefCntPtr< const ProgramState > ProgramStateRef
std::pair< const clang::VarDecl *, const clang::Expr * > parseAssignment(const Stmt *S)
The JSON file list parser is used to communicate input to InstallAPI.