39class MIGChecker :
public Checker<check::PostCall, check::PreStmt<ReturnStmt>,
41 BugType BT{
this,
"Use-after-free (MIG calling convention violation)",
49 CallDescriptionMap<unsigned> Deallocators = {
50#define CALL(required_args, deallocated_arg, ...) \
51 {{CDM::SimpleFunc, {__VA_ARGS__}, required_args}, deallocated_arg}
56 CALL(3, 1,
"vm_deallocate"),
57 CALL(3, 1,
"mach_vm_deallocate"),
58 CALL(2, 0,
"mig_deallocate"),
59 CALL(2, 1,
"mach_port_deallocate"),
60 CALL(1, 0,
"device_deallocate"),
61 CALL(1, 0,
"iokit_remove_connect_reference"),
62 CALL(1, 0,
"iokit_remove_reference"),
63 CALL(1, 0,
"iokit_release_port"),
64 CALL(1, 0,
"ipc_port_release"),
65 CALL(1, 0,
"ipc_port_release_sonce"),
66 CALL(1, 0,
"ipc_voucher_attr_control_release"),
67 CALL(1, 0,
"ipc_voucher_release"),
68 CALL(1, 0,
"lock_set_dereference"),
69 CALL(1, 0,
"memory_object_control_deallocate"),
70 CALL(1, 0,
"pset_deallocate"),
71 CALL(1, 0,
"semaphore_dereference"),
72 CALL(1, 0,
"space_deallocate"),
73 CALL(1, 0,
"space_inspect_deallocate"),
74 CALL(1, 0,
"task_deallocate"),
75 CALL(1, 0,
"task_inspect_deallocate"),
76 CALL(1, 0,
"task_name_deallocate"),
77 CALL(1, 0,
"thread_deallocate"),
78 CALL(1, 0,
"thread_inspect_deallocate"),
79 CALL(1, 0,
"upl_deallocate"),
80 CALL(1, 0,
"vm_map_deallocate"),
82#define CALL(required_args, deallocated_arg, ...) \
83 {{CDM::CXXMethod, {__VA_ARGS__}, required_args}, deallocated_arg}
88 CALL(1, 0,
"IOUserClient",
"releaseAsyncReference64"),
89 CALL(1, 0,
"IOUserClient",
"releaseNotificationPort"),
93 CallDescription OsRefRetain{CDM::SimpleFunc, {
"os_ref_retain"}, 1};
95 void checkReturnAux(
const ReturnStmt *RS, CheckerContext &
C)
const;
98 void checkPostCall(
const CallEvent &
Call, CheckerContext &
C)
const;
106 void checkPreStmt(
const ReturnStmt *RS, CheckerContext &
C)
const {
107 checkReturnAux(RS,
C);
109 void checkEndFunction(
const ReturnStmt *RS, CheckerContext &
C)
const {
110 checkReturnAux(RS,
C);
124 bool IncludeBaseRegions =
false) {
126 SymbolRef Sym =
V.getAsSymbol(IncludeBaseRegions);
136 const auto *VR = dyn_cast<VarRegion>(MR);
137 if (VR && VR->hasMemorySpace<StackArgumentsSpaceRegion>(C.getState()) &&
138 VR->getStackFrame()->inTopFrame())
139 return cast<ParmVarDecl>(VR->getDecl());
141 const SymbolicRegion *SR = MR->getSymbolicBase();
145 Sym = SR->getSymbol();
153 assert(LC &&
"Unknown location context");
170 if (!AC->getReturnType(
C.getASTContext())
171 .getCanonicalType()->isSignedIntegerType())
175 if (D->
hasAttr<MIGServerRoutineAttr>())
179 if (
const auto *MD = dyn_cast<CXXMethodDecl>(D))
180 for (
const auto *OMD: MD->overridden_methods())
181 if (OMD->hasAttr<MIGServerRoutineAttr>())
192 if (
const ParmVarDecl *PVD =
196 C.addTransition(
C.getState()->add<RefCountedParameters>(PVD));
204 const unsigned *ArgIdxPtr = Deallocators.lookup(
Call);
209 unsigned ArgIdx = *ArgIdxPtr;
210 SVal Arg =
Call.getArgSVal(ArgIdx);
212 if (!PVD || State->contains<RefCountedParameters>(PVD))
216 C.getNoteTag([
this, PVD](PathSensitiveBugReport &BR) -> std::string {
220 llvm::raw_svector_ostream
OS(Str);
221 OS <<
"Value passed through parameter '" << PVD->
getName()
222 <<
"\' is deallocated";
223 return std::string(
OS.str());
225 C.addTransition(State->set<ReleasedParameter>(
true),
T);
233 if (!State->isNull(
V).isConstrainedFalse())
240 static const int MigNoReply = -305;
242 if (!State->isNull(
V).isConstrainedTrue())
249void MIGChecker::checkReturnAux(
const ReturnStmt *RS, CheckerContext &
C)
const {
270 if (!State->get<ReleasedParameter>())
273 SVal
V =
C.getSVal(RS);
277 ExplodedNode *N =
C.generateErrorNode();
281 auto R = std::make_unique<PathSensitiveBugReport>(
283 "MIG callback fails with error after deallocating argument value. "
284 "This is a use-after-free vulnerability because the caller will try to "
285 "deallocate it again",
291 {bugreporter::TrackingKind::Thorough, false});
292 C.emitReport(std::move(R));
295void ento::registerMIGChecker(CheckerManager &Mgr) {
299bool ento::shouldRegisterMIGChecker(
const CheckerManager &mgr) {
#define CALL(required_args, deallocated_arg,...)
static bool mayBeSuccess(SVal V, CheckerContext &C)
static bool isInMIGCall(CheckerContext &C)
static const ParmVarDecl * getOriginParam(SVal V, CheckerContext &C, bool IncludeBaseRegions=false)
#define REGISTER_SET_WITH_PROGRAMSTATE(Name, Elem)
Declares an immutable set of type NameTy, suitable for placement into the ProgramState.
#define REGISTER_TRAIT_WITH_PROGRAMSTATE(Name, Type)
Declares a program state trait for type Type called Name, and introduce a type named NameTy.
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
static std::optional< AnyCall > forDecl(const Decl *D)
If D is a callable (Objective-C method or a function), return a constructed AnyCall object.
Decl - This represents one declaration (or definition), e.g.
It wraps the AnalysisDeclContext to represent both the call stack with the help of StackFrameContext ...
const Decl * getDecl() const
const LocationContext * getParent() const
It might return null.
const StackFrameContext * getStackFrame() const
StringRef getName() const
Get the name of identifier for this declaration as a StringRef.
Represents a parameter to a function.
It represents a stack frame of the call stack (based on CallEvent).
SourceRange getSourceRange() const LLVM_READONLY
SourceLocation tokens are not useful in isolation - they are low level value objects created/interpre...
const BugType & getBugType() const
bool matches(const CallEvent &Call) const
Returns true if the CallEvent is a call to a function that matches the CallDescription.
Represents an abstract call to a function or method along a particular path.
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.
MemRegion - The root abstract class for all memory regions.
nonloc::ConcreteInt makeIntVal(const IntegerLiteral *integer)
SVal evalEQ(ProgramStateRef state, SVal lhs, SVal rhs)
SVal - This represents a symbolic expression, which can be either an L-value or an R-value.
virtual const MemRegion * getOriginRegion() const
Find the region from which this symbol originates.
bool trackExpressionValue(const ExplodedNode *N, const Expr *E, PathSensitiveBugReport &R, TrackingOptions Opts={})
Attempts to add visitors to track expression value back to its point of origin.
const char *const MemoryError
IntrusiveRefCntPtr< const ProgramState > ProgramStateRef
const SymExpr * SymbolRef
@ OS
Indicates that the tracking object is a descendant of a referenced-counted OSObject,...
The JSON file list parser is used to communicate input to InstallAPI.
const FunctionProtoType * T